Small, focused GitHub Actions for release pipelines. Use v0 to follow
compatible updates on the current major line, or pin an exact version, which is
written once and never moves. The releases
say what each one changed.
Publish a local directory to a branch in any repository with a commit signed server-side by GitHub. It can replace the branch contents, update only the files you provide, and attach one or more lightweight tags to the resulting commit.
- uses: actions/create-github-app-token@v3
id: app-token
with:
client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
owner: my-org
repositories: my-target-repo
- uses: releasetools/actions/signed-push@v0
with:
source-dir: ./dist
target-repo: my-org/my-target-repo
headline: "publish: v1.2.3"
tags: |
v1.2.3
v1
force-tags: true
token: ${{ steps.app-token.outputs.token }}The action uses GitHub's createCommitOnBranch GraphQL mutation, so a GitHub
App token produces a Verified commit without placing a private signing key on
the runner. It also handles base64 file contents, race protection, pruning, and
tag creation—the repetitive plumbing that otherwise ends up in every release
workflow.
See the signed-push guide for mirroring, upserts, inputs,
outputs, permissions, and behavior.
Fail a pull request when a project changed without moving its version far
enough for what changed. How far follows from what the changes say they are,
by Conventional Commits and
Semantic Versioning: a fix asks for a
patch, a feat for a minor, a ! or a BREAKING CHANGE: footer for a major,
and the largest in the range wins.
- uses: actions/checkout@v6
with:
# The comparison needs the fork point, so the whole history.
fetch-depth: 0
- uses: releasetools/actions/versions-guard@v0
if: github.event_name == 'pull_request'A pull request already says what it is against, and the repository already says what it holds, so including the action is the whole of switching the check on. The baseline is the newest tag reachable from the commit rather than the newest by date, so a backport released yesterday on a release branch is not mistaken for this line's last release.
See the versions-guard guide for the rule, the baseline,
and where a version is read from.
Fail a pull request that changes a project and writes nothing down about it.
The project's changelog has to carry a ## heading naming the version its
manifest declares, which is a new heading whenever the version moved.
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: releasetools/actions/changelog-guard@v0
if: github.event_name == 'pull_request'Each project that failed becomes an annotation on the pull request. A group that names no changelog owes none.
See the changelog-guard guide.
Both read .releasetools.yaml at the repository root, the same file every
releasetools tool reads. A repository that keeps no such file gets a warning
and no check: a guessed project would be reported on as though somebody had
asked for it.
projects:
- path: [packages/api, packages/web]
manifest: package.json
changelog: CHANGELOG.md
- path: crates/core
manifest: Cargo.tomlpath names one directory or a list of directories. Patterns such as
packages/* are refused. Only named projects are checked, and a directory
named by more than one group belongs to the first.
manifest is required and names every file carrying that project's version,
since a project keeping it in two places has to keep them in step. A version is
read out of any .json, .toml, .yaml or .properties file, or one holding
the version and nothing else; a project holding none of the files it names
passes the version guard. Files that are not committed yet count as well as the
diff.
Hand one version's changelog section to whatever publishes the release. It
reads the heading the way changelog-guard reads it, out of the same module, so
the entry a pull request was made to write is the entry the release publishes.
- uses: releasetools/actions/extract-release-notes@v0
id: notes
with:
version: ${{ inputs.version }}
- env:
NOTES: ${{ steps.notes.outputs.notes }}
run: |
printf '%s\n' "$NOTES" > notes.md
gh release create "${{ inputs.version }}" --notes-file notes.md --verify-tagfound says whether there was a section at all, so a workflow decides for
itself whether a release nothing describes should stop.
See the extract-release-notes guide.
More actions are planned for common cross-workflow release patterns.
See CONTRIBUTING.md for the repository layout, local development commands, and how action releases are assembled.
Apache 2.0. See LICENSE.