diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9978cce..c91347b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,10 +3,17 @@ name: Release # Builds and publishes the Docker image to GitHub Container Registry. # - push to main -> ghcr.io//study-helper:main + :edge # - push a v* git tag -> :1.2.3, :1.2, :1, :latest (semver) +# +# workflow_dispatch exists so version-bump.yml can trigger this explicitly: +# GITHUB_TOKEN-authored pushes (which is how version-bump.yml pushes its +# release commit + tag) do not fire push-triggered workflow runs — GitHub +# suppresses that to prevent recursion — but an explicit workflow_dispatch +# call is exempt from that restriction. on: push: branches: [main] tags: ["v*"] + workflow_dispatch: env: REGISTRY: ghcr.io diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml index 9d6ce0e..9d44039 100644 --- a/.github/workflows/version-bump.yml +++ b/.github/workflows/version-bump.yml @@ -1,9 +1,9 @@ name: Version Bump # Bumps the app version and tags the release the moment a PR is merged into -# main, so release.yml (which listens for pushes to main and v* tags) -# builds and publishes a new Docker image automatically. No manual release -# step is needed for normal PRs — see docs/releasing.md. +# main, then explicitly triggers release.yml to build and publish the +# Docker image. No manual release step is needed for normal PRs — see +# docs/releasing.md. # # Bump type is derived from the PR title (Conventional Commits): # - a "!" after the type, e.g. "feat!: ..." or "fix!: ..." -> major @@ -12,6 +12,12 @@ name: Version Bump # # Add the "skip-release" label to a PR to opt it out entirely (e.g. a # docs-only or CI-only change that shouldn't ship a new image). +# +# Note: the commit + tag below are pushed using the default GITHUB_TOKEN. +# GitHub does not let GITHUB_TOKEN-authored pushes trigger other workflows' +# push events (anti-recursion protection), so release.yml would otherwise +# never run for these pushes — that's why the last step dispatches it +# explicitly via `gh workflow run`, which IS allowed from a GITHUB_TOKEN. on: pull_request: @@ -20,6 +26,7 @@ on: permissions: contents: write + actions: write concurrency: group: version-bump @@ -85,3 +92,9 @@ jobs: gh release create "v${VERSION}" \ --title "v${VERSION}" \ --notes "${TITLE} (#${PR_NUMBER})" + + - name: Trigger Docker image build + env: + GH_TOKEN: ${{ github.token }} + VERSION: ${{ steps.version.outputs.version }} + run: gh workflow run release.yml --ref "v${VERSION}" diff --git a/docs/releasing.md b/docs/releasing.md index 37053ac..5d80284 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -17,18 +17,22 @@ GitHub Actions. In the normal case there is nothing to do manually. Release is created. - Add the **`skip-release`** label to a PR to opt it out entirely (e.g. a docs-only or CI-only change that shouldn't ship a new image). + - The commit + tag are pushed with the default `GITHUB_TOKEN`, and GitHub + does not let `GITHUB_TOKEN`-authored pushes trigger other workflows' + `push` events (anti-recursion protection). So the last step explicitly + runs `gh workflow run release.yml --ref vX.Y.Z` to kick off the image + build — `workflow_dispatch` calls are exempt from that restriction. -2. **On the resulting push to `main` and the `vX.Y.Z` tag** - ([`.github/workflows/release.yml`](../.github/workflows/release.yml)): +2. **`release.yml`** builds and publishes the image: - | Git event | Published image tags | + | Trigger | Published image tags | | --- | --- | - | Push to `main` | `ghcr.io/veniplex/study-helper:main`, `:edge` | - | Push a tag `vX.Y.Z` | `:X.Y.Z`, `:X.Y`, `:X`, `:latest` | + | Push to `main` (a normal PR merge) | `ghcr.io/veniplex/study-helper:main`, `:edge` | + | `workflow_dispatch` on tag `vX.Y.Z` (from step 1) or a manual `v*` tag push | `:X.Y.Z`, `:X.Y`, `:X`, `:latest` | - So merging a PR produces both events back to back — `:main`/`:edge` - update immediately, and the versioned tags (including `:latest`) follow - right after once the tag is pushed. + So merging a PR produces both back to back — `:main`/`:edge` update from + the merge itself, and the versioned tags (including `:latest`) follow + once `version-bump.yml` tags and dispatches the release build. 3. **Update the deployment** (e.g. Portainer): - If the stack uses `:latest` (default), re-pull the image and