Reads your commits. Writes your history.
  • Python 95.5%
  • Dockerfile 4.5%
Find a file
2026-05-30 22:22:27 +00:00
.forgejo refactor(ci): drop obsolete runner image and bump checkout to v5 #93 2026-05-31 06:07:31 +08:00
docs chore(version): Bump to 2026.05.30.1 2026-05-30 22:21:41 +00:00
images feat(logo): Add avatar and svg logos #9 2026-04-14 19:47:12 +08:00
src fix(format): Insert paragraph-break separators between changelog blocks #89 2026-04-25 19:39:49 +08:00
tests test(changelog): Add tests for format renderer fix #89 2026-04-25 19:39:07 +08:00
.gitignore Initial commit 2026-04-13 22:43:22 +00:00
.pre-commit-config.yaml feat(pre-commit): Add pre-commit to run tox envs #54 2026-04-16 09:28:23 +08:00
action.yaml fix(action): Change from setup-python to packaged UV #74 2026-04-20 14:52:06 +08:00
CHANGELOG.md chore(version): Bump to 2026.05.30.1 2026-05-30 22:21:41 +00:00
CODE_OF_CONDUCT.md docs(git-herald): Add diataxis style project documentation #7 2026-04-14 15:26:10 +08:00
CONTRIBUTING.md docs(git-herald): Add diataxis style project documentation #7 2026-04-14 15:26:10 +08:00
delete.txt fix(format): Insert paragraph-break separators between changelog blocks #91 2026-04-25 20:05:46 +08:00
Dockerfile fix(docker): Add docker back into build #84 2026-04-25 13:13:36 +08:00
LICENSE docs(initial): Update README, Add how-tos #5 2026-04-14 13:21:47 +08:00
pyproject.toml chore(version): Bump to 2026.05.30.1 2026-05-30 22:21:41 +00:00
README.md chore(version): Bump to 2026.05.30.1 2026-05-30 22:21:41 +00:00
tox.ini fix(tests): Remove pipupgrade from tox. Using UV #72 2026-04-20 14:31:55 +08:00
version.toml chore(version): Bump to 2026.05.30.1 2026-05-30 22:21:41 +00:00

git-herald

git-herald   Version

Project Status: WIP Python License Forgejo Action CI

A Forgejo Action that parses conventional commits from a pull request and automatically updates your changelog, version files, and any other files you specify.

Features

Commit parsing

  • Parses conventional commits (feat, fix, chore, etc.) from PR commits
  • Three accepted forms for breaking changes: BREAKING prefix, ! marker, or BREAKING CHANGE: footer trailer
  • Footer trailer support for Closes, Fixes, Resolves, Refs, and See also — multiple issues per line, colon optional
  • Optional [dev-notes] and [doc-notes] blocks in commit bodies for dev- and doc-audience context
  • Automatic revert handling

Output formatting

  • Groups entries by type under a CalVer version heading (YYYY.MM.DD.N)
  • Highlights breaking changes in a dedicated section with migration detail when provided
  • Hyperlinks issue references to your Forgejo or GitHub instance
  • Falls back to the PR number when no issue reference is present in the commit subject

Version file updates

  • Updates any number of version files using a sentinel marker — no hardcoded paths
  • Writes version.toml with a configurable section key
  • Supports .py, .toml, .cfg, .ini, .txt, .rst, and .md files

Platform support

  • Compatible with Forgejo and GitHub Actions
  • Installs its own Python — no setup-python step needed in your workflow

Requirements

  • A Linux runner (glibc or musl) with network access to github.com releases. git-herald uses uv internally to install Python on first run, and uv downloads Python builds from GitHub releases.
  • If uv is already installed on the runner, git-herald uses it in place. Otherwise it installs uv for the duration of the step.
  • No prior setup-python step is needed — in fact, adding one can cause conflicts on slim container images where setup-python fails to detect the distro.

Usage

Add to your .forgejo/workflows/ workflow file. Use the full URL so the runner always resolves to the correct instance regardless of DEFAULT_ACTIONS_URL.

Minimal complete example

A working workflow you can paste as-is and adapt:

name: Update Changelog
on:
  pull_request:
    branches: [main]

jobs:
  update_changelog:
    runs-on: docker
    permissions:
      contents: write
      pull-requests: read
    steps:
      - uses: https://code.forgejo.org/actions/checkout@v5
        with:
          fetch-depth: 0
          token: ${{ secrets.FORGEJO_TOKEN }}

      - uses: https://forge.tail7f01cb.ts.net/dunwright/git-herald@v1
        with:
          token: ${{ secrets.FORGEJO_TOKEN }}
          version-files: |
            pyproject.toml
            myapp/__init__.py

FORGEJO_TOKEN is a PAT with read/write repo access. The auto-generated GITHUB_TOKEN also works if you only need access to the current repo and are not on a protected branch.

Custom bot identity

By default git-herald commits as git-herald <action@forgejo.com>. You can override this to match your organisation's conventions:

- uses: https://forge.tail7f01cb.ts.net/dunwright/git-herald@v1
  with:
    token: ${{ secrets.FORGEJO_TOKEN }}
    git-user-name: "mycompany-bot"
    git-user-email: "ci-bot@mycompany.com"
    version-files: |
      pyproject.toml
      README.md

Version bump commits are unsigned by default. If your repo requires signed commits, configure GPG signing in a step before calling git-herald.

GitHub Actions

GitHub Actions supports referencing actions hosted on external instances using the full URL — the same pattern as Forgejo. No mirroring or checkout workaround needed.

- uses: https://forge.tail7f01cb.ts.net/dunwright/git-herald@v1
  with:
    token: ${{ secrets.GITHUB_TOKEN }}
    version-files: |
      pyproject.toml
      myapp/__init__.py
      docs/source/conf.py
      README.rst
    version-toml-key: "tb.version"

Inputs

Input Required Default Description
token Forgejo/GitHub token with write access
changelog-path CHANGELOG.md Path to changelog file
version-toml-path version.toml Path to version TOML file
version-toml-key version Section name in version.toml, e.g. tb.version
version-files "" Newline-separated list of additional files to update
python-version 3.13 Python version used to run the action's script. Installed on-demand by uv — no separate setup step required
git-user-email action@forgejo.com Email used for the version bump commit
git-user-name git-herald Display name used for the version bump commit

Outputs

Output Description
changes-made "true" if the changelog was updated, "false" if no relevant commits found
version The version string written, e.g. 2026.04.13.1
commit-sha SHA of the version bump commit pushed to the PR branch. Empty if no changes were made

First-run setup

Before the first run, two files must exist in your repository:

  1. version.toml — tracks the current version between runs.
  2. CHANGELOG.md — contains a placeholder marking where new versions should be inserted.

Create version.toml

Place this at the root of your repository:

[version]
__version__ = "2026.01.01.1"

The section name (version by default) is controlled by the version-toml-key input. For example, version-toml-key: "tb.version" means your file should be:

[tb.version]
__version__ = "2026.01.01.1"

git-herald overwrites this file on every run with the new version — you do not need to update it manually after the first run.

Add the CHANGELOG placeholder

In CHANGELOG.md, add this comment on the line where new versions should be inserted:

<!--next-version-placeholder-->

Every new version is written directly below this line, so the most recent release appears at the top of the changelog.

Commit format

Commits must follow this pattern to be picked up:

type(scope): description #ISSUE_NUMBER

The type and scope are required. The #ISSUE_NUMBER is optional — when omitted, git-herald falls back to the PR number and renders the entry as PR #nn. See Issue reference and PR fallback below.

Supported types:

Type Changelog section
feat Features
fix Bug Fixes
perf Performance
refactor Code Refactoring
docs Documentation
style Formatting
test Testing
chore Maintenance

Breaking changes

Any of three forms will flip the breaking-change flag; you can combine them if you like:

1. Legacy prefix — prepend BREAKING to the subject:

BREAKING feat(api): remove legacy endpoint #42

2. Bang marker — append ! after the scope:

feat(api)!: remove legacy endpoint #42

3. Footer trailer — add a BREAKING CHANGE: line in the commit footer. The description text is rendered in the changelog alongside the entry:

feat(api): remove legacy endpoint #42

BREAKING CHANGE: /v1 endpoints are gone. Migrate callers to /v2 —
see docs/migration.md for the field renames.

Breaking changes appear in a dedicated ⚠ BREAKING CHANGES section at the top of the version entry, and also in their normal type section.

Issue reference and PR fallback

The #nn reference in the subject is optional but strongly preferred. When present, the entry links to the issue. When absent, git-herald falls back to the PR number and renders the entry as PR #nn linking to the pull request.

The fallback exists for commits where no issue was filed — typo fixes, routine chore work, emergency hotfixes. When you do have an issue, reference it: issues are durable across PRs, branch renames, and merge-squash rewrites, making the changelog more useful for archaeology.

git-herald recognises standard git footer trailers. All trailer keys are case-insensitive and the colon is optional:

Trailer Purpose Rendered as
Closes #n / Fixes #n / Resolves #n Issue-closing references > Closes: [#n](...)
Refs #n / See also #n Non-closing references > Refs: [#n](...)
BREAKING CHANGE: desc Breaking change with description > ⚠ desc + flags the entry

Multiple issues per trailer line are supported:

Closes #17, #23, #42

Optional body blocks

Add context for developers and doc writers by including one or both blocks in the commit body. Both are optional and can appear in any order.

feat(payments): add stripe checkout button #42

Introduces a Stripe checkout flow with support for saved cards.

[dev-notes]:
"""
PaymentContext now exposes a usePaymentButton hook.
"""

[doc-notes]:
"""
A new payment button is available in the checkout flow.
"""

Closes #17, #23
BREAKING CHANGE: payload shape changed, migrate callers to v2
Refs #51

Rendered examples

The basic form renders as a single bullet:

- add payment button (ui) [#42](https://forge.example.com/dunwright/myapp/issues/42)

When no issue is referenced, the PR fallback kicks in:

- bump actions/checkout to v5 (ci) [PR #99](https://forge.example.com/dunwright/myapp/pulls/99)

A fully-loaded commit with breaking change, body blocks, and footer trailers renders with blockquote detail beneath. Each block (breaking description, dev notes, doc notes, closes, refs) is separated by a blank > line so CommonMark renderers display each on its own visual line:

- BREAKING: add stripe checkout button (payments) [#42](https://forge.example.com/dunwright/myapp/issues/42)
  > ⚠ payload shape changed, migrate callers to v2
  >
  > 🔧 PaymentContext now exposes a usePaymentButton hook.
  >
  > 📝 A new payment button is available in the checkout flow.
  >
  > Closes: [#17](https://forge.example.com/dunwright/myapp/issues/17), [#23](https://forge.example.com/dunwright/myapp/issues/23)
  >
  > Refs: [#51](https://forge.example.com/dunwright/myapp/issues/51)

Sentinel marker

For each file listed in version-files, place a sentinel comment on the line immediately above your version string. On each run git-herald finds the sentinel and updates the line directly below it:

  • If that line already contains a version (a YYYY.MM.DD.N CalVer string), git-herald replaces only the version, leaving the rest of the line intact. This is what lets the version live inside richer formatting such as a badge URL.
  • If no version is present yet, git-herald writes the default version line for that file type, shown in the examples below.
Extension Sentinel to add
.py .toml .cfg .ini .txt # {{version}}
.rst .. {{version}}
.md <!-- {{version}} -->

Examples

pyproject.toml

[project]
name = "myapp"
# {{version}}
version = "2026.01.01.1"

myapp/__init__.py

# {{version}}
__version__ = "2026.01.01.1"

docs/source/conf.py

# {{version}}
__version__ = "2026.01.01.1"

README.rst

.. {{version}}
**Version = 2026.01.01.1**

Version badges

Because git-herald swaps only the CalVer substring when one is already present, you can embed the version inside a shields.io badge and the number stays current on every run. Add the badge once with a starting version — any valid CalVer — directly below the sentinel. From there git-herald takes over bumping it.

README.md — the badge can share the heading line, since markdown allows inline images:

<!-- {{version}} -->
# myproject &nbsp; [![Version](https://img.shields.io/badge/version-2026.01.01.1-blue)](https://forge.example.com/you/myproject/src/branch/main/CHANGELOG.md)

README.rst — reStructuredText can't place an image inside an underlined heading, so put the badge above or below the title on its own:

.. {{version}}
.. image:: https://img.shields.io/badge/version-2026.01.01.1-blue
   :target: https://forge.example.com/you/myproject/src/branch/main/CHANGELOG.md
   :alt: Version

In both cases the line carrying the version must sit immediately below the sentinel — for RST that is the image:: line, and its :target: and :alt: options are left untouched on every run. The badge label and colour are yours to choose; only the CalVer is rewritten.

Versioning this action

Pin to a tag or branch:

# Track the main branch — receives updates immediately.
uses: https://forge.tail7f01cb.ts.net/dunwright/git-herald@main

# Pin to a specific release tag — stable, updated only when you bump.
uses: https://forge.tail7f01cb.ts.net/dunwright/git-herald@v1.2.0

A formal release cadence will be published once the action stabilises. For now, pinning to a commit SHA is the safest choice if you need full reproducibility:

uses: https://forge.tail7f01cb.ts.net/dunwright/git-herald@abc1234

License

MIT © Dunwright