@node-core/utils 5.12.1 → 5.13.0
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/lib/cherry_pick.js +19 -185
- package/lib/ci/run_ci.js +1 -1
- package/lib/landing_session.js +17 -3
- package/lib/pr_checker.js +2 -14
- package/lib/session.js +2 -1
- package/lib/update-v8/constants.js +13 -1
- package/package.json +13 -13
package/lib/cherry_pick.js
CHANGED
@@ -1,23 +1,13 @@
|
|
1
|
-
import os from 'node:os';
|
2
1
|
import path from 'node:path';
|
3
2
|
import { getMetadata } from '../components/metadata.js';
|
4
3
|
|
5
4
|
import {
|
6
|
-
runAsync, runSync
|
5
|
+
runAsync, runSync
|
7
6
|
} from './run.js';
|
8
|
-
import { writeFile } from './file.js';
|
9
|
-
import {
|
10
|
-
shortSha, getEditor
|
11
|
-
} from './utils.js';
|
12
7
|
import { getNcuDir } from './config.js';
|
8
|
+
import LandingSession, { LINT_RESULTS } from './landing_session.js';
|
13
9
|
|
14
|
-
|
15
|
-
SKIPPED: 'skipped',
|
16
|
-
FAILED: 'failed',
|
17
|
-
SUCCESS: 'success'
|
18
|
-
};
|
19
|
-
|
20
|
-
export default class CheckPick {
|
10
|
+
export default class CherryPick {
|
21
11
|
constructor(prid, dir, cli, {
|
22
12
|
owner,
|
23
13
|
repo,
|
@@ -46,11 +36,6 @@ export default class CheckPick {
|
|
46
36
|
return this.options.lint;
|
47
37
|
}
|
48
38
|
|
49
|
-
getUpstreamHead() {
|
50
|
-
const { upstream, branch } = this;
|
51
|
-
return runSync('git', ['rev-parse', `${upstream}/${branch}`]).trim();
|
52
|
-
}
|
53
|
-
|
54
39
|
getCurrentRev() {
|
55
40
|
return runSync('git', ['rev-parse', 'HEAD']).trim();
|
56
41
|
}
|
@@ -73,16 +58,6 @@ export default class CheckPick {
|
|
73
58
|
return path.resolve(this.ncuDir, `${this.prid}`);
|
74
59
|
}
|
75
60
|
|
76
|
-
getMessagePath(rev) {
|
77
|
-
return path.resolve(this.pullDir, `${shortSha(rev)}.COMMIT_EDITMSG`);
|
78
|
-
}
|
79
|
-
|
80
|
-
saveMessage(rev, message) {
|
81
|
-
const file = this.getMessagePath(rev);
|
82
|
-
writeFile(file, message);
|
83
|
-
return file;
|
84
|
-
}
|
85
|
-
|
86
61
|
async start() {
|
87
62
|
const { cli } = this;
|
88
63
|
|
@@ -91,7 +66,7 @@ export default class CheckPick {
|
|
91
66
|
owner: this.owner,
|
92
67
|
repo: this.repo
|
93
68
|
}, false, cli);
|
94
|
-
|
69
|
+
this.expectedCommitShas =
|
95
70
|
metadata.data.commits.map(({ commit }) => commit.oid);
|
96
71
|
|
97
72
|
const amend = await cli.prompt(
|
@@ -104,7 +79,7 @@ export default class CheckPick {
|
|
104
79
|
}
|
105
80
|
|
106
81
|
try {
|
107
|
-
const commitInfo = await this.downloadAndPatch(
|
82
|
+
const commitInfo = await this.downloadAndPatch();
|
108
83
|
const cleanLint = await this.validateLint();
|
109
84
|
if (cleanLint === LINT_RESULTS.FAILED) {
|
110
85
|
cli.error('Patch still contains lint errors. ' +
|
@@ -120,68 +95,6 @@ export default class CheckPick {
|
|
120
95
|
}
|
121
96
|
}
|
122
97
|
|
123
|
-
async downloadAndPatch(expectedCommitShas) {
|
124
|
-
const { cli, repo, owner, prid } = this;
|
125
|
-
|
126
|
-
cli.startSpinner(`Downloading patch for ${prid}`);
|
127
|
-
// fetch via ssh to handle private repo
|
128
|
-
await runAsync('git', [
|
129
|
-
'fetch', `git@github.com:${owner}/${repo}.git`,
|
130
|
-
`refs/pull/${prid}/merge`]);
|
131
|
-
// We fetched the commit that would result if we used `git merge`.
|
132
|
-
// ^1 and ^2 refer to the PR base and the PR head, respectively.
|
133
|
-
const [base, head] = await runAsync('git',
|
134
|
-
['rev-parse', 'FETCH_HEAD^1', 'FETCH_HEAD^2'],
|
135
|
-
{ captureStdout: 'lines' });
|
136
|
-
const commitShas = await runAsync('git',
|
137
|
-
['rev-list', `${base}..${head}`],
|
138
|
-
{ captureStdout: 'lines' });
|
139
|
-
cli.stopSpinner(`Fetched commits as ${shortSha(base)}..${shortSha(head)}`);
|
140
|
-
cli.separator();
|
141
|
-
|
142
|
-
const mismatchedCommits = [
|
143
|
-
...commitShas.filter((sha) => !expectedCommitShas.includes(sha))
|
144
|
-
.map((sha) => `Unexpected commit ${sha}`),
|
145
|
-
...expectedCommitShas.filter((sha) => !commitShas.includes(sha))
|
146
|
-
.map((sha) => `Missing commit ${sha}`)
|
147
|
-
].join('\n');
|
148
|
-
if (mismatchedCommits.length > 0) {
|
149
|
-
throw new Error(`Mismatched commits:\n${mismatchedCommits}`);
|
150
|
-
}
|
151
|
-
|
152
|
-
const commitInfo = { base, head, shas: commitShas };
|
153
|
-
|
154
|
-
try {
|
155
|
-
await forceRunAsync('git', ['cherry-pick', `${base}..${head}`], {
|
156
|
-
ignoreFailure: false
|
157
|
-
});
|
158
|
-
} catch (ex) {
|
159
|
-
await forceRunAsync('git', ['cherry-pick', '--abort']);
|
160
|
-
throw new Error('Failed to apply patches');
|
161
|
-
}
|
162
|
-
|
163
|
-
cli.ok('Patches applied');
|
164
|
-
return commitInfo;
|
165
|
-
}
|
166
|
-
|
167
|
-
async validateLint() {
|
168
|
-
// The linter is currently only run on non-Windows platforms.
|
169
|
-
if (os.platform() === 'win32') {
|
170
|
-
return LINT_RESULTS.SKIPPED;
|
171
|
-
}
|
172
|
-
|
173
|
-
if (!this.lint) {
|
174
|
-
return LINT_RESULTS.SKIPPED;
|
175
|
-
}
|
176
|
-
|
177
|
-
try {
|
178
|
-
await runAsync('make', ['lint']);
|
179
|
-
return LINT_RESULTS.SUCCESS;
|
180
|
-
} catch {
|
181
|
-
return LINT_RESULTS.FAILED;
|
182
|
-
}
|
183
|
-
}
|
184
|
-
|
185
98
|
async amend(metadata, commitInfo) {
|
186
99
|
const { cli } = this;
|
187
100
|
const subjects = await runAsync('git',
|
@@ -203,102 +116,23 @@ export default class CheckPick {
|
|
203
116
|
await runAsync('git', ['commit', '--amend', '--no-edit']);
|
204
117
|
}
|
205
118
|
|
206
|
-
return
|
119
|
+
return LandingSession.prototype.amend.call(this, metadata);
|
207
120
|
}
|
208
121
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
const rev = this.getCurrentRev();
|
213
|
-
const original = runSync('git', [
|
214
|
-
'show', 'HEAD', '-s', '--format=%B'
|
215
|
-
]).trim();
|
216
|
-
// git has very specific rules about what is a trailer and what is not.
|
217
|
-
// Instead of trying to implement those ourselves, let git parse the
|
218
|
-
// original commit message and see if it outputs any trailers.
|
219
|
-
const originalHasTrailers = runSync('git', [
|
220
|
-
'interpret-trailers', '--parse', '--no-divider'
|
221
|
-
], {
|
222
|
-
input: `${original}\n`
|
223
|
-
}).trim().length !== 0;
|
224
|
-
const metadata = metadataStr.trim().split('\n');
|
225
|
-
const amended = original.split('\n');
|
226
|
-
|
227
|
-
// If the original commit message already contains trailers (such as
|
228
|
-
// "Co-authored-by"), we simply add our own metadata after those. Otherwise,
|
229
|
-
// we have to add an empty line so that git recognizes our own metadata as
|
230
|
-
// trailers in the amended commit message.
|
231
|
-
if (!originalHasTrailers) {
|
232
|
-
amended.push('');
|
233
|
-
}
|
234
|
-
|
235
|
-
const BACKPORT_RE = /BACKPORT-PR-URL\s*:\s*(\S+)/i;
|
236
|
-
const PR_RE = /PR-URL\s*:\s*(\S+)/i;
|
237
|
-
const REVIEW_RE = /Reviewed-By\s*:\s*(\S+)/i;
|
238
|
-
const CVE_RE = /CVE-ID\s*:\s*(\S+)/i;
|
239
|
-
|
240
|
-
let containCVETrailer = false;
|
241
|
-
for (const line of metadata) {
|
242
|
-
if (line.length !== 0 && original.includes(line)) {
|
243
|
-
if (line.match(CVE_RE)) {
|
244
|
-
containCVETrailer = true;
|
245
|
-
}
|
246
|
-
if (originalHasTrailers) {
|
247
|
-
cli.warn(`Found ${line}, skipping..`);
|
248
|
-
} else {
|
249
|
-
throw new Error(
|
250
|
-
'Git found no trailers in the original commit message, ' +
|
251
|
-
`but '${line}' is present and should be a trailer.`);
|
252
|
-
}
|
253
|
-
} else {
|
254
|
-
if (line.match(BACKPORT_RE)) {
|
255
|
-
let prIndex = amended.findIndex(datum => datum.match(PR_RE));
|
256
|
-
if (prIndex === -1) {
|
257
|
-
prIndex = amended.findIndex(datum => datum.match(REVIEW_RE)) - 1;
|
258
|
-
}
|
259
|
-
amended.splice(prIndex + 1, 0, line);
|
260
|
-
} else {
|
261
|
-
amended.push(line);
|
262
|
-
}
|
263
|
-
}
|
264
|
-
}
|
265
|
-
|
266
|
-
if (!containCVETrailer && this.includeCVE) {
|
267
|
-
const cveID = await cli.prompt(
|
268
|
-
'Git found no CVE-ID trailer in the original commit message. ' +
|
269
|
-
'Please, provide the CVE-ID',
|
270
|
-
{ questionType: 'input', defaultAnswer: 'CVE-2023-XXXXX' }
|
271
|
-
);
|
272
|
-
amended.push('CVE-ID: ' + cveID);
|
273
|
-
}
|
122
|
+
readyToAmend() {
|
123
|
+
return true;
|
124
|
+
}
|
274
125
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
cli.log(message.trim());
|
279
|
-
const takeMessage = await cli.prompt('Use this message?');
|
280
|
-
if (takeMessage) {
|
281
|
-
await runAsync('git', ['commit', '--amend', '-F', messageFile]);
|
282
|
-
return true;
|
283
|
-
}
|
126
|
+
startAmending() {
|
127
|
+
// No-op
|
128
|
+
}
|
284
129
|
|
285
|
-
|
286
|
-
|
287
|
-
try {
|
288
|
-
await forceRunAsync(
|
289
|
-
editor,
|
290
|
-
[`"${messageFile}"`],
|
291
|
-
{ ignoreFailure: false, spawnArgs: { shell: true } }
|
292
|
-
);
|
293
|
-
await runAsync('git', ['commit', '--amend', '-F', messageFile]);
|
294
|
-
return true;
|
295
|
-
} catch {
|
296
|
-
cli.warn(`Please manually edit ${messageFile}, then run\n` +
|
297
|
-
`\`git commit --amend -F ${messageFile}\` ` +
|
298
|
-
'to finish amending the message');
|
299
|
-
throw new Error(
|
300
|
-
'Failed to edit the message using the configured editor');
|
301
|
-
}
|
302
|
-
}
|
130
|
+
saveCommitInfo() {
|
131
|
+
// No-op
|
303
132
|
}
|
304
133
|
}
|
134
|
+
|
135
|
+
CherryPick.prototype.downloadAndPatch = LandingSession.prototype.downloadAndPatch;
|
136
|
+
CherryPick.prototype.validateLint = LandingSession.prototype.validateLint;
|
137
|
+
CherryPick.prototype.getMessagePath = LandingSession.prototype.getMessagePath;
|
138
|
+
CherryPick.prototype.saveMessage = LandingSession.prototype.saveMessage;
|
package/lib/ci/run_ci.js
CHANGED
@@ -26,7 +26,7 @@ export class RunPRJob {
|
|
26
26
|
this.prData = new PRData({ prid, owner, repo }, cli, request);
|
27
27
|
this.certifySafe =
|
28
28
|
certifySafe ||
|
29
|
-
Promise.all([this.prData.getReviews(), this.prData.
|
29
|
+
Promise.all([this.prData.getReviews(), this.prData.getCommits()]).then(() =>
|
30
30
|
(this.certifySafe = new PRChecker(cli, this.prData, request, {}).getApprovedTipOfHead())
|
31
31
|
);
|
32
32
|
}
|
package/lib/landing_session.js
CHANGED
@@ -10,7 +10,7 @@ import {
|
|
10
10
|
|
11
11
|
const isWindows = process.platform === 'win32';
|
12
12
|
|
13
|
-
const LINT_RESULTS = {
|
13
|
+
export const LINT_RESULTS = {
|
14
14
|
SKIPPED: 'skipped',
|
15
15
|
FAILED: 'failed',
|
16
16
|
SUCCESS: 'success'
|
@@ -84,11 +84,11 @@ export default class LandingSession extends Session {
|
|
84
84
|
}
|
85
85
|
|
86
86
|
async downloadAndPatch() {
|
87
|
-
const { cli,
|
87
|
+
const { cli, upstream, prid, expectedCommitShas } = this;
|
88
88
|
|
89
89
|
cli.startSpinner(`Downloading patch for ${prid}`);
|
90
90
|
await runAsync('git', [
|
91
|
-
'fetch',
|
91
|
+
'fetch', upstream,
|
92
92
|
`refs/pull/${prid}/merge`]);
|
93
93
|
// We fetched the commit that would result if we used `git merge`.
|
94
94
|
// ^1 and ^2 refer to the PR base and the PR head, respectively.
|
@@ -315,9 +315,14 @@ export default class LandingSession extends Session {
|
|
315
315
|
const BACKPORT_RE = /BACKPORT-PR-URL\s*:\s*(\S+)/i;
|
316
316
|
const PR_RE = /PR-URL\s*:\s*(\S+)/i;
|
317
317
|
const REVIEW_RE = /Reviewed-By\s*:\s*(\S+)/i;
|
318
|
+
const CVE_RE = /CVE-ID\s*:\s*(\S+)/i;
|
318
319
|
|
320
|
+
let containCVETrailer = false;
|
319
321
|
for (const line of metadata) {
|
320
322
|
if (line.length !== 0 && original.includes(line)) {
|
323
|
+
if (line.match(CVE_RE)) {
|
324
|
+
containCVETrailer = true;
|
325
|
+
}
|
321
326
|
if (originalHasTrailers) {
|
322
327
|
cli.warn(`Found ${line}, skipping..`);
|
323
328
|
} else {
|
@@ -338,6 +343,15 @@ export default class LandingSession extends Session {
|
|
338
343
|
}
|
339
344
|
}
|
340
345
|
|
346
|
+
if (!containCVETrailer && this.includeCVE) {
|
347
|
+
const cveID = await cli.prompt(
|
348
|
+
'Git found no CVE-ID trailer in the original commit message. ' +
|
349
|
+
'Please, provide the CVE-ID',
|
350
|
+
{ questionType: 'input', defaultAnswer: 'CVE-2023-XXXXX' }
|
351
|
+
);
|
352
|
+
amended.push('CVE-ID: ' + cveID);
|
353
|
+
}
|
354
|
+
|
341
355
|
const message = amended.join('\n');
|
342
356
|
const messageFile = this.saveMessage(rev, message);
|
343
357
|
cli.separator('New Message');
|
package/lib/pr_checker.js
CHANGED
@@ -30,15 +30,6 @@ const FAST_TRACK_RE = /^Fast-track has been requested by @(.+?)\. Please 👍 to
|
|
30
30
|
const FAST_TRACK_MIN_APPROVALS = 2;
|
31
31
|
const GIT_CONFIG_GUIDE_URL = 'https://github.com/nodejs/node/blob/99b1ada/doc/guides/contributing/pull-requests.md#step-1-fork';
|
32
32
|
|
33
|
-
// eslint-disable-next-line no-extend-native
|
34
|
-
Array.prototype.findLastIndex ??= function findLastIndex(fn) {
|
35
|
-
const reversedIndex = Reflect.apply(
|
36
|
-
Array.prototype.findIndex,
|
37
|
-
this.slice().reverse(),
|
38
|
-
arguments);
|
39
|
-
return reversedIndex === -1 ? -1 : this.length - reversedIndex - 1;
|
40
|
-
};
|
41
|
-
|
42
33
|
export default class PRChecker {
|
43
34
|
/**
|
44
35
|
* @param {{}} cli
|
@@ -49,7 +40,7 @@ export default class PRChecker {
|
|
49
40
|
this.request = request;
|
50
41
|
this.data = data;
|
51
42
|
const {
|
52
|
-
pr, reviewers, comments, reviews, commits
|
43
|
+
pr, reviewers, comments, reviews, commits
|
53
44
|
} = data;
|
54
45
|
this.reviewers = reviewers;
|
55
46
|
this.pr = pr;
|
@@ -61,9 +52,6 @@ export default class PRChecker {
|
|
61
52
|
this.reviews = reviews;
|
62
53
|
this.commits = commits;
|
63
54
|
this.argv = argv;
|
64
|
-
this.collaboratorEmails = new Set(
|
65
|
-
Array.from(collaborators).map((c) => c[1].email)
|
66
|
-
);
|
67
55
|
}
|
68
56
|
|
69
57
|
get waitTimeSingleApproval() {
|
@@ -531,7 +519,7 @@ export default class PRChecker {
|
|
531
519
|
const { maxCommits } = argv;
|
532
520
|
|
533
521
|
if (commits.length === 0) {
|
534
|
-
cli.warn('No commits
|
522
|
+
cli.warn('No commits detected');
|
535
523
|
return false;
|
536
524
|
}
|
537
525
|
|
package/lib/session.js
CHANGED
@@ -347,7 +347,8 @@ export default class Session {
|
|
347
347
|
const { cli, upstream, branch } = this;
|
348
348
|
const branchName = `${upstream}/${branch}`;
|
349
349
|
cli.startSpinner(`Bringing ${branchName} up to date...`);
|
350
|
-
|
350
|
+
const maybeUnshallow = fs.existsSync('.git/shallow') ? ['--unshallow'] : [];
|
351
|
+
await runAsync('git', ['fetch', ...maybeUnshallow, upstream, branch]);
|
351
352
|
cli.stopSpinner(`${branchName} is now up-to-date`);
|
352
353
|
const stray = this.getStrayCommits(true);
|
353
354
|
if (!stray.length) {
|
@@ -44,6 +44,9 @@ const fastFloatReplace = `/third_party/fast_float/src/*
|
|
44
44
|
const highwayIgnore = `/third_party/highway/src/*
|
45
45
|
!/third_party/highway/src/hwy`;
|
46
46
|
|
47
|
+
const dragonboxIgnore = `/third_party/dragonbox/src/*
|
48
|
+
!/third_party/dragonbox/src/include`;
|
49
|
+
|
47
50
|
export const v8Deps = [
|
48
51
|
{
|
49
52
|
name: 'trace_event',
|
@@ -133,5 +136,14 @@ export const v8Deps = [
|
|
133
136
|
repo: 'third_party/simdutf',
|
134
137
|
gitignore: '!/third_party/simdutf',
|
135
138
|
since: 134
|
136
|
-
}
|
139
|
+
},
|
140
|
+
{
|
141
|
+
name: 'dragonbox',
|
142
|
+
repo: 'third_party/dragonbox/src',
|
143
|
+
gitignore: {
|
144
|
+
match: '/third_party/dragonbox/src',
|
145
|
+
replace: dragonboxIgnore
|
146
|
+
},
|
147
|
+
since: 138
|
148
|
+
},
|
137
149
|
];
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@node-core/utils",
|
3
|
-
"version": "5.
|
3
|
+
"version": "5.13.0",
|
4
4
|
"description": "Utilities for Node.js core collaborators",
|
5
5
|
"type": "module",
|
6
6
|
"engines": {
|
@@ -34,40 +34,40 @@
|
|
34
34
|
],
|
35
35
|
"license": "MIT",
|
36
36
|
"dependencies": {
|
37
|
-
"@inquirer/prompts": "^7.
|
37
|
+
"@inquirer/prompts": "^7.4.1",
|
38
38
|
"@listr2/prompt-adapter-enquirer": "^2.0.12",
|
39
39
|
"@node-core/caritat": "^1.6.0",
|
40
40
|
"@pkgjs/nv": "^0.2.2",
|
41
41
|
"branch-diff": "^3.1.1",
|
42
42
|
"chalk": "^5.4.1",
|
43
|
-
"changelog-maker": "^4.
|
43
|
+
"changelog-maker": "^4.4.1",
|
44
44
|
"cheerio": "^1.0.0",
|
45
45
|
"clipboardy": "^4.0.0",
|
46
46
|
"core-validate-commit": "^4.1.0",
|
47
47
|
"figures": "^6.1.0",
|
48
|
-
"ghauth": "^6.0.
|
48
|
+
"ghauth": "^6.0.12",
|
49
49
|
"git-secure-tag": "^2.3.1",
|
50
50
|
"js-yaml": "^4.1.0",
|
51
51
|
"listr2": "^8.2.5",
|
52
52
|
"lodash": "^4.17.21",
|
53
53
|
"log-symbols": "^7.0.0",
|
54
|
-
"ora": "^8.
|
54
|
+
"ora": "^8.2.0",
|
55
55
|
"replace-in-file": "^8.3.0",
|
56
|
-
"semver": "^7.
|
57
|
-
"undici": "^7.
|
56
|
+
"semver": "^7.7.1",
|
57
|
+
"undici": "^7.7.0",
|
58
58
|
"which": "^5.0.0",
|
59
59
|
"yargs": "^17.7.2"
|
60
60
|
},
|
61
61
|
"devDependencies": {
|
62
|
-
"@eslint/js": "^9.
|
62
|
+
"@eslint/js": "^9.24.0",
|
63
63
|
"@reporters/github": "^1.7.2",
|
64
64
|
"c8": "^10.1.3",
|
65
|
-
"eslint": "^9.
|
65
|
+
"eslint": "^9.24.0",
|
66
66
|
"eslint-plugin-import": "^2.31.0",
|
67
|
-
"eslint-plugin-n": "^17.
|
67
|
+
"eslint-plugin-n": "^17.17.0",
|
68
68
|
"eslint-plugin-promise": "^7.2.1",
|
69
|
-
"globals": "^
|
70
|
-
"neostandard": "^0.12.
|
71
|
-
"sinon": "^
|
69
|
+
"globals": "^16.0.0",
|
70
|
+
"neostandard": "^0.12.1",
|
71
|
+
"sinon": "^20.0.0"
|
72
72
|
}
|
73
73
|
}
|