Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions sbin/gh_manage_milestones
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#!/usr/bin/env bash

# ----------------------------------------------------------------------------
# (C) Crown copyright Met Office. All rights reserved.
# The file LICENCE, distributed with this code, contains details of the terms
# under which the code may be used.
# ----------------------------------------------------------------------------

# Script to create, update and close milestones in multiple GitHub repositories
# Requires GitHub CLI: https://cli.github.com/ and Admin privileges to the repos

set -euo pipefail

usage() {
cat <<EOF
Usage: ${0##*/} -t <title> [options]
-t <title> Title of milestone to be created, updated or closed.
-c Close milestone. Otherwise will create a new milestone or
update an existing milestone.
-d <due on> Milestone due date. Format: YYYY-MM-DDTHH:MM:SSZ
-p <description> Description of the milestone
-n Dry Run, print actions without making changes
-h, --help Show this help message

Examples:
# Create a new milestone
${0##*/} -t <title> [-d YYYY-MM-DDTHH:MM:SSZ] [-p <description>]

# Update all milestones with a new date
${0##*/} -t <title> -d <YYYY-MM-DDTHH:MM:SSZ>

# Close a milestone
${0##*/} -t <title> -c
EOF
exit 1
}

# -- Defaults
STATE="open"
TITLE=""
DUE=""
DESC=""
DRY_RUN=0

# -- Parse options
while getopts "t:d:p:cnh-:" opt; do
case $opt in
t) TITLE="$OPTARG" ;;
c) STATE="closed" ;;
d) DUE="$OPTARG" ;;
p) DESC="$OPTARG" ;;
n) DRY_RUN=1 ;;
h) usage ;;
-) [ "$OPTARG" = "help" ] && usage ;;
*) usage ;;
esac
done

# -- Modify milestones in relevant repositories
repos=(
"MetOffice/um"
"MetOffice/jules"
"MetOffice/lfric_apps"
"MetOffice/lfric_core"
"MetOffice/ukca"
"MetOffice/casim"
"MetOffice/socrates"
"MetOffice/um_doc"
"MetOffice/simulation-systems"
"MetOffice/SimSys_Scripts"
"MetOffice/git_playground"
)
#
# -- Helper functions
get_milestone_number(){
local repo_name="$1"
gh api /repos/"${repo_name}"/milestones --jq ".[] | select(.title == \"${TITLE}\") | .number"
}

run_command(){
local gh_command="$1"

if (( DRY_RUN )); then
echo "[DRY RUN] $gh_command"
else
eval "$gh_command"
fi
}


# -- Change milestone for each repository

for repo in "${repos[@]}"; do
echo "Processing milestone in repository: $repo"


# -- If milestone exists then fetch the number
NUMBER=$(get_milestone_number "${repo}")
if (( NUMBER )); then
echo "${TITLE} in ${repo} is milestone ${NUMBER}"
else
echo "Milestone does not exist in ${repo}"
fi

# -- Build GH command from optional arguments.
GH_COMMAND="gh api -f \"title=${TITLE}\""
if [[ ${DUE} ]]; then
GH_COMMAND=$GH_COMMAND" -f \"due_on=${DUE}\""
fi
if [[ ${DESC} ]]; then
GH_COMMAND=$GH_COMMAND" -f \"description=${DESC}\""
fi

# -- Create or update the milestone
if [[ "$STATE" == "open" ]]; then

if (( NUMBER )); then
echo "Updating milestone"
GH_COMMAND=$GH_COMMAND" --method PATCH"
GH_COMMAND=$GH_COMMAND" /repos/${repo}/milestones/${NUMBER}"
run_command "${GH_COMMAND}"
else
echo "Creating new milestone"
GH_COMMAND=$GH_COMMAND" --method POST"
GH_COMMAND=$GH_COMMAND" /repos/${repo}/milestones"
run_command "${GH_COMMAND}"
fi

# -- Close the milestone
else

if (( NUMBER )); then
echo "Closing milestone"
GH_COMMAND=$GH_COMMAND" --method PATCH"
GH_COMMAND=$GH_COMMAND" /repos/${repo}/milestones/${NUMBER}"
GH_COMMAND=$GH_COMMAND" -f \"state=closed\""
run_command "${GH_COMMAND}"
fi
fi

done