From c7da399cf3cf5ac10579685237034ed9c34da1be Mon Sep 17 00:00:00 2001 From: Nayan Date: Sat, 25 Jul 2026 11:58:00 +0530 Subject: [PATCH] chore(hooks): enforce conventional commits and the branch policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commitlint has been sitting in the repo wired to nothing. Hook it up: commit-msg lints the message, pre-commit formats staged files and blocks direct commits to main, pre-push blocks pushing it. The test suite deliberately does not run in pre-commit. It runs in checks.yml on every PR and locally via `make preflight`, and a full `turbo run test` on every commit would tax exactly the fast checkpoint commits this repo lives on while catching nothing the PR gate would not. A hook is only ever a courtesy — it can be skipped with --no-verify — so CI runs the same rules over a PR's commits. --- .husky/commit-msg | 6 ++++++ .husky/pre-commit | 41 +++++++++++++++++++++++++++++++++++++++++ .husky/pre-push | 13 +++++++++++++ commitlint.config.ts | 7 +++++++ 4 files changed, 67 insertions(+) create mode 100755 .husky/commit-msg create mode 100755 .husky/pre-commit create mode 100755 .husky/pre-push create mode 100644 commitlint.config.ts diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..b2d1b69 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,6 @@ +#!/bin/sh +# Conventional Commits, enforced. commitlint.config.ts has been in this repo +# since the beginning wired to nothing, which is why the log is a wall of +# "checkpoint". checks.yml runs the same rule over a PR's commits, because a +# hook is only ever a courtesy — it can be skipped with --no-verify. +pnpm commitlint --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..d6e3eeb --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,41 @@ +#!/bin/sh +# Block direct commits to main — branch first, then open a PR. This and the +# pre-push guard are the only main protection there is until the repo has a +# remote with branch protection turned on (see .github/README.md). +branch="$(git rev-parse --abbrev-ref HEAD)" +if [ "$branch" = "main" ]; then + echo "✖ Direct commits to 'main' are blocked — branch first: git switch -c " + exit 1 +fi + +# The test suite deliberately does NOT run here. It runs in checks.yml on every +# PR, and locally via `make preflight` before you open one. A full `turbo run +# test` on every commit taxes exactly the fast checkpoint commits this repo +# lives on, and catches nothing that the PR gate would not. + +# ultracite +# Check if there are any staged files +STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR) +if [ -z "$STAGED_FILES" ]; then + echo "No staged files to format" + exit 0 +fi + +# Run formatter, capturing the exit code so we can still re-stage and report +FORMAT_EXIT_CODE=0 +pnpm dlx ultracite fix || FORMAT_EXIT_CODE=$? + +# Re-stage files that were already staged +echo "$STAGED_FILES" | while IFS= read -r file; do + if [ -f "$file" ]; then + git add -- "$file" + fi +done + +if [ $FORMAT_EXIT_CODE -ne 0 ]; then + echo "Ultracite found issues that could not be auto-fixed." + exit $FORMAT_EXIT_CODE +fi + +echo "✨ Files formatted by Ultracite" +# ultracite end diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 0000000..c4392cf --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,13 @@ +#!/bin/sh +# Block pushing to main — open a PR from a branch instead. +# +# git feeds pre-push the refs being pushed on stdin, one per line: +# +while read -r _local_ref _local_sha remote_ref _remote_sha; do + case "$remote_ref" in + refs/heads/main) + echo "✖ Pushing to 'main' is blocked — open a PR from your branch." + exit 1 + ;; + esac +done diff --git a/commitlint.config.ts b/commitlint.config.ts new file mode 100644 index 0000000..76dcb70 --- /dev/null +++ b/commitlint.config.ts @@ -0,0 +1,7 @@ +import type { UserConfig } from "@commitlint/types"; + +const config: UserConfig = { + extends: ["@commitlint/config-conventional"], +}; + +export default config;