From 0dca676bd569cab4ba2098e59cdd0afdcf4702d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bru=C5=BEina?= Date: Thu, 1 Oct 2026 16:50:27 +0200 Subject: [PATCH 1/2] feat: add semantic release composite action --- README.md | 41 +++++++++++++++++++++ semantic-release/action.yaml | 71 ++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 semantic-release/action.yaml diff --git a/README.md b/README.md index ceb9982..e9dc3f0 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,14 @@ Reusable GitHub Actions workflows forming the CI baseline for every BruzIT repos ## Features +- [Semantic Release Action](#semantic-release-composite-action) - [Semantic Release Workflow](#reusable-semantic-release-workflow) - [MegaLinter Workflow](#reusable-megalinter-workflow) +### Semantic Release Composite Action + +[Semantic Release composite action](semantic-release/action.yaml) with the same steps as the reusable workflow. It checks out the repository with the GitHub App token, so the changelog commit and the major tags are pushed as the GitHub App. + ### Reusable Semantic Release Workflow Reusable [Semantic Release workflow](.github/workflows/semantic-release.yaml) using the Conventional Commits preset to automate versioning, tags with SemVer and major tag, generates [GitHub releases](https://github.com/bruzit/github-actions-and-workflows/releases), and updates the [CHANGELOG](CHANGELOG.md). @@ -17,6 +22,42 @@ Reusable [MegaLinter workflow](.github/workflows/megalinter.yaml) linting pull r ## Usage +### Use Semantic Release Action + +Create a workflow, for example, `.github/workflows/semantic-release.yaml`; the job's `release` environment holds `GH_SEM_REL_APP_ID` and `GH_SEM_REL_APP_PEM_FILE`: + +```yaml +--- +name: Semantic Release + +on: + push: + branches: + - main + +jobs: + release: + name: Release + runs-on: ubuntu-latest + environment: release + permissions: + contents: write + issues: write + pull-requests: write + concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + steps: + - name: Semantic Release + uses: bruzit/github-actions-and-workflows/semantic-release@v0 + with: + app-id: ${{ vars.GH_SEM_REL_APP_ID }} + app-private-key: ${{ secrets.GH_SEM_REL_APP_PEM_FILE }} + plugins: "@semantic-release/exec" # OPTIONAL Space-separated list of additional semantic-release plugins to install. +``` + +The action checks out the repository itself. A local `uses: ./semantic-release` needs a prior `actions/checkout` with `persist-credentials: false`. + ### Use Semantic Release Workflow Create a workflow, for example, `.github/workflows/semantic-release.yaml`: diff --git a/semantic-release/action.yaml b/semantic-release/action.yaml new file mode 100644 index 0000000..fa7cf10 --- /dev/null +++ b/semantic-release/action.yaml @@ -0,0 +1,71 @@ +--- +name: Semantic Release +description: Run semantic-release with the Conventional Commits preset and move the major tags. +inputs: + app-id: + required: false + default: '' + description: GitHub App ID used to create the GitHub App token. + app-private-key: + required: false + default: '' + description: GitHub App private key used to create the GitHub App token. + plugins: + required: false + default: '' + description: Space-separated list of additional semantic-release plugins to install. +runs: + using: composite + steps: + - name: Create GitHub App token + uses: actions/create-github-app-token@v3 + id: gh-app-token + if: inputs.app-id != '' + with: + app-id: ${{ inputs.app-id }} + private-key: ${{ inputs.app-private-key }} + repositories: ${{ github.repository }} + permission-contents: write + permission-issues: write + permission-pull-requests: write + - name: Checkout repository + uses: actions/checkout@v7 + with: + token: ${{ steps.gh-app-token.outputs.token || github.token }} + fetch-depth: 0 + persist-credentials: true + - name: Set up Node.js + uses: actions/setup-node@v7 + with: + node-version: 'lts/*' + - name: Install Semantic Release # zizmor: ignore[adhoc-packages] lockfiles are not committed by design + shell: bash + env: + SEMANTIC_RELEASE_PLUGINS: ${{ inputs.plugins }} + run: | + mapfile -t plugins <<< "$SEMANTIC_RELEASE_PLUGINS" + npm install --ignore-scripts semantic-release conventional-changelog-conventionalcommits@9 @semantic-release/changelog @semantic-release/git "${plugins[@]}" + - name: Verify Semantic Release + shell: bash + run: npm audit signatures + - name: Run Semantic Release + shell: bash + env: + GITHUB_TOKEN: ${{ steps.gh-app-token.outputs.token || github.token }} + run: npx semantic-release + - name: Move major tags + if: ${{ !cancelled() }} + shell: bash + run: | + git fetch --force --prune --prune-tags origin + re='^(v(0|[1-9][0-9]*))\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(\+[0-9A-Za-z.-]+)?$' + declare -A latest=() + while read -r tag; do + [[ $tag =~ $re ]] && latest[${BASH_REMATCH[1]}]=$tag + done < <(git tag --list 'v*.*.*' --merged HEAD --sort=v:refname) + for major in "${!latest[@]}"; do + tag=${latest[$major]} + [ "$(git rev-parse -q --verify "refs/tags/$major^{commit}")" = "$(git rev-parse "$tag^{commit}")" ] && continue + git tag --force "$major" "$tag" + git push --force origin "refs/tags/$major" + done From b5e2cfde3d7e9775e54358d15ecc0aac64ae9f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bru=C5=BEina?= Date: Thu, 1 Oct 2026 17:18:58 +0200 Subject: [PATCH 2/2] docs: describe semantic release action fully, workflow as similar --- README.md | 66 ++++++++++++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index e9dc3f0..fbe0107 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ Reusable GitHub Actions workflows forming the CI baseline for every BruzIT repos ### Semantic Release Composite Action -[Semantic Release composite action](semantic-release/action.yaml) with the same steps as the reusable workflow. It checks out the repository with the GitHub App token, so the changelog commit and the major tags are pushed as the GitHub App. +[Semantic Release composite action](semantic-release/action.yaml) using the Conventional Commits preset to automate versioning, tags with SemVer and major tag, generates [GitHub releases](https://github.com/bruzit/github-actions-and-workflows/releases), and updates the [CHANGELOG](CHANGELOG.md). It checks out the repository with the GitHub App token, so the changelog commit and the major tags are pushed as the GitHub App; without `app-id` it uses `GITHUB_TOKEN`. ### Reusable Semantic Release Workflow -Reusable [Semantic Release workflow](.github/workflows/semantic-release.yaml) using the Conventional Commits preset to automate versioning, tags with SemVer and major tag, generates [GitHub releases](https://github.com/bruzit/github-actions-and-workflows/releases), and updates the [CHANGELOG](CHANGELOG.md). +Reusable [Semantic Release workflow](.github/workflows/semantic-release.yaml), similar to the [Semantic Release Action](#semantic-release-composite-action). ### Reusable MegaLinter Workflow @@ -24,7 +24,7 @@ Reusable [MegaLinter workflow](.github/workflows/megalinter.yaml) linting pull r ### Use Semantic Release Action -Create a workflow, for example, `.github/workflows/semantic-release.yaml`; the job's `release` environment holds `GH_SEM_REL_APP_ID` and `GH_SEM_REL_APP_PEM_FILE`: +Create a workflow, for example, `.github/workflows/semantic-release.yaml`: ```yaml --- @@ -39,14 +39,10 @@ jobs: release: name: Release runs-on: ubuntu-latest - environment: release permissions: contents: write issues: write pull-requests: write - concurrency: - group: release-${{ github.ref }} - cancel-in-progress: false steps: - name: Semantic Release uses: bruzit/github-actions-and-workflows/semantic-release@v0 @@ -58,34 +54,6 @@ jobs: The action checks out the repository itself. A local `uses: ./semantic-release` needs a prior `actions/checkout` with `persist-credentials: false`. -### Use Semantic Release Workflow - -Create a workflow, for example, `.github/workflows/semantic-release.yaml`: - -```yaml ---- -name: Semantic Release - -on: - push: - branches: - - main - -jobs: - release: - name: Release - uses: bruzit/github-actions-and-workflows/.github/workflows/semantic-release.yaml@v0 - permissions: - contents: write - issues: write - pull-requests: write - with: - GH_SEM_REL_APP_ID: ${{ vars.GH_SEM_REL_APP_ID }} - semantic_release_plugins: "@semantic-release/exec" # OPTIONAL Space-separated list of additional semantic-release plugins to install. - secrets: - GH_SEM_REL_APP_PEM_FILE: ${{ secrets.GH_SEM_REL_APP_PEM_FILE }} -``` - To create a GitHub App and a GitHub App Installation: - GitHub @@ -123,6 +91,34 @@ To create a GitHub App and a GitHub App Installation: Configure Semantic Release in the repository, for example like this repository's [`.releaserc.yaml`](.releaserc.yaml). +### Use Semantic Release Workflow + +Similar to [Use Semantic Release Action](#use-semantic-release-action), with the reusable workflow: + +```yaml +--- +name: Semantic Release + +on: + push: + branches: + - main + +jobs: + release: + name: Release + uses: bruzit/github-actions-and-workflows/.github/workflows/semantic-release.yaml@v0 + permissions: + contents: write + issues: write + pull-requests: write + with: + GH_SEM_REL_APP_ID: ${{ vars.GH_SEM_REL_APP_ID }} + semantic_release_plugins: "@semantic-release/exec" # OPTIONAL Space-separated list of additional semantic-release plugins to install. + secrets: + GH_SEM_REL_APP_PEM_FILE: ${{ secrets.GH_SEM_REL_APP_PEM_FILE }} +``` + ### Use MegaLinter Workflow Create `.github/workflows/megalinter.yaml`: