Newer
Older
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p git curl python3
set -eux -o pipefail
main() {
local TOKEN=$1
shift
local SERVER_URL=$1
shift
local PROJECT_ID=$1
shift
local SOURCE_BRANCH=$1
shift
local TARGET_BRANCH=$1
shift
# Make sure the things we want to talk about are locally known. GitLab
# seems to prefer to know about as few refs as possible.
checkout_git_ref "$SOURCE_BRANCH"
checkout_git_ref "$TARGET_BRANCH"
# If there have been no changes we'll just abandon this update.
if ! ensure_changes "$SOURCE_BRANCH" "$TARGET_BRANCH"; then
echo "No changes."
exit 0
fi
local NOTES=$(describe_update "$SOURCE_BRANCH" "$TARGET_BRANCH")
create_merge_request "$TOKEN" "$SERVER_URL" "$PROJECT_ID" "$SOURCE_BRANCH" "$TARGET_BRANCH" "$NOTES"
}
checkout_git_ref() {
local REF=$1
shift
git fetch origin "$REF"
}
ensure_changes() {
local SOURCE_BRANCH=$1
shift
local TARGET_BRANCH=$1
shift
if [ "$(git rev-parse origin/"$SOURCE_BRANCH")" = "$(git rev-parse origin/"$TARGET_BRANCH")" ]; then
return 1
describe_merge_request() {
git show $rev | grep 'See merge request' | sed -e 's/See merge request //' | tr -d '[:space:]'
}
describe_merge_requests() {
local RANGE=$1
shift
local TARGET=$1
shift
# Find all of the relevant merge revisions
local onelines=$(git log --merges --first-parent -m --oneline "$RANGE" | grep "into '$TARGET'")
# Describe each merge revision
local IFS=$'\n'
for line in $onelines; do
local rev=$(echo "$line" | cut -d ' ' -f 1)
echo -n "* "
describe_merge_request $rev
echo
done
}
local SOURCE_BRANCH=$1
shift
local TARGET_BRANCH=$1
shift
# Since production production (target) should not diverge from develop
# (source) it is fine to use `..` instead of `...` in the git ranges here.
# `...` encounters problems related to discovering the merge base because
# of the way GitLab manages the git checkout on CI (I think).
local NOTES=$(git diff origin/"$TARGET_BRANCH"..origin/"$SOURCE_BRANCH" -- DEPLOYMENT-NOTES.rst)
# There often are no notes and that makes for boring reading so toss in a
# diffstat as well.
local DIFFSTAT=$(git diff --stat origin/"$TARGET_BRANCH"..origin/"$SOURCE_BRANCH")
local WHEN=$(git log --max-count=1 --format='%cI' origin/"$TARGET_BRANCH")
# Describe all of the MRs that were merged into the source branch that are
# about to be merged into the target branch.
local MR=$(describe_merge_requests origin/"$TARGET_BRANCH"..origin/"$SOURCE_BRANCH" "$SOURCE_BRANCH")
echo "\
Changes from $SOURCE_BRANCH since $WHEN
=======================================
Deployment Notes
----------------
\`\`\`
$NOTES
\`\`\`
Included Merge Requests
-----------------------
$MR
Diff Stat
---------
\`\`\`
$DIFFSTAT
\`\`\`
"
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
}
create_merge_request() {
local TOKEN=$1
shift
local SERVER_URL=$1
shift
local PROJECT_ID=$1
shift
# THe source branch of the MR.
local SOURCE_BRANCH=$1
shift
# The target branch of the MR.
local TARGET_BRANCH=$1
shift
local NOTES=$1
shift
local BODY=$(python3 -c '
import sys, json
print(json.dumps({
"id": sys.argv[1],
"source_branch": sys.argv[2],
"target_branch": sys.argv[3],
"remove_source_branch": True,
"title": f"update {sys.argv[3]}",
"description": sys.argv[4],
}))
' "$PROJECT_ID" "$SOURCE_BRANCH" "$TARGET_BRANCH" "$NOTES")
curl --verbose -X POST --data "${BODY}" --header "Content-Type: application/json" --header "PRIVATE-TOKEN: ${TOKEN}" "${SERVER_URL}/api/v4/projects/${PROJECT_ID}/merge_requests"
}
# Pull the GitLab token from the environment here so we can work with them as
# arguments everywhere else. They're passed to us in the environment because
# *maybe* this is *slightly* safer than passing them in argv.
#
# The name is slightly weird because it is shared with the update-nixpkgs job.
TOKEN="$UPDATE_NIXPKGS_PRIVATE_TOKEN"
# Before proceeding, remove the secrets from our environment so we don't pass
# them to child processes - none of which need them.
unset UPDATE_NIXPKGS_PRIVATE_TOKEN
main "$TOKEN" "$@"