wuguishifu/version-bump-workflow

View on GitHub

Reusable GitHub Actions for tag-based semver releases. The version lives only in git tags: each release reads the latest <prefix>X.Y.Z tag on the remote, bumps it, and whatever creates the release (gh release create, softprops/action-gh-release, ...) creates the new tag.

ActionWhat it does
wuguishifu/version-bump-workflow@v1Computes the next version from the latest tag
wuguishifu/version-bump-workflow/set-package-version@v1Writes a version into package.json, preserving its formatting
wuguishifu/version-bump-workflow/docker-image@v1Builds <registry>/<image>:<version>-<sha> and :latest refs

Version bump

- uses: actions/checkout@v4

- name: bump version
  id: version
  uses: wuguishifu/version-bump-workflow@v1
  with:
    bump-type: ${{ inputs.version-bump-type }}

The repo must be checked out first (tags are read with git ls-remote origin, so a shallow checkout is fine). The job that creates the release needs contents: write.

InputDefaultDescription
bump-typepatchmajor, minor or patch
tag-prefixvPrefix in front of X.Y.Z, e.g. my-application-v for per-app tags in a monorepo. May be empty
initial-version0.0.0Version to bump from when no matching tag exists, so the first major is 1.0.0
remoteoriginGit remote to read tags from
OutputExample
version1.2.3
tagv1.2.3
previous-version1.2.2 (empty if there was no tag)
previous-tagv1.2.2 (empty if there was no tag)

Only tags that are exactly <prefix>X.Y.Z count: pre-release tags like v2.0.0-beta and tags from other prefixes like my-application-v1.0.0 (when the prefix is v) are ignored.

Set package version

- uses: wuguishifu/version-bump-workflow/set-package-version@v1
  with:
    version: ${{ needs.version.outputs.version }}
    path: package.json # default

Fails if the file has no top-level "version" field.

Docker image

- name: docker image
  id: docker
  uses: wuguishifu/version-bump-workflow/docker-image@v1
  with:
    version: ${{ steps.version.outputs.tag }}
    image: wuguishifu/my-application
    registry: ghcr.io # default

- run: |
    docker build -t ${{ steps.docker.outputs.image }} -t ${{ steps.docker.outputs.image-latest }} .
    docker push ${{ steps.docker.outputs.image }}
    docker push ${{ steps.docker.outputs.image-latest }}

Outputs tag (my-application-v1.2.3-abcd1234), image (ghcr.io/wuguishifu/my-application:my-application-v1.2.3-abcd1234), image-latest (ghcr.io/wuguishifu/my-application:latest) and image-name (ghcr.io/wuguishifu/my-application). The image name is lowercased.

Examples

Single-package app with binaries

jobs:
  version:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.version }}
      tag: ${{ steps.version.outputs.tag }}
    steps:
      - uses: actions/checkout@v4
      - id: version
        uses: wuguishifu/version-bump-workflow@v1
        with:
          bump-type: ${{ inputs.version-bump-type }}

  build:
    needs: version
    steps:
      - uses: actions/checkout@v4
      - uses: wuguishifu/version-bump-workflow/set-package-version@v1
        with:
          version: ${{ needs.version.outputs.version }}
      # ... build

  release:
    needs: [version, build]
    permissions:
      contents: write
    steps:
      - uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.version.outputs.tag }}

Monorepo with per-app tags

- id: version
  uses: wuguishifu/version-bump-workflow@v1
  with:
    bump-type: ${{ inputs.version-bump-type }}
    tag-prefix: ${{ inputs.app }}-v

- id: docker
  uses: wuguishifu/version-bump-workflow/docker-image@v1
  with:
    version: ${{ steps.version.outputs.tag }}
    image: ${{ steps.config.outputs.registry_path }}

# ... build and push

- run: gh release create "${{ steps.version.outputs.tag }}" --target "$GITHUB_SHA" --latest=false