From 15076d0ffec3705e77c5f8ff335594d1c8f3d305 Mon Sep 17 00:00:00 2001 From: Thiago Perrotta Date: Mon, 22 Jun 2026 12:04:07 +0200 Subject: [PATCH] Add todo-requires-jira-ticket hook Fail when newly added TODO comments lack a parenthesised JIRA issue key, e.g. TODO(PROJ-1234). Checks only newly added lines via a diff (PR base in CI via PR_BASE_SHA, else the staged index locally). Co-Authored-By: Claude Opus 4.8 (1M context) --- .pre-commit-hooks.yaml | 8 +++++++ README.md | 11 ++++++++++ scripts/todo_requires_jira_ticket.sh | 32 ++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100755 scripts/todo_requires_jira_ticket.sh diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index bddef18..6cd0260 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -61,4 +61,12 @@ language: script entry: scripts/sort_codeowners_sections.sh --fix files: 'OWNERS$' + +- id: todo-requires-jira-ticket + name: TODO comments must reference a JIRA ticket, e.g. TODO(PROJ-1234) + description: Require a JIRA issue key on newly added TODO(KEY-1) comments + language: script + entry: scripts/todo_requires_jira_ticket.sh + pass_filenames: false + always_run: true # keep-sorted end diff --git a/README.md b/README.md index c52dfa7..0859ec2 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ repos: - id: just-format - id: pint - id: sort-codeowners-sections + - id: todo-requires-jira-ticket ``` Then, run `prek auto-update` to update the hooks to the latest version and @@ -98,6 +99,16 @@ This hook sorts `[section]` blocks alphabetically in CODEOWNERS-style files. It preserves the header (comments, settings, and global owners before the first section) while ensuring all `[filename]` sections are in alphabetical order. +### todo-requires-jira-ticket + +This hook fails when newly added comments contain a `TODO` without a +parenthesised [JIRA](https://www.atlassian.com/software/jira) issue key, e.g. +`TODO(PROJ-1234)`. The key follows JIRA's `PROJECT-NUMBER` convention +(uppercase project, hyphen, number). Only newly added lines are checked, via a +diff. The range is the PR base in CI (`PR_BASE_SHA`, if set), otherwise the +staged index locally. `FIXME`, `XXX`, lowercase variants, and +loosely-formatted keys are intentionally not accepted. + ## See also - https://github.com/Lucas-C/pre-commit-hooks diff --git a/scripts/todo_requires_jira_ticket.sh b/scripts/todo_requires_jira_ticket.sh new file mode 100755 index 0000000..076ef12 --- /dev/null +++ b/scripts/todo_requires_jira_ticket.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Fail when newly added comments contain a TODO without a parenthesised JIRA +# issue key (the accepted form writes the key as a single token, following +# JIRA's PROJECT-NUMBER convention, e.g. TODO(PROJ-1234)). +# +# Only newly added lines are checked, via a diff. The range is the PR base in +# CI (PR_BASE_SHA, if set), else the staged index locally. A two-dot tree diff +# is used, so only the base commit needs to be present (no full history). +# +# TODO only, strict JIRA key format, no FIXME/XXX/lowercase -- deliberate. + +if [ -n "${PR_BASE_SHA:-}" ]; then + range="${PR_BASE_SHA}..HEAD" +else + range="--cached" +fi + +added=$(git diff -U0 "$range" | grep -E '^\+' | grep -vE '^\+\+\+' || true) + +# Judge each TODO occurrence on its own, so a valid key elsewhere on the line +# can't excuse a bare one. +bad=$(printf '%s\n' "$added" | + grep -oE '(#|//|/\*|