diff --git a/.github/workflows/release-finish.yml b/.github/workflows/release-finish.yml new file mode 100644 index 0000000..6dabf39 --- /dev/null +++ b/.github/workflows/release-finish.yml @@ -0,0 +1,66 @@ +# Reusable workflow — publishes a draft release or deletes it on failure. +# Pair with release-start.yml: call this after your gate jobs succeed or fail. +--- +name: Release - Finish + +on: + workflow_call: + inputs: + runs-on: + description: | + JSON array of runner(s) to use. + See https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job. + type: string + default: '["ubuntu-latest"]' + required: false + tag: + description: "The tag of the draft release to publish or delete (output of the release-start.yml workflow)." + type: string + required: true + publish: + description: "Set to true to publish the draft, false to delete it." + type: boolean + default: true + required: false + +permissions: {} + +jobs: + publish: + if: ${{ !inputs.publish }} + name: Publish draft release + runs-on: ${{ fromJson(inputs.runs-on) }} + permissions: + contents: write + steps: + - id: local-workflow-actions + uses: hoverkraft-tech/ci-github-common/actions/local-workflow-actions@f24ce3360a8abf9bf386a62ab13d0ae5de5f9d13 # 0.31.7 + with: + actions-path: actions + + - id: create-release + uses: ./self-workflow/actions/release/create + with: + publish: true + tag: ${{ inputs.tag }} + + # jscpd:ignore-start + - uses: hoverkraft-tech/ci-github-common/actions/local-workflow-actions@f24ce3360a8abf9bf386a62ab13d0ae5de5f9d13 # 0.31.7 + if: always() && steps.local-workflow-actions.outputs.repository + with: + actions-path: actions + repository: ${{ steps.local-workflow-actions.outputs.repository }} + ref: ${{ steps.local-workflow-actions.outputs.ref }} + # jscpd:ignore-end + cancel: + if: ${{ inputs.publish }} + name: Cancel release + runs-on: ${{ fromJson(inputs.runs-on) }} + permissions: + contents: write + steps: + - env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + shell: bash + run: gh release delete "${{ inputs.tag }}" --cleanup-tag --yes diff --git a/.github/workflows/release-start.md b/.github/workflows/release-start.md new file mode 100644 index 0000000..561f5f3 --- /dev/null +++ b/.github/workflows/release-start.md @@ -0,0 +1,110 @@ + + +# GitHub Workflow: Release - Start + +
+ Release +
+ +--- + + + + +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-publish)](https://github.com/hoverkraft-tech/ci-github-publish/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-publish)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-publish?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-publish?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-publish/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Reusable release workflow +This workflow delegates release tasks by reusing a shared release workflow, ensuring standardized publishing across projects. + +### Permissions + +- **`contents`**: `write` +- **`id-token`**: `write` +- **`pull-requests`**: `read` + + + + +## Usage + +```yaml +name: Release +on: + push: + branches: + - main +permissions: {} +jobs: + release: + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-start.yml@84e8ace407055e7a40ba6670a8c697e1ce2dfafa # 0.20.1 + permissions: {} + with: + # JSON array of runner(s) to use. + # See https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job. + # + # Default: `["ubuntu-latest"]` + runs-on: '["ubuntu-latest"]' + + # Whether to mark the release as a prerelease + # See ../../actions/release/create/README.md for more information. + prerelease: false +``` + + + + +## Inputs + +### Workflow Dispatch Inputs + +| **Input** | **Description** | **Required** | **Type** | **Default** | +| ---------------- | ---------------------------------------------------------------------------------- | ------------ | ----------- | ------------------- | +| **`runs-on`** | JSON array of runner(s) to use. | **false** | **string** | `["ubuntu-latest"]` | +| | See . | | | | +| **`prerelease`** | Whether to mark the release as a prerelease | **false** | **boolean** | `false` | +| | See ../../actions/release/create/README.md for more information. | | | | + + + + + + + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-publish/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright © 2026 hoverkraft-tech + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + diff --git a/.github/workflows/release.yml b/.github/workflows/release-start.yml similarity index 63% rename from .github/workflows/release.yml rename to .github/workflows/release-start.yml index 06903e6..a4e2abd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release-start.yml @@ -1,9 +1,29 @@ -# Reusable release workflow -# This workflow delegates release tasks by reusing a shared release workflow, ensuring standardized publishing across projects. +# Reusable release workflow — creates a draft release and outputs the tag. +# Pair with release-finish.yml to publish or delete the draft after running your own gate. --- -name: Release +name: Release - Start on: + workflow_call: + inputs: + runs-on: + description: | + JSON array of runner(s) to use. + See https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job. + type: string + default: '["ubuntu-latest"]' + required: false + prerelease: + description: | + Whether to mark the release as a prerelease. + See ../../actions/release/create/README.md for more information. + type: boolean + default: false + required: false + outputs: + tag: + description: "The tag of the draft release." + value: ${{ jobs.release.outputs.tag }} workflow_dispatch: inputs: #checkov:skip=CKV_GHA_7: required @@ -16,7 +36,7 @@ on: required: false prerelease: description: | - Whether to mark the release as a prerelease + Whether to mark the release as a prerelease. See ../../actions/release/create/README.md for more information. type: boolean default: false @@ -44,6 +64,7 @@ jobs: uses: ./self-workflow/actions/release/create with: prerelease: ${{ inputs.prerelease }} + publish: false # jscpd:ignore-start - uses: hoverkraft-tech/ci-github-common/actions/local-workflow-actions@f24ce3360a8abf9bf386a62ab13d0ae5de5f9d13 # 0.31.7 diff --git a/.github/workflows/release.md b/.github/workflows/release.md index 0852868..111f5c4 100644 --- a/.github/workflows/release.md +++ b/.github/workflows/release.md @@ -1,110 +1,184 @@ - +# Release — combining `release-start` and `release-finish` -# GitHub Workflow: Release +The release process is split into two composable reusable workflows: -
- Release -
+| Workflow | Purpose | +| ----------------------------------------- | --------------------------------------------------------------------------------------- | +| [`release-start.yml`](release-start.md) | Creates a **draft** release via Release Drafter and outputs the `tag`. | +| [`release-finish.yml`](release-finish.md) | **Publishes** the draft (or **deletes** it). Controlled by the `publish` boolean input. | ---- - - - - -[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-publish)](https://github.com/hoverkraft-tech/ci-github-publish/releases) -[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-publish)](http://choosealicense.com/licenses/mit/) -[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-publish?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-publish?style=social) -[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-publish/blob/main/CONTRIBUTING.md) - - - +Between them, you own the **gate**: any job(s) you want to run before deciding whether to publish. GitHub Actions `needs` wires it all together — no polling, no scripting. -## Overview - -Reusable release workflow -This workflow delegates release tasks by reusing a shared release workflow, ensuring standardized publishing across projects. - -### Permissions +```txt +release-start → [your gate job(s)] → release-finish + ↓ ↑ + outputs tag publish: gate succeeded? +``` -- **`contents`**: `write` -- **`id-token`**: `write` -- **`pull-requests`**: `read` +--- - - +## Use case 1 — no gate (publish immediately) -## Usage +The simplest setup: draft is published right away. ```yaml -name: Release -on: - push: - branches: - - main -permissions: {} jobs: - release: - uses: hoverkraft-tech/ci-github-publish/.github/workflows/release.yml@84e8ace407055e7a40ba6670a8c697e1ce2dfafa # 0.20.1 - permissions: {} + start: + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-start.yml@main + permissions: + contents: write + pull-requests: read + id-token: write + + finish: + needs: start + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-finish.yml@main + permissions: + contents: write with: - # JSON array of runner(s) to use. - # See https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job. - # - # Default: `["ubuntu-latest"]` - runs-on: '["ubuntu-latest"]' - - # Whether to mark the release as a prerelease - # See ../../actions/release/create/README.md for more information. - prerelease: false + tag: ${{ needs.start.outputs.tag }} + publish: true ``` - - - -## Inputs - -### Workflow Dispatch Inputs +--- -| **Input** | **Description** | **Required** | **Type** | **Default** | -| ---------------- | ---------------------------------------------------------------------------------- | ------------ | ----------- | ------------------- | -| **`runs-on`** | JSON array of runner(s) to use. | **false** | **string** | `["ubuntu-latest"]` | -| | See . | | | | -| **`prerelease`** | Whether to mark the release as a prerelease | **false** | **boolean** | `false` | -| | See ../../actions/release/create/README.md for more information. | | | | +## Use case 2 — gate: automated test suite - - - - - - - - +Run your test suite before committing to publish. If tests fail, the draft is deleted. -## Contributing +```yaml +jobs: + start: + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-start.yml@main + permissions: + contents: write + pull-requests: read + id-token: write + + tests: + needs: start + uses: ./.github/workflows/tests.yml # your own workflow + + finish: + needs: [start, tests] + if: always() && needs.start.result == 'success' + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-finish.yml@main + permissions: + contents: write + with: + tag: ${{ needs.start.outputs.tag }} + publish: ${{ needs.tests.result == 'success' }} +``` -Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-publish/blob/main/CONTRIBUTING.md) for more details. +--- - - - - +## Use case 3 — gate: deploy to staging and run smoke tests -## License +Draft a release, deploy it to staging with the candidate tag, run smoke tests, then decide. -This project is licensed under the MIT License. +```yaml +jobs: + start: + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-start.yml@main + permissions: + contents: write + pull-requests: read + id-token: write + + deploy-staging: + needs: start + uses: ./.github/workflows/deploy.yml + with: + environment: staging + tag: ${{ needs.start.outputs.tag }} + + smoke-tests: + needs: deploy-staging + uses: ./.github/workflows/smoke-tests.yml + + finish: + needs: [start, smoke-tests] + if: always() && needs.start.result == 'success' + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-finish.yml@main + permissions: + contents: write + with: + tag: ${{ needs.start.outputs.tag }} + publish: ${{ needs.smoke-tests.result == 'success' }} +``` -SPDX-License-Identifier: MIT +--- -Copyright © 2026 hoverkraft-tech +## Use case 4 — gate: manual approval via environment protection -For more details, see the [license](http://choosealicense.com/licenses/mit/). +Use a GitHub [environment with required reviewers](https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-deployments/managing-environments-for-deployment#required-reviewers) to gate the publish step. - - +```yaml +jobs: + start: + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-start.yml@main + permissions: + contents: write + pull-requests: read + id-token: write + + approve: + needs: start + runs-on: ubuntu-latest + environment: production # ← reviewers must approve before this job runs + steps: + - run: echo "Approved for ${{ needs.start.outputs.tag }}" + + finish: + needs: [start, approve] + if: always() && needs.start.result == 'success' + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-finish.yml@main + permissions: + contents: write + with: + tag: ${{ needs.start.outputs.tag }} + publish: ${{ needs.approve.result == 'success' }} +``` --- -This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). +## Use case 5 — gate: multiple parallel gates - +Run several independent checks in parallel; publish only if all pass. + +```yaml +jobs: + start: + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-start.yml@main + permissions: + contents: write + pull-requests: read + id-token: write + + unit-tests: + needs: start + uses: ./.github/workflows/unit-tests.yml + + integration-tests: + needs: start + uses: ./.github/workflows/integration-tests.yml + + security-scan: + needs: start + uses: ./.github/workflows/security-scan.yml + + finish: + needs: [start, unit-tests, integration-tests, security-scan] + if: always() && needs.start.result == 'success' + uses: hoverkraft-tech/ci-github-publish/.github/workflows/release-finish.yml@main + permissions: + contents: write + with: + tag: ${{ needs.start.outputs.tag }} + publish: >- + ${{ + needs.unit-tests.result == 'success' && + needs.integration-tests.result == 'success' && + needs.security-scan.result == 'success' + }} +``` diff --git a/README.md b/README.md index ba9d181..6ff38dd 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,11 @@ _Reusable workflows for managing release process._ #### - [Prepare release](.github/workflows/prepare-release.md) -#### - [Release](.github/workflows/release.md) +#### - [Release](.github/workflows/release.md) - combining start + finish + +#### - [Release - Start](.github/workflows/release-start.md) + +#### - [Release - Finish](.github/workflows/release-finish.md) #### - [Release actions](.github/workflows/release-actions.md)