CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | /**
* Issue + PR template loader. Looks for the standard locations and
* returns the first match. Fails silently (returns null) so new-issue /
* new-PR forms always render — templates are a convenience, not a
* requirement.
*/
import { getBlob, getDefaultBranch } from "../git/repository";
const ISSUE_PATHS = [
".github/ISSUE_TEMPLATE.md",
".github/issue_template.md",
".gluecron/ISSUE_TEMPLATE.md",
"ISSUE_TEMPLATE.md",
"docs/ISSUE_TEMPLATE.md",
];
const PR_PATHS = [
".github/PULL_REQUEST_TEMPLATE.md",
".github/pull_request_template.md",
".gluecron/PULL_REQUEST_TEMPLATE.md",
"PULL_REQUEST_TEMPLATE.md",
"docs/PULL_REQUEST_TEMPLATE.md",
];
const MAX_TEMPLATE_BYTES = 16 * 1024;
async function loadFirst(
owner: string,
repo: string,
ref: string,
paths: string[]
): Promise<string | null> {
for (const p of paths) {
try {
const blob = await getBlob(owner, repo, ref, p);
if (blob && !blob.isBinary && blob.content) {
// Guard against someone committing a 5MB template.
if (blob.content.length > MAX_TEMPLATE_BYTES) {
return blob.content.slice(0, MAX_TEMPLATE_BYTES);
}
return stripFrontmatter(blob.content);
}
} catch {
// keep looking
}
}
return null;
}
/**
* GitHub-style templates can have YAML frontmatter (---\nname: ...\n---).
* Strip it — we don't use the name/about fields here.
*/
function stripFrontmatter(content: string): string {
if (!content.startsWith("---\n")) return content;
const end = content.indexOf("\n---", 4);
if (end < 0) return content;
return content.slice(end + 4).replace(/^\n+/, "");
}
export async function loadIssueTemplate(
owner: string,
repo: string
): Promise<string | null> {
try {
const ref = (await getDefaultBranch(owner, repo)) || "HEAD";
return await loadFirst(owner, repo, ref, ISSUE_PATHS);
} catch {
return null;
}
}
export async function loadPrTemplate(
owner: string,
repo: string
): Promise<string | null> {
try {
const ref = (await getDefaultBranch(owner, repo)) || "HEAD";
return await loadFirst(owner, repo, ref, PR_PATHS);
} catch {
return null;
}
}
export { stripFrontmatter as _stripFrontmatterForTest };
|