diff --git a/documentation/IssueFeatures.md b/documentation/IssueFeatures.md index 72abd5f90e..de7db2dff0 100644 --- a/documentation/IssueFeatures.md +++ b/documentation/IssueFeatures.md @@ -111,3 +111,6 @@ Some of the settings (ex. `githubIssues.workingIssueFormatScm` and `githubIssues - `${owner}`: The owner of the current repository. - `${sanitizedIssueTitle}`: The title of the current issue with characters that git forbids removed. - `${sanitizedLowercaseIssueTitle}`: The lowercase title of the current issue with characters that git forbids removed. +- `${issueType}`: The name of the issue type (e.g. `Feature`, `Hotfix`), if the issue has an issue type set. If the issue does not have an issue type, the variable is left as-is. +- `${sanitizedIssueType}`: The issue type name with characters that git forbids removed. +- `${sanitizedLowercaseIssueType}`: The lowercase issue type name with characters that git forbids removed. diff --git a/package.nls.json b/package.nls.json index bd16502abe..080e04dc5e 100644 --- a/package.nls.json +++ b/package.nls.json @@ -125,7 +125,7 @@ "githubIssues.ignoreUserCompletionTrigger.description": "Languages that the '@' character should not be used to trigger user completion suggestions.", "githubIssues.ignoreUserCompletionTrigger.items": "Language that user completions should not trigger on '@'.", "githubIssues.issueBranchTitle.markdownDescription": { - "message": "Advanced settings for the name of the branch that is created when you start working on an issue. \n- `${user}` will be replaced with the currently logged in username \n- `${issueNumber}` will be replaced with the current issue number \n- `${sanitizedIssueTitle}` will be replaced with the issue title, with all spaces and unsupported characters (https://git-scm.com/docs/git-check-ref-format) removed. For lowercase, use `${sanitizedLowercaseIssueTitle}` ", + "message": "Advanced settings for the name of the branch that is created when you start working on an issue. \n- `${user}` will be replaced with the currently logged in username \n- `${issueNumber}` will be replaced with the current issue number \n- `${issueType}` will be replaced with the issue type name (e.g. `Feature`, `Hotfix`). For branch-safe variants, use `${sanitizedIssueType}` or `${sanitizedLowercaseIssueType}` \n- `${sanitizedIssueTitle}` will be replaced with the issue title, with all spaces and unsupported characters (https://git-scm.com/docs/git-check-ref-format) removed. For lowercase, use `${sanitizedLowercaseIssueTitle}` ", "comment": [ "{Locked='${...}'}", "Do not translate what's inside of the '${..}'. It is an internal syntax for the extension" diff --git a/src/github/graphql.ts b/src/github/graphql.ts index ea05342343..0d00a5fd6b 100644 --- a/src/github/graphql.ts +++ b/src/github/graphql.ts @@ -733,6 +733,9 @@ export interface Issue { totalCount: number; } reactionGroups: ReactionGroup[]; + issueType?: { + name: string; + } | null; } diff --git a/src/github/interface.ts b/src/github/interface.ts index 4bf23999c5..c10a2c5870 100644 --- a/src/github/interface.ts +++ b/src/github/interface.ts @@ -221,6 +221,7 @@ export interface Issue { commentCount: number; reactionCount: number; reactions: Reaction[]; + issueType?: string; } export interface PullRequest extends Issue { diff --git a/src/github/queries.gql b/src/github/queries.gql index b4fe0a69fa..bf47921324 100644 --- a/src/github/queries.gql +++ b/src/github/queries.gql @@ -110,6 +110,9 @@ fragment IssueBase on Issue { } url } + issueType { + name + } } fragment IssueFragment on Issue { diff --git a/src/github/queriesExtra.gql b/src/github/queriesExtra.gql index ccb1c9f107..dd39ff8b11 100644 --- a/src/github/queriesExtra.gql +++ b/src/github/queriesExtra.gql @@ -119,6 +119,9 @@ fragment IssueBase on Issue { } } } + issueType { + name + } } fragment IssueFragment on Issue { diff --git a/src/github/utils.ts b/src/github/utils.ts index 62035f7119..f108f25f08 100644 --- a/src/github/utils.ts +++ b/src/github/utils.ts @@ -1036,7 +1036,8 @@ export async function parseGraphQLIssue(issue: GraphQL.Issue, githubRepository: comments: issue.comments.nodes?.map(comment => parseIssueComment(comment, githubRepository)), reactionCount: issue.reactions.totalCount, reactions: parseGraphQLReaction(issue.reactionGroups), - commentCount: issue.comments.totalCount + commentCount: issue.comments.totalCount, + issueType: issue.issueType?.name }; } @@ -1833,6 +1834,15 @@ export function variableSubstitution( case 'sanitizedLowercaseIssueTitle': result = issueModel ? sanitizeIssueTitle(issueModel.title).toLowerCase() : match; break; + case 'issueType': + result = issueModel?.item.issueType ? issueModel.item.issueType : match; + break; + case 'sanitizedIssueType': + result = issueModel?.item.issueType ? sanitizeIssueTitle(issueModel.item.issueType) : match; + break; + case 'sanitizedLowercaseIssueType': + result = issueModel?.item.issueType ? sanitizeIssueTitle(issueModel.item.issueType).toLowerCase() : match; + break; case 'today': result = computeSinceValue(extra); break; diff --git a/src/test/github/utils.test.ts b/src/test/github/utils.test.ts index 94683fcf85..12db79f4cb 100644 --- a/src/test/github/utils.test.ts +++ b/src/test/github/utils.test.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { default as assert } from 'assert'; -import { getPRFetchQuery, sanitizeIssueTitle } from '../../github/utils'; +import { getPRFetchQuery, sanitizeIssueTitle, variableSubstitution } from '../../github/utils'; +import { IssueModel } from '../../github/issueModel'; describe('utils', () => { @@ -41,4 +42,38 @@ describe('utils', () => { }); }); }); + + describe('variableSubstitution', () => { + function makeIssueModel(overrides: { title?: string; number?: number; issueType?: string } = {}): IssueModel { + const number = overrides.number ?? 42; + const title = overrides.title ?? 'Some Issue'; + return { + number, + title, + item: { + issueType: overrides.issueType, + }, + } as unknown as IssueModel; + } + + it('replaces ${issueType} with the issue type name', () => { + const result = variableSubstitution('${issueType}-${issueNumber}', makeIssueModel({ issueType: 'Feature', number: 7 })); + assert.strictEqual(result, 'Feature-7'); + }); + + it('replaces ${sanitizedIssueType} with a branch-safe issue type', () => { + const result = variableSubstitution('${sanitizedIssueType}-${issueNumber}', makeIssueModel({ issueType: 'Production Bug Fix', number: 7 })); + assert.strictEqual(result, 'Production-Bug-Fix-7'); + }); + + it('replaces ${sanitizedLowercaseIssueType} with a lowercase branch-safe issue type', () => { + const result = variableSubstitution('${sanitizedLowercaseIssueType}-${issueNumber}', makeIssueModel({ issueType: 'Production Bug Fix', number: 7 })); + assert.strictEqual(result, 'production-bug-fix-7'); + }); + + it('leaves ${issueType} unsubstituted when the issue has no issue type', () => { + const result = variableSubstitution('${issueType}-${issueNumber}', makeIssueModel({ issueType: undefined, number: 7 })); + assert.strictEqual(result, '${issueType}-7'); + }); + }); }); \ No newline at end of file