From 8b561233403ae158e73d0905a2f407716ef4cf35 Mon Sep 17 00:00:00 2001 From: tak Date: Mon, 3 Jun 2024 10:55:25 +0900 Subject: [PATCH 1/3] ci: remove no-response workflow --- .github/workflows/no-response-issues.yml | 15 --------------- .github/workflows/stale_issues.yml | 10 +++++----- 2 files changed, 5 insertions(+), 20 deletions(-) delete mode 100644 .github/workflows/no-response-issues.yml diff --git a/.github/workflows/no-response-issues.yml b/.github/workflows/no-response-issues.yml deleted file mode 100644 index 9385a4f..0000000 --- a/.github/workflows/no-response-issues.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: No Response - -on: - issue_comment: - types: [created] - schedule: - - cron: '0 0 * * *' - -jobs: - noResponse: - runs-on: ubuntu-latest - steps: - - uses: lee-dohm/no-response@v0.5.0 - with: - token: ${{ github.token }} diff --git a/.github/workflows/stale_issues.yml b/.github/workflows/stale_issues.yml index 7eea656..25702cb 100644 --- a/.github/workflows/stale_issues.yml +++ b/.github/workflows/stale_issues.yml @@ -18,9 +18,9 @@ jobs: stale-issue-message: This issue has not received a response in 1 week. If you still think there is a problem, please leave a comment to avoid the issue from automatically closing. stale-pr-message: This PR has not received a response in 1 week. If you still think there is a problem, please leave a comment to avoid the PR from automatically closing. # These labels are required - stale-issue-label: closing-soon - exempt-issue-label: no-autoclose - stale-pr-label: closing-soon + stale-issue-label: stale + exempt-issue-label: 'pinned, security, no-autoclose' + stale-pr-label: stale exempt-pr-label: pr/needs-review response-requested-label: response-requested @@ -29,8 +29,8 @@ jobs: closed-for-staleness-label: closed-for-staleness # Issue timing - days-before-stale: 10 - days-before-close: 4 + days-before-stale: 7 + days-before-close: 2 days-before-ancient: 365 # If you don't want to mark a issue as being ancient based on a From e8a3d368fd0333870a15e7d6ce37b059d6e8e562 Mon Sep 17 00:00:00 2001 From: tak Date: Mon, 3 Jun 2024 11:42:38 +0900 Subject: [PATCH 2/3] fix: update gitmoji regular expression --- src/services/ai/ai.service.ts | 8 +++----- src/utils/prompt.ts | 20 +++++++++++++------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/services/ai/ai.service.ts b/src/services/ai/ai.service.ts index 8de4956..151cd64 100644 --- a/src/services/ai/ai.service.ts +++ b/src/services/ai/ai.service.ts @@ -75,9 +75,9 @@ export abstract class AIService { const match = text.match(regex); return match ? match[0].replace(/: (\w)/, (_: any, firstLetter: string) => `: ${firstLetter.toLowerCase()}`) : ''; case 'gitmoji': - const gitmojiRegexp = new RegExp(/^\:\w+\: (.*)$/gm); + const gitmojiRegexp = new RegExp(/:\w*:/); const gitmojoMatched = text.match(gitmojiRegexp); - return gitmojoMatched ? gitmojoMatched[0] : ''; + return gitmojoMatched ? text : ''; default: return text; } @@ -87,9 +87,7 @@ export abstract class AIService { const messages = generatedText .split('\n') .map((message: string) => message.trim().replace(/^\d+\.\s/, '')) - .map((message: string) => message.replace(/`/g, '')) - .map((message: string) => message.replace(/"/g, '')) - .map((message: string) => message.replace(/\*/g, '')) + .map((message: string) => message.replace(/[`'"*]/g, '')) .map((message: string) => this.extractCommitMessageFromRawText(type, message)) .filter((message: string) => !!message); diff --git a/src/utils/prompt.ts b/src/utils/prompt.ts index 32830e8..4f6378a 100644 --- a/src/utils/prompt.ts +++ b/src/utils/prompt.ts @@ -4,15 +4,21 @@ const MAX_COMMIT_LENGTH = 80; const commitTypeFormats: Record = { '': '', - conventional: `(): `, - gitmoji: `:: `, + conventional: `(): `, + gitmoji: `:: `, +}; + +const exampleCommitByType: Record = { + '': '', + conventional: `Example commit message: 'feat: add new disabled boolean variable to button'`, + gitmoji: `Example commit message: ':sparkles: Add a generic preset using configuration'`, }; const specifyCommitFormat = (type: CommitType = 'conventional') => { if (type === '') { return ''; } - return `The commit message must be in format:\n${commitTypeFormats[type]}`; + return `The commit message must be in format:\n${commitTypeFormats[type]}\n${exampleCommitByType[type]}`; }; const commitTypes: Record = { @@ -44,7 +50,7 @@ const commitTypes: Record = { * Conventional Changelog: * https://github.com/conventional-changelog/conventional-changelog/blob/d0e5d5926c8addba74bc962553dd8bcfba90e228/packages/conventional-changelog-conventionalcommits/writer-opts.js#L182-L193 */ - conventional: `Choose a type from the type-to-description JSON below that best describes the git diff\n${JSON.stringify( + conventional: `Choose a type from the type-to-description JSON below that best describes the git diff.\n${JSON.stringify( { docs: 'Documentation only changes', style: 'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)', @@ -65,7 +71,7 @@ const commitTypes: Record = { export const generateDefaultPrompt = (locale: string, maxLength: number, type: CommitType, additionalPrompts: string = '') => [ - 'You are the expert programmer. You are going to provide a professional git commit message.', + 'You are the expert programmer, trained to write commit messages. You are going to provide a professional git commit message.', 'Generate a concise git commit message written in present tense with the given specifications below:', `Message language: ${locale}`, `Commit message must be a maximum of ${Math.min(Math.max(maxLength, 0), MAX_COMMIT_LENGTH)} characters.`, @@ -77,7 +83,7 @@ export const generateDefaultPrompt = (locale: string, maxLength: number, type: C .filter(Boolean) .join('\n'); -export const extraPrompt = (generate: number) => `You must generate ${generate} commit messages in numbered list output format.`; +export const extraPrompt = (generate: number) => `THE RESULT MUST BE ${generate} COMMIT MESSAGES AND MUST BE IN NUMBERED LIST FORMAT.`; export const isValidConventionalMessage = (message: string): boolean => { const conventionalReg = @@ -86,6 +92,6 @@ export const isValidConventionalMessage = (message: string): boolean => { }; export const isValidGitmojiMessage = (message: string): boolean => { - const gitmojiCommitMessageRegex = /^\:\w+\: (.*)$/; + const gitmojiCommitMessageRegex = /:\w*:/; return gitmojiCommitMessageRegex.test(message); }; From 4bf6e3e47a46010b76f189dc8e7e48c8614fce00 Mon Sep 17 00:00:00 2001 From: tak Date: Mon, 3 Jun 2024 11:57:00 +0900 Subject: [PATCH 3/3] refactor: modify validation and message formatting --- src/services/ai/ai.service.ts | 36 +++++++++++++++++------------------ src/utils/prompt.ts | 10 ++++++---- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/services/ai/ai.service.ts b/src/services/ai/ai.service.ts index 151cd64..e4bf687 100644 --- a/src/services/ai/ai.service.ts +++ b/src/services/ai/ai.service.ts @@ -3,7 +3,7 @@ import { Observable, of } from 'rxjs'; import { CommitType, ValidConfig } from '../../utils/config.js'; import { StagedDiff } from '../../utils/git.js'; -import { extraPrompt, generateDefaultPrompt } from '../../utils/prompt.js'; +import { extraPrompt, generateDefaultPrompt, isValidConventionalMessage, isValidGitmojiMessage } from '../../utils/prompt.js'; // NOTE: get AI Type from key names export const AIType = { @@ -67,28 +67,28 @@ export abstract class AIService { }); }; - protected extractCommitMessageFromRawText(type: CommitType, text: string): string { - switch (type) { - case 'conventional': - // NOTE: check loosely for issue that message is not coming out - const regex = new RegExp(/(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(.*\))?: .*$/); - const match = text.match(regex); - return match ? match[0].replace(/: (\w)/, (_: any, firstLetter: string) => `: ${firstLetter.toLowerCase()}`) : ''; - case 'gitmoji': - const gitmojiRegexp = new RegExp(/:\w*:/); - const gitmojoMatched = text.match(gitmojiRegexp); - return gitmojoMatched ? text : ''; - default: - return text; - } - } - protected sanitizeMessage(generatedText: string, type: CommitType, maxCount: number) { const messages = generatedText .split('\n') .map((message: string) => message.trim().replace(/^\d+\.\s/, '')) .map((message: string) => message.replace(/[`'"*]/g, '')) - .map((message: string) => this.extractCommitMessageFromRawText(type, message)) + .filter((message: string) => { + switch (type) { + case 'conventional': + return isValidConventionalMessage(message); + case 'gitmoji': + return isValidGitmojiMessage(message); + default: + return true; + } + }) + .map(message => { + if (type === 'conventional') { + const regex = /: (\w)/; + return message.replace(regex, (_: any, firstLetter: string) => `: ${firstLetter.toLowerCase()}`); + } + return message; + }) .filter((message: string) => !!message); if (messages.length > maxCount) { diff --git a/src/utils/prompt.ts b/src/utils/prompt.ts index 4f6378a..4eef889 100644 --- a/src/utils/prompt.ts +++ b/src/utils/prompt.ts @@ -10,8 +10,8 @@ const commitTypeFormats: Record = { const exampleCommitByType: Record = { '': '', - conventional: `Example commit message: 'feat: add new disabled boolean variable to button'`, - gitmoji: `Example commit message: ':sparkles: Add a generic preset using configuration'`, + conventional: `Example commit message => feat: add new disabled boolean variable to button`, + gitmoji: `Example commit message => :sparkles: Add a generic preset using configuration`, }; const specifyCommitFormat = (type: CommitType = 'conventional') => { @@ -86,8 +86,10 @@ export const generateDefaultPrompt = (locale: string, maxLength: number, type: C export const extraPrompt = (generate: number) => `THE RESULT MUST BE ${generate} COMMIT MESSAGES AND MUST BE IN NUMBERED LIST FORMAT.`; export const isValidConventionalMessage = (message: string): boolean => { - const conventionalReg = - /^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\([\w\-]+\))?(!)?: .{1,80}(\n|\r\n){2}(.*(\n|\r\n)*)*$/; + // TODO: check loosely for issue that message is not coming out + // const conventionalReg = + // /^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\([\w\-]+\))?(!)?: .{1,80}(\n|\r\n){2}(.*(\n|\r\n)*)*$/; + const conventionalReg = /(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(.*\))?: .*$/; return conventionalReg.test(message); };