CI: Update lftools release workflow 29/73629/2
authorModeSevenIndustrialSolutions <mwatkins@linuxfoundation.org>
Wed, 10 Sep 2025 08:02:24 +0000 (09:02 +0100)
committerModeSevenIndustrialSolutions <mwatkins@linuxfoundation.org>
Wed, 10 Sep 2025 15:39:55 +0000 (16:39 +0100)
Change-Id: I652bc530e9bac63f47dff7482c49484480bf87dc
Signed-off-by: ModeSevenIndustrialSolutions <mwatkins@linuxfoundation.org>
.github/workflows/release.yaml

index d3901a0..2df1644 100644 (file)
 ---
-name: PyPI release
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-FileCopyrightText: 2025 The Linux Foundation
+
+# Runs on a new pull request, performs build and runs tests
+name: 'Python Build/Test/Release'
 
 # yamllint disable-line rule:truthy
-on: push
+on:
+  # Trigger on tag push events
+  push:
+    tags:
+      - '**'
 
 permissions: {}
 
 jobs:
-  publish:
-    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
-    runs-on: ubuntu-latest
+  tag-validate:
+    name: 'Validate Tag Push'
+    runs-on: 'ubuntu-latest'
+    permissions:
+      contents: read
+    timeout-minutes: 1
+    outputs:
+      tag: "${{ steps.tag-validate.outputs.tag }}"
+    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'
+
+      - name: 'Verify Pushed Tag'
+        id: 'tag-validate'
+        # yamllint disable-line rule:line-length
+        uses: lfreleng-actions/tag-push-verify-action@80e2bdbbb9ee7b67557a31705892b75e75d2859e # v0.1.1
+        with:
+          versioning: 'semver'
+
+      - name: 'Reject Development Tags'
+        if: steps.tag-validate.outputs.dev_version == 'true'
+        shell: bash
+        run: |
+          # Reject Development Tags
+          echo "Development tag pushed; aborting release workflow ðŸ›‘"
+          echo "Development tag pushed; aborting release workflow ðŸ›‘" \
+            >> "$GITHUB_STEP_SUMMARY"
+          exit 1
+
+  python-build:
+    name: 'Python Build'
+    needs: 'tag-validate'
+    runs-on: 'ubuntu-latest'
+    outputs:
+      matrix_json: "${{ steps.python-build.outputs.matrix_json }}"
+      artefact_name: "${{ steps.python-build.outputs.artefact_name }}"
+      artefact_path: "${{ steps.python-build.outputs.artefact_path }}"
+    permissions:
+      contents: read
+      id-token: write       # Needed for attestations
+      attestations: write   # Needed for attestations
+    timeout-minutes: 12
     env:
       GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+    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: 'Build Python project'
+        id: 'python-build'
+        # yamllint disable-line rule:line-length
+        uses: lfreleng-actions/python-build-action@48381cece78a990a6ba93bd5924bcd40bf0d1a7d # v0.1.20
+        with:
+          sigstore_sign: true
+          attestations: true
+
+  python-tests:
+    name: 'Python Tests'
+    runs-on: 'ubuntu-latest'
+    needs: 'python-build'
+    # Matrix job
+    strategy:
+      fail-fast: false
+      matrix: "${{ fromJson(needs.python-build.outputs.matrix_json) }}"
     permissions:
-      contents: write
+      contents: read
+    timeout-minutes: 12
     steps:
-      - name: Checkout repository
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-      - name: Configure Python
-        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
-        with:
-          python-version: "3.8"
-      - name: Build package distribution files
-        run: >-
-          pipx run tox -e clean,build
-      - name: Configure TWINE
-        run: |
-          echo "TWINE_USERNAME=__token__" >> "$GITHUB_ENV"
-          echo "TWINE_PASSWORD=${{ secrets.PYPI_API_TOKEN }}" >> "$GITHUB_ENV"
-      - name: Publish to PyPI
-        run: >-
-          pipx run tox -e publish -- --repository pypi
-      - name: Get tag
-        id: tag
-        uses: devops-actions/action-get-tag@v1.0.2
-      - name: Convert tag
-        run: |
-          VER=$(echo "${{ steps.tag.outputs.tag }}" | tr . -)
-          echo "ANCHOR=${VER}" >> "$GITHUB_ENV"
-      - name: Generate reno report
-        run: |
-          # fetch last 30 changes
-          git fetch --depth=30
-          pipx run tox -e reno -- report \
-            --version "${{ steps.tag.outputs.tag }}" \
-            2>/dev/null > reno-notes.md || true
-          if grep -q 'reno: FAIL' reno-notes.md
-          then
-            touch modified-reno-notes.md
-          else
-            sed '/^\.pkg.*$/d' reno-notes.md |
-            sed '/^reno:.*$/d' |
-            sed '/^\.\. .*$/d' |
-            sed '$d' |
-            sed '$d' |
-            sed '1d' > modified-reno-notes.md
-          fi
-      - name: Create Release Notes
-        run: |
-          gh release create ${{ steps.tag.outputs.tag }} --generate-notes \
-            -F modified-reno-notes.md
+      # 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: 'Test Python project [PYTEST]'
+        # yamllint disable-line rule:line-length
+        uses: lfreleng-actions/python-test-action@bdde9e4e6221e858359f9036bd4f41ab3b1af90e # v0.1.11
+        with:
+          python_version: "${{ matrix.python-version }}"
+
+  python-audit:
+    name: 'Python Audit'
+    runs-on: 'ubuntu-latest'
+    needs: 'python-build'
+    # Matrix job
+    strategy:
+      fail-fast: false
+      matrix: "${{ fromJson(needs.python-build.outputs.matrix_json) }}"
+    permissions:
+      contents: read
+    timeout-minutes: 10
+    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: 'Audit Python project'
+        # yamllint disable-line rule:line-length
+        uses: lfreleng-actions/python-audit-action@bab5316468c108870eb759ef0de622bae9239aad # v0.2.2
+        with:
+          python_version: "${{ matrix.python-version }}"
+
+  test-pypi:
+    name: 'Test PyPI Publishing'
+    runs-on: 'ubuntu-latest'
+    needs:
+      - 'tag-validate'
+      - 'python-tests'
+      - 'python-audit'
+    environment:
+      name: 'development'
+    permissions:
+      contents: read
+      id-token: write # IMPORTANT: mandatory for trusted publishing
+    timeout-minutes: 5
+    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: 'Test PyPI publishing'
+        # yamllint disable-line rule:line-length
+        uses: lfreleng-actions/pypi-publish-action@81a056957ed050f8305760055b1fd8103a916989 # v0.1.1
+        with:
+          environment: 'development'
+          tag: "${{ needs.tag-validate.outputs.tag }}"
+
+  pypi:
+    name: 'Release PyPI Package'
+    runs-on: 'ubuntu-latest'
+    needs:
+      - 'tag-validate'
+      - 'test-pypi'
+    environment:
+      name: 'production'
+    permissions:
+      contents: read
+      id-token: write # IMPORTANT: mandatory for trusted publishing
+    timeout-minutes: 5
+    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: 'PyPI release'
+        # yamllint disable-line rule:line-length
+        uses: lfreleng-actions/pypi-publish-action@81a056957ed050f8305760055b1fd8103a916989 # v0.1.1
+        with:
+          environment: 'production'
+          attestations: true
+          tag: "${{ needs.tag-validate.outputs.tag }}"
+
+  promote-release:
+    name: 'Promote Draft Release'
+    # yamllint disable-line rule:line-length
+    if: startsWith(github.ref, 'refs/tags/')
+    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: 'Promote draft release'
+        id: 'promote-release'
+        # 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
+
+  # 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)
+  attach-artefacts:
+    name: 'Attach Artefacts to Release'
+    runs-on: 'ubuntu-latest'
+    needs:
+      - 'tag-validate'
+      - 'python-build'
+      - 'promote-release'
+    permissions:
+      contents: write # IMPORTANT: needed to edit release, attach artefacts
+    timeout-minutes: 5
+    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'
+
+      # Note: no need for a checkout step in this job
+
+      - name: '⬇ Download build artefacts'
+        # yamllint disable-line rule:line-length
+        uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
+        with:
+          name: "${{ needs.python-build.outputs.artefact_name }}"
+          path: "${{ needs.python-build.outputs.artefact_path }}"
+
+      - name: 'Attach build artefacts to release'
+        # yamllint disable-line rule:line-length
+        uses: alexellis/upload-assets@13926a61cdb2cb35f5fdef1c06b8b591523236d3 # 0.4.1
         env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          GITHUB_TOKEN: "${{ github.token }}"
+        with:
+          asset_paths: '["${{ needs.python-build.outputs.artefact_path }}/**"]'