Skip to content

Commit 0d84fe9

Browse files
committed
ci: add PR-title commitlint as a standalone workflow
Pulls the conventional-commit check out of ci.yml's lint job into its own workflow (.github/workflows/pr-title.yml) so it exposes a stable, isolated status-check name that branch protection on develop and main can require independently. Why this matters: the repo enforces squash-merge, so the PR title becomes the commit message on develop/main. semantic-release then reads that message through commitlint.config.js's type-enum to decide whether to cut a release. PR #245 ("release: audit...") squashed to a non-conventional commit, semantic-release silently exited with "no release", and that's the trap that produced the v0.15.0 stale-version tag. Blocking non-conventional titles at the merge gate stops it recurring. The new workflow uses the env-var pattern for github.event.pull_request.title (never interpolating it directly into a run: command) and printf '%s' instead of echo to avoid PR titles starting with -e/-n being interpreted as echo flags. Co-required with the upcoming branch-protection update (Phase 0 C2) which will mark PR title / commitlint as required.
1 parent 047d020 commit 0d84fe9

2 files changed

Lines changed: 57 additions & 5 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,9 @@ jobs:
7171
- name: Prettier
7272
run: pnpm format:check
7373

74-
- name: Commitlint (PR title)
75-
if: github.event_name == 'pull_request'
76-
env:
77-
PR_TITLE: ${{ github.event.pull_request.title }}
78-
run: echo "$PR_TITLE" | pnpm commitlint
74+
# PR title commitlint moved to .github/workflows/pr-title.yml so it
75+
# exposes a stable, standalone status-check name for branch protection
76+
# (squash-merge makes the PR title the release-trigger commit message).
7977

8078
# ── Tier 1: Tests + Coverage ───────────────────────
8179
test:

.github/workflows/pr-title.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: PR title
2+
3+
# Runs commitlint against the PR title as a standalone status check.
4+
#
5+
# Why standalone (and not a step inside ci.yml `lint`):
6+
# - The repo enforces squash merges (see GitHub Settings > Pull Requests).
7+
# On squash, the PR title becomes the commit message on develop/main.
8+
# - semantic-release then analyses that message with the type-enum from
9+
# commitlint.config.js to decide whether to cut a release. If the type
10+
# isn't recognised (e.g. PR #245's "release: audit..."), semantic-release
11+
# silently exits with "no release". This is the trap that blew up
12+
# v0.15.0.
13+
# - Pulling the check into its own workflow gives it a clear, stable
14+
# status-check name so branch protection on develop and main can require
15+
# it independently of the broader CI lint job.
16+
17+
on:
18+
pull_request:
19+
types: [opened, edited, reopened, synchronize]
20+
21+
permissions:
22+
contents: read
23+
24+
concurrency:
25+
# Re-running on title edits is cheap; cancel any in-flight check for
26+
# the same PR when a new event arrives.
27+
group: pr-title-${{ github.event.pull_request.number }}
28+
cancel-in-progress: true
29+
30+
jobs:
31+
commitlint:
32+
runs-on: ubuntu-latest
33+
steps:
34+
- uses: actions/checkout@v5
35+
with:
36+
fetch-depth: 0
37+
38+
- uses: pnpm/action-setup@v5
39+
40+
- uses: actions/setup-node@v5
41+
with:
42+
node-version: '22'
43+
cache: 'pnpm'
44+
45+
# Title check only needs commitlint + its config — no workspace
46+
# native deps, no postinstall.
47+
- name: Install commitlint
48+
run: pnpm install --frozen-lockfile --ignore-scripts
49+
50+
- name: Lint PR title
51+
env:
52+
PR_TITLE: ${{ github.event.pull_request.title }}
53+
run: |
54+
printf '%s' "$PR_TITLE" | pnpm commitlint

0 commit comments

Comments
 (0)