No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Charley Sheets ab72f88bfc fix(normalize): wrap without splitting multibyte characters
coreutils `fold` counts bytes, not characters, so wrapping at 78 could cut a
multibyte character in half whenever a break landed mid-character, corrupting
Chinese/Japanese/accented text. Replace it with an awk word-wrap that breaks
only at spaces and never splits a token: a space-less run (e.g. a line of
Chinese) is emitted whole instead of mangled. ASCII prose wraps as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 16:42:42 -07:00
hack fix(normalize): wrap without splitting multibyte characters 2026-07-23 16:42:42 -07:00
action.yaml feat: reusable Forgejo changelog-action 2026-07-23 16:20:55 -07:00
README.md feat: reusable Forgejo changelog-action 2026-07-23 16:20:55 -07:00

changelog-action

A reusable Forgejo composite action that writes CHANGELOG.md entries from a release's commit range. It asks an OpenAI-compatible inference service to turn the commits since the previous v* tag into a short, plain-language summary, splices a dated ## [x.y.z] section into the changelog, refreshes the compare links, and commits the result back to the branch.

It is composite (shell only) — it needs git, curl, and jq in the job, but no Node runtime — so it runs on any of our Forgejo runner pools, including the ones without a DinD sidecar.

One release can produce several changelog files in different languages (for example CHANGELOG.md in English and CHANGELOG.es.md in Spanish) in a single commit.

Using it

Add a step after your tag is pushed:

- name: Update changelog for the new release
  uses: https://git.brooktrails.org/brooktrails/changelog-action@v1
  with:
    tag: v${{ steps.tags.outputs.version }}
    token: ${{ secrets.FORGEJO_TOKEN }}
    inference-url: ${{ vars.INFERENCE_URL }}   # optional; omit for the default

and commit a .changelog.env at your repo root stating what your software is:

PRODUCT_NAME="SLP (Simple LLM Proxy)"
PRODUCT_DESCRIPTION="an OpenAI-compatible HTTP router that forwards requests to upstream inference backends based on the model ID in the request body."
# optional per-repo defaults:
# INFERENCE_MODEL=mistral-small-4

Those two strings become the first sentence of the prompt: "You write release notes for SLP (Simple LLM Proxy), an OpenAI-compatible HTTP router that…". Everything else in the prompt (voice, what to leave out, no attribution, output-only) is fixed in the action so every project's entries read the same way.

Multiple languages

- uses: https://git.brooktrails.org/brooktrails/changelog-action@v1
  with:
    tag: v${{ steps.tags.outputs.version }}
    token: ${{ secrets.FORGEJO_TOKEN }}
    targets: |
      CHANGELOG.md:US English
      CHANGELOG.es.md:Spanish

Each path:language pair gets its own inference call and its own file; all changed files land in one docs(changelog): update for <tag> [skip ci] commit. The target files must already exist (create CHANGELOG.es.md with the same heading/link-block scaffold your CHANGELOG.md uses).

Why it never fails your release

The release has already happened by the time this step runs, so a changelog problem must not fail the job. Every failure path logs a ::warning:: and exits 0. A failed summary leaves that file untouched — recoverable by re-running update-changelog.sh against the tag later — rather than committing a wrong or placeholder entry that would silently become the historical record.

Inputs

Input Required Default Purpose
tag yes Release tag to write an entry for, e.g. v1.2.3.
token yes Forgejo token for clone + push (secrets.FORGEJO_TOKEN).
targets no (from changelog-path/language) path:language pairs, one per line.
changelog-path no CHANGELOG.md File for the single-target case.
language no US English Language for the single-target case (free text).
product-name no (from .changelog.env) Override the product name in the prompt.
product-description no (from .changelog.env) Override the product description in the prompt.
inference-url no script default OpenAI-compatible endpoint base URL.
inference-model no script default Model id to route to.
config-file no .changelog.env Per-repo config file the scripts source.
branch no main Branch to update.
server-url no workflow server Forgejo base URL.
repository no current repo owner/name.
git-user-name no forgejo-actions Commit author/committer name.
git-user-email no forgejo-actions@localhost Commit author/committer email.

Precedence for identity/inference values is: action input > .changelog.env > built-in default. For a fully custom prompt, set SYSTEM_PROMPT in .changelog.env; that bypasses product-name/product-description.

Local maintenance

The hack/ scripts also run by hand, against a repo that adopts the action, to fix up history. Run them from inside the target repo (so git ranges and .changelog.env resolve there), pointing at this checkout:

# rewrite one release's entry: excise to a stub, then regenerate
/path/to/changelog-action/hack/enstubbify.sh 0.6.0
/path/to/changelog-action/hack/backfill-changelog.sh 0.6.0
git diff CHANGELOG.md            # review; git checkout to discard

# a different language / file:
CHANGELOG=CHANGELOG.es.md LANGUAGE=Spanish \
  /path/to/changelog-action/hack/backfill-changelog.sh 0.6.0
  • hack/update-changelog.sh <tag> — write the entry for one release.
  • hack/backfill-changelog.sh [version…] — rewrite STUB: entries into real summaries (no-op on real prose, so safe to re-run).
  • hack/enstubbify.sh [--create] <version…> — replace an entry with a STUB: line to be regenerated; --create adds a missing section in sorted position.
  • hack/changelog-lib.sh — shared plumbing; not run directly.

Identity comes from the target repo's .changelog.env; override anything via environment (PRODUCT_NAME, PRODUCT_DESCRIPTION, LANGUAGE, CHANGELOG, INFERENCE_URL, INFERENCE_MODEL).

Requirements

The job needs git, curl, and jq on PATH, and network access to the inference endpoint. Install them in a prior step if your job image lacks them, e.g. apt-get install -y --no-install-recommends git curl jq ca-certificates.