Complete guide for using hyperfleet-hooks commitlint in local development and Prow CI.
- Overview
- Local Development
- Prow CI Setup
- Cross-Component Usage
- CLI Reference
- Commit Message Standard
- Troubleshooting
hyperfleet-hooks commitlint validates commit messages against the HyperFleet Commit Standard, based on Conventional Commits.
Key Features:
- ✅ Validates commit message format locally (pre-commit)
- ✅ Validates the PR title in Prow CI (the title becomes the squashed commit)
- ✅ Optional per-commit validation in CI with
--commits - ✅ Zero configuration for other components
What is checked where: CI validates the PR title, which becomes the squashed commit on main. Commits inside a PR need only the <type>: <subject> shape, enforced locally by the commit-msg hook. Push review fixes as new commits instead of amending.
-
Install pre-commit framework:
pip install pre-commit
-
Add to
.pre-commit-config.yaml:repos: - repo: https://github.com/openshift-hyperfleet/hyperfleet-hooks rev: v0.1.0 # pin to a specific tag hooks: - id: hyperfleet-commitlint
-
Install the hook:
pre-commit install --hook-type commit-msg
Note: Pre-commit will automatically clone the repository and build the binary. No manual installation of hyperfleet-hooks is needed.
# From file
hyperfleet-hooks commitlint .git/COMMIT_EDITMSG
# From stdin
echo "feat: add new feature" | hyperfleet-hooks commitlinthyperfleet-hooks commitlint --pr automatically:
- Reads the PR title from the
JOB_SPECenvironment variable that Prow sets on every job - Falls back to the GitHub API (
REPO_OWNER,REPO_NAME,PULL_NUMBER) whenJOB_SPEChas no pull request - Fails the job when no title can be obtained from either source
- Validates the PR title and reports the result
With --pr --commits it also detects the commit range from the environment and validates every commit in the PR before the title.
PR titles must include JIRA ticket: <JIRA_PROJECT_ID>-<TICKET_NUM> - <type>: <subject>
Why? PRs are squashed on merge, so the PR title becomes the commit message on main and carries the traceability to JIRA. Individual commits inside the PR do not reach main, which is why CI does not check them.
Examples:
- ✅
HYPERFLEET-123 - feat: add cluster validation - ✅
SENTINEL-42 - fix: resolve timeout - ❌
feat: add cluster validation(missing JIRA)
Add a presubmit job to your component's Prow configuration:
# ci-operator/jobs/openshift-hyperfleet/<component>/<component>-main-presubmits.yaml
presubmits:
openshift-hyperfleet/<component>:
- name: pull-ci-openshift-hyperfleet-<component>-main-validate-commits
cluster: build05
always_run: true
decorate: true
spec:
containers:
- name: validate
image: quay.io/openshift-hyperfleet/hyperfleet-git-hooks:latest
command:
- hyperfleet-hooks
- commitlint
- --pr
resources:
requests:
cpu: 50m
memory: 64MiProw automatically provides these variables (no configuration needed):
| Variable | Example | Description |
|---|---|---|
JOB_SPEC |
{"refs":{"pulls":[{"number":123,"title":"..."}]}} |
Prow job spec JSON, the primary source of the PR title and author |
PULL_NUMBER |
123 |
PR number (GitHub API fallback for the title) |
REPO_OWNER |
openshift-hyperfleet |
Repository owner (GitHub API fallback) |
REPO_NAME |
hyperfleet-api |
Repository name (GitHub API fallback) |
GITHUB_TOKEN |
ghp_... |
GitHub API token (optional, only used by the fallback) |
PULL_REFS |
main:abc123,456:def789 |
Base and PR SHAs for --commits (most accurate) |
PULL_BASE_SHA |
abc123... |
Base branch SHA for --commits (fallback) |
PULL_PULL_SHA |
def789... |
PR head SHA for --commits (fallback) |
PULL_BASE_REF |
main |
Target branch name for --commits |
Note: If
GITHUB_TOKENis not set, the GitHub API fallback is unauthenticated (60 req/hr rate limit) and prints a warning to stderr. In Prow the title normally comes fromJOB_SPEC, so the API is only reached when that spec has no pull request.
PR title source priority:
JOB_SPEC(refs.pulls[0].title, set by Prow on every decorated job)- GitHub API via
REPO_OWNER,REPO_NAME,PULL_NUMBER - Neither available: the job fails
Commit range detection priority (--commits only):
PULL_REFS(most accurate)PULL_BASE_SHA+PULL_PULL_SHAPULL_BASE_REF+HEAD(local fallback)
/test validate-commits # Run validation job
/test all # Run all tests
/retest # Rerun failed testsAll HyperFleet components use the same container image. No installation required in component repositories.
┌─────────────────────────────────┐
│ hyperfleet-hooks Repository │
│ │
│ 1. Build Go binary │
│ 2. Build container image │
│ 3. Push to quay.io │
└─────────────────────────────────┘
│
▼
quay.io/openshift-hyperfleet/hyperfleet-git-hooks:latest
│
┌─────────┼─────────┬─────────┐
▼ ▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ API │ │Sentinel│ │Adapter │ │ Broker │
└────────┘ └────────┘ └────────┘ └────────┘
Use pre-built image, no dependencies!
Components just reference the image in Prow configuration. No dependencies to install.
# In openshift/release repository
cd ci-operator/jobs/openshift-hyperfleet/
sed -i 's|hyperfleet-git-hooks:v1.0.0|hyperfleet-git-hooks:v1.1.0|g' */*-presubmits.yaml
git commit -m "ci: update hyperfleet-git-hooks to v1.1.0"# Validate single commit message
hyperfleet-hooks commitlint [file]
# Validate the PR title (CI mode)
hyperfleet-hooks commitlint --pr
# Validate the PR title and every commit in the PR
hyperfleet-hooks commitlint --pr --commits
# Show version
hyperfleet-hooks version| Flag | Description |
|---|---|
--pr |
Validate the PR title (CI mode, title read from JOB_SPEC or the GitHub API) |
--commits |
With --pr, also validate every commit in the PR range |
-h, --help |
Show help |
0: All validations passed1: Validation failed
[<JIRA_PROJECT_ID>-<TICKET_NUM> - ]<type>: <subject>
[body]
[footer]
feat: New featurefix: Bug fixdocs: Documentationstyle: Code style (formatting)refactor: Code refactoringperf: Performance improvementtest: Add/update testsbuild: Build system changesci: CI configuration changeschore: Maintenance tasksrevert: Revert previous commit
- JIRA ID: Optional, format
<JIRA_PROJECT_ID>-<TICKET_NUM> - - Type: Required, one of the valid types (see above)
- Subject: Required, imperative mood, no period
- Header Length:
<type>: <subject>must not exceed 72 characters (excluding JIRA prefix) - Body: Optional, separated by blank line
- Footer: Optional, e.g.,
BREAKING CHANGE:,Fixes #123
Valid:
✅ feat: add user authentication
✅ HYPERFLEET-123 - fix: resolve memory leak
✅ SENTINEL-42 - docs: update API documentation
✅ refactor: simplify error handling
Invalid:
❌ added new feature # Missing type
❌ feat add feature # Missing colon
❌ Feat: add feature # Type must be lowercase
❌ feature: add feature # Invalid type
Common errors:
header must match format→ Add type:feat:,fix:, etc.type must be one of→ Use valid type (feat, fix, docs, etc.)header must not exceed 72 characters→<type>: <subject>must be ≤ 72 chars (excluding JIRA prefix)pr-title-requires-jira→ PR titles must start with<JIRA_PROJECT_ID>-<TICKET_NUM> -could not get PR title→ neitherJOB_SPECnor the GitHub API env (REPO_OWNER,REPO_NAME,PULL_NUMBER) yielded a title; check the Prow job is decorated
Hook issues:
- Reinstall:
pre-commit install --hook-type commit-msg - Update version:
pre-commit autoupdate
See HyperFleet Commit Standard for details.