CI: Add release-drafter workflow/config 90/73690/1
authorMatthew Watkins <mwatkins@linuxfoundation.org>
Wed, 8 Oct 2025 11:25:45 +0000 (12:25 +0100)
committerMatthew Watkins <mwatkins@linuxfoundation.org>
Wed, 8 Oct 2025 11:25:45 +0000 (12:25 +0100)
- Automatically creates GitHub draft releases
- Amend release.yaml to promote draft release on tag push

Change-Id: Ia8d95253aa5a03bf59ccb7b45d7dfea28e47c16e
Signed-off-by: Matthew Watkins <mwatkins@linuxfoundation.org>
.github/release-drafter.yml [new file with mode: 0644]
.github/workflows/release-drafter.yaml [new file with mode: 0644]
.github/workflows/release.yaml

diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
new file mode 100644 (file)
index 0000000..7bbe8b1
--- /dev/null
@@ -0,0 +1,70 @@
+---
+# SPDX-FileCopyrightText: 2021 Andrew Grimberg <tykeal@bardicgrove.org>
+# SPDX-License-Identifier: Apache-2.0
+
+name-template: "v$RESOLVED_VERSION"
+tag-template: "v$RESOLVED_VERSION"
+change-template: "- $TITLE @$AUTHOR (#$NUMBER)"
+sort-direction: ascending
+categories:
+  - title: ":boom: Breaking Change :boom:"
+    labels:
+      - "breaking-change"
+  - title: ":zap: Enhancements :zap:"
+    labels:
+      - "enhancement"
+  - title: ":sparkles: New Features :sparkles:"
+    labels:
+      - "feature"
+  - title: ":bug: Bug Fixes :bug:"
+    labels:
+      - "fix"
+      - "bugfix"
+      - "bug"
+  - title: ":wrench: Maintenance :wrench:"
+    labels:
+      - "chore"
+      - "documentation"
+      - "maintenance"
+      - "repo"
+      - "dependencies"
+      - "github_actions"
+      - "refactor"
+  - title: ":mortar_board: Code Quality :mortar_board:"
+    labels:
+      - "code-quality"
+      - "CI"
+      - "test"
+autolabeler:
+  - label: "breaking-change"
+    title:
+      - "/!:/i"
+  - label: "feature"
+    title:
+      - "/feat:/i"
+  - label: "bug"
+    title:
+      - "/fix:/i"
+  - label: "refactor"
+    title:
+      - "/refactor:/i"
+  - label: "code-quality"
+    title:
+      - "/test:/i"
+  - label: "CI"
+    title:
+      - "/ci:/i"
+  - label: "chore"
+    title:
+      - "/chore:/i"
+  - label: "documentation"
+    title:
+      - "/docs:/i"
+# yamllint disable rule:line-length
+template: |
+  [![Downloads for this release](https://img.shields.io/github/downloads/os-climate/osc-github-devops/v$RESOLVED_VERSION/total.svg)](https://github.com/os-climate/osc-github-devops/releases/v$RESOLVED_VERSION)
+
+  $CHANGES
+
+  ## Links
+  - [Submit bugs/feature requests](https://github.com/os-climate/osc-github-devops/issues)
diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml
new file mode 100644 (file)
index 0000000..33c0d60
--- /dev/null
@@ -0,0 +1,71 @@
+---
+# SPDX-FileCopyrightText: 2025 The Linux Foundation
+# SPDX-License-Identifier: Apache-2.0
+
+name: 'Release Drafter'
+
+"on":
+  push:
+    branches:
+      - main
+      - master
+  # pull_request is required for autolabeler
+  pull_request:
+    types:
+      - opened
+      - synchronize
+      - reopened
+  #  pull_request_target is required for autolabeler on PRs from forks
+  pull_request_target:
+    types:
+      - opened
+      - synchronize
+      - reopened
+
+permissions: {}
+
+concurrency:
+  # yamllint disable-line rule:line-length
+  group: >-
+    rd-${{ github.event_name }}-${{ github.event.number }}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  show_concurrency_group:
+    name: 'Concurrency Group'
+    runs-on: 'ubuntu-latest'
+    timeout-minutes: 2
+    steps:
+      - name: 'Concurrency Group'
+        shell: bash
+        # yamllint disable rule:line-length
+        run: |
+          #  Concurrency Group
+          echo "Concurrency group: rd-${{ github.event_name }}-${{ github.event.number }}-${{ github.ref }}"
+          #  shellcheck disable=SC2129
+          echo "## Release Drafter" \
+            >> "$GITHUB_STEP_SUMMARY"
+          echo "Concurrency group: rd-${{ github.event_name }}-${{ github.event.number }}-${{ github.ref }}" \
+            >> "$GITHUB_STEP_SUMMARY"
+
+  # yamllint enable rule:line-length
+  update_release_draft:
+    name: 'Update Release Draft'
+    permissions:
+      # write permission is required to create releases
+      contents: write
+      # write permission is required for autolabeler
+      pull-requests: write
+    runs-on: 'ubuntu-latest'
+    timeout-minutes: 3
+    steps:
+      # Harden the runner used by this workflow
+      # yamllint disable-line rule:line-length
+      - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
+        with:
+          egress-policy: 'audit'
+
+      # yamllint disable-line rule:line-length
+      - uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
+        env:
+          GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
index 02d18fb..9c665eb 100644 (file)
@@ -23,6 +23,7 @@ jobs:
     timeout-minutes: 1
     outputs:
       tag: "${{ steps.tag-validate.outputs.tag }}"
+      should_promote: "${{ steps.check-release.outputs.should_promote }}"
     steps:
       # Harden the runner used by this workflow
       # yamllint disable-line rule:line-length
@@ -47,6 +48,32 @@ jobs:
             >> "$GITHUB_STEP_SUMMARY"
           exit 1
 
+      - name: 'Check if release exists'
+        id: 'check-release'
+        shell: bash
+        env:
+          GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+        run: |
+          TAG="${{ steps.tag-validate.outputs.tag }}"
+
+          # Check if release exists and get its draft status
+          if RELEASE_INFO=$(gh release view "$TAG" --json isDraft \
+              2>/dev/null); then
+            IS_DRAFT=$(echo "$RELEASE_INFO" | jq -r '.isDraft')
+            if [ "$IS_DRAFT" = "false" ]; then
+              echo "should_promote=false" >> "$GITHUB_OUTPUT"
+              echo "Published release already exists for tag $TAG, " \
+                   "skipping promotion"
+            else
+              echo "should_promote=true" >> "$GITHUB_OUTPUT"
+              echo "Draft release exists for tag $TAG, " \
+                   "will proceed with promotion"
+            fi
+          else
+            echo "should_promote=true" >> "$GITHUB_OUTPUT"
+            echo "No release found for tag $TAG, will proceed with promotion"
+          fi
+
   python-build:
     name: 'Python Build'
     needs: 'tag-validate'
@@ -133,7 +160,6 @@ jobs:
         uses: lfreleng-actions/python-audit-action@bab5316468c108870eb759ef0de622bae9239aad # v0.2.2
         with:
           python_version: "${{ matrix.python-version }}"
-          permit_fail: 'true'
 
   test-pypi:
     name: 'Test PyPI Publishing'
@@ -197,6 +223,67 @@ jobs:
           tag: "${{ needs.tag-validate.outputs.tag }}"
           pypi_credential: "${{ secrets.PYPI_CREDENTIAL }}"
 
+
+  promote-release:
+    name: 'Promote Draft Release'
+    # yamllint disable-line rule:line-length
+    if: needs.tag-validate.outputs.should_promote == 'true'
+    needs:
+      - 'tag-validate'
+      - 'pypi'
+    runs-on: 'ubuntu-latest'
+    permissions:
+      contents: write # IMPORTANT: needed to edit a draft release and promote it
+    timeout-minutes: 2
+    outputs:
+      release_url: "${{ steps.promote-release.outputs.release_url }}"
+    steps:
+      # Harden the runner used by this workflow
+      # yamllint disable-line rule:line-length
+      - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
+        with:
+          egress-policy: 'audit'
+
+      # yamllint disable-line rule:line-length
+      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+
+      - name: 'Check if release is already promoted'
+        id: 'check-promoted'
+        shell: bash
+        env:
+          GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+        run: |
+          TAG="${{ needs.tag-validate.outputs.tag }}"
+          if gh release view "$TAG" --json isDraft --jq '.isDraft' \
+              2>/dev/null | grep -q "false"; then
+            echo "Release $TAG is already promoted, skipping promotion"
+            echo "already_promoted=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "Release $TAG is draft or doesn't exist, " \
+                 "proceeding with promotion"
+            echo "already_promoted=false" >> "$GITHUB_OUTPUT"
+          fi
+
+      - name: 'Promote draft release'
+        id: 'promote-release'
+        if: steps.check-promoted.outputs.already_promoted == 'false'
+        # yamllint disable-line rule:line-length
+        uses: lfreleng-actions/draft-release-promote-action@d7e7df12e32fa26b28dbc2f18a12766482785399 # v0.1.2
+        with:
+          token: "${{ secrets.GITHUB_TOKEN }}"
+          tag: "${{ needs.tag-validate.outputs.tag }}"
+          latest: true
+
+      - name: 'Set release URL for already promoted release'
+        if: steps.check-promoted.outputs.already_promoted == 'true'
+        shell: bash
+        env:
+          GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+        run: |
+          TAG="${{ needs.tag-validate.outputs.tag }}"
+          RELEASE_URL=$(gh release view "$TAG" --json url --jq '.url')
+          echo "release_url=$RELEASE_URL" >> "$GITHUB_OUTPUT"
+
   # Need to attach build artefacts to the release
   # This step could potentially be moved
   # (May be better to when/where the release is still in draft state)
@@ -206,8 +293,9 @@ jobs:
     needs:
       - 'tag-validate'
       - 'python-build'
-      - 'test-pypi'
-      - 'pypi'
+      - 'promote-release'
+    # yamllint disable-line rule:line-length
+    if: always() && (needs.promote-release.result == 'success' || needs.promote-release.result == 'skipped')
     permissions:
       contents: write # IMPORTANT: needed to edit release, attach artefacts
     timeout-minutes: 5