Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Latest commit

 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHub Release Action

This GitHub action is designed to generate release notes between 2 tags and use them to create a GitHub release.

The notes open with a ## Changelog heading, then one line per commit in the range:

## Changelog

- feat: add a widget ([#12](https://github.com/acme/widgets/pull/12)) (@octocat)
- fix: stop the thing exploding ([#34](https://github.com/acme/widgets/pull/34)) (@hubot)
- docs: tidy the readme ([ccccccc](https://github.com/acme/widgets/commit/ccccccc)) (Ada Lovelace)

**Full changelog**: https://github.com/acme/widgets/compare/v1.9.0...v2.0.0

It is a composite action — no Node runtime, no bundled dist/. It calls the GitHub API through the gh CLI that is preinstalled on GitHub-hosted runners.

Usage

The common case: tag a commit, push the tag, get a release.

name: Release

on:
  push:
    tags: ["v*"]

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # so the previous tag can be detected

      - uses: bobbymannino/github-release-action@v1

With no inputs, the action releases the tag that triggered the workflow and works out which tag to compare against on its own.

Comparing two specific tags

- uses: bobbymannino/github-release-action@v1
  with:
    tag: v2.0.0
    previous-tag: v1.9.0

A draft prerelease with a custom title

- uses: bobbymannino/github-release-action@v1
  with:
    tag: v2.0.0-rc.1
    name: Release candidate 1
    draft: true
    prerelease: true
    make-latest: false

Using the outputs

- uses: bobbymannino/github-release-action@v1
  id: release

- run: gh release upload "${{ github.ref_name }}" ./dist/*.tar.gz
  env:
    GH_TOKEN: ${{ github.token }}

- run: echo "Released at ${{ steps.release.outputs.url }}"

How a line is built

For each commit between the two tags, in order:

Part Where it comes from
title The commit subject. A trailing (#12) — how GitHub writes squash merges — is stripped, and for a merge commit the merged branch's subject is used instead.
link The pull request, when the commit references one (… (#12) or Merge pull request #34 from …). Otherwise the commit itself, linked by short SHA.
@username The commit author's GitHub account. When GitHub cannot match the commit to an account, the raw commit author name is used instead, without the @.

The body always starts with a ## Changelog heading and ends with a Full changelog link to the diff between the two tags — or, when there is no previous tag, to the tag's commit history. Merge commits are included by default; set skip-merge-commits: true to leave them out. If a range has no commits the notes read _No commits in this range._. Ranges longer than 1000 commits are truncated, with a warning on the step.

Choosing the previous tag

previous-tag is used when you give one. Otherwise the action tries, in order:

  1. git describe --tags --abbrev=0 <tag>^ in the checked-out repository — the correct answer topologically, but it needs fetch-depth: 0 on the checkout;
  2. the tag of the latest published release;
  3. nothing — in which case the notes cover every commit up to the tag, which is what you want for a first release.

Inputs

Input Default Description
tag the triggering tag The tag to release. Required if the workflow was not triggered by a tag push.
previous-tag detected The tag to compare against.
name the tag Release title.
skip-merge-commits false Leave merge commits out of the notes.
target-commitish Branch or SHA the tag should point at. Only needed when the tag does not exist yet.
draft false Create the release as a draft.
prerelease false Mark the release as a prerelease.
make-latest true Whether this release is the latest. One of true, false, legacy.
overwrite false Delete an existing release for the tag instead of failing.
token ${{ github.token }} Token used for the API calls. Needs contents: write permission.

Boolean inputs also accept yes/no and 1/0, and are case-insensitive. Anything else fails the step rather than being silently treated as false.

Outputs

Output Description
id ID of the created release.
url HTML URL of the created release.
upload-url Asset upload URL of the created release.
notes The generated release notes.
previous-tag The tag the notes were generated against. Empty if there was none.
title The release title that was used.

The notes are also written to the job summary, so you can read them without leaving the workflow run.

Permissions

The job needs contents: write. Creating a release for a tag that does not exist yet also requires target-commitish.

Failure modes

The step fails, loudly, when:

  • no tag is given and the workflow was not triggered by a tag;
  • tag and previous-tag are the same;
  • a release already exists for the tag and overwrite is not true;
  • a boolean input is not recognisable as a boolean;
  • the GitHub API rejects the request — the API's error body is included in the message.

Development

bash tests/run-tests.sh   # runs the scripts against a stubbed gh CLI
shellcheck scripts/*.sh   # lint

The scripts under scripts/ hold all the logic and read their inputs from INPUT_* environment variables, which is what makes them testable outside of a workflow. tests/stubs/gh records the requests the scripts make and replies with canned API responses built from tests/fixtures/commits.json.

Licence

MIT. See LICENSE.

About

Automate your GitHub releases.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages