#!/bin/bash # milestone-create.sh - Create milestones on Gitea or GitHub # Usage: milestone-create.sh -t "Title" [-d "Description"] [--due "YYYY-MM-DD"] set -e set -o pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/detect-platform.sh" # Default values TITLE="" DESCRIPTION="" DUE_DATE="" LIST_ONLY=false usage() { cat <&2 usage >&2 } while [[ $# -gt 0 ]]; do case $1 in -t|--title) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)" TITLE="$2" shift 2 ;; -d|--desc) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)" DESCRIPTION="$2" shift 2 ;; --due) [[ $# -ge 2 && "$2" != - && "$2" != --* && ! "$2" =~ ^-[[:alnum:]] ]] || usage_error "option $1 requires a value (option-like values are rejected; bare - is reserved)" DUE_DATE="$2" shift 2 ;; --list) LIST_ONLY=true shift ;; -h|--help) usage 0 ;; *) echo "Unknown option: $1" >&2 usage ;; esac done PLATFORM=$(detect_platform) if [[ "$LIST_ONLY" == true ]]; then case "$PLATFORM" in github) prov_rc=0 gh api repos/:owner/:repo/milestones --jq '.[] | "\(.number)\t\(.title)\t\(.state)\t\(.open_issues)/\(.closed_issues) issues"' || prov_rc=$? [[ "$prov_rc" -eq 0 ]] || { echo "Error: provider command failed (exit ${prov_rc}; provider failure, not a usage error)" >&2; exit 1; } ;; gitea) REPO_ARGS=$(get_gitea_repo_args) || { echo "Error: Could not resolve Gitea repo/login for remote host" >&2 exit 1 } prov_rc=0 tea milestones list $REPO_ARGS || prov_rc=$? [[ "$prov_rc" -eq 0 ]] || { echo "Error: provider command failed (exit ${prov_rc}; provider failure, not a usage error)" >&2; exit 1; } ;; *) echo "Error: Could not detect git platform" >&2 exit 1 ;; esac exit 0 fi if [[ -z "$TITLE" ]]; then usage_error "Title is required (-t) for creating milestones" fi case "$PLATFORM" in github) # GitHub uses the API for milestone creation # Use jq to safely construct JSON so titles/descriptions containing # quotes or special characters do not corrupt the payload (F-07). JSON_PAYLOAD=$(jq -n \ --arg t "$TITLE" \ --arg d "$DESCRIPTION" \ --arg due "${DUE_DATE}" \ '{"title": $t} + (if $d != "" then {"description": $d} else {} end) + (if $due != "" then {"due_on": ($due + "T00:00:00Z")} else {} end)') prov_rc=0 gh api repos/:owner/:repo/milestones --method POST --input - <<< "$JSON_PAYLOAD" || prov_rc=$? [[ "$prov_rc" -eq 0 ]] || { echo "Error: provider command failed (exit ${prov_rc}; provider failure, not a usage error)" >&2; exit 1; } echo "Milestone '$TITLE' created successfully" ;; gitea) REPO_ARGS=$(get_gitea_repo_args) || { echo "Error: Could not resolve Gitea repo/login for remote host" >&2 exit 1 } CMD=(tea milestones create --title "$TITLE") [[ -n "$DESCRIPTION" ]] && CMD+=(--description "$DESCRIPTION") [[ -n "$DUE_DATE" ]] && CMD+=(--deadline "$DUE_DATE") prov_rc=0 "${CMD[@]}" $REPO_ARGS || prov_rc=$? [[ "$prov_rc" -eq 0 ]] || { echo "Error: provider command failed (exit ${prov_rc}; provider failure, not a usage error)" >&2; exit 1; } echo "Milestone '$TITLE' created successfully" ;; *) echo "Error: Could not detect git platform" >&2 exit 1 ;; esac