@mui/internal-code-infra 0.0.4-canary.10 → 0.0.4-canary.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +21 -7
- package/build/babel-config.d.mts +5 -1
- package/build/brokenLinksChecker/crawlWorker.d.mts +1 -0
- package/build/brokenLinksChecker/index.d.mts +192 -2
- package/build/changelog/fetchChangelogs.d.mts +3 -0
- package/build/changelog/types.d.ts +3 -1
- package/build/cli/cmdArgosPush.d.mts +8 -2
- package/build/cli/cmdBuild.d.mts +48 -2
- package/build/cli/cmdCopyFiles.d.mts +14 -2
- package/build/cli/cmdExtractErrorCodes.d.mts +2 -2
- package/build/cli/cmdGenerateChangelog.d.mts +17 -2
- package/build/cli/cmdGithubAuth.d.mts +2 -2
- package/build/cli/cmdListWorkspaces.d.mts +14 -2
- package/build/cli/cmdNetlifyIgnore.d.mts +12 -2
- package/build/cli/cmdPublish.d.mts +23 -4
- package/build/cli/cmdPublishCanary.d.mts +20 -2
- package/build/cli/cmdPublishNewPackage.d.mts +10 -2
- package/build/cli/cmdRenameScope.d.mts +18 -0
- package/build/cli/cmdSetVersionOverrides.d.mts +5 -2
- package/build/cli/cmdVale.d.mts +46 -0
- package/build/cli/cmdValidateBuiltTypes.d.mts +2 -2
- package/build/eslint/baseConfig.d.mts +3 -1
- package/build/eslint/mui/rules/disallow-react-api-in-server-components.d.mts +2 -2
- package/build/eslint/mui/rules/docgen-ignore-before-comment.d.mts +2 -2
- package/build/eslint/mui/rules/no-floating-cleanup.d.mts +5 -0
- package/build/eslint/mui/rules/no-guarded-throw.d.mts +31 -0
- package/build/eslint/mui/rules/no-presentation-role.d.mts +5 -0
- package/build/eslint/mui/rules/no-restricted-resolved-imports.d.mts +8 -2
- package/build/eslint/mui/rules/nodeEnvUtils.d.mts +18 -0
- package/build/remark/config.d.mts +43 -0
- package/build/remark/createLintTester.d.mts +10 -0
- package/build/remark/firstBlockHeading.d.mts +4 -0
- package/build/remark/gitDiff.d.mts +2 -0
- package/build/remark/noSpaceInLinks.d.mts +2 -0
- package/build/remark/straightQuotes.d.mts +2 -0
- package/build/remark/tableAlignment.d.mts +2 -0
- package/build/remark/terminalLanguage.d.mts +2 -0
- package/build/utils/babel.d.mts +7 -1
- package/build/utils/build.d.mts +59 -37
- package/build/utils/extractErrorCodes.d.mts +9 -0
- package/build/utils/git.d.mts +16 -0
- package/build/utils/github.d.mts +13 -1
- package/build/utils/pnpm.d.mts +226 -20
- package/build/utils/testUtils.d.mts +28 -0
- package/build/utils/typescript.d.mts +6 -16
- package/package.json +79 -53
- package/src/babel-config.mjs +3 -1
- package/src/brokenLinksChecker/crawlWorker.mjs +240 -0
- package/src/brokenLinksChecker/index.mjs +263 -188
- package/src/changelog/fetchChangelogs.mjs +8 -2
- package/src/changelog/renderChangelog.mjs +1 -1
- package/src/changelog/types.ts +3 -1
- package/src/cli/cmdBuild.mjs +53 -88
- package/src/cli/cmdListWorkspaces.mjs +7 -1
- package/src/cli/cmdNetlifyIgnore.mjs +30 -5
- package/src/cli/cmdPublish.mjs +79 -37
- package/src/cli/cmdPublishCanary.mjs +96 -24
- package/src/cli/cmdPublishNewPackage.mjs +31 -8
- package/src/cli/cmdRenameScope.mjs +76 -0
- package/src/cli/cmdSetVersionOverrides.mjs +40 -34
- package/src/cli/cmdVale.mjs +513 -0
- package/src/cli/index.mjs +4 -0
- package/src/cli/packageJson.d.ts +2 -3
- package/src/eslint/baseConfig.mjs +51 -19
- package/src/eslint/docsConfig.mjs +2 -1
- package/src/eslint/mui/config.mjs +24 -4
- package/src/eslint/mui/index.mjs +6 -0
- package/src/eslint/mui/rules/no-floating-cleanup.mjs +187 -0
- package/src/eslint/mui/rules/no-guarded-throw.mjs +115 -0
- package/src/eslint/mui/rules/no-presentation-role.mjs +60 -0
- package/src/eslint/mui/rules/nodeEnvUtils.mjs +52 -0
- package/src/eslint/mui/rules/require-dev-wrapper.mjs +25 -40
- package/src/estree-typescript.d.ts +1 -1
- package/src/remark/config.mjs +157 -0
- package/src/remark/createLintTester.mjs +19 -0
- package/src/remark/firstBlockHeading.mjs +87 -0
- package/src/remark/gitDiff.mjs +43 -0
- package/src/remark/noSpaceInLinks.mjs +42 -0
- package/src/remark/straightQuotes.mjs +31 -0
- package/src/remark/tableAlignment.mjs +23 -0
- package/src/remark/terminalLanguage.mjs +19 -0
- package/src/stylelint/index.mjs +2 -2
- package/src/untyped-plugins.d.ts +14 -14
- package/src/utils/build.mjs +604 -270
- package/src/utils/git.mjs +27 -7
- package/src/utils/pnpm.mjs +636 -60
- package/src/utils/testUtils.mjs +53 -0
- package/src/utils/typescript.mjs +23 -42
- package/vale/.vale.ini +1 -0
- package/vale/styles/MUI/CorrectReferenceAllCases.yml +42 -0
- package/vale/styles/MUI/CorrectRererenceCased.yml +14 -0
- package/vale/styles/MUI/GoogleLatin.yml +11 -0
- package/vale/styles/MUI/MuiBrandName.yml +22 -0
- package/vale/styles/MUI/NoBritish.yml +112 -0
- package/vale/styles/MUI/NoCompanyName.yml +17 -0
- package/build/markdownlint/duplicate-h1.d.mts +0 -56
- package/build/markdownlint/git-diff.d.mts +0 -11
- package/build/markdownlint/index.d.mts +0 -52
- package/build/markdownlint/straight-quotes.d.mts +0 -11
- package/build/markdownlint/table-alignment.d.mts +0 -11
- package/build/markdownlint/terminal-language.d.mts +0 -11
- package/src/brokenLinksChecker/__fixtures__/static-site/broken-links.html +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/broken-targets.html +0 -22
- package/src/brokenLinksChecker/__fixtures__/static-site/example.md +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/external-links.html +0 -21
- package/src/brokenLinksChecker/__fixtures__/static-site/ignored-page.html +0 -17
- package/src/brokenLinksChecker/__fixtures__/static-site/index.html +0 -28
- package/src/brokenLinksChecker/__fixtures__/static-site/known-targets.json +0 -5
- package/src/brokenLinksChecker/__fixtures__/static-site/nested/page.html +0 -21
- package/src/brokenLinksChecker/__fixtures__/static-site/orphaned-page.html +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/page-with-api-links.html +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/page-with-custom-targets.html +0 -24
- package/src/brokenLinksChecker/__fixtures__/static-site/page-with-ignored-content.html +0 -28
- package/src/brokenLinksChecker/__fixtures__/static-site/page-with-known-target-links.html +0 -19
- package/src/brokenLinksChecker/__fixtures__/static-site/unclosed-tags.html +0 -1
- package/src/brokenLinksChecker/__fixtures__/static-site/valid.html +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/with-anchors.html +0 -31
- package/src/brokenLinksChecker/index.test.ts +0 -261
- package/src/changelog/categorizeCommits.test.ts +0 -319
- package/src/changelog/filterCommits.test.ts +0 -363
- package/src/changelog/parseCommitLabels.test.ts +0 -509
- package/src/changelog/renderChangelog.test.ts +0 -378
- package/src/changelog/sortSections.test.ts +0 -199
- package/src/eslint/mui/rules/add-undef-to-optional.test.mjs +0 -361
- package/src/eslint/mui/rules/consistent-production-guard.test.mjs +0 -162
- package/src/eslint/mui/rules/disallow-active-elements-as-key-event-target.test.mjs +0 -66
- package/src/eslint/mui/rules/disallow-react-api-in-server-components.test.mjs +0 -305
- package/src/eslint/mui/rules/docgen-ignore-before-comment.test.mjs +0 -52
- package/src/eslint/mui/rules/flatten-parentheses.test.mjs +0 -245
- package/src/eslint/mui/rules/mui-name-matches-component-name.test.mjs +0 -247
- package/src/eslint/mui/rules/no-empty-box.test.mjs +0 -40
- package/src/eslint/mui/rules/no-styled-box.test.mjs +0 -73
- package/src/eslint/mui/rules/require-dev-wrapper.test.mjs +0 -265
- package/src/eslint/mui/rules/rules-of-use-theme-variants.test.mjs +0 -149
- package/src/eslint/mui/rules/straight-quotes.test.mjs +0 -67
- package/src/markdownlint/duplicate-h1.mjs +0 -69
- package/src/markdownlint/git-diff.mjs +0 -31
- package/src/markdownlint/index.mjs +0 -62
- package/src/markdownlint/straight-quotes.mjs +0 -26
- package/src/markdownlint/table-alignment.mjs +0 -42
- package/src/markdownlint/terminal-language.mjs +0 -19
- package/src/utils/build.test.mjs +0 -705
- package/src/utils/template.test.mjs +0 -133
- package/src/utils/typescript.test.mjs +0 -380
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
// eslint-disable-next-line import/extensions
|
|
3
|
-
import { categorizeCommits } from './categorizeCommits.mjs';
|
|
4
|
-
import type { FetchedCommitDetails, CategorizationConfig, LabelConfig } from './types';
|
|
5
|
-
|
|
6
|
-
const baseLabelConfig: LabelConfig = {
|
|
7
|
-
plan: {
|
|
8
|
-
values: ['pro', 'premium'],
|
|
9
|
-
},
|
|
10
|
-
flags: {
|
|
11
|
-
'breaking change': { name: 'breaking change' },
|
|
12
|
-
},
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
function createCommit(
|
|
16
|
-
prNumber: number,
|
|
17
|
-
labels: string[],
|
|
18
|
-
overrides?: Partial<FetchedCommitDetails>,
|
|
19
|
-
): FetchedCommitDetails {
|
|
20
|
-
return {
|
|
21
|
-
sha: `sha-${prNumber}`,
|
|
22
|
-
message: `feat: feature for PR #${prNumber}`,
|
|
23
|
-
labels,
|
|
24
|
-
prNumber,
|
|
25
|
-
html_url: `https://github.com/mui/mui-x/pull/${prNumber}`,
|
|
26
|
-
author: { login: 'dev', association: 'team' },
|
|
27
|
-
createdAt: null,
|
|
28
|
-
mergedAt: null,
|
|
29
|
-
...overrides,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
describe('categorizeCommits', () => {
|
|
34
|
-
describe('component strategy', () => {
|
|
35
|
-
const componentConfig: CategorizationConfig = {
|
|
36
|
-
strategy: 'component',
|
|
37
|
-
labels: baseLabelConfig,
|
|
38
|
-
sections: {
|
|
39
|
-
fallbackSection: 'Other',
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
it('should categorize commits by component label', () => {
|
|
44
|
-
const commits = [
|
|
45
|
-
createCommit(1, ['component: Button']),
|
|
46
|
-
createCommit(2, ['component: Checkbox']),
|
|
47
|
-
createCommit(3, ['component: Button']),
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
const result = categorizeCommits(commits, componentConfig);
|
|
51
|
-
|
|
52
|
-
expect(result.size).toBe(2);
|
|
53
|
-
// Component labels are normalized to lowercase by parseCommitLabels
|
|
54
|
-
expect(result.get('Button')).toHaveLength(2);
|
|
55
|
-
expect(result.get('Checkbox')).toHaveLength(1);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should place commits without component labels in fallback section', () => {
|
|
59
|
-
const commits = [createCommit(1, []), createCommit(2, ['breaking change'])];
|
|
60
|
-
|
|
61
|
-
const result = categorizeCommits(commits, componentConfig);
|
|
62
|
-
|
|
63
|
-
expect(result.size).toBe(1);
|
|
64
|
-
expect(result.get('Other')).toHaveLength(2);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should place commits with multiple component labels in multiple sections', () => {
|
|
68
|
-
const commits = [createCommit(1, ['component: Button', 'component: Checkbox'])];
|
|
69
|
-
|
|
70
|
-
const result = categorizeCommits(commits, componentConfig);
|
|
71
|
-
|
|
72
|
-
expect(result.size).toBe(2);
|
|
73
|
-
// Component labels are normalized to lowercase by parseCommitLabels
|
|
74
|
-
expect(result.get('Button')).toHaveLength(1);
|
|
75
|
-
expect(result.get('Checkbox')).toHaveLength(1);
|
|
76
|
-
// Same commit object in both categories
|
|
77
|
-
expect(result.get('Button')?.[0].prNumber).toBe(1);
|
|
78
|
-
expect(result.get('Checkbox')?.[0].prNumber).toBe(1);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should use categoryOverride when present', () => {
|
|
82
|
-
const configWithOverrides: CategorizationConfig = {
|
|
83
|
-
...componentConfig,
|
|
84
|
-
labels: {
|
|
85
|
-
...baseLabelConfig,
|
|
86
|
-
categoryOverrides: {
|
|
87
|
-
'all components': 'General changes',
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const commits = [
|
|
93
|
-
createCommit(1, ['component: Button', 'all components']),
|
|
94
|
-
createCommit(2, ['component: Checkbox']),
|
|
95
|
-
createCommit(3, ['component: Button', 'all components']),
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
const result = categorizeCommits(commits, configWithOverrides);
|
|
99
|
-
|
|
100
|
-
expect(result.size).toBe(2);
|
|
101
|
-
expect(result.get('General changes')).toHaveLength(2);
|
|
102
|
-
expect(result.get('General changes')?.[0].prNumber).toBe(1);
|
|
103
|
-
expect(result.get('General changes')?.[1].prNumber).toBe(3);
|
|
104
|
-
// Component labels are normalized to lowercase by parseCommitLabels
|
|
105
|
-
expect(result.get('Checkbox')).toHaveLength(1);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('package strategy', () => {
|
|
110
|
-
const packageConfig: CategorizationConfig = {
|
|
111
|
-
strategy: 'package',
|
|
112
|
-
labels: baseLabelConfig,
|
|
113
|
-
packageNaming: {
|
|
114
|
-
mappings: {
|
|
115
|
-
'data grid': '@mui/x-data-grid',
|
|
116
|
-
charts: '@mui/x-charts',
|
|
117
|
-
pickers: '@mui/x-date-pickers',
|
|
118
|
-
},
|
|
119
|
-
genericScopes: ['docs', 'code-infra'],
|
|
120
|
-
plans: {
|
|
121
|
-
pro: {
|
|
122
|
-
'@mui/x-data-grid': '@mui/x-data-grid-pro',
|
|
123
|
-
'@mui/x-charts': '@mui/x-charts-pro',
|
|
124
|
-
'@mui/x-date-pickers': '@mui/x-date-pickers-pro',
|
|
125
|
-
},
|
|
126
|
-
premium: {
|
|
127
|
-
'@mui/x-data-grid': '@mui/x-data-grid-premium',
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
sections: {
|
|
132
|
-
fallbackSection: 'Other',
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
it('should categorize commits by scope to package mapping', () => {
|
|
137
|
-
const commits = [
|
|
138
|
-
createCommit(1, ['scope: data grid']),
|
|
139
|
-
createCommit(2, ['scope: charts']),
|
|
140
|
-
createCommit(3, ['scope: data grid']),
|
|
141
|
-
];
|
|
142
|
-
|
|
143
|
-
const result = categorizeCommits(commits, packageConfig);
|
|
144
|
-
|
|
145
|
-
expect(result.size).toBe(2);
|
|
146
|
-
expect(result.get('@mui/x-data-grid')).toHaveLength(2);
|
|
147
|
-
expect(result.get('@mui/x-charts')).toHaveLength(1);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should place commits without scope in fallback section', () => {
|
|
151
|
-
const commits = [createCommit(1, []), createCommit(2, ['breaking change'])];
|
|
152
|
-
|
|
153
|
-
const result = categorizeCommits(commits, packageConfig);
|
|
154
|
-
|
|
155
|
-
expect(result.size).toBe(1);
|
|
156
|
-
expect(result.get('Other')).toHaveLength(2);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('should place commits with multiple scope labels in multiple sections', () => {
|
|
160
|
-
const commits = [createCommit(1, ['scope: data grid', 'scope: charts'])];
|
|
161
|
-
|
|
162
|
-
const result = categorizeCommits(commits, packageConfig);
|
|
163
|
-
|
|
164
|
-
expect(result.size).toBe(2);
|
|
165
|
-
expect(result.get('@mui/x-data-grid')).toHaveLength(1);
|
|
166
|
-
expect(result.get('@mui/x-charts')).toHaveLength(1);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('should use generic scopes directly as section names', () => {
|
|
170
|
-
const commits = [createCommit(1, ['scope: docs']), createCommit(2, ['scope: code-infra'])];
|
|
171
|
-
|
|
172
|
-
const result = categorizeCommits(commits, packageConfig);
|
|
173
|
-
|
|
174
|
-
expect(result.size).toBe(2);
|
|
175
|
-
expect(result.get('docs')).toHaveLength(1);
|
|
176
|
-
expect(result.get('code-infra')).toHaveLength(1);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('should apply plan to package name when plan label is present', () => {
|
|
180
|
-
const commits = [
|
|
181
|
-
createCommit(1, ['scope: data grid', 'plan: pro']),
|
|
182
|
-
createCommit(2, ['scope: data grid', 'plan: premium']),
|
|
183
|
-
createCommit(3, ['scope: data grid']),
|
|
184
|
-
];
|
|
185
|
-
|
|
186
|
-
const result = categorizeCommits(commits, packageConfig);
|
|
187
|
-
|
|
188
|
-
expect(result.size).toBe(3);
|
|
189
|
-
expect(result.get('@mui/x-data-grid-pro')).toHaveLength(1);
|
|
190
|
-
expect(result.get('@mui/x-data-grid-premium')).toHaveLength(1);
|
|
191
|
-
expect(result.get('@mui/x-data-grid')).toHaveLength(1);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should throw error when scope mapping is not found', () => {
|
|
195
|
-
const commits = [createCommit(42, ['scope: unknown-package'])];
|
|
196
|
-
|
|
197
|
-
expect(() => categorizeCommits(commits, packageConfig)).toThrow(
|
|
198
|
-
'No package mapping found for scope "unknown-package" in commit #42',
|
|
199
|
-
);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it('should throw error when plan mapping is not found for package', () => {
|
|
203
|
-
const commits = [createCommit(42, ['scope: charts', 'plan: premium'])];
|
|
204
|
-
|
|
205
|
-
expect(() => categorizeCommits(commits, packageConfig)).toThrow(
|
|
206
|
-
'No premium plan package mapping found for base package "@mui/x-charts" in commit #42',
|
|
207
|
-
);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it('should throw error when package naming config is missing', () => {
|
|
211
|
-
const configWithoutNaming: CategorizationConfig = {
|
|
212
|
-
strategy: 'package',
|
|
213
|
-
labels: baseLabelConfig,
|
|
214
|
-
sections: {
|
|
215
|
-
fallbackSection: 'Other',
|
|
216
|
-
},
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const commits = [createCommit(1, ['scope: data grid'])];
|
|
220
|
-
|
|
221
|
-
expect(() => categorizeCommits(commits, configWithoutNaming)).toThrow(
|
|
222
|
-
'Package naming configuration is required for package-first strategy',
|
|
223
|
-
);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it('should use categoryOverride when present', () => {
|
|
227
|
-
const configWithOverrides: CategorizationConfig = {
|
|
228
|
-
...packageConfig,
|
|
229
|
-
labels: {
|
|
230
|
-
...baseLabelConfig,
|
|
231
|
-
categoryOverrides: {
|
|
232
|
-
'all packages': 'General changes',
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
const commits = [
|
|
238
|
-
createCommit(1, ['scope: data grid', 'all packages']),
|
|
239
|
-
createCommit(2, ['scope: charts']),
|
|
240
|
-
];
|
|
241
|
-
|
|
242
|
-
const result = categorizeCommits(commits, configWithOverrides);
|
|
243
|
-
|
|
244
|
-
expect(result.size).toBe(2);
|
|
245
|
-
expect(result.get('General changes')).toHaveLength(1);
|
|
246
|
-
expect(result.get('@mui/x-charts')).toHaveLength(1);
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
describe('unknown strategy', () => {
|
|
251
|
-
it('should throw error for unknown strategy', () => {
|
|
252
|
-
const invalidConfig = {
|
|
253
|
-
strategy: 'invalid' as 'component',
|
|
254
|
-
labels: baseLabelConfig,
|
|
255
|
-
sections: {
|
|
256
|
-
fallbackSection: 'Other',
|
|
257
|
-
},
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
const commits = [createCommit(1, [])];
|
|
261
|
-
|
|
262
|
-
expect(() => categorizeCommits(commits, invalidConfig)).toThrow(
|
|
263
|
-
'Unknown categorization strategy: invalid',
|
|
264
|
-
);
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
describe('parsed labels', () => {
|
|
269
|
-
const config: CategorizationConfig = {
|
|
270
|
-
strategy: 'component',
|
|
271
|
-
labels: {
|
|
272
|
-
...baseLabelConfig,
|
|
273
|
-
flags: {
|
|
274
|
-
'breaking change': { name: 'breaking change' },
|
|
275
|
-
enhancement: { name: 'enhancement' },
|
|
276
|
-
},
|
|
277
|
-
},
|
|
278
|
-
sections: {
|
|
279
|
-
fallbackSection: 'Other',
|
|
280
|
-
},
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
it('should include parsed labels in categorized commits', () => {
|
|
284
|
-
const commits = [createCommit(1, ['component: Button', 'breaking change', 'enhancement'])];
|
|
285
|
-
|
|
286
|
-
const result = categorizeCommits(commits, config);
|
|
287
|
-
|
|
288
|
-
const categorizedCommit = result.get('Button')?.[0];
|
|
289
|
-
expect(categorizedCommit?.parsed.components).toEqual(['Button']);
|
|
290
|
-
expect(categorizedCommit?.parsed.flags).toEqual(['breaking change', 'enhancement']);
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
it('should include plan in parsed labels', () => {
|
|
294
|
-
const commits = [createCommit(1, ['component: Button', 'plan: pro'])];
|
|
295
|
-
|
|
296
|
-
const result = categorizeCommits(commits, config);
|
|
297
|
-
|
|
298
|
-
// Component labels are normalized to lowercase by parseCommitLabels
|
|
299
|
-
const categorizedCommit = result.get('Button')?.[0];
|
|
300
|
-
expect(categorizedCommit?.parsed.plan).toBe('pro');
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
describe('empty input', () => {
|
|
305
|
-
const config: CategorizationConfig = {
|
|
306
|
-
strategy: 'component',
|
|
307
|
-
labels: baseLabelConfig,
|
|
308
|
-
sections: {
|
|
309
|
-
fallbackSection: 'Other',
|
|
310
|
-
},
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
it('should return empty map for empty commits array', () => {
|
|
314
|
-
const result = categorizeCommits([], config);
|
|
315
|
-
|
|
316
|
-
expect(result.size).toBe(0);
|
|
317
|
-
});
|
|
318
|
-
});
|
|
319
|
-
});
|
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
// eslint-disable-next-line import/extensions
|
|
3
|
-
import { filterCommits } from './filterCommits.mjs';
|
|
4
|
-
import type { FetchedCommitDetails, FilterConfig } from './types';
|
|
5
|
-
|
|
6
|
-
function createCommit(overrides: Partial<FetchedCommitDetails> = {}): FetchedCommitDetails {
|
|
7
|
-
return {
|
|
8
|
-
sha: 'abc123',
|
|
9
|
-
message: 'test commit',
|
|
10
|
-
labels: [],
|
|
11
|
-
prNumber: 1,
|
|
12
|
-
html_url: 'https://github.com/test/repo/pull/1',
|
|
13
|
-
author: {
|
|
14
|
-
login: 'testuser',
|
|
15
|
-
association: 'contributor',
|
|
16
|
-
},
|
|
17
|
-
createdAt: '2025-01-01T00:00:00Z',
|
|
18
|
-
mergedAt: '2025-01-01T00:00:00Z',
|
|
19
|
-
...overrides,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
describe('filterCommits', () => {
|
|
24
|
-
describe('no filter config', () => {
|
|
25
|
-
it('should return all commits when filterConfig is undefined', () => {
|
|
26
|
-
const commits = [
|
|
27
|
-
createCommit({ sha: '1' }),
|
|
28
|
-
createCommit({ sha: '2' }),
|
|
29
|
-
createCommit({ sha: '3' }),
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const result = filterCommits(commits, undefined);
|
|
33
|
-
|
|
34
|
-
expect(result).toEqual(commits);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should return empty array for empty input', () => {
|
|
38
|
-
const result = filterCommits([], undefined);
|
|
39
|
-
|
|
40
|
-
expect(result).toEqual([]);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('excludeCommitByAuthors', () => {
|
|
45
|
-
it('should exclude commits by author login string match', () => {
|
|
46
|
-
const commits = [
|
|
47
|
-
createCommit({ sha: '1', author: { login: 'dependabot', association: 'contributor' } }),
|
|
48
|
-
createCommit({ sha: '2', author: { login: 'human-user', association: 'contributor' } }),
|
|
49
|
-
createCommit({
|
|
50
|
-
sha: '3',
|
|
51
|
-
author: { login: 'another-dependabot-account', association: 'contributor' },
|
|
52
|
-
}),
|
|
53
|
-
];
|
|
54
|
-
const filterConfig: FilterConfig = {
|
|
55
|
-
excludeCommitByAuthors: ['dependabot'],
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const result = filterCommits(commits, filterConfig);
|
|
59
|
-
|
|
60
|
-
expect(result.map((c) => c.sha)).toEqual(['2']);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should exclude commits by author login regex match', () => {
|
|
64
|
-
const commits = [
|
|
65
|
-
createCommit({ sha: '1', author: { login: 'renovate[bot]', association: 'contributor' } }),
|
|
66
|
-
createCommit({ sha: '2', author: { login: 'human-user', association: 'contributor' } }),
|
|
67
|
-
createCommit({
|
|
68
|
-
sha: '3',
|
|
69
|
-
author: { login: 'dependabot[bot]', association: 'contributor' },
|
|
70
|
-
}),
|
|
71
|
-
];
|
|
72
|
-
const filterConfig: FilterConfig = {
|
|
73
|
-
excludeCommitByAuthors: [/\[bot\]$/],
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const result = filterCommits(commits, filterConfig);
|
|
77
|
-
|
|
78
|
-
expect(result.map((c) => c.sha)).toEqual(['2']);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should handle commits with null author', () => {
|
|
82
|
-
const commits = [
|
|
83
|
-
createCommit({ sha: '1', author: null }),
|
|
84
|
-
createCommit({ sha: '2', author: { login: 'dependabot', association: 'contributor' } }),
|
|
85
|
-
createCommit({ sha: '3', author: { login: 'human-user', association: 'contributor' } }),
|
|
86
|
-
];
|
|
87
|
-
const filterConfig: FilterConfig = {
|
|
88
|
-
excludeCommitByAuthors: ['dependabot'],
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const result = filterCommits(commits, filterConfig);
|
|
92
|
-
|
|
93
|
-
expect(result.map((c) => c.sha)).toEqual(['1', '3']);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should handle multiple author exclusion patterns', () => {
|
|
97
|
-
const commits = [
|
|
98
|
-
createCommit({
|
|
99
|
-
sha: '1',
|
|
100
|
-
author: { login: 'dependabot[bot]', association: 'contributor' },
|
|
101
|
-
}),
|
|
102
|
-
createCommit({ sha: '2', author: { login: 'renovate', association: 'contributor' } }),
|
|
103
|
-
createCommit({ sha: '3', author: { login: 'human-user', association: 'contributor' } }),
|
|
104
|
-
];
|
|
105
|
-
const filterConfig: FilterConfig = {
|
|
106
|
-
excludeCommitByAuthors: [/\[bot\]$/, 'renovate'],
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const result = filterCommits(commits, filterConfig);
|
|
110
|
-
|
|
111
|
-
expect(result.map((c) => c.sha)).toEqual(['3']);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('should handle empty excludeCommitByAuthors array', () => {
|
|
115
|
-
const commits = [createCommit({ sha: '1' }), createCommit({ sha: '2' })];
|
|
116
|
-
const filterConfig: FilterConfig = {
|
|
117
|
-
excludeCommitByAuthors: [],
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const result = filterCommits(commits, filterConfig);
|
|
121
|
-
|
|
122
|
-
expect(result.map((c) => c.sha)).toEqual(['1', '2']);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
describe('excludeCommitWithLabels', () => {
|
|
127
|
-
it('should exclude commits with matching label string', () => {
|
|
128
|
-
const commits = [
|
|
129
|
-
createCommit({ sha: '1', labels: ['bug', 'skip-changelog'] }),
|
|
130
|
-
createCommit({ sha: '2', labels: ['enhancement'] }),
|
|
131
|
-
createCommit({ sha: '3', labels: ['internal', 'skip-changelog'] }),
|
|
132
|
-
];
|
|
133
|
-
const filterConfig: FilterConfig = {
|
|
134
|
-
excludeCommitWithLabels: ['skip-changelog'],
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const result = filterCommits(commits, filterConfig);
|
|
138
|
-
|
|
139
|
-
expect(result.map((c) => c.sha)).toEqual(['2']);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should exclude commits with matching label regex', () => {
|
|
143
|
-
const commits = [
|
|
144
|
-
createCommit({ sha: '1', labels: ['scope: docs'] }),
|
|
145
|
-
createCommit({ sha: '2', labels: ['scope: core'] }),
|
|
146
|
-
createCommit({ sha: '3', labels: ['enhancement'] }),
|
|
147
|
-
];
|
|
148
|
-
const filterConfig: FilterConfig = {
|
|
149
|
-
excludeCommitWithLabels: [/^scope: docs$/],
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const result = filterCommits(commits, filterConfig);
|
|
153
|
-
|
|
154
|
-
expect(result.map((c) => c.sha)).toEqual(['2', '3']);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('should handle multiple label exclusion patterns', () => {
|
|
158
|
-
const commits = [
|
|
159
|
-
createCommit({ sha: '1', labels: ['skip-changelog'] }),
|
|
160
|
-
createCommit({ sha: '2', labels: ['internal'] }),
|
|
161
|
-
createCommit({ sha: '3', labels: ['enhancement'] }),
|
|
162
|
-
createCommit({ sha: '4', labels: ['docs-only'] }),
|
|
163
|
-
];
|
|
164
|
-
const filterConfig: FilterConfig = {
|
|
165
|
-
excludeCommitWithLabels: ['skip-changelog', 'internal', /docs/],
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
const result = filterCommits(commits, filterConfig);
|
|
169
|
-
|
|
170
|
-
expect(result.map((c) => c.sha)).toEqual(['3']);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('should handle commits with empty labels array', () => {
|
|
174
|
-
const commits = [
|
|
175
|
-
createCommit({ sha: '1', labels: [] }),
|
|
176
|
-
createCommit({ sha: '2', labels: ['skip-changelog'] }),
|
|
177
|
-
];
|
|
178
|
-
const filterConfig: FilterConfig = {
|
|
179
|
-
excludeCommitWithLabels: ['skip-changelog'],
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
const result = filterCommits(commits, filterConfig);
|
|
183
|
-
|
|
184
|
-
expect(result.map((c) => c.sha)).toEqual(['1']);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('should handle empty excludeCommitWithLabels array', () => {
|
|
188
|
-
const commits = [
|
|
189
|
-
createCommit({ sha: '1', labels: ['any-label'] }),
|
|
190
|
-
createCommit({ sha: '2', labels: [] }),
|
|
191
|
-
];
|
|
192
|
-
const filterConfig: FilterConfig = {
|
|
193
|
-
excludeCommitWithLabels: [],
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
const result = filterCommits(commits, filterConfig);
|
|
197
|
-
|
|
198
|
-
expect(result.map((c) => c.sha)).toEqual(['1', '2']);
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
describe('customFilter', () => {
|
|
203
|
-
it('should apply custom filter function', () => {
|
|
204
|
-
const commits = [
|
|
205
|
-
createCommit({ sha: '1', prNumber: 100 }),
|
|
206
|
-
createCommit({ sha: '2', prNumber: 200 }),
|
|
207
|
-
createCommit({ sha: '3', prNumber: 300 }),
|
|
208
|
-
];
|
|
209
|
-
const filterConfig: FilterConfig = {
|
|
210
|
-
customFilter: (commit) => commit.prNumber >= 200,
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
const result = filterCommits(commits, filterConfig);
|
|
214
|
-
|
|
215
|
-
expect(result.map((c) => c.sha)).toEqual(['2', '3']);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
it('should apply custom filter after author and label filters', () => {
|
|
219
|
-
const commits = [
|
|
220
|
-
createCommit({
|
|
221
|
-
sha: '1',
|
|
222
|
-
author: { login: 'bot', association: 'contributor' },
|
|
223
|
-
prNumber: 100,
|
|
224
|
-
}),
|
|
225
|
-
createCommit({
|
|
226
|
-
sha: '2',
|
|
227
|
-
author: { login: 'human', association: 'contributor' },
|
|
228
|
-
prNumber: 200,
|
|
229
|
-
}),
|
|
230
|
-
createCommit({
|
|
231
|
-
sha: '3',
|
|
232
|
-
author: { login: 'human', association: 'contributor' },
|
|
233
|
-
prNumber: 300,
|
|
234
|
-
}),
|
|
235
|
-
];
|
|
236
|
-
const filterConfig: FilterConfig = {
|
|
237
|
-
excludeCommitByAuthors: ['bot'],
|
|
238
|
-
customFilter: (commit) => commit.prNumber >= 250,
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
const result = filterCommits(commits, filterConfig);
|
|
242
|
-
|
|
243
|
-
// sha: '1' excluded by author filter
|
|
244
|
-
// sha: '2' excluded by custom filter (prNumber < 250)
|
|
245
|
-
// sha: '3' passes both filters
|
|
246
|
-
expect(result.map((c) => c.sha)).toEqual(['3']);
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it('should filter based on commit message content', () => {
|
|
250
|
-
const commits = [
|
|
251
|
-
createCommit({ sha: '1', message: '[skip ci] Update dependencies' }),
|
|
252
|
-
createCommit({ sha: '2', message: 'Fix critical bug' }),
|
|
253
|
-
createCommit({ sha: '3', message: 'chore: update config [skip ci]' }),
|
|
254
|
-
];
|
|
255
|
-
const filterConfig: FilterConfig = {
|
|
256
|
-
customFilter: (commit) => !commit.message.includes('[skip ci]'),
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
const result = filterCommits(commits, filterConfig);
|
|
260
|
-
|
|
261
|
-
expect(result.map((c) => c.sha)).toEqual(['2']);
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
describe('combined filters', () => {
|
|
266
|
-
it('should apply all filters together', () => {
|
|
267
|
-
const commits = [
|
|
268
|
-
createCommit({
|
|
269
|
-
sha: '1',
|
|
270
|
-
author: { login: 'dependabot[bot]', association: 'contributor' },
|
|
271
|
-
labels: ['dependencies'],
|
|
272
|
-
}),
|
|
273
|
-
createCommit({
|
|
274
|
-
sha: '2',
|
|
275
|
-
author: { login: 'human', association: 'team' },
|
|
276
|
-
labels: ['skip-changelog'],
|
|
277
|
-
}),
|
|
278
|
-
createCommit({
|
|
279
|
-
sha: '3',
|
|
280
|
-
author: { login: 'human', association: 'team' },
|
|
281
|
-
labels: ['bug'],
|
|
282
|
-
prNumber: 50,
|
|
283
|
-
}),
|
|
284
|
-
createCommit({
|
|
285
|
-
sha: '4',
|
|
286
|
-
author: { login: 'human', association: 'contributor' },
|
|
287
|
-
labels: ['enhancement'],
|
|
288
|
-
prNumber: 200,
|
|
289
|
-
}),
|
|
290
|
-
];
|
|
291
|
-
const filterConfig: FilterConfig = {
|
|
292
|
-
excludeCommitByAuthors: [/\[bot\]$/],
|
|
293
|
-
excludeCommitWithLabels: ['skip-changelog'],
|
|
294
|
-
customFilter: (commit) => commit.prNumber >= 100,
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
const result = filterCommits(commits, filterConfig);
|
|
298
|
-
|
|
299
|
-
// sha: '1' excluded by author filter (bot)
|
|
300
|
-
// sha: '2' excluded by label filter (skip-changelog)
|
|
301
|
-
// sha: '3' excluded by custom filter (prNumber < 100)
|
|
302
|
-
// sha: '4' passes all filters
|
|
303
|
-
expect(result.map((c) => c.sha)).toEqual(['4']);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
it('should return empty array when all commits are filtered', () => {
|
|
307
|
-
const commits = [
|
|
308
|
-
createCommit({ sha: '1', author: { login: 'bot', association: 'contributor' } }),
|
|
309
|
-
createCommit({ sha: '2', labels: ['internal'] }),
|
|
310
|
-
];
|
|
311
|
-
const filterConfig: FilterConfig = {
|
|
312
|
-
excludeCommitByAuthors: ['bot'],
|
|
313
|
-
excludeCommitWithLabels: ['internal'],
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
const result = filterCommits(commits, filterConfig);
|
|
317
|
-
|
|
318
|
-
expect(result).toEqual([]);
|
|
319
|
-
});
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
describe('edge cases', () => {
|
|
323
|
-
it('should not mutate the original commits array', () => {
|
|
324
|
-
const commits = [
|
|
325
|
-
createCommit({ sha: '1', author: { login: 'bot', association: 'contributor' } }),
|
|
326
|
-
createCommit({ sha: '2', author: { login: 'human', association: 'contributor' } }),
|
|
327
|
-
];
|
|
328
|
-
const originalLength = commits.length;
|
|
329
|
-
const filterConfig: FilterConfig = {
|
|
330
|
-
excludeCommitByAuthors: ['bot'],
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
filterCommits(commits, filterConfig);
|
|
334
|
-
|
|
335
|
-
expect(commits.length).toBe(originalLength);
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it('should handle filterConfig with no filter properties set', () => {
|
|
339
|
-
const commits = [createCommit({ sha: '1' }), createCommit({ sha: '2' })];
|
|
340
|
-
const filterConfig: FilterConfig = {};
|
|
341
|
-
|
|
342
|
-
const result = filterCommits(commits, filterConfig);
|
|
343
|
-
|
|
344
|
-
expect(result.map((c) => c.sha)).toEqual(['1', '2']);
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
it('should use substring matching for string patterns in author exclusion', () => {
|
|
348
|
-
const commits = [
|
|
349
|
-
createCommit({ sha: '1', author: { login: 'my-bot-account', association: 'contributor' } }),
|
|
350
|
-
createCommit({ sha: '2', author: { login: 'botuser', association: 'contributor' } }),
|
|
351
|
-
createCommit({ sha: '3', author: { login: 'human', association: 'contributor' } }),
|
|
352
|
-
];
|
|
353
|
-
const filterConfig: FilterConfig = {
|
|
354
|
-
excludeCommitByAuthors: ['bot'],
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
const result = filterCommits(commits, filterConfig);
|
|
358
|
-
|
|
359
|
-
// Both 'my-bot-account' and 'botuser' contain 'bot'
|
|
360
|
-
expect(result.map((c) => c.sha)).toEqual(['3']);
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
});
|