asyncapi / asyncapi/generator

CI Guard PR titles against changesets so Release workflow is not skipped

Open
#2,203 0 comments 0 reactions 1 assignee Claimed by @Adi-204 View on GitHub
Dominant language
JavaScript
Stars
1.1k
Forks
397
Avg merge
1d 7h
Merged PRs (30d)
25

Description

## Problem

In #2189 we merged hook bundling work with a squash-merge title `fix(hooks): …` and a changeset for `@asyncapi/generator-hooks`. That title is valid under Conventional Commits and passes central `lint-pr-title.yml` (semantic-pull-request allows scopes), but **Release** only runs when the commit on `master` starts with an **unscoped** prefix:

- `fix:`, `fix!:`, `feat:`, `feat!:`, or `chore(release):`

See `.github/workflows/release-with-changesets.yml` (`startsWith` on `github.event.commits[0].message`).

Squash merges use the **PR title** as that message (`MERGE_COMMIT_MESSAGE: "{pullRequest.title} (#{pullRequest.number})"` in automerge). Result: Release was **skipped**, the changeset stayed on `master`, and `@asyncapi/generator-hooks` was not published until a follow-up `fix:` PR.

## Proposal

Add a **generator-local** required check (similar in spirit to `verify-ai-disclosure.yml`), without changing centrally managed `lint-pr-title.yml` from `asyncapi/.github`.

### Rule A — changeset ⇒ release-trigger title

If the PR **adds or modifies** any `.changeset/*.md` file (excluding `config.json`), the PR title must use a Release-compatible **unscoped** prefix (same list as Release workflow). This would have blocked #2189 (`fix(hooks):` + changeset).

### Rule B — release title + publishable code ⇒ changeset

If the PR title **will trigger Release** and the diff touches **publishable package source paths** (e.g. `apps/hooks/src/`, `packages/components/src/`, baked-in `packages/templates/`, etc., excluding tests/snapshots), require either:

- a changeset file in the PR diff, **or**
- pending changesets already on the branch (`npx -p @changesets/cli@2.27.7 changeset status` reports packages to bump).

**Wake-up PRs** (`fix: trigger release…` with no publishable path changes) should **not** fail Rule B.

### Bot exemptions

Skip the check for known bots, aligned with existing workflows:

- `asyncapi-bot` / `asyncapi-bot-eve` when title starts with `chore(release):` or `ci: update of files from global .github repo`
- `dependabot[bot]` / `dependabot-preview[bot]`
- `allcontributors[bot]` when title starts with `docs: add`

### Implementation sketch

- Small Node module under `.github/workflows/scripts/release-pr-guard/` with unit tests (`node:test`).
- Workflow: e.g. `verify-changeset-release-alignment.yml` on `pull_request`.
- Docs: `Development.md` + `.github/pr-review-checklist.md` — scoped `fix(hooks):` does **not** trigger Release.
- Maintainers: add the new check to branch protection after merge.

### Non-goals (optional follow-ups)

- Changing Release `if:` to accept scoped prefixes (policy decision).
- Org-wide changes to `lint-pr-title.yml`.

## Related

- Merged PR: #2189
- Issue: #2144 (hook bundling)

## Acceptance criteria

- [ ] PR with changeset + `fix(hooks):` title fails CI with a clear message.
- [ ] PR with changeset + `fix:` title passes.
- [ ] `fix:` PR changing `apps/hooks/src/` without changeset fails (unless pending changeset on branch).
- [ ] `fix:` empty/doc-only wake-up PR passes.
- [ ] Bot release PRs (`chore(release):`) are exempt.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.