Skip to content

Commit 35ac347

Browse files
feat: add commit-author for customization (#53)
* feat: add commit-author and commit-body inputs to action * feat: implement commit-body and commit-author input parsing with validation * test: add tests for commit-body and commit-author features * docs: document commit-author and commit-body inputs * refactor: remove commit-body input in favor of multi-line message --------- Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
1 parent e0d02c4 commit 35ac347

File tree

5 files changed

+161
-8
lines changed

5 files changed

+161
-8
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,26 @@ jobs:
6161
token: ${{ steps.generate-token.outputs.token }}
6262
```
6363
64+
#### With multi-line message and custom author
65+
66+
```yaml
67+
- name: Commit with details
68+
uses: dsanders11/github-app-commit-action@v1
69+
with:
70+
message: |
71+
feat: add new feature
72+
73+
This change adds support for the new API.
74+
75+
Closes #123
76+
commit-author: 'Bot User <bot@example.com>'
77+
token: ${{ steps.generate-token.outputs.token }}
78+
```
79+
6480
### Inputs
6581
82+
- `commit-author` - _(optional)_ Commit author in format "Name &lt;email&gt;".
83+
If not provided, the commit will be authored by the GitHub App.
6684
- `fail-on-no-changes` - _(optional)_ Whether or not to set action failure if
6785
there are no changes to commit (default: `true`)
6886
- `force` - _(optional)_ Whether to force the update or to make sure the update

__tests__/main.test.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,120 @@ describe('action', () => {
342342
expect(core.setOutput).toHaveBeenCalledWith('sha', commitSha);
343343
});
344344

345+
it('uses multi-line message for commit', async () => {
346+
const multiLineMessage =
347+
'feat: add new feature\n\nThis is the body\nwith multiple lines';
348+
const commitSha = 'commit-sha';
349+
350+
mockGetInput({ message: multiLineMessage, token });
351+
mockGetBooleanInput({});
352+
vi.mocked(lib.getHeadRef).mockResolvedValue('main');
353+
vi.mocked(lib.getHeadSha).mockResolvedValue('head-sha');
354+
vi.mocked(lib.getHeadTreeHash).mockResolvedValue('head-tree-hash');
355+
vi.mocked(lib.getStagedFiles).mockResolvedValue(stagedFiles);
356+
vi.mocked(createTree).mockResolvedValue({ data: { sha: 'tree-sha' } });
357+
vi.mocked(createCommit).mockResolvedValue({ data: { sha: commitSha } });
358+
vi.mocked(updateRef).mockResolvedValue({ data: {} });
359+
360+
await main.run();
361+
expect(runSpy).toHaveReturned();
362+
363+
expect(createCommit).toHaveBeenCalledWith(
364+
expect.objectContaining({
365+
message: multiLineMessage
366+
})
367+
);
368+
369+
expect(core.setOutput).toHaveBeenCalledWith('message', multiLineMessage);
370+
});
371+
372+
it('uses commit-author with valid format', async () => {
373+
const commitAuthor = 'John Doe <john@example.com>';
374+
const commitSha = 'commit-sha';
375+
376+
mockGetInput({ message, token, 'commit-author': commitAuthor });
377+
mockGetBooleanInput({});
378+
vi.mocked(lib.getHeadRef).mockResolvedValue('main');
379+
vi.mocked(lib.getHeadSha).mockResolvedValue('head-sha');
380+
vi.mocked(lib.getHeadTreeHash).mockResolvedValue('head-tree-hash');
381+
vi.mocked(lib.getStagedFiles).mockResolvedValue(stagedFiles);
382+
vi.mocked(createTree).mockResolvedValue({ data: { sha: 'tree-sha' } });
383+
vi.mocked(createCommit).mockResolvedValue({ data: { sha: commitSha } });
384+
vi.mocked(updateRef).mockResolvedValue({ data: {} });
385+
386+
await main.run();
387+
expect(runSpy).toHaveReturned();
388+
389+
expect(createCommit).toHaveBeenCalledWith(
390+
expect.objectContaining({
391+
author: {
392+
name: 'John Doe',
393+
email: 'john@example.com'
394+
}
395+
})
396+
);
397+
});
398+
399+
it('warns and ignores invalid commit-author format', async () => {
400+
const commitAuthor = 'invalid-format';
401+
const commitSha = 'commit-sha';
402+
403+
mockGetInput({ message, token, 'commit-author': commitAuthor });
404+
mockGetBooleanInput({});
405+
vi.mocked(lib.getHeadRef).mockResolvedValue('main');
406+
vi.mocked(lib.getHeadSha).mockResolvedValue('head-sha');
407+
vi.mocked(lib.getHeadTreeHash).mockResolvedValue('head-tree-hash');
408+
vi.mocked(lib.getStagedFiles).mockResolvedValue(stagedFiles);
409+
vi.mocked(createTree).mockResolvedValue({ data: { sha: 'tree-sha' } });
410+
vi.mocked(createCommit).mockResolvedValue({ data: { sha: commitSha } });
411+
vi.mocked(updateRef).mockResolvedValue({ data: {} });
412+
413+
await main.run();
414+
expect(runSpy).toHaveReturned();
415+
416+
expect(core.warning).toHaveBeenCalledWith(
417+
'Invalid commit-author format: "invalid-format". Expected format: "Name <email>". Ignoring author.'
418+
);
419+
expect(createCommit).toHaveBeenCalledWith(
420+
expect.not.objectContaining({
421+
author: expect.anything()
422+
})
423+
);
424+
});
425+
426+
it('uses multi-line message with commit-author', async () => {
427+
const multiLineMessage = 'feat: add feature\n\nBody text here';
428+
const commitAuthor = 'Jane Smith <jane@example.com>';
429+
const commitSha = 'commit-sha';
430+
431+
mockGetInput({
432+
message: multiLineMessage,
433+
token,
434+
'commit-author': commitAuthor
435+
});
436+
mockGetBooleanInput({});
437+
vi.mocked(lib.getHeadRef).mockResolvedValue('main');
438+
vi.mocked(lib.getHeadSha).mockResolvedValue('head-sha');
439+
vi.mocked(lib.getHeadTreeHash).mockResolvedValue('head-tree-hash');
440+
vi.mocked(lib.getStagedFiles).mockResolvedValue(stagedFiles);
441+
vi.mocked(createTree).mockResolvedValue({ data: { sha: 'tree-sha' } });
442+
vi.mocked(createCommit).mockResolvedValue({ data: { sha: commitSha } });
443+
vi.mocked(updateRef).mockResolvedValue({ data: {} });
444+
445+
await main.run();
446+
expect(runSpy).toHaveReturned();
447+
448+
expect(createCommit).toHaveBeenCalledWith(
449+
expect.objectContaining({
450+
message: multiLineMessage,
451+
author: {
452+
name: 'Jane Smith',
453+
email: 'jane@example.com'
454+
}
455+
})
456+
);
457+
});
458+
345459
it('handles generic errors', async () => {
346460
mockGetInput({ message, token });
347461
vi.mocked(lib.getStagedFiles).mockImplementation(() => {

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ inputs:
1515
description: Whether to force the update or to make sure the update is a fast-forward update when updating an existing ref
1616
required: false
1717
default: false
18+
commit-author:
19+
description: 'Optional commit author in format "Name <email>"'
20+
required: false
1821
message:
1922
description: The commit message
2023
required: true

dist/index.js

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export async function run(): Promise<void> {
8080
const owner = core.getInput('owner') || github.context.repo.owner;
8181
const repo = core.getInput('repository') || github.context.repo.repo;
8282
const workingDirectory = core.getInput('working-directory');
83+
const commitAuthor = core.getInput('commit-author');
8384

8485
if (workingDirectory) {
8586
process.chdir(workingDirectory);
@@ -122,12 +123,29 @@ export async function run(): Promise<void> {
122123
});
123124
core.debug(`New tree SHA: ${newTree.data.sha}`);
124125

126+
// Parse optional commit author
127+
let author: { name: string; email: string } | undefined;
128+
if (commitAuthor) {
129+
const authorMatch = commitAuthor.match(/^(.+?)\s*<(.+?)>$/);
130+
if (authorMatch) {
131+
author = {
132+
name: authorMatch[1].trim(),
133+
email: authorMatch[2].trim()
134+
};
135+
} else {
136+
core.warning(
137+
`Invalid commit-author format: "${commitAuthor}". Expected format: "Name <email>". Ignoring author.`
138+
);
139+
}
140+
}
141+
125142
const newCommit = await octokit.rest.git.createCommit({
126143
owner,
127144
repo,
128145
parents: [await getHeadSha()],
129146
message,
130-
tree: newTree.data.sha
147+
tree: newTree.data.sha,
148+
...(author && { author })
131149
});
132150
core.debug(`New commit SHA: ${newCommit.data.sha}`);
133151

0 commit comments

Comments
 (0)