Skip to content

ci: enforce conventional commits with commitlint and husky#454

Merged
ericksoa merged 10 commits intoNVIDIA:mainfrom
cv:ci/enforce-conventional-commits
Mar 21, 2026
Merged

ci: enforce conventional commits with commitlint and husky#454
ericksoa merged 10 commits intoNVIDIA:mainfrom
cv:ci/enforce-conventional-commits

Conversation

@cv
Copy link
Copy Markdown
Contributor

@cv cv commented Mar 20, 2026

Summary

Enforce the conventional commit format documented in CONTRIBUTING.md.

Client-side (Husky + commitlint)

  • Add @commitlint/cli and @commitlint/config-conventional as dev dependencies.
  • Add commitlint.config.js with the 8 allowed types from CONTRIBUTING.md (feat, fix, docs, chore, refactor, test, ci, perf).
  • Add a Husky commit-msg hook that rejects non-conforming commits locally.

CI-side (GitHub Actions)

  • Add a dedicated commit-lint.yaml workflow (separate from pr.yaml to avoid cancelling in-flight test runs via the shared concurrency group).
  • Lint all commits in the PR range on opened/synchronize/reopened events.
  • Lint the PR title on all events including edited (relevant for squash-merge workflows where the PR title becomes the commit message).
  • Pass all untrusted inputs (PR title, SHAs) through env vars to prevent shell injection.

Files changed

  • package.json / package-lock.json — new dev dependencies + prepare script
  • commitlint.config.js — new
  • .husky/commit-msg — new
  • .github/workflows/commit-lint.yaml — new workflow
  • .github/workflows/pr.yaml — remove edited trigger (no longer needed here)

Test plan

  • Husky hook rejects non-conventional commits locally
  • CI commit-lint job passes on conforming commits
  • CI commit-lint job fails on a non-conventional commit message
  • Editing a PR title re-runs title linting without cancelling test runs

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The pull request introduces commit message linting infrastructure by adding Husky hooks for local validation and a GitHub Actions workflow for continuous integration checks. Configuration files for Commitlint and package dependencies are also added to enforce conventional commit formats.

Changes

Cohort / File(s) Summary
Commit Message Linting Configuration
.husky/commit-msg, commitlint.config.js
Adds local Husky hook for pre-commit validation and Commitlint configuration enforcing conventional commit types (feat, fix, docs, chore, refactor, test, ci, perf).
Package Dependencies and Lifecycle
package.json
Adds husky, @commitlint/cli, and @commitlint/config-conventional as devDependencies; introduces prepare script to initialize Husky.
CI/CD Workflow
.github/workflows/commit-lint.yaml
Adds GitHub Actions workflow that lints commit messages in pull requests and validates PR titles against Commitlint rules on multiple trigger events.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 With hooks and configs, we hop along,
Commit messages now, oh so strong!
Conventional formats, clean and neat,
Linting workflows make the dance complete!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'ci: enforce conventional commits with commitlint and husky' accurately summarizes the main changes—adding tooling and enforcement for conventional commits through commitlint and Husky hooks.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/pr.yaml:
- Line 8: The workflow enables the pull_request "edited" trigger but the
existing commitlint step (the commit range lint on the step that currently uses
the commit range logic referenced around line 37) only lints commits and thus
misses PR title edits; update the job to also lint the PR title when
github.event.pull_request is present by adding or modifying the commitlint step
to run against github.event.pull_request.title (e.g., invoke commitlint CLI or
the existing action with the PR title input) whenever the workflow was triggered
by an edited PR, so both commit messages and PR title edits are validated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c6d3ae9e-537d-4d9c-afb4-c174934c327f

📥 Commits

Reviewing files that changed from the base of the PR and between dbfd78c and 5e41df6.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • .github/workflows/pr.yaml
  • .husky/commit-msg
  • commitlint.config.js
  • package.json

@ericksoa
Copy link
Copy Markdown
Contributor

Review comments:

  1. edited trigger scope — Won't adding edited to the PR-level trigger also re-run test-unit and test-e2e-sandbox on every title/description/label edit? Might be worth moving commit-lint to its own workflow file with edited in its trigger, or adding if: github.event.action != 'edited' to the test jobs to avoid unnecessary CI runs.

  2. Unquoted $1 in .husky/commit-msg — Should $1 be quoted as "$1" here to handle paths with spaces?

    npx --no -- commitlint --edit "$1"
    
  3. Full npm install in the lint job — Would npm ci --ignore-scripts work here instead? The commit-lint job only needs commitlint, and the current npm install also runs the prepare script (which calls husky).

- Skip test jobs on edited events to avoid unnecessary CI runs
- Quote $1 in husky commit-msg hook for paths with spaces
- Use npm ci --ignore-scripts in lint job for faster, cleaner installs
@wscurran wscurran added priority: high Important issue that should be resolved in the next release CI/CD Use this label to identify issues with NemoClaw CI/CD pipeline or GitHub Actions. labels Mar 20, 2026
@cv
Copy link
Copy Markdown
Contributor Author

cv commented Mar 21, 2026

All three addressed in 2bd485c — added if guard on test jobs for edited events, quoted $1 in commit-msg hook, and switched to npm ci --ignore-scripts. Ready for re-review!

cv and others added 2 commits March 21, 2026 00:31
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/pr.yaml:
- Around line 39-40: The workflow step "Lint PR title (squash-merge path)"
currently expands github.event.pull_request.title directly into the run string
which can lead to shell injection; change it to pass the PR title via an env var
(e.g., PR_TITLE: ${{ github.event.pull_request.title }}) and read that var
inside the run command (use a quoted variable like echo "$PR_TITLE" | npx
commitlint --verbose) so the title is not shell-interpolated.
- Line 8: The workflow-level concurrency is cancelling running test runs when an
`edited` PR event triggers (because `types: [opened, synchronize, reopened,
edited]` is evaluated before job-level `if:` conditions), so either extract the
commit-lint step into its own workflow that uses `on: pull_request: types:
[edited]` or change the concurrency grouping for metadata-only runs by using a
different concurrency key for the job that runs on `edited` (so it does not
share the same workflow-level concurrency as the test jobs); update
.github/workflows/pr.yaml to implement one of these: create a new workflow file
for commit-lint bound to `edited` or modify the existing workflow’s
`concurrency` key to be conditional (or use a separate key) for the
metadata/commit-lint path so in-flight `synchronize`/`reopened` runs are not
cancelled.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bb601617-1d85-4890-b2bc-702aa5983397

📥 Commits

Reviewing files that changed from the base of the PR and between 2bd485c and cef13ed.

📒 Files selected for processing (1)
  • .github/workflows/pr.yaml

Comment thread .github/workflows/pr.yaml Outdated
Comment thread .github/workflows/pr.yaml Outdated
cv and others added 2 commits March 21, 2026 01:20
Move commit-lint job to its own workflow file to prevent the `edited`
trigger from cancelling in-flight test runs via the shared concurrency
group. Also fix shell injection vulnerability by passing PR title
through an env var instead of inline interpolation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.github/workflows/commit-lint.yaml (1)

36-38: Consider using environment variables for SHAs for consistency.

While SHA values are inherently safe (hex-only strings from GitHub), using environment variables would be consistent with how PR_TITLE is handled below and aligns with the general best practice of avoiding direct ${{ }} interpolation in run: commands.

♻️ Optional: Pass SHAs via environment variables
       - name: Lint commits
         if: github.event.action != 'edited'
-        run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose
+        env:
+          BASE_SHA: ${{ github.event.pull_request.base.sha }}
+          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
+        run: npx commitlint --from "$BASE_SHA" --to "$HEAD_SHA" --verbose
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/commit-lint.yaml around lines 36 - 38, Replace direct
github expression interpolation in the run step with environment variables:
define FROM_SHA and TO_SHA in the step's env using ${{
github.event.pull_request.base.sha }} and ${{ github.event.pull_request.head.sha
}} (mirroring how PR_TITLE is handled), and update the run invocation of npx
commitlint to use --from $FROM_SHA and --to $TO_SHA so the SHAs are passed
consistently via env vars.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/commit-lint.yaml:
- Around line 36-38: Replace direct github expression interpolation in the run
step with environment variables: define FROM_SHA and TO_SHA in the step's env
using ${{ github.event.pull_request.base.sha }} and ${{
github.event.pull_request.head.sha }} (mirroring how PR_TITLE is handled), and
update the run invocation of npx commitlint to use --from $FROM_SHA and --to
$TO_SHA so the SHAs are passed consistently via env vars.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bc31bac9-545f-4f87-bbdc-9a27ca67b3a2

📥 Commits

Reviewing files that changed from the base of the PR and between cef13ed and efe629c.

📒 Files selected for processing (1)
  • .github/workflows/commit-lint.yaml

cv and others added 3 commits March 21, 2026 09:04
The lock file was generated with npm 11 (Node 25) which omits optional
peer dependency entries that npm 10 (Node 22, used in CI) requires.
Regenerating with npm 10 adds the missing opusscript@0.0.8 entries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@ericksoa ericksoa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean setup. Types match CONTRIBUTING.md, shell injection is handled via env vars, and the separate workflow avoids cancelling test runs on title edits.

Verified the prepare script change doesn't break any install path — install.sh uses --ignore-scripts, CI has explicit build steps, and CONTRIBUTING.md already documents a separate build step.

@ericksoa ericksoa merged commit 829825c into NVIDIA:main Mar 21, 2026
5 checks passed
@cv cv deleted the ci/enforce-conventional-commits branch March 21, 2026 16:48
Ryuketsukami pushed a commit to Ryuketsukami/NemoClaw that referenced this pull request Mar 24, 2026
* ci: enforce conventional commits with commitlint and husky

* ci: lint PR title in addition to commit messages

* ci: address review feedback

- Skip test jobs on edited events to avoid unnecessary CI runs
- Quote $1 in husky commit-msg hook for paths with spaces
- Use npm ci --ignore-scripts in lint job for faster, cleaner installs

* ci: add PR title linting for squash-merge path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: trigger workflow re-run

* ci: split commit-lint into separate workflow

Move commit-lint job to its own workflow file to prevent the `edited`
trigger from cancelling in-flight test runs via the shared concurrency
group. Also fix shell injection vulnerability by passing PR title
through an env var instead of inline interpolation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): regenerate package-lock.json for Node 22 compatibility

The lock file was generated with npm 11 (Node 25) which omits optional
peer dependency entries that npm 10 (Node 22, used in CI) requires.
Regenerating with npm 10 adds the missing opusscript@0.0.8 entries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: pass commit SHAs through env vars in commit-lint workflow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jessesanford pushed a commit to jessesanford/NemoClaw that referenced this pull request Mar 24, 2026
* ci: enforce conventional commits with commitlint and husky

* ci: lint PR title in addition to commit messages

* ci: address review feedback

- Skip test jobs on edited events to avoid unnecessary CI runs
- Quote $1 in husky commit-msg hook for paths with spaces
- Use npm ci --ignore-scripts in lint job for faster, cleaner installs

* ci: add PR title linting for squash-merge path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: trigger workflow re-run

* ci: split commit-lint into separate workflow

Move commit-lint job to its own workflow file to prevent the `edited`
trigger from cancelling in-flight test runs via the shared concurrency
group. Also fix shell injection vulnerability by passing PR title
through an env var instead of inline interpolation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): regenerate package-lock.json for Node 22 compatibility

The lock file was generated with npm 11 (Node 25) which omits optional
peer dependency entries that npm 10 (Node 22, used in CI) requires.
Regenerating with npm 10 adds the missing opusscript@0.0.8 entries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: pass commit SHAs through env vars in commit-lint workflow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mafueee pushed a commit to mafueee/NemoClaw that referenced this pull request Mar 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/CD Use this label to identify issues with NemoClaw CI/CD pipeline or GitHub Actions. priority: high Important issue that should be resolved in the next release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants