Add description template variable

This commit is contained in:
Cole Davis
2025-09-12 18:53:08 -04:00
committed by Cole D
parent 9c4bc5dc35
commit 40c2c1e7b4
4 changed files with 167 additions and 1 deletions

View File

@@ -24,7 +24,7 @@ inputs:
required: false required: false
default: "claude/" default: "claude/"
branch_name_template: branch_name_template:
description: "Template for branch naming. Available variables: {{prefix}}, {{entityType}}, {{entityNumber}}, {{timestamp}}, {{year}}, {{month}}, {{day}}, {{hour}}, {{minute}}, {{sha}}, {{label}}. The {{label}} variable uses the first label from the issue/PR, falling back to {{entityType}} if no labels exist. Default: '{{prefix}}{{entityType}}-{{entityNumber}}-{{timestamp}}'" description: "Template for branch naming. Available variables: {{prefix}}, {{entityType}}, {{entityNumber}}, {{timestamp}}, {{year}}, {{month}}, {{day}}, {{hour}}, {{minute}}, {{sha}}, {{label}}, {{description}}. The {{label}} variable uses the first label from the issue/PR, falling back to {{entityType}} if no labels exist. The {{description}} variable uses the first 3 words of the issue/PR title converted to kebab-case. Default: '{{prefix}}{{entityType}}-{{entityNumber}}-{{timestamp}}'"
required: false required: false
default: "" default: ""
allowed_bots: allowed_bots:

View File

@@ -113,6 +113,9 @@ export async function setupBranch(
// Extract first label from GitHub data // Extract first label from GitHub data
const firstLabel = extractFirstLabel(githubData); const firstLabel = extractFirstLabel(githubData);
// Extract title from GitHub data
const title = githubData.contextData.title;
// Generate branch name using template or default format // Generate branch name using template or default format
const newBranch = generateBranchName( const newBranch = generateBranchName(
branchNameTemplate, branchNameTemplate,
@@ -121,6 +124,7 @@ export async function setupBranch(
entityNumber, entityNumber,
sourceSHA, sourceSHA,
firstLabel, firstLabel,
title,
); );
// For commit signing, defer branch creation to the file ops server // For commit signing, defer branch creation to the file ops server

View File

@@ -4,6 +4,25 @@
* Branch name template parsing and variable substitution utilities * Branch name template parsing and variable substitution utilities
*/ */
/**
* Extracts the first three words from a title and converts them to kebab-case
*/
function extractDescription(title: string): string {
if (!title || title.trim() === "") {
return "";
}
return title
.trim() // Remove leading/trailing whitespace
.split(/\s+/) // Split on whitespace
.slice(0, 3) // Take first 3 words
.join("-") // Join with hyphens
.toLowerCase() // Convert to lowercase
.replace(/[^a-z0-9-]/g, "") // Remove non-alphanumeric except hyphens
.replace(/-+/g, "-") // Replace multiple hyphens with single
.replace(/^-|-$/g, ""); // Remove leading/trailing hyphens
}
export interface BranchTemplateVariables { export interface BranchTemplateVariables {
prefix: string; prefix: string;
entityType: string; entityType: string;
@@ -16,6 +35,7 @@ export interface BranchTemplateVariables {
minute: string; minute: string;
sha?: string; sha?: string;
label?: string; label?: string;
description?: string;
} }
/** /**
@@ -48,6 +68,7 @@ export function createBranchTemplateVariables(
entityNumber: number, entityNumber: number,
sha?: string, sha?: string,
label?: string, label?: string,
title?: string,
): BranchTemplateVariables { ): BranchTemplateVariables {
const now = new Date(); const now = new Date();
@@ -63,6 +84,7 @@ export function createBranchTemplateVariables(
minute: String(now.getMinutes()).padStart(2, "0"), minute: String(now.getMinutes()).padStart(2, "0"),
sha: sha?.substring(0, 8), // First 8 characters of SHA sha: sha?.substring(0, 8), // First 8 characters of SHA
label: label || entityType, // Fall back to entityType if no label label: label || entityType, // Fall back to entityType if no label
description: title !== undefined ? extractDescription(title) : undefined,
}; };
} }
@@ -76,6 +98,7 @@ export function generateBranchName(
entityNumber: number, entityNumber: number,
sha?: string, sha?: string,
label?: string, label?: string,
title?: string,
): string { ): string {
const variables = createBranchTemplateVariables( const variables = createBranchTemplateVariables(
branchPrefix, branchPrefix,
@@ -83,6 +106,7 @@ export function generateBranchName(
entityNumber, entityNumber,
sha, sha,
label, label,
title,
); );
let branchName: string; let branchName: string;

View File

@@ -131,6 +131,83 @@ describe("branch template utilities", () => {
); );
expect(result.label).toBe("issue"); expect(result.label).toBe("issue");
}); });
it("should extract description from title when provided", () => {
const result = createBranchTemplateVariables(
"test/",
"issue",
123,
undefined,
undefined,
"Fix login bug with OAuth",
);
expect(result.description).toBe("fix-login-bug");
});
it("should handle title with special characters", () => {
const result = createBranchTemplateVariables(
"test/",
"issue",
456,
undefined,
undefined,
"Add: User Registration & Email Validation",
);
expect(result.description).toBe("add-user-registration");
});
it("should handle title with fewer than 3 words", () => {
const result = createBranchTemplateVariables(
"test/",
"issue",
789,
undefined,
undefined,
"Bug fix",
);
expect(result.description).toBe("bug-fix");
});
it("should handle single word title", () => {
const result = createBranchTemplateVariables(
"test/",
"issue",
101,
undefined,
undefined,
"Refactoring",
);
expect(result.description).toBe("refactoring");
});
it("should handle empty title", () => {
const result = createBranchTemplateVariables(
"test/",
"issue",
202,
undefined,
undefined,
"",
);
expect(result.description).toBe("");
});
it("should handle title with extra whitespace", () => {
const result = createBranchTemplateVariables(
"test/",
"issue",
303,
undefined,
undefined,
" Update README documentation ",
);
expect(result.description).toBe("update-readme-documentation");
});
it("should not set description when title is not provided", () => {
const result = createBranchTemplateVariables("test/", "issue", 404);
expect(result.description).toBeUndefined();
});
}); });
describe("generateBranchName", () => { describe("generateBranchName", () => {
@@ -216,5 +293,66 @@ describe("branch template utilities", () => {
expect(result).toBe("dev/enhancement-issue_789"); expect(result).toBe("dev/enhancement-issue_789");
}); });
it("should use description in template when provided", () => {
const template = "{{prefix}}{{description}}/{{entityNumber}}";
const result = generateBranchName(
template,
"feature/",
"issue",
123,
undefined,
undefined,
"Fix login bug with OAuth",
);
expect(result).toBe("feature/fix-login-bug/123");
});
it("should handle template with multiple variables including description", () => {
const template =
"{{prefix}}{{label}}/{{description}}-{{entityType}}_{{entityNumber}}";
const result = generateBranchName(
template,
"dev/",
"issue",
456,
undefined,
"bug",
"User authentication fails completely",
);
expect(result).toBe("dev/bug/user-authentication-fails-issue_456");
});
it("should handle description with special characters in template", () => {
const template = "{{prefix}}{{description}}-{{entityNumber}}";
const result = generateBranchName(
template,
"fix/",
"pr",
789,
undefined,
undefined,
"Add: User Registration & Email Validation",
);
expect(result).toBe("fix/add-user-registration-789");
});
it("should handle empty description in template", () => {
const template = "{{prefix}}{{description}}-{{entityNumber}}";
const result = generateBranchName(
template,
"test/",
"issue",
101,
undefined,
undefined,
"",
);
expect(result).toBe("test/-101");
});
}); });
}); });