Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for prepending reference to commit messages #14

Merged
merged 1 commit into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,20 @@ Automatically confirm the generated commit message without prompting the user.
aicommit config set auto-confirm=true
```

#### prepend-reference

Default: `false`

Prepends issue reference from branch name to commit message.

branch name: `feature/abc-123-branch-name`

commit message: `ABC-123: <generated commit message>`

```sh
aicommit config set prepend-reference=true
```

## How it works

This CLI tool runs `git diff` to grab all your latest code changes, sends them to OpenAI's GPT-3, then returns the AI
Expand Down
13 changes: 13 additions & 0 deletions src/commands/aicommit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,19 @@ export default async (
message = selected as string;
}

if (config['prepend-reference']) {
// Get the current branch name
const { stdout} = await execa('git', ['branch', '--show-current']);

// Get reference from branch name
const taskNumber = stdout.match(/([a-zA-Z])+-([0-9]+)/)?.[0];

if (taskNumber?.length) {
// Prepend reference to commit message
message = `${taskNumber?.toUpperCase()}: ${message}`;
}
}

await execa('git', ['commit', '-m', message, ...rawArgv]);

outro(`${green('✔')} Successfully committed!`);
Expand Down
12 changes: 12 additions & 0 deletions src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ const configParsers = {
parseAssert('auto-confirm', /^(?:true|false)$/.test(autoConfirm), 'Must be a boolean');
return autoConfirm === 'true';
},
'prepend-reference'(prependReference?: string | boolean) {
if (!prependReference) {
return false;
}

if (typeof prependReference === 'boolean') {
return prependReference;
}

parseAssert('prepend-reference', /^(?:true|false)$/.test(prependReference), 'Must be a boolean');
return prependReference === 'true';
},
} as const;

type ConfigKeys = keyof typeof configParsers;
Expand Down
62 changes: 62 additions & 0 deletions tests/specs/cli/commits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,68 @@ export default testSuite(({ describe }) => {
await fixture.rm();
});

test('Generates commit message with prepended reference from branch name', async () => {

const { fixture, aicommit } = await createFixture(files);
const git = await createGit(fixture.path);

await git('checkout', ['-b', 'feature/abc-123-some-feature']);
await git('add', ['data.json']);

const autoConfirm = 'prepend-reference=true'
await aicommit(['config', 'set', autoConfirm])

const committing = aicommit();
committing.stdout!.on('data', (buffer: Buffer) => {
const stdout = buffer.toString();
if (stdout.match('└')) {
committing.stdin!.write('y');
committing.stdin!.end();
}
});

await committing;

const { stdout: commitMessage } = await git('log', ['--pretty=format:%s']);
console.log({
commitMessage,
length: commitMessage.length,
});
expect(commitMessage.startsWith('ABC-123: ')).toBe(true);
await fixture.rm();
});

test('Generates commit message will no prepend if no valid reference', async () => {

const { fixture, aicommit } = await createFixture(files);
const git = await createGit(fixture.path);

await git('checkout', ['-b', 'feature/some-feature']);
await git('add', ['data.json']);

const autoConfirm = 'prepend-reference=true'
await aicommit(['config', 'set', autoConfirm])

const committing = aicommit();
committing.stdout!.on('data', (buffer: Buffer) => {
const stdout = buffer.toString();
if (stdout.match('└')) {
committing.stdin!.write('y');
committing.stdin!.end();
}
});

await committing;

const { stdout: commitMessage } = await git('log', ['--pretty=format:%s']);
console.log({
commitMessage,
length: commitMessage.length,
});
expect(commitMessage.length).toBeLessThanOrEqual(50);
await fixture.rm();
});

test('Generated commit message must be under 50 characters', async () => {
const { fixture, aicommit } = await createFixture({
...files,
Expand Down
24 changes: 24 additions & 0 deletions tests/specs/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,30 @@ export default testSuite(({ describe }) => {
})
})

await describe('prepend-reference', ({ test }) => {
test('must be a boolean', async () => {
const { stderr } = await aicommit(['config', 'set', 'prepend-reference=abc'], {
reject: false
})

expect(stderr).toMatch('Must be a boolean')
})

test('updates config', async () => {
const defaultConfig = await aicommit(['config', 'get', 'prepend-reference'])
expect(defaultConfig.stdout).toBe('prepend-reference=false')

const autoConfirm = 'prepend-reference=true'
await aicommit(['config', 'set', autoConfirm])

const configFile = await fs.readFile(configPath, 'utf8')
expect(configFile).toMatch(autoConfirm)

const get = await aicommit(['config', 'get', 'prepend-reference'])
expect(get.stdout).toBe(autoConfirm)
})
})

await test('set config file', async () => {
await aicommit(['config', 'set', openAiToken])

Expand Down