Skip to content

feat(commits): add Conventional Commits message normalizer + lint fixes - #248

Open
iamlasse wants to merge 4 commits into
marcus:mainfrom
iamlasse:chore/lint-fix-20260918
Open

iamlasse wants to merge 4 commits into
marcus:mainfrom
iamlasse:chore/lint-fix-20260918

Conversation

@iamlasse

@iamlasse iamlasse commented Sep 18, 2026 •

Copy link
Copy Markdown

Summary

This PR brings the Conventional Commits message normalizer to the CLI, plus related lint and hook-install fixes.

Conventional Commits normalizer (commit-normalize)

  • internal/commits — pure Normalize/validate functions enforcing Conventional Commits rules:
    • Allowed types: feat, fix, docs, style, refactor, test, chore, perf, build, ci
    • Type and scope are lower-cased automatically (FEAT(UI): … → feat(ui): …); unknown/missing types are hard errors
    • The ! breaking-change marker is accepted and preserved (feat!: / feat(api)!:) per Conventional Commits 1.0.0
    • Subject must be lowercase, ≤ 72 chars, no trailing period (auto-trimmed); capitalized subject is a hard error
    • Body is hard-wrapped at 72 columns with paragraph breaks preserved; bullet-list items (- / * ) stay on their own lines; git comment lines (#) are stripped
    • Normalization is idempotent and fully unit-tested (normalizer_test.go)
  • nightshift commit normalize — CLI command with positional arg, --file (for commit-msg hooks), stdin fallback, and --check validation-only mode (prints nothing on success; non-zero exit when the message is invalid or not already in canonical form)
  • scripts/commit-msg.sh — git commit-msg hook that normalizes the message file in place and rejects unfixable messages; install via make install-hooks
  • docs/commit-messages.md — documents the format, the command, and the hook
  • Makefile — install-hooks now installs the commit-msg hook too (previously it only installed pre-commit, so the documented command didn't work)

Lint fixes (lint-fix)

Fixes the 4 issues reported by golangci-lint run (default config):

errcheck (2) — cmd/nightshift/commands/commit.go

  • Unchecked return values of fmt.Fprintln(os.Stdout, normalized) in the commit-normalize RunE (lines 55 and 58). Now captured and returned as an error, consistent with the surrounding error handling.

govet inline (2) — cmd/nightshift/commands/config.go

  • Replaced the deprecated alias constant reflect.Ptr with reflect.Pointer in the printStruct switch (line 373) and the isZero switch (line 411).

Review fixes (iteration 2)

Addresses the code-review findings on the initial implementation:

  • commit-msg hook errexit bug — with set -euo pipefail, the NORMALIZED=$(...) assignment aborted the script before STATUS=$?, making the documented error-guidance block dead code and rejecting bad messages silently. Errexit is now disabled around the invocation, so bad messages print the expected format and exit 1. Also fixed the quoted multi-word go run fallback (it previously tried to exec a binary literally named go run …) and replaced the shared /tmp error file with mktemp + cleanup trap.
  • --check was a no-op — both branches printed the normalized message. --check now validates only: silent on success, non-zero exit when the message is invalid or not already in canonical form (commit.go isCanonical).
  • ! breaking-change markers were rejected while the docs claimed Conventional Commits 1.0.0 compliance — now parsed and preserved with or without a scope; scope is lower-cased like the type.
  • Bullet-list bodies were merged into prose (- item one - item two) — list items now stay on their own lines (with wrapped continuation lines kept in the list block so normalization remains idempotent).
  • Duplicated CLI error output — removed the manual fmt.Fprintf(os.Stderr, …) (cobra already prints Error: …) and set SilenceUsage so validation failures don't dump the usage text.
  • New tests: breaking-change markers, bullet-list preservation, idempotency with lists, and CLI-level tests for input resolution and canonicality (commit_test.go).

Verification

  • go build ./... → succeeds
  • go vet ./... → clean
  • go test ./... → all packages pass (incl. internal/commits)
  • golangci-lint run → 0 issues (baseline was 4)
  • Smoke-tested nightshift commit normalize via positional/stdin/--file/--check with valid, bad-type, capitalized, overlong-subject, and multi-paragraph messages — output and exit codes as documented
  • Re-verified after review fixes: hook empirically tested end-to-end (bad message → guidance + exit 1 + file untouched; fixable message → rewritten in place with bullets preserved, exit 0); --check silent-zero on canonical, non-zero otherwise; golangci-lint run → 0 issues

Nightshift-Task: commit-normalize
Nightshift-Ref: https://github.com/marcus/nightshift


Automated by nightshift

iamlasse added 3 commits June 28, 2026 02:10
Add internal/commits with pure Normalize/validate functions enforcing the project's Conventional Commits rules (known type set, lowercase type, lowercase subject, 72-char subject limit, whitespace trimming, and 72-column body wrapping). Wire it into the CLI as 'nightshift commit normalize' (positional, --file, and stdin sources; --check to validate only), ship a commit-msg git hook under scripts/, and document the format and installation in docs/commit-messages.md.

Nightshift-Task: commit-normalize
Nightshift-Ref: https://github.com/marcus/nightshift
- errcheck: handle fmt.Fprintln error in commit-normalize RunE - govet:
replace deprecated reflect.Ptr alias with reflect.Pointer

Nightshift-Task: lint-fix
Nightshift-Ref: https://github.com/marcus/nightshift
The commit-msg hook docs and hook header instruct users to run 'make
install-hooks', but the target only installed the pre-commit hook. Also
symlink scripts/commit-msg.sh so the documented command actually
installs it.

Nightshift-Task: commit-normalize
Nightshift-Ref: https://github.com/marcus/nightshift
@iamlasse iamlasse changed the title chore: fix lint errors in commit and config commands feat(commits): add Conventional Commits message normalizer + lint fixes Sep 20, 2026
…and hook

- commit-msg hook: disable errexit around the normalizer invocation so a
  failing command substitution no longer aborts the script before the
  error guidance runs; bad messages now print the expected format and
  exit 1 instead of failing silently. Also fix the quoted multi-word
  'go run' fallback and use a mktemp error file.
- commit normalize --check: actually validate instead of duplicating the
  rewrite path; exits non-zero (silently on success) when the message is
  invalid or not already in canonical form.
- normalizer: accept and preserve the Conventional Commits '!' breaking
  change marker (feat! / feat(scope)!), lowercase the scope, and keep
  bullet-list body items on their own lines instead of merging them into
  prose; wrapped bullet continuation lines keep normalization idempotent.
- CLI: drop the manual stderr print so errors are reported once by cobra,
  and silence the usage dump for runtime validation errors.
- docs/tests updated to match; new table cases for '!', bullet lists,
  idempotency, and CLI-level tests for input resolution and canonicality.

Nightshift-Task: commit-normalize
Nightshift-Ref: https://github.com/marcus/nightshift

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant