From 9d2906203e30de7d89b079bfc041e3baab842418 Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Fri, 22 Jul 2022 13:39:28 -0400
Subject: [PATCH] first attempt at develop-to-production merge bot

---
 .gitlab-ci.yml             | 10 +++++
 ci-tools/update-production | 87 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)
 create mode 100644 ci-tools/update-production

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 210486ac..a1ac2ba2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -167,3 +167,13 @@ update-nixpkgs:
               "$CI_PROJECT_PATH" \
               "$CI_PROJECT_ID" \
               "$CI_DEFAULT_BRANCH"
+
+update-production:
+  <<: *RUN_ON_MERGE_REQUEST
+  script:
+    - |
+      ./ci-tools/update-production \
+              "$CI_SERVER_URL" \
+              "$CI_PROJECT_ID" \
+              "develop" \
+              "production
diff --git a/ci-tools/update-production b/ci-tools/update-production
new file mode 100644
index 00000000..e7cd557f
--- /dev/null
+++ b/ci-tools/update-production
@@ -0,0 +1,87 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i bash -p git curl
+
+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
+
+    # If there have been no changes we'll just abandon this update.
+    ensure_changes "$SOURCE_BRANCH" "$TARGET_BRANCH"
+
+    local NOTES=$(compute_notes_diff "$SOURCE_BRANCH" "$TARGET_BRANCH")
+
+    create_merge_request "$TOKEN" "$SERVER_URL" "$PROJECT_ID" "$SOURCE_BRANCH" "$TARGET_BRANCH" "$NOTES"
+}
+
+ensure_changes() {
+    local SOURCE_BRANCH=$1
+    shift
+    local TARGET_BRANCH=$1
+    shift
+
+    if [ $(git rev-parse "$SOURCE_BRANCH") -eq $(git rev-parse "$TARGET_BRANCH") ]; then
+	echo "No changes."
+	exit 0
+    fi
+}
+
+compute_notes_diff() {
+    local SOURCE_BRANCH=$1
+    shift
+    local TARGET_BRANCH=$1
+    shift
+
+    git diff origin/"$SOURCE_BRANCH"...origin/"$TARGET_BRANCH" -- DEPLOYMENT-NOTES.rst
+}
+
+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": f"```diff\n{sys.argv[4]}\n```",
+}))
+' "$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.
+TOKEN="$UPDATE_PRODUCTION_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_PRODUCTION_PRIVATE_TOKEN
+
+main "$TOKEN" "$@"
-- 
GitLab