Skip to content

Commit d36ce80

Browse files
YTDB-509: Add automation to prefix commits and PR titles with issue number (#621)
#### Motivation: When working on issue-related branches, developers often forget to include the issue number in commit messages and PR titles, making it harder to trace changes back to their associated issues. This PR adds automation and documentation to ensure consistent formatting across the team, improving traceability and reducing manual effort. #### Changes: **Git hook** (`prepare-commit-msg` in `.githooks/` directory): - Matches branches starting with `YTDB` prefix (case-insensitive) followed by optional separator and numbers (e.g., `ytdb-509`, `YTDB_123`, `ytdb509`) - Automatically prepends `YTDB-<number>: ` to commit messages - Normalizes output to uppercase `YTDB` with `-` separator - Skips prefixing if the issue number already exists anywhere in the message (case-insensitive check) - Ignores merge, squash, and amend commits to avoid interference with git workflows - Handles detached HEAD state gracefully **GitHub Action** (`.github/workflows/pr-title-prefix.yml`): - Triggers on PR open, edit, and synchronize events targeting `develop` branch - Automatically prefixes PR title with `YTDB-<number>:` based on branch name - Skips if the issue prefix already exists in the title (case-insensitive check) **PR template** (`.github/pull_request_template.md`): - Added guidance to prefix PR titles with issue number (e.g., `YTDB-123: Your PR title`) #### Setup: Developers need to enable the git hook by running: ```bash git config core.hooksPath .githooks ``` --------- Co-authored-by: Claude Opus 4.5 <[email protected]>
1 parent 692e1fc commit d36ce80

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed

.githooks/prepare-commit-msg

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/bin/bash
2+
#
3+
# Git hook to automatically add issue prefix to commit messages
4+
# based on the branch name pattern: ytdb/YTDB + optional non-letter + numbers (case-insensitive)
5+
# Examples: ytdb-509-feature -> "YTDB-509: <message>"
6+
# YTDB509-feature -> "YTDB-509: <message>"
7+
8+
COMMIT_MSG_FILE=$1
9+
COMMIT_SOURCE=$2
10+
11+
# Only process regular commits (not merges, amends with existing message, etc.)
12+
# Allow: no source (regular commit), "message" (-m flag), "template"
13+
if [ "$COMMIT_SOURCE" = "merge" ] || [ "$COMMIT_SOURCE" = "squash" ] || [ "$COMMIT_SOURCE" = "commit" ]; then
14+
exit 0
15+
fi
16+
17+
# Get current branch name
18+
BRANCH_NAME=$(git symbolic-ref --short HEAD 2>/dev/null)
19+
20+
# Exit if not on a branch (detached HEAD)
21+
if [ -z "$BRANCH_NAME" ]; then
22+
exit 0
23+
fi
24+
25+
# Extract issue prefix: "ytdb" (case-insensitive) followed by optional non-letter followed by numbers
26+
# Pattern explanation: ^(ytdb)([^a-zA-Z0-9]?)([0-9]+)
27+
# - ^ : start of string
28+
# - ytdb : literal "ytdb" prefix (matched case-insensitively)
29+
# - [^a-zA-Z0-9]?: optional single non-alphanumeric character (separator like - or _)
30+
# - [0-9]+ : one or more digits
31+
BRANCH_NAME_LOWER=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]')
32+
if [[ $BRANCH_NAME_LOWER =~ ^(ytdb)([^a-zA-Z0-9]?)([0-9]+) ]]; then
33+
# Normalize the prefix: always use uppercase 'YTDB' and '-' as separator
34+
ISSUE_PREFIX="YTDB-${BASH_REMATCH[3]}"
35+
FULL_PREFIX="$ISSUE_PREFIX: "
36+
37+
# Read current commit message
38+
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
39+
40+
# Check if the issue number already exists anywhere in the message (case-insensitive)
41+
ISSUE_PREFIX_LOWER=$(echo "$ISSUE_PREFIX" | tr '[:upper:]' '[:lower:]')
42+
COMMIT_MSG_LOWER=$(echo "$COMMIT_MSG" | tr '[:upper:]' '[:lower:]')
43+
44+
if [[ ! "$COMMIT_MSG_LOWER" =~ $ISSUE_PREFIX_LOWER ]]; then
45+
# Prepend the issue prefix to the commit message
46+
echo -n "$FULL_PREFIX" > "$COMMIT_MSG_FILE"
47+
echo "$COMMIT_MSG" >> "$COMMIT_MSG_FILE"
48+
fi
49+
fi
50+
51+
exit 0

.github/pull_request_template.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
#### PR Title:
2+
3+
If this PR is related to an issue, prefix the title with the issue number (e.g., `YTDB-123: Your PR title`).
4+
15
#### Motivation:
26

37
A clear and concise explanation of why this change is necessary and what problem it solves.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: PR Title Issue Prefix
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, synchronize]
6+
branches: [develop]
7+
8+
permissions:
9+
contents: read
10+
pull-requests: write
11+
12+
jobs:
13+
add-issue-prefix:
14+
name: Add issue prefix to PR title
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Check and update PR title
18+
uses: actions/github-script@v8
19+
with:
20+
script: |
21+
const prNumber = context.payload.pull_request.number;
22+
const branchName = context.payload.pull_request.head.ref;
23+
const currentTitle = context.payload.pull_request.title;
24+
25+
// Match YTDB prefix (case-insensitive) with optional separator followed by numbers
26+
// Pattern: ytdb/YTDB + optional non-alphanumeric + digits
27+
const branchMatch = branchName.toLowerCase().match(/^(ytdb)[^a-z0-9]?(\d+)/);
28+
29+
if (!branchMatch) {
30+
console.log(`Branch "${branchName}" does not match YTDB pattern. Skipping.`);
31+
return;
32+
}
33+
34+
const issueNumber = branchMatch[2];
35+
const issuePrefix = `YTDB-${issueNumber}`;
36+
37+
// Check if the issue prefix already exists in the title (case-insensitive)
38+
const titleLower = currentTitle.toLowerCase();
39+
const prefixLower = issuePrefix.toLowerCase();
40+
41+
if (titleLower.includes(prefixLower)) {
42+
console.log(`PR title already contains "${issuePrefix}". Skipping.`);
43+
return;
44+
}
45+
46+
// Update PR title with the prefix
47+
const newTitle = `${issuePrefix}: ${currentTitle}`;
48+
49+
await github.rest.pulls.update({
50+
owner: context.repo.owner,
51+
repo: context.repo.repo,
52+
pull_number: prNumber,
53+
title: newTitle
54+
});
55+
56+
console.log(`Updated PR title from "${currentTitle}" to "${newTitle}"`);

0 commit comments

Comments
 (0)