forked from NixOS/nixpkgs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlint-commits.js
More file actions
155 lines (136 loc) · 4.72 KB
/
lint-commits.js
File metadata and controls
155 lines (136 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// @ts-check
const { classify } = require('../supportedBranches.js')
const { getCommitDetailsForPR } = require('./get-pr-commit-details.js')
/**
* @param {{
* github: InstanceType<import('@actions/github/lib/utils').GitHub>,
* context: import('@actions/github/lib/context').Context,
* core: import('@actions/core'),
* repoPath?: string,
* }} CheckCommitMessagesProps
*/
async function checkCommitMessages({ github, context, core, repoPath }) {
// This check should only be run when we have the pull_request context.
const pull_number = context.payload.pull_request?.number
if (!pull_number) {
core.info('This is not a pull request. Skipping checks.')
return
}
const pr = (
await github.rest.pulls.get({
...context.repo,
pull_number,
})
).data
const baseBranchType = classify(
pr.base.ref.replace(/^refs\/heads\//, ''),
).type
const headBranchType = classify(
pr.head.ref.replace(/^refs\/heads\//, ''),
).type
if (
baseBranchType.includes('development') &&
headBranchType.includes('development') &&
pr.base.repo.id === pr.head.repo?.id
) {
// This matches, for example, PRs from NixOS:staging-next to NixOS:master, or vice versa.
// Ignore them: we should only care about PRs introducing *new* commits.
// We still want to run on PRs from, e.g., Someone:master to NixOS:master, though.
core.info(
'This PR is from one development branch to another. Skipping checks.',
)
return
}
const commits = await getCommitDetailsForPR({ core, pr, repoPath })
const failures = new Set()
const conventionalCommitTypes = [
'build',
'chore',
'ci',
'doc',
'docs',
'feat',
'feature',
'fix',
'perf',
'refactor',
'style',
'test',
]
/**
* @param {string[]} types e.g. ["fix", "feat"]
* @param {string?} sha commit hash
*/
function makeConventionalCommitRegex(types, sha = null) {
core.info(
`${
sha
? `Conventional commit types for ${sha?.slice(0, 16)}`
: 'Default conventional commit types'
}: ${JSON.stringify(types)}`,
)
return new RegExp(`^(${types.join('|')})!?(\\(.*\\))?!?:`)
}
// Optimize for the common case that we don't have path segments with the
// same name as a conventional commit type.
const fullConventionalCommitRegex = makeConventionalCommitRegex(
conventionalCommitTypes,
)
for (const commit of commits) {
const logMsgStart = `Commit ${commit.sha}'s message's subject ("${commit.subject}")`
// If we have a commit `perf: ...`, and we touch a file containing the path
// segment "perf", we don't want to flag this.
const filteredTypes = conventionalCommitTypes.filter(
(type) => !commit.changedPathSegments.has(type),
)
const conventionalCommitRegex =
filteredTypes.length === conventionalCommitTypes.length
? fullConventionalCommitRegex
: makeConventionalCommitRegex(filteredTypes, commit.sha)
if (!commit.subject.includes(': ')) {
core.error(
`${logMsgStart} was detected as not meeting our guidelines because ` +
'it does not contain a colon followed by a whitespace. ' +
'There are likely other issues as well.',
)
failures.add(commit.sha)
}
if (commit.subject.endsWith('.')) {
core.error(
`${logMsgStart} was detected as not meeting our guidelines because ` +
'it ends in a period. There may be other issues as well.',
)
failures.add(commit.sha)
}
const fixups = ['amend!', 'fixup!', 'squash!']
if (fixups.some((s) => commit.subject.startsWith(s))) {
core.error(
`${logMsgStart} was detected as not meeting our guidelines because ` +
`it begins with "${fixups.find((s) => commit.subject.startsWith(s))}". ` +
'Did you forget to run `git rebase -i --autosquash`?',
)
failures.add(commit.sha)
}
if (conventionalCommitRegex.test(commit.subject)) {
core.error(
`${logMsgStart} was detected as not meeting our guidelines because ` +
'it seems to use conventional commit (conventionalcommits.org) ' +
'formatting. Nixpkgs has its own, different, commit message ' +
'formatting standards.',
)
failures.add(commit.sha)
}
if (!failures.has(commit.sha)) {
core.info(`${logMsgStart} passed our automated checks!`)
}
}
if (failures.size !== 0) {
core.error(
'Please review the guidelines at ' +
'<https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#commit-conventions>, ' +
'as well as the applicable area-specific guidelines linked there.',
)
core.setFailed('Committers: merging is discouraged.')
}
}
module.exports = checkCommitMessages