Skip to content

feat(github.pr.lint-title): add composite action to lint pull request titles with commitlint - #35

Open
posquit0 wants to merge 3 commits into
mainfrom
feat/github-pr-lint-title
Open

posquit0 wants to merge 3 commits into
mainfrom
feat/github-pr-lint-title

Conversation

@posquit0

@posquit0 posquit0 commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

👋 Background

Most repositories squash-merge pull requests with the PR title as the commit title (squash_merge_commit_title: PR_TITLE). The local commit-msg hook only checks local commit messages, so a non-conventional PR title still lands on main as-is. That breaks tools that read commit titles to compute versions, such as release-please, which we are piloting.

The first version of this PR used a hand-written bash regex. It now uses commitlint, the de facto standard commit linter, so that:

  • the same tool, version and config can lint local commits (commit-msg hook) and PR titles in CI, and
  • the title is parsed by commitlint's own parser, which exposes breaking changes (!).

What changed

  • Add the github.pr.lint-title composite action:
    1. Set up mise with mise.setup-tools (install: false, its own cache key), so the repository's other tools are not installed.
    2. Resolve the commitlint version: the commitlint_version input, else the version of npm:@commitlint/cli in the repository's mise config (e.g. .mise/conf.d/common.toml), else 21.2.3. Install @commitlint/cli, config-conventional, load and parse at that version with mise's npm: backend.
    3. Lint the title with the repository's commitlint config (config_file, default .commitlintrc.yaml) when it exists, otherwise with @commitlint/config-conventional. On failure, report commitlint's findings as an ::error annotation.
    4. Parse the title with the same parser preset and expose type, scope, breaking and subject as outputs (plus the version used). breaking is true when the parser reports a BREAKING CHANGE note, which the conventionalcommits preset adds for type!: titles.

Keeping local and CI rules the same

The version comes from the repository's mise config, the same file local development uses, so local commits and PR titles are checked by the same commitlint version with the same .commitlintrc.yaml. The common files that pin npm:@commitlint/* in .mise/conf.d/common.toml, add .commitlintrc.yaml, and switch the local commit-msg hook to commitlint are proposed in tedilabs/github.

Notes

  • @commitlint/config-conventional is stricter than conventional-pre-commit: besides the same 11 types, it rejects subjects in sentence/start/pascal/upper case (feat: Add X), a trailing full stop, and headers longer than 100 characters.
  • The title and inputs are passed through env, never interpolated into scripts, so a title such as feat: $(id) is treated as text. The resolved commitlint version must be an exact version.
  • A commitlint config can load code from the repository. Use this action on pull_request, or on pull_request_target only with the base branch checked out, never the head of the pull request.

Verification

  • Ran the install and lint steps locally (bash 5.3, mise 2026.10.4, Node.js) in an isolated mise data directory:
    • with npm:@commitlint/cli = "21.2.2" in .mise/conf.d/common.toml, all four packages are installed at 21.2.2; without a mise config, 21.2.3 is used; commitlint_version: latest is rejected
    • valid titles (feat: ..., refactor(scope)!: ...) pass with the expected outputs, including breaking=true for !; Feat: ... fails with commitlint's findings in the annotation
    • a repository .commitlintrc.yaml is honored (a custom header-max-length: 72 rejects an 86-character title that the default config accepts), and the default config is used when the file is missing
    • feat: $(id) 100% is not executed
  • shellcheck, yamllint (repository config) and check-jsonschema --builtin-schema vendor.github-actions pass.

@github-actions

Copy link
Copy Markdown

👋 Welcome! Looks like this is your first pull request.

Hey, thanks for your contribution! Please give us a bit of time to review it. 😄

Please check out our contributing guidelines.

@github-actions github-actions Bot added 💾 actions This issue or pull request is related to actions. size/M Medium size issue or PR. labels Oct 10, 2026
@posquit0 posquit0 changed the title feat(github.pr.lint-title): add composite action to lint pull request titles feat(github.pr.lint-title): add composite action to lint pull request titles with commitlint Oct 10, 2026
@posquit0
posquit0 force-pushed the feat/github-pr-lint-title branch from 6cc87b0 to 4f5d589 Compare October 11, 2026 17:13
@github-actions

Copy link
Copy Markdown

GitHub Actions Integration

Repository jactionlint check-jsonschema (workflows) check-jsonschema (actions)
tedilabs/github-actions ✅ ✅ ✅

✅ All 1 passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💾 actions This issue or pull request is related to actions. size/M Medium size issue or PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant