Skip to content

Commit 7e823d7

Browse files
[FEATURE] Add failOnMatch option
This option, when `"true"` will fail the checker when the given pattern matches the commit message. This allows for a simpler kind check for negative conditions such as "The commit message does not start with 'fixup'." I rewrote some test cases here so that they were grouped into input types. This allowed me to use the same inputs for both the default settings and also the `failOnMatch` setting. Each of the "default" tests are exactly the same as they were before, with the "via `failOnMatch`" tests being the tests that were actually added.
1 parent 4c06ad2 commit 7e823d7

File tree

6 files changed

+127
-29
lines changed

6 files changed

+127
-29
lines changed

README.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,15 @@ jobs:
6767
error: 'The maximum line length of 74 characters is exceeded.'
6868
excludeDescription: 'true' # optional: this excludes the description body of a pull request
6969
excludeTitle: 'true' # optional: this excludes the title of a pull request
70-
checkAllCommitMessages: 'true' # optional: this checks all commits associated with a pull request
71-
accessToken: ${{ secrets.GITHUB_TOKEN }} # github access token is only required if checkAllCommitMessages is true
70+
- name: Squash/Fixup Check
71+
uses: gsactions/commit-message-checker@v2
72+
with:
73+
pattern: '^(fixup|squash)'
74+
failOnMatch: 'true' # optional: this will fail the test if the pattern matches a commit message
75+
error: Don't forget to squash/fixup your commits before merging
76+
excludeDescription: 'true'
77+
checkAllCommitMessages: 'true'
78+
accessToken: ${{ secrets.GITHUB_TOKEN }}
7279
- name: Check for Resolves / Fixes
7380
uses: gsactions/commit-message-checker@v2
7481
with:

__tests__/commit-message-checker.test.ts

+90-18
Original file line numberDiff line numberDiff line change
@@ -77,51 +77,123 @@ describe('commit-message-checker tests', () => {
7777
).rejects.toThrow('MESSAGES not defined.')
7878
})
7979

80-
it('check fails single message', async () => {
80+
describe('single message, without a match', () => {
8181
const checkerArguments: ICheckerArguments = {
8282
pattern: 'some-pattern',
8383
flags: '',
8484
error: 'some-error',
8585
messages: ['some-message']
8686
}
87-
await expect(
88-
commitMessageChecker.checkCommitMessages(checkerArguments)
89-
).rejects.toThrow('some-error')
87+
88+
it('fails by default', async () => {
89+
await expect(
90+
commitMessageChecker.checkCommitMessages(checkerArguments)
91+
).rejects.toThrow('some-error')
92+
})
93+
94+
it('succeeds via `failOnMatch`', async () => {
95+
await expect(
96+
commitMessageChecker.checkCommitMessages({
97+
...checkerArguments,
98+
failOnMatch: true
99+
})
100+
).resolves.toBeUndefined()
101+
})
90102
})
91103

92-
it('check fails multiple messages', async () => {
104+
describe('single message, with a match', () => {
105+
const checkerArguments: ICheckerArguments = {
106+
pattern: '.*',
107+
flags: '',
108+
error: 'some-error',
109+
messages: ['some-message']
110+
}
111+
112+
it('succeeds by default', async () => {
113+
await expect(
114+
commitMessageChecker.checkCommitMessages(checkerArguments)
115+
).resolves.toBeUndefined()
116+
})
117+
118+
it('fails via `failOnMatch`', async () => {
119+
await expect(
120+
commitMessageChecker.checkCommitMessages({
121+
...checkerArguments,
122+
failOnMatch: true
123+
})
124+
).rejects.toThrow('some-error')
125+
})
126+
})
127+
128+
describe('multiple messages, with a single match', () => {
93129
const checkerArguments: ICheckerArguments = {
94130
pattern: 'some-pattern',
95131
flags: '',
96132
error: 'some-error',
97133
messages: ['some-message', 'some-pattern']
98134
}
99-
await expect(
100-
commitMessageChecker.checkCommitMessages(checkerArguments)
101-
).rejects.toThrow('some-error')
135+
136+
it('fails by default', async () => {
137+
await expect(
138+
commitMessageChecker.checkCommitMessages(checkerArguments)
139+
).rejects.toThrow('some-error')
140+
})
141+
142+
it('fails via `failOnMatch`', async () => {
143+
await expect(
144+
commitMessageChecker.checkCommitMessages({
145+
...checkerArguments,
146+
failOnMatch: true
147+
})
148+
).rejects.toThrow('some-error')
149+
})
102150
})
103151

104-
it('check succeeds on single message', async () => {
152+
describe('multiple messages, without any match', () => {
105153
const checkerArguments: ICheckerArguments = {
106-
pattern: '.*',
154+
pattern: 'some-pattern',
107155
flags: '',
108156
error: 'some-error',
109-
messages: ['some-message']
157+
messages: ['some-message', 'other-message']
110158
}
111-
await expect(
112-
commitMessageChecker.checkCommitMessages(checkerArguments)
113-
).resolves.toBeUndefined()
159+
160+
it('fails by default', async () => {
161+
await expect(
162+
commitMessageChecker.checkCommitMessages(checkerArguments)
163+
).rejects.toThrow('some-error')
164+
})
165+
166+
it('succeeds via `failOnMatch`', async () => {
167+
await expect(
168+
commitMessageChecker.checkCommitMessages({
169+
...checkerArguments,
170+
failOnMatch: true
171+
})
172+
).resolves.toBeUndefined()
173+
})
114174
})
115175

116-
it('check succeeds on multiple messages', async () => {
176+
describe('multiple messages, all matching', () => {
117177
const checkerArguments: ICheckerArguments = {
118178
pattern: '.*',
119179
flags: '',
120180
error: 'some-error',
121181
messages: ['some-message', 'other-message']
122182
}
123-
await expect(
124-
commitMessageChecker.checkCommitMessages(checkerArguments)
125-
).resolves.toBeUndefined()
183+
184+
it('succeeds by default', async () => {
185+
await expect(
186+
commitMessageChecker.checkCommitMessages(checkerArguments)
187+
).resolves.toBeUndefined()
188+
})
189+
190+
it('fails via `failOnMatch`', async () => {
191+
await expect(
192+
commitMessageChecker.checkCommitMessages({
193+
...checkerArguments,
194+
failOnMatch: true
195+
})
196+
).rejects.toThrow('some-error')
197+
})
126198
})
127199
})

action.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@ inputs:
1010
required: false
1111
default: 'gm'
1212
error:
13-
description: 'A error message which will be returned in case of an error.'
13+
description: 'An error message which will be returned in case of an error.'
1414
required: true
1515
excludeTitle:
1616
description: 'Setting this input to true will exclude the Pull Request title from the check.'
1717
required: false
1818
default: 'false'
19+
failOnMatch:
20+
description: 'Setting this input to true will reverse the logic so that a positive match will fail the check.'
21+
required: false
22+
default: 'false'
1923
excludeDescription:
2024
description: 'Setting this input to true will exclude the Pull Request description from the check.'
2125
required: false

dist/index.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ function checkCommitMessages(args) {
8989
}
9090
// Check messages
9191
let result = true;
92-
core.info(`Checking commit messages against "${args.pattern}"...`);
92+
core.info(`Checking commit messages ${args.failOnMatch ? 'do not ' : ''}match "${args.pattern}"...`);
9393
for (const message of args.messages) {
94-
if (checkMessage(message, args.pattern, args.flags)) {
94+
if (checkMessage(message, args.pattern, args.flags, args.failOnMatch)) {
9595
core.info(`- OK: "${message}"`);
9696
}
9797
else {
@@ -113,9 +113,10 @@ exports.checkCommitMessages = checkCommitMessages;
113113
* @param pattern regex pattern for the check.
114114
* @returns boolean
115115
*/
116-
function checkMessage(message, pattern, flags) {
116+
function checkMessage(message, pattern, flags, failOnMatch) {
117117
const regex = new RegExp(pattern, flags);
118-
return regex.test(message);
118+
const result = regex.test(message);
119+
return failOnMatch ? !result : result;
119120
}
120121

121122

@@ -200,6 +201,9 @@ function getInputs() {
200201
// Get error message
201202
result.error = core.getInput('error', { required: true });
202203
core.debug(`error: ${result.error}`);
204+
// Get failOnMatch
205+
result.failOnMatch = core.getInput('failOnMatch') === 'true';
206+
core.debug(`failOnMatch: ${result.failOnMatch}`);
203207
// Get excludeTitle
204208
const excludeTitleStr = core.getInput('excludeTitle');
205209
core.debug(`excludeTitle: ${excludeTitleStr}`);

src/commit-message-checker.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import * as core from '@actions/core'
2626
*/
2727
export interface ICheckerArguments {
2828
pattern: string
29+
failOnMatch?: boolean
2930
flags: string
3031
error: string
3132
messages: string[]
@@ -66,10 +67,14 @@ export async function checkCommitMessages(
6667
// Check messages
6768
let result = true
6869

69-
core.info(`Checking commit messages against "${args.pattern}"...`)
70+
core.info(
71+
`Checking commit messages ${args.failOnMatch ? 'do not ' : ''}match "${
72+
args.pattern
73+
}"...`
74+
)
7075

7176
for (const message of args.messages) {
72-
if (checkMessage(message, args.pattern, args.flags)) {
77+
if (checkMessage(message, args.pattern, args.flags, args.failOnMatch)) {
7378
core.info(`- OK: "${message}"`)
7479
} else {
7580
core.info(`- failed: "${message}"`)
@@ -93,8 +98,10 @@ export async function checkCommitMessages(
9398
function checkMessage(
9499
message: string,
95100
pattern: string,
96-
flags: string
101+
flags: string,
102+
failOnMatch?: boolean
97103
): boolean {
98104
const regex = new RegExp(pattern, flags)
99-
return regex.test(message)
105+
const result = regex.test(message)
106+
return failOnMatch ? !result : result
100107
}

src/input-helper.ts

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ export async function getInputs(): Promise<ICheckerArguments> {
5252
result.error = core.getInput('error', {required: true})
5353
core.debug(`error: ${result.error}`)
5454

55+
// Get failOnMatch
56+
result.failOnMatch = core.getInput('failOnMatch') === 'true'
57+
core.debug(`failOnMatch: ${result.failOnMatch}`)
58+
5559
// Get excludeTitle
5660
const excludeTitleStr = core.getInput('excludeTitle')
5761
core.debug(`excludeTitle: ${excludeTitleStr}`)

0 commit comments

Comments
 (0)