Internal tool for generating release notes from GitHub repository activity.
Setting up a new consumer repo? See Setting up a receiver repo below for the step-by-step guide, including the tag naming convention required for branch-aware changelogs.
- name: Generate release notes
uses: XPGAMESLLC/AutoChangelog@v1.0.4
with:
organization: XPGAMESLLC
repo_name: Biomes
auth_token: ${{ secrets.AUTH_TOKEN }}This creates body.txt in the workflow workspace by default.
- name: Generate release notes and send to Discord
uses: XPGAMESLLC/AutoChangelog@v1.0.4
with:
organization: XPGAMESLLC
repo_name: Biomes
auth_token: ${{ secrets.AUTH_TOKEN }}
discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
discord_role_tag: "<@&123456789012345678>"
discord_role_tags: "<@&123456789012345678>,<@&987654321098765432>"When discord_webhook_url is provided, the action posts changelog text to Discord as:
<repo_name> [<tag>](<release_page>)
<changelog>
<role_tag(s)> (optional)
For multiple pings, provide discord_role_tags (comma/newline/semicolon separated).
<version> is taken from github.ref_name (usually your release tag).
Long changelogs are automatically split into multiple Discord messages to stay under webhook limits.
Pass prerelease: "true" (a plain string) to mark a run as a prerelease build. This does two things:
- The Discord message header/emoji switches from
🎉 New release for <repo>!to🧪 Pre-release for <repo>, anddiscord_role_tag/discord_role_tagspings are skipped — nobody needs an @-mention for a WIP branch build. - It's purely presentational for the Discord message; the changelog content (which commits/PRs/ issues are included) is driven entirely by the tag naming convention described in Setting up a receiver repo, not by this flag.
- uses: XPGAMESLLC/AutoChangelog@v1.1.0
with:
organization: XPGAMESLLC
repo_name: Biomes
auth_token: ${{ secrets.AUTH_TOKEN }}
discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
prerelease: "true"- name: Generate release notes with AI summary
uses: XPGAMESLLC/AutoChangelog@v1.0.4
with:
organization: XPGAMESLLC
repo_name: Biomes
auth_token: ${{ secrets.AUTH_TOKEN }}
ai_summary: "true"
ai_api_key: ${{ secrets.AI_API_KEY }}
# ai_model is optional, defaults to claude-haiku-4-5-20251001
# ai_model: "claude-haiku-4-5-20251001"python -m releasenotes.generator XPGAMESLLC Biomes# --ai-model is optional, defaults to claude-haiku-4-5-20251001
AI_API_KEY=*** python -m releasenotes.generator XPGAMESLLC Biomes --ai-summaryYou can dry-run the exact behavior a receiver repo's workflow would trigger — including the
branch-aware windowing, AI summary, and Discord notification — without touching CI, by pointing a
local .env at that repo's secrets and picking the tag to simulate.
.env (gitignored; mirror whatever the receiver repo's workflow passes as with: secrets):
AUTH_TOKEN='<github token with access to the receiver repo>'
ORGANIZATION='XPGAMESLLC'
AI_API_KEY='<optional, enables --ai-summary>'
DISCORD_WEBHOOK_URL='<optional, enables the Discord notification>'
DISCORD_ROLE_TAGS='<optional>'
With ORGANIZATION set, only repo_name is required on the command line — pass --tag for the
tag you're testing:
python -m releasenotes.generator Biomes --tag v1.1.0-poolrooms.1 --ai-summary# Stable tag, with Discord notification
python -m releasenotes.generator Biomes --tag v1.2.3 --ai-summary
# Prerelease tag: also pass --prerelease to preview the alternate Discord header (no role pings)
python -m releasenotes.generator Biomes --tag v1.1.0-poolrooms.2 --ai-summary --prerelease--tag overrides GITHUB_REF_NAME for the run (setting GITHUB_REF_NAME yourself works
identically, --tag just saves a step).
You don't need to actually push v1.1.0-poolrooms.1 to preview it — pass it to --tag as-is.
Windowing and commit collection go through repo.compare(...), which needs real refs on both
ends, so if the exact tag doesn't exist yet the tool automatically falls back to comparing against
the branch the tag would be cut from instead (the <branch-slug> for a prerelease tag, or the
repo's default branch for a stable one) — that branch's current tip is what the tag would point to
once you actually push it. You'll see a note on stdout when this fallback kicks in:
Tag 'v1.1.0-poolrooms.1' not found on XPGAMESLLC/Backrooms; comparing against branch
'poolrooms' instead (pre-push preview).
The only requirement is that the fallback branch itself exists (which it will, since you're
presumably about to tag it). If neither the tag nor that branch exists — e.g. a typo in the
slug — you get a clear error telling you so instead of a raw 404 from the GitHub API.
This means the full local-testing loop for a prerelease is just:
python -m releasenotes.generator Biomes --tag v1.1.0-poolrooms.1 --ai-summary --prereleaserun from your local checkout of the poolrooms branch (or any checkout — the branch is read from
GitHub, not your working tree), no push required. Once you push the real tag, running the same
command (or the CI workflow) picks up the actual tagged commit instead of the fallback.
Other notes:
AUTH_TOKENis required to read repo activity.organizationcan still be passed positionally instead of viaORGANIZATION(e.g. if you're testing against more than one org and don't want to keep editing.env).DISCORD_WEBHOOK_URL/DISCORD_ROLE_TAG/DISCORD_ROLE_TAGScan come from.envor their matching--discord-*flags — a local test run with a webhook set will actually post to Discord, so use a scratch webhook/channel if you don't want real notifications going out.- If no tag is resolved at all, version falls back to
latestin the Discord title.
This is the step-by-step guide for wiring AutoChangelog into another repository (a "receiver"),
for example Backrooms.
Secrets the receiver repo needs, set in its GitHub repo/environment settings:
- Required:
AUTH_TOKEN— a GitHub token with access to read the repo's tags, PRs, issues, and releases (and create releases, if usingsoftprops/action-gh-release). - Required if the repo builds via Regolith: a filter-dependency token (e.g. a
FLICKER_TOKEN-style secret) thatBedrock-OSS/regolith-actionneeds to pull private filter dependencies. Name and value depend on what the repo'sconfig.jsonfilters require. - Optional:
AI_API_KEY(enables theai_summarysection),DISCORD_WEBHOOK_URLandDISCORD_ROLE_TAGS(enables the Discord notification).
Start from a complete, runnable workflow rather than assembling one from scratch:
examples/full-build.yaml— for Regolith-based Bedrock add-on repos: classifies the tag, builds dev + release artifacts, generates the changelog, and publishes a GitHub release.examples/minimal-changelog.yaml— for repos that already build/release another way and just want the tag-triggered changelog + Discord notification bolted on.
Copy the chosen file into the receiver repo as .github/workflows/build.yaml (or similar).
Replace every <angle-bracket> value in the copied file: organization/repo name, Regolith
profile names (build-dev/build-release), the filter-dependency secret name, the AutoChangelog
version pin, and Discord role-mention IDs.
AutoChangelog's branch-aware changelog windowing depends on tags following this shape:
v<MAJOR>.<MINOR>.<PATCH> (stable release)
v<MAJOR>.<MINOR>.<PATCH>-<branch-slug>.<N> (prerelease build on a feature branch)
- Stable tags (
v1.2.3) are only ever compared against the nearest earlier stable tag — prerelease tags from feature branches are ignored, even if they sit chronologically in between. - Prerelease tags (
v1.1.0-poolrooms.1,v1.1.0-poolrooms.2, ...) are grouped by their<branch-slug>into a family. The first tag in a family is compared against the repo's default branch (so the changelog only shows commits unique to that branch); later tags in the same family are compared against the previous tag in that family.
This shape is also what drives the classify job in the example workflows (it decides
is_prerelease, which feeds both AutoChangelog's prerelease input and
softprops/action-gh-release's prerelease/make_latest inputs). Get the shape wrong and a
prerelease tag either won't be recognized as one, or won't be grouped with its branch's earlier
builds.
- Push a throwaway prerelease tag on a scratch branch, e.g.
v0.0.1-test.1. Confirm a non-"latest" GitHub prerelease is created with a changelog scoped to that branch (commits unique to the branch since it diverged from the default branch). - Push a second prerelease tag on the same branch, e.g.
v0.0.1-test.2. Confirm the changelog only covers what changed sincev0.0.1-test.1. - Push a stable tag, e.g.
v0.0.1. Confirm it ignores any prerelease tags sitting chronologically in between and diffs against the previous stable tag instead.
The example workflows in examples/ are the source of truth for what a working
pipeline looks like — this section explains the concepts, but for the actual steps/inputs, follow
the example files rather than a copy pasted here.
python -m releasenotes.legacy_generator XPGAMESLLC Biomes