Skip to content

Commit 0a8a802

Browse files
committed
Adding wrappedRuleResolver to be able to delegate to standard rules offered by commitlint. Will be used by subject and type rules.
1 parent 3c1a991 commit 0a8a802

File tree

5 files changed

+149
-1
lines changed

5 files changed

+149
-1
lines changed

packages/commitlint-plugin-github-rules/@types/index.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { When } from 'commitlint-github-utils/@types';
2+
import { ParsedCommitMessage } from 'commitlint-github-utils';
23

34
export type RuleResolverResult = [boolean, string?];
45

@@ -19,6 +20,20 @@ export type BaseParsedCommit = Partial<{
1920

2021
export type RuleResolver<T> = (parsed: BaseParsedCommit, when?: When, value?: T) => RuleResolverResult;
2122

23+
export type WrappedRuleResolver<T> = (
24+
baseResolver: RuleResolver<T>,
25+
adapter: BaseParsedCommitAdapter,
26+
parsed: BaseParsedCommit,
27+
when?: When,
28+
value?: T,
29+
) => RuleResolverResult;
30+
31+
export type BaseParsedCommitAdapter = (parsed: ParsedCommitMessage) => BaseParsedCommit;
32+
33+
export type WhenAndValue<T> = [When, T?];
34+
35+
export type WhenAndRequiredValue<T> = [When, T];
36+
2237
export interface CommitlintPluginGitHub {
2338
rules: {
2439
[key: string]: unknown;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { When } from 'commitlint-github-utils/@types';
2+
import utils, { ParsedCommitMessage } from 'commitlint-github-utils';
3+
import { BaseParsedCommitAdapter, RuleResolver, RuleResolverResult } from '../../../../@types';
4+
import wrappedRuleResolver from '../wrappedRuleResolver';
5+
import { createBaseParsedCommit } from './utils';
6+
7+
// Mock the parseCommitMessage() method so we can isolate our test to just wrappedRuleResolver
8+
// (though note we aren't mocking utils.handleWipResult() currently which is called by wrappedRuleResolver)
9+
const mockedParseCommitMessage: jest.Mock<ParsedCommitMessage> = jest.fn() as jest.Mock<ParsedCommitMessage>;
10+
utils.parseCommitMessage = mockedParseCommitMessage;
11+
12+
export const EXPECTED_WHEN = When.NEVER;
13+
export const EXPECTED_VALUE = 'dummy-value';
14+
export const COMMIT_FROM_ADAPTER = createBaseParsedCommit('DUMMY_COMMIT');
15+
export const RESULT_FROM_BASE_RESOLVER: RuleResolverResult = [true, 'DUMMY_RESULT'];
16+
17+
export type WrappedRuleResolverResult = {
18+
result: RuleResolverResult;
19+
baseResolver: RuleResolver<string>;
20+
adapter: BaseParsedCommitAdapter;
21+
};
22+
23+
export const executeFunctionUnderTest = (
24+
rawCommitMessage: string,
25+
when: When,
26+
value: string,
27+
): WrappedRuleResolverResult => {
28+
const baseParsedCommit = createBaseParsedCommit(rawCommitMessage);
29+
30+
const parsedCommitMessage: ParsedCommitMessage = {
31+
issueNumbers: [],
32+
isWip: rawCommitMessage === 'WIP',
33+
body: [],
34+
};
35+
36+
mockedParseCommitMessage.mockReturnValue(parsedCommitMessage);
37+
38+
const baseResolver: RuleResolver<string> = jest.fn(() => RESULT_FROM_BASE_RESOLVER);
39+
const adapter: BaseParsedCommitAdapter = jest.fn(() => COMMIT_FROM_ADAPTER);
40+
41+
const result = wrappedRuleResolver(baseResolver, adapter, baseParsedCommit, when, value);
42+
43+
return { result, baseResolver, adapter };
44+
};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { When } from 'commitlint-github-utils/@types';
2+
3+
import {
4+
executeFunctionUnderTest,
5+
EXPECTED_WHEN,
6+
EXPECTED_VALUE,
7+
RESULT_FROM_BASE_RESOLVER,
8+
COMMIT_FROM_ADAPTER,
9+
WrappedRuleResolverResult,
10+
} from './wrappedRuleResolver.test.setup';
11+
12+
describe('wrappedRuleResolver', () => {
13+
it('should return false if an empty commit message is provided', () => {
14+
const results: WrappedRuleResolverResult[] = [
15+
executeFunctionUnderTest('', EXPECTED_WHEN, EXPECTED_VALUE),
16+
executeFunctionUnderTest('', EXPECTED_WHEN, EXPECTED_VALUE),
17+
];
18+
19+
results.forEach(execution => {
20+
expect(execution.result[0]).toEqual(false);
21+
expect(execution.baseResolver).not.toHaveBeenCalled();
22+
expect(execution.adapter).not.toHaveBeenCalled();
23+
});
24+
});
25+
26+
it('should delegate for non-WIP Commits when validating "always"', () => {
27+
const execution: WrappedRuleResolverResult = executeFunctionUnderTest('dummy commit', When.ALWAYS, EXPECTED_VALUE);
28+
29+
expect(execution.result).toEqual(RESULT_FROM_BASE_RESOLVER);
30+
expect(execution.adapter).toHaveBeenCalled();
31+
expect(execution.baseResolver).toHaveBeenCalledWith(COMMIT_FROM_ADAPTER, When.ALWAYS, EXPECTED_VALUE);
32+
});
33+
34+
it('should delegate for non-WIP Commits when validating "never"', () => {
35+
const execution: WrappedRuleResolverResult = executeFunctionUnderTest('dummy commit', When.NEVER, EXPECTED_VALUE);
36+
37+
expect(execution.result).toEqual(RESULT_FROM_BASE_RESOLVER);
38+
expect(execution.adapter).toHaveBeenCalled();
39+
expect(execution.baseResolver).toHaveBeenCalledWith(COMMIT_FROM_ADAPTER, When.NEVER, EXPECTED_VALUE);
40+
});
41+
42+
it('should always return true for WIP Commits when validating "always" and not delegate', () => {
43+
const execution: WrappedRuleResolverResult = executeFunctionUnderTest('WIP', When.ALWAYS, EXPECTED_VALUE);
44+
45+
expect(execution.result[0]).toEqual(true);
46+
expect(execution.baseResolver).not.toHaveBeenCalled();
47+
expect(execution.adapter).not.toHaveBeenCalled();
48+
});
49+
50+
it('should always return true for WIP Commits when validating "never" and not delegate', () => {
51+
const execution: WrappedRuleResolverResult = executeFunctionUnderTest('WIP', When.NEVER, EXPECTED_VALUE);
52+
53+
expect(execution.result[0]).toEqual(true);
54+
expect(execution.baseResolver).not.toHaveBeenCalled();
55+
expect(execution.adapter).not.toHaveBeenCalled();
56+
});
57+
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { When } from 'commitlint-github-utils/@types';
2+
import utils from 'commitlint-github-utils';
3+
4+
import { BaseParsedCommit, BaseParsedCommitAdapter, RuleResolver, RuleResolverResult } from '../../../@types';
5+
6+
function resolveRuleUsingBaseResolver<T>(
7+
baseResolver: RuleResolver<T>,
8+
adapter: BaseParsedCommitAdapter,
9+
parsed: BaseParsedCommit,
10+
whenPassedIn?: When,
11+
value?: T,
12+
): RuleResolverResult {
13+
const rawCommitMessage = parsed.raw;
14+
if (!rawCommitMessage) return [false, 'Commit message should not be empty'];
15+
16+
const commitMessage = utils.parseCommitMessage(rawCommitMessage);
17+
18+
// We short circuit if the When requested is only for non-WIPs and the commit is a WIP
19+
const wipHandledResult = utils.handleWipCommits(commitMessage, whenPassedIn);
20+
if (wipHandledResult.isWipValidated) {
21+
// In that case we just return true immediately
22+
return [true];
23+
}
24+
25+
// Otherwise we call the base resolver with the When returned as if it was passed a NON-WIPs one
26+
// it has been converted to a standard ALWAYS or NEVER which is suitable for passing to the base resolver
27+
// See the docs on handleWipCommits() for more info
28+
29+
return baseResolver(adapter(commitMessage), wipHandledResult.when, value);
30+
}
31+
32+
export default resolveRuleUsingBaseResolver;

packages/commitlint-plugin-github-rules/src/tests/index.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import commitlintPluginGitHub from '../index';
22

33
describe('commitlintPluginGitHub', () => {
44
it('should return a valid config', () => {
5-
expect(commitlintPluginGitHub).toHaveProperty('rules')
5+
expect(commitlintPluginGitHub).toHaveProperty('rules');
66
expect(Object.keys(commitlintPluginGitHub.rules).length).toBeGreaterThan(0);
77
});
88
});

0 commit comments

Comments
 (0)