Releases on deploy – setup¶
What it does¶
When deploying to production (master, main or production), the workflow automatically:
- Creates a tag on the deployed commit, e.g.
v2026.09.11.1 - Creates a GitHub release with that tag, titled
v2026.09.11.1 — production - Fills the release notes with the PRs merged since the previous release
The Releases page in the project repo then answers, at a glance, what is live, when it went out, and what it contained. Nothing is created for development deploys.
Versioning¶
Tags use the date of the deploy plus a counter for that day:
v2026.09.11.1 first production deploy on 11 September 2026
v2026.09.11.2 second deploy the same day
v2026.09.12.1 counter resets the next day
The date is UTC, so it matches the timestamps shown on the workflow run. There is nothing to bump manually – the counter is derived from the tags already in the repo.
Setup¶
1. Allow the workflow to create releases¶
The release is created with the built-in GITHUB_TOKEN, which needs write access to repository contents. A reusable workflow can never have more permissions than the job calling it, so this has to be granted on the calling job:
If this is missing, the step fails with a 403 even though the deploy itself succeeded. Alternatively, set Settings → Actions → General → Workflow permissions to Read and write permissions for the repo.
2. Call create-release in your deploy workflow¶
Add it as a job that runs after the deploy has succeeded:
name: Deploy Nuxt
on:
push:
branches:
- master
jobs:
deploy:
uses: subscribed-aps/workflows/.github/workflows/deploy-nuxt.yml@main
with:
environment: master
secrets: inherit
release:
needs: deploy
if: needs.deploy.result == 'success'
permissions:
contents: write
uses: subscribed-aps/workflows/.github/workflows/create-release.yml@main
with:
environment: master
The environment input is the same value passed to the deploy workflow, so a workflow_dispatch that can pick between development and production works without extra conditions – the release job simply does nothing when the environment is not a production one.
3. Combine with Asana notifications¶
If the repo already calls notify-asana, both jobs can hang off the same deploy. The order does not matter:
notify-asana:
needs: deploy
if: needs.deploy.result == 'success'
uses: subscribed-aps/workflows/.github/workflows/notify-asana.yml@main
with:
environment: master
base_sha: ${{ github.event.before }}
secrets:
ASANA_TOKEN: ${{ secrets.ASANA_TOKEN }}
release:
needs: deploy
if: needs.deploy.result == 'success'
permissions:
contents: write
uses: subscribed-aps/workflows/.github/workflows/create-release.yml@main
with:
environment: master
As a bonus, notify-asana falls back to the most recent tag when no base_sha is given. Once these releases exist, that fallback becomes an exact "since the last deploy" range instead of a guess at the last 20 commits.
Optional parameters¶
| Input | Default | Description |
|---|---|---|
environment | Required | Environment deployed. The release is only created for master, main or production |
tag_prefix | v | Prefix for the generated tag. Use to namespace tags in a monorepo, e.g. api-v |
sha | Current commit | Commit to tag. Only needed if the release should point somewhere other than the commit that triggered the workflow |
Outputs¶
| Output | Description |
|---|---|
tag | The tag that was created, e.g. v2026.09.11.1 |
url | URL of the created release |
Error handling¶
Unlike the Asana notification, a failed release does fail the job. The release log is only useful if it is complete, so a missing release should be visible rather than silently swallowed. The job runs after the deploy, so a failure here never blocks or rolls back the deploy itself.
If two production deploys land at nearly the same time, a concurrency group serialises them so they do not claim the same tag number. Should it happen anyway, the workflow refreshes its tags and retries once.