From 900fb3f88bba8c46baec938d4a9342b95635cbda Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Wei=C3=9Fe?=
 <66256922+daniel-weisse@users.noreply.github.com>
Date: Wed, 27 Nov 2024 08:52:54 +0100
Subject: [PATCH] ci: automate manual post-release steps (#3498)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Daniel Weiße <dw@edgeless.systems>
---
 .github/workflows/release-publish.yml | 79 +++++++++++++++++++++++++++
 .github/workflows/release.yml         | 36 ++++++++++--
 dev-docs/workflows/release.md         | 18 +++---
 3 files changed, 116 insertions(+), 17 deletions(-)
 create mode 100644 .github/workflows/release-publish.yml

diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml
new file mode 100644
index 0000000000..2699b08955
--- /dev/null
+++ b/.github/workflows/release-publish.yml
@@ -0,0 +1,79 @@
+name: 'Release: on-publish'
+
+on:
+  release:
+    types:
+      - published
+  workflow_dispatch:
+    inputs:
+      tag:
+        description: 'Semantic version tag of the release (vX.Y.Z).'
+        required: true
+
+jobs:
+  post-release-actions:
+    runs-on: ubuntu-24.04
+    permissions:
+      issues: write
+    env:
+      FULL_VERSION: ${{ github.event.release.tag_name }}${{ github.event.inputs.tag }}
+      GH_TOKEN: ${{ github.token }}
+    steps:
+      - name: Mark milestone as complete
+        run: |
+          milestones=$(gh api \
+            -H "Accept: application/vnd.github+json" \
+            -H "X-GitHub-Api-Version: 2022-11-28" \
+            /repos/edgelesssys/constellation/milestones)
+
+          current_milestone=$(echo "${milestones}" | jq -r ".[] | select(.title == \"${FULL_VERSION}\")")
+          echo "current milestone: ${current_milestone}"
+          if [[ -z "${current_milestone}" ]]; then
+            echo "milestone ${FULL_VERSION} does not exist, nothing to do..."
+            exit 0
+          fi
+
+          current_milestone_state=$(echo "${current_milestone}" | jq -r '.state')
+          echo "current milestone state: ${current_milestone_state}"
+          if [[ "${current_milestone_state}" != "open" ]]; then
+            echo "milestone ${FULL_VERSION} is already closed, nothing to do..."
+            exit 0
+          fi
+
+          milestone_number=$(echo "${current_milestone}" | jq -r '.number')
+          echo "milestone number: ${milestone_number}"
+          if [[ -z "${milestone_number}" ]]; then
+            echo "failed parsing milestone number"
+            exit 1
+          fi
+
+          gh api \
+            --method PATCH \
+            -H "Accept: application/vnd.github+json" \
+            -H "X-GitHub-Api-Version: 2022-11-28" \
+            "/repos/edgelesssys/constellation/milestones/${milestone_number}" \
+            -f state=closed
+
+      - name: Create next milestone
+        run: |
+          WITHOUT_V=${FULL_VERSION#v}
+          PART_MAJOR=${WITHOUT_V%%.*}
+          PART_MINOR=${WITHOUT_V#*.}
+          PART_MINOR=${PART_MINOR%%.*}
+          NEXT_MINOR=v${PART_MAJOR}.$((PART_MINOR + 1)).0
+
+          gh api \
+            -H "Accept: application/vnd.github+json" \
+            -H "X-GitHub-Api-Version: 2022-11-28" \
+            /repos/edgelesssys/constellation/milestones |
+            jq -r '.[].title' | \
+            grep -xqF "${NEXT_MINOR}" && exit 0
+
+          gh api \
+            --method POST \
+            -H "Accept: application/vnd.github+json" \
+            -H "X-GitHub-Api-Version: 2022-11-28" \
+            /repos/edgelesssys/constellation/milestones \
+            -f title="${NEXT_MINOR}" \
+            -f state='open' \
+            -f "due_on=$(date -d '2 months' +'%Y-%m-%dT00:00:00Z')"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 63c29d9339..6b1f3acc11 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -72,10 +72,9 @@ jobs:
             echo "WORKING_BRANCH=${WORKING_BRANCH}"
           } | tee -a "$GITHUB_OUTPUT"
 
-  docs:
-    name: Create docs release (from main)
+  update-main-branch:
+    name: Update main branch with release changes
     runs-on: ubuntu-24.04
-    if: inputs.kind == 'minor'
     needs: verify-inputs
     permissions:
       contents: write
@@ -89,26 +88,51 @@ jobs:
         with:
           ref: main
 
+      - name: Configure git
+        run: |
+          git config --global user.name "edgelessci"
+          git config --global user.email "edgelessci@users.noreply.github.com"
+
       - name: Create docs release
+        if: inputs.kind == 'minor'
         working-directory: docs
         run: |
           npm ci
           npm run docusaurus docs:version "${MAJOR_MINOR}"
+          git add .
+          git commit -am "docs: release ${MAJOR_MINOR}"
+          # Clean up auxiliary files, so next steps run on a clean tree
+          git clean -fdx :/
+
+      - name: Update version.txt
+        if: inputs.kind == 'minor'
+        run: |
+          pre_release_version="v${{ needs.verify-inputs.outputs.PART_MAJOR }}.$((${{ needs.verify-inputs.outputs.PART_MINOR }} + 1)).0-pre"
+          echo "${pre_release_version}" > version.txt
+          git add version.txt
+          git commit -m "chore: update version.txt to ${pre_release_version}"
+
+      - name: Update CI for new version
+        run: |
+          sed -i 's/fromVersion: \["[^"]*"\]/fromVersion: ["${{ inputs.version }}"]/g' .github/workflows/e2e-test-release.yml
+          sed -i 's/fromVersion: \["[^"]*"\]/fromVersion: ["${{ inputs.version }}"]/g' .github/workflows/e2e-test-weekly.yml
 
       - name: Create docs pull request
         uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
         with:
           branch: ${{ env.BRANCH }}
           base: main
-          title: "docs: add release ${{ env.VERSION }}"
+          title: "Post ${{ env.VERSION }} release updates to main"
           body: |
             :robot: *This is an automated PR.* :robot:
 
             The PR is triggered as part of the automated release process of version ${{ env.VERSION }}.
-            It releases a new version of the documentation.
-          commit-message: "docs: add release ${{ env.VERSION }}"
+          commit-message: "chore: update CI for ${{ env.VERSION }}"
           committer: edgelessci <edgelessci@users.noreply.github.com>
+          author: edgelessci <edgelessci@users.noreply.github.com>
           labels: no changelog
+          assignees: ${{ github.actor }}
+          reviewers: ${{ github.actor }}
           # We need to push changes using a token, otherwise triggers like on:push and on:pull_request won't work.
           token: ${{ !github.event.pull_request.head.repo.fork && secrets.CI_COMMIT_PUSH_PR || '' }}
 
diff --git a/dev-docs/workflows/release.md b/dev-docs/workflows/release.md
index f250b340a5..be873d5634 100644
--- a/dev-docs/workflows/release.md
+++ b/dev-docs/workflows/release.md
@@ -85,17 +85,9 @@ Releases should be performed using [the automated release pipeline](https://gith
 ## Post release steps
 
 1. Publish the [provider release](https://github.com/edgelesssys/terraform-provider-constellation/releases)
-2. Merge the versioned docs PR
-3. Close fixed "known issues"
-4. Milestones management
-   1. Create a new milestone for the next release
-   2. Add the next release manager and an approximate release date to the milestone description
-   3. Close the milestone for the release
-   4. Move open issues and PRs from closed milestone to next milestone
-5. If the release is a minor version release, bump the pre-release version in the `version.txt` file.
-6. Update the `fromVersion` in `e2e-test-release.yml` and `e2e-test-weekly.yaml` to the newly released version. To check the current values, run: `grep "fromVersion: \[.*\]" -R .github`.
-7. Reset `UpgradeRequiresIAMMigration`  in [`iamupgrade.go`](https://github.com/edgelesssys/constellation/blob/a88a731576184e3c5ee8527741c4a0cdaa4e9b24/cli/internal/cloudcmd/iamupgrade.go#L23).
-8. Write an email to STACKIT to inform them of the new relase. For this, you require the name and UUID of the release image. You can find the email address in our internal [wiki](https://github.com/edgelesssys/wiki/blob/master/documentation/constellation/stackit.md):
+2. Merge the automated post release PR
+3. Write an email to STACKIT to inform them of the new release. For this, you require the name and UUID of the release image. You can find the email address in our internal [wiki](https://github.com/edgelesssys/wiki/blob/master/documentation/constellation/stackit.md):
+
     ```shell-session
     export OS_CLOUD=stackit
     openstack image list | grep constellation
@@ -103,6 +95,10 @@ Releases should be performed using [the automated release pipeline](https://gith
     # | 25edf48d-161f-452b-b420-963c3a80abd8 | constellation-stable-v2.16.4-qemu-vtpm | active |
     ```
 
+4. Close fixed "known issues"
+5. Move open issues and PRs from this release's closed milestone to next milestone
+6. Reset `UpgradeRequiresIAMMigration`  in [`iamupgrade.go`](https://github.com/edgelesssys/constellation/blob/a88a731576184e3c5ee8527741c4a0cdaa4e9b24/cli/internal/cloudcmd/iamupgrade.go#L23).
+
 ## Troubleshooting: Pipeline cleanup
 
 No manual steps should be necessary anymore but in case you encounter issues, create a ticket to fix it. These are instructions to do some cleanup steps manually: