@node-core/utils 6.3.3 → 7.0.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.
Files changed (56) hide show
  1. package/README.md +2 -5
  2. package/bin/ncu-ci.js +3 -19
  3. package/components/git/benchmark.js +112 -0
  4. package/components/git/land.js +3 -3
  5. package/components/git/metadata.js +34 -1
  6. package/components/git/release.js +3 -5
  7. package/components/git/security.js +258 -27
  8. package/components/git/v8.js +6 -3
  9. package/components/metadata.js +75 -7
  10. package/lib/auth.js +3 -4
  11. package/lib/backport_session.js +3 -3
  12. package/lib/benchmark.js +243 -0
  13. package/lib/cherry_pick.js +32 -11
  14. package/lib/ci/failure_aggregator.js +16 -20
  15. package/lib/ci/run_ci.js +1 -1
  16. package/lib/cli.js +33 -1
  17. package/lib/config.js +7 -7
  18. package/lib/file.js +5 -5
  19. package/lib/landing_session.js +65 -24
  20. package/lib/links.js +4 -4
  21. package/lib/pr_checker.js +163 -31
  22. package/lib/pr_data.js +1 -1
  23. package/lib/pr_summary.js +1 -1
  24. package/lib/prepare_release.js +270 -85
  25. package/lib/prepare_security.js +367 -41
  26. package/lib/promote_release.js +19 -16
  27. package/lib/queries/ListSecurityReleasePRs.gql +19 -0
  28. package/lib/queries/PR.gql +4 -1
  29. package/lib/request.js +41 -0
  30. package/lib/run.js +5 -5
  31. package/lib/security-announcement.js +10 -5
  32. package/lib/security-release/security-release.js +160 -20
  33. package/lib/security_blog.js +130 -65
  34. package/lib/session.js +4 -3
  35. package/lib/team_info.js +1 -1
  36. package/lib/update-v8/applyNodeChanges.js +1 -3
  37. package/lib/update-v8/backport.js +6 -6
  38. package/lib/update-v8/commitUpdate.js +3 -6
  39. package/lib/update-v8/common.js +30 -6
  40. package/lib/update-v8/constants.js +22 -0
  41. package/lib/update-v8/deps.js +3 -5
  42. package/lib/update-v8/index.js +14 -5
  43. package/lib/update-v8/majorUpdate.js +5 -4
  44. package/lib/update-v8/minorUpdate.js +4 -4
  45. package/lib/update-v8/updateCrates.js +192 -0
  46. package/lib/update-v8/updateV8Clone.js +1 -1
  47. package/lib/update-v8/updateVersionNumbers.js +3 -6
  48. package/lib/update-v8/util.js +3 -3
  49. package/lib/update_security_release.js +347 -105
  50. package/lib/utils.js +5 -5
  51. package/lib/verbosity.js +3 -3
  52. package/lib/wpt/index.js +1 -23
  53. package/package.json +18 -22
  54. package/bin/get-metadata.js +0 -11
  55. package/lib/wpt/templates/README.md +0 -16
  56. package/npm-shrinkwrap.json +0 -20380
@@ -1,6 +1,5 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import _ from 'lodash';
4
3
  import nv from '@pkgjs/nv';
5
4
  import {
6
5
  PLACEHOLDERS,
@@ -8,10 +7,16 @@ import {
8
7
  validateDate,
9
8
  SecurityRelease,
10
9
  commitAndPushVulnerabilitiesJSON,
10
+ getAffectedVersionLines,
11
+ getDependencyUpdates,
12
+ getHighestSeverityAnnouncement,
13
+ writeSecurityFile,
11
14
  } from './security-release/security-release.js';
12
15
  import auth from './auth.js';
13
16
  import Request from './request.js';
14
17
 
18
+ const SEVERITY_ORDER = ['critical', 'high', 'medium', 'low'];
19
+
15
20
  export default class SecurityBlog extends SecurityRelease {
16
21
  req;
17
22
 
@@ -19,15 +24,14 @@ export default class SecurityBlog extends SecurityRelease {
19
24
  const { cli } = this;
20
25
 
21
26
  // checkout on security release branch
22
- checkoutOnSecurityReleaseBranch(cli, this.repository);
27
+ await checkoutOnSecurityReleaseBranch(cli, this.repository);
23
28
 
24
29
  // read vulnerabilities JSON file
25
30
  const content = this.readVulnerabilitiesJSON();
26
31
  // validate the release date read from vulnerabilities JSON
27
32
  if (!content.releaseDate) {
28
- cli.error('Release date is not set in vulnerabilities.json,' +
33
+ throw new Error('Release date is not set in vulnerabilities.json,' +
29
34
  ' run `git node security --update-date=YYYY/MM/DD` to set the release date.');
30
- process.exit(1);
31
35
  }
32
36
 
33
37
  validateDate(content.releaseDate);
@@ -38,7 +42,7 @@ export default class SecurityBlog extends SecurityRelease {
38
42
  annoucementDate: await this.getAnnouncementDate(cli),
39
43
  releaseDate: this.formatReleaseDate(releaseDate),
40
44
  affectedVersions: this.getAffectedVersions(content),
41
- vulnerabilities: this.getVulnerabilities(content),
45
+ vulnerabilities: this.getPreReleaseVulnerabilities(content),
42
46
  slug: this.getSlug(releaseDate),
43
47
  impact: this.getImpact(content)
44
48
  };
@@ -58,14 +62,19 @@ export default class SecurityBlog extends SecurityRelease {
58
62
  endDate.setDate(endDate.getDate() + 7);
59
63
 
60
64
  const link = `https://nodejs.org/en/blog/vulnerability/${fileName}`;
61
- this.updateWebsiteBanner(site, {
65
+ await this.updateWebsiteBanner(site, {
62
66
  startDate: data.annoucementDate,
63
67
  endDate: endDate.toISOString(),
64
68
  text: `New security releases to be made available ${data.releaseDate}`,
65
69
  link,
66
70
  type: 'warning'
67
71
  });
68
- fs.writeFileSync(file, preRelease);
72
+ await writeSecurityFile(
73
+ cli,
74
+ file,
75
+ preRelease,
76
+ 'This writes the pre-release vulnerability announcement post.'
77
+ );
69
78
 
70
79
  cli.ok(`Announcement file created and banner has been updated. Folder: ${nodejsOrgFolder}`);
71
80
  await this.updateAnnouncementLink(link);
@@ -74,23 +83,23 @@ export default class SecurityBlog extends SecurityRelease {
74
83
  async updateAnnouncementLink(link) {
75
84
  const vulnerabilitiesJSONPath = this.getVulnerabilitiesJSONPath();
76
85
  const content = this.readVulnerabilitiesJSON(vulnerabilitiesJSONPath);
77
- let shouldCommit = false;
78
- for (let i = 0; i < content.reports.length; ++i) {
79
- if (content.reports[i].announcement !== link) {
80
- content.reports[i].announcement = link;
81
- shouldCommit = true;
82
- }
83
- };
84
86
 
85
- if (shouldCommit) {
86
- fs.writeFileSync(vulnerabilitiesJSONPath, JSON.stringify(content, null, 2));
87
- const commitMessage = 'chore: add announcement link';
88
- commitAndPushVulnerabilitiesJSON([vulnerabilitiesJSONPath],
89
- commitMessage, { cli: this.cli, repository: this.repository });
90
-
91
- this.cli.ok('Updated the announcement link in vulnerabilities.json');
87
+ if (content.announcement === link) {
88
+ return [vulnerabilitiesJSONPath];
92
89
  }
93
90
 
91
+ content.announcement = link;
92
+ await writeSecurityFile(
93
+ this.cli,
94
+ vulnerabilitiesJSONPath,
95
+ JSON.stringify(content, null, 2),
96
+ 'This writes the announcement link to vulnerabilities.json.'
97
+ );
98
+ const commitMessage = 'chore: add announcement link';
99
+ await commitAndPushVulnerabilitiesJSON([vulnerabilitiesJSONPath],
100
+ commitMessage, { cli: this.cli, repository: this.repository });
101
+
102
+ this.cli.ok('Updated the announcement link in vulnerabilities.json');
94
103
  return [vulnerabilitiesJSONPath];
95
104
  }
96
105
 
@@ -104,14 +113,13 @@ export default class SecurityBlog extends SecurityRelease {
104
113
  this.req = new Request(credentials);
105
114
 
106
115
  // checkout on security release branch
107
- checkoutOnSecurityReleaseBranch(cli, this.repository);
116
+ await checkoutOnSecurityReleaseBranch(cli, this.repository);
108
117
 
109
118
  // read vulnerabilities JSON file
110
119
  const content = this.readVulnerabilitiesJSON();
111
120
  if (!content.releaseDate) {
112
- cli.error('Release date is not set in vulnerabilities.json,' +
121
+ throw new Error('Release date is not set in vulnerabilities.json,' +
113
122
  ' run `git node security --update-date=YYYY/MM/DD` to set the release date.');
114
- process.exit(1);
115
123
  }
116
124
 
117
125
  validateDate(content.releaseDate);
@@ -133,8 +141,7 @@ export default class SecurityBlog extends SecurityRelease {
133
141
  const preReleasePath = path.resolve(pathToBlogPosts, data.slug + '.md');
134
142
  let preReleaseContent = this.findExistingPreRelease(preReleasePath);
135
143
  if (!preReleaseContent) {
136
- cli.error(`Existing pre-release not found! Path: ${preReleasePath} `);
137
- process.exit(1);
144
+ throw new Error(`Existing pre-release not found! Path: ${preReleasePath} `);
138
145
  }
139
146
 
140
147
  const postReleaseContent = await this.buildPostRelease(template, data, content);
@@ -150,13 +157,18 @@ export default class SecurityBlog extends SecurityRelease {
150
157
  const month = releaseDate.toLocaleString('en-US', { month: 'long' });
151
158
  const capitalizedMonth = month[0].toUpperCase() + month.slice(1);
152
159
 
153
- this.updateWebsiteBanner(pathToBannerJson, {
160
+ await this.updateWebsiteBanner(pathToBannerJson, {
154
161
  startDate: releaseDate,
155
162
  endDate,
156
163
  text: `${capitalizedMonth} Security Release is available`
157
164
  });
158
165
 
159
- fs.writeFileSync(preReleasePath, updatedContent);
166
+ await writeSecurityFile(
167
+ cli,
168
+ preReleasePath,
169
+ updatedContent,
170
+ 'This writes the post-release vulnerability announcement post.'
171
+ );
160
172
  cli.ok(`Announcement file and banner has been updated. Folder: ${nodejsOrgFolder}`);
161
173
  }
162
174
 
@@ -176,7 +188,7 @@ export default class SecurityBlog extends SecurityRelease {
176
188
  });
177
189
  }
178
190
 
179
- updateWebsiteBanner(siteJsonPath, content) {
191
+ async updateWebsiteBanner(siteJsonPath, content) {
180
192
  const siteJson = JSON.parse(fs.readFileSync(siteJsonPath));
181
193
 
182
194
  const currentValue = siteJson.websiteBanners.index;
@@ -187,7 +199,12 @@ export default class SecurityBlog extends SecurityRelease {
187
199
  link: content.link ?? currentValue.link,
188
200
  type: content.type ?? currentValue.type
189
201
  };
190
- fs.writeFileSync(siteJsonPath, JSON.stringify(siteJson, null, 2) + '\n');
202
+ await writeSecurityFile(
203
+ this.cli,
204
+ siteJsonPath,
205
+ JSON.stringify(siteJson, null, 2) + '\n',
206
+ 'This writes the updated security release website banner.'
207
+ );
191
208
  }
192
209
 
193
210
  formatReleaseDate(releaseDate) {
@@ -242,28 +259,26 @@ export default class SecurityBlog extends SecurityRelease {
242
259
  }
243
260
 
244
261
  async getReportsTemplate(content) {
245
- const reports = content.reports;
262
+ const reports = [...content.reports].sort((a, b) =>
263
+ this.getSeverityOrder(a) - this.getSeverityOrder(b));
246
264
  let template = '';
247
265
  for (const report of reports) {
248
266
  const cveId = report.cveIds?.join(', ');
249
267
  if (!cveId) {
250
- this.cli.error(`CVE ID for vulnerability ${report.link} ${report.title} not found`);
251
- process.exit(1);
268
+ throw new Error(`CVE ID for vulnerability ${report.link} ${report.title} not found`);
252
269
  }
253
270
  template += `## ${report.title} (${cveId}) - (${report.severity.rating})\n\n`;
254
271
  if (!report.summary) {
255
- this.cli.error(`Summary missing for vulnerability ${report.link} ` +
272
+ throw new Error(`Summary missing for vulnerability ${report.link} ` +
256
273
  `${report.title}. Please create it before continuing.`);
257
- process.exit(1);
258
274
  }
259
275
 
260
276
  template += `${report.summary}\n\n`;
261
- const releaseLines = report.affectedVersions.join(', ');
277
+ const releaseLines = getAffectedVersionLines(report.affectedVersions).join(', ');
262
278
  template += `Impact:\n\n- This vulnerability affects all users\
263
279
  in active release lines: ${releaseLines}\n\n`;
264
280
  if (!report.patchAuthors) {
265
- this.cli.error(`Missing patch author for vulnerability ${report.link} ${report.title}`);
266
- process.exit(1);
281
+ throw new Error(`Missing patch author for vulnerability ${report.link} ${report.title}`);
267
282
  }
268
283
  template += `Thank you, to ${report.reporter} for reporting this vulnerability\
269
284
  and thank you ${report.patchAuthors.join(' and ')} for fixing it.\n\n`;
@@ -271,17 +286,58 @@ export default class SecurityBlog extends SecurityRelease {
271
286
  return template;
272
287
  }
273
288
 
289
+ getSeverityOrder(report) {
290
+ const rating = report.severity?.rating?.toLowerCase();
291
+ const index = SEVERITY_ORDER.indexOf(rating);
292
+ if (index === -1) return SEVERITY_ORDER.length;
293
+ return index;
294
+ }
295
+
274
296
  getDependencyUpdatesTemplate(dependencyUpdates) {
275
- if (typeof dependencyUpdates !== 'object') return '';
276
- if (Object.keys(dependencyUpdates).length === 0) return '';
297
+ const updates = getDependencyUpdates(dependencyUpdates);
298
+ if (updates.length === 0) return '';
277
299
  let template = '\nThis security release includes the following dependency' +
278
300
  ' updates to address public vulnerabilities:\n';
279
- for (const [dependency, { versions, affectedVersions }] of Object.entries(dependencyUpdates)) {
280
- template += `- ${dependency} (${versions.join(', ')}) on ${affectedVersions.join(', ')}\n`;
301
+ for (const update of updates) {
302
+ const title = this.formatDependencyUpdateTitle(update) || update.name;
303
+ const releaseLines = getAffectedVersionLines(update.affectedVersions);
304
+ const formattedVersions = this.formatDependencyVersions(update.versions);
305
+ const versionText = formattedVersions ? ` (${formattedVersions})` : '';
306
+ template += `- ${title}${versionText} on ${releaseLines.join(', ')}\n`;
281
307
  }
282
308
  return template;
283
309
  }
284
310
 
311
+ formatDependencyUpdateVersion(version) {
312
+ if (typeof version === 'string' || typeof version === 'number') {
313
+ return String(version);
314
+ }
315
+
316
+ if (!version || typeof version !== 'object') return '';
317
+
318
+ return version.version || version.to || version.patched || version.name ||
319
+ this.formatDependencyUpdateTitle(version) || version.url || JSON.stringify(version);
320
+ }
321
+
322
+ formatDependencyVersions(versions) {
323
+ if (!Array.isArray(versions)) return '';
324
+ // The current schema carries one entry per release line, so the same
325
+ // version repeats when every line gets the same update.
326
+ return [...new Set(versions
327
+ .map((version) => this.formatDependencyUpdateVersion(version))
328
+ .filter(Boolean))]
329
+ .join(', ');
330
+ }
331
+
332
+ formatDependencyUpdateTitle(dependency) {
333
+ if (!dependency || typeof dependency !== 'object') return '';
334
+ if (!dependency.title) return dependency.name ?? '';
335
+
336
+ const titleSeparator = dependency.title.indexOf(':');
337
+ if (titleSeparator === -1) return dependency.title;
338
+ return dependency.title.substring(titleSeparator + ':'.length).trim();
339
+ }
340
+
285
341
  async getDownloadsTemplate(affectedVersions) {
286
342
  let template = '';
287
343
  const versionsToBeReleased = (await nv('supported')).filter(
@@ -306,7 +362,7 @@ export default class SecurityBlog extends SecurityRelease {
306
362
  const date = await this.promptAnnouncementDate(cli);
307
363
  validateDate(date);
308
364
  return new Date(date).toISOString();
309
- } catch (error) {
365
+ } catch {
310
366
  return PLACEHOLDERS.annoucementDate;
311
367
  }
312
368
  }
@@ -323,7 +379,11 @@ export default class SecurityBlog extends SecurityRelease {
323
379
  getImpact(content) {
324
380
  const impact = new Map();
325
381
  for (const report of content.reports) {
326
- for (const version of report.affectedVersions) {
382
+ if (!report.severity?.rating) {
383
+ throw new Error(`severity.rating not found for report ${report.id}.`);
384
+ }
385
+
386
+ for (const version of getAffectedVersionLines(report.affectedVersions)) {
327
387
  if (!impact.has(version)) impact.set(version, []);
328
388
  impact.get(version).push(report);
329
389
  }
@@ -331,38 +391,43 @@ export default class SecurityBlog extends SecurityRelease {
331
391
 
332
392
  const result = Array.from(impact.entries())
333
393
  .sort(([a], [b]) => b.localeCompare(a)) // DESC
334
- .map(([version, reports]) => {
335
- const severityCount = new Map();
336
-
337
- for (const report of reports) {
338
- const rating = report.severity.rating?.toLowerCase();
339
- if (!rating) {
340
- this.cli.error(`severity.rating not found for report ${report.id}.`);
341
- process.exit(1);
342
- }
343
- severityCount.set(rating, (severityCount.get(rating) || 0) + 1);
344
- }
345
-
346
- const groupedByRating = Array.from(severityCount.entries())
347
- .map(([rating, count]) => `${count} ${rating} severity issues`)
348
- .join(', ');
349
-
350
- return `The ${version} release line of Node.js is vulnerable to ${groupedByRating}.`;
351
- })
394
+ .map(([version, reports]) =>
395
+ getHighestSeverityAnnouncement(reports, `the ${version} release line`))
352
396
  .join('\n');
353
397
 
354
398
  return result;
355
399
  }
356
400
 
357
401
  getVulnerabilities(content) {
358
- const grouped = _.groupBy(content.reports, 'severity.rating');
402
+ const severityCount = new Map();
403
+
404
+ for (const report of content.reports) {
405
+ if (!report.severity?.rating) {
406
+ throw new Error(`severity.rating not found for report ${report.id}.`);
407
+ }
408
+
409
+ const rating = report.severity.rating;
410
+ severityCount.set(rating, (severityCount.get(rating) || 0) + 1);
411
+ }
412
+
359
413
  const text = [];
360
- for (const [key, value] of Object.entries(grouped)) {
361
- text.push(`- ${value.length} ${key.toLocaleLowerCase()} severity issues.`);
414
+ for (const [rating, count] of severityCount) {
415
+ text.push(`- ${count} ${rating} severity issues.`);
362
416
  }
417
+
363
418
  return text.join('\n');
364
419
  }
365
420
 
421
+ getPreReleaseVulnerabilities(content) {
422
+ for (const report of content.reports) {
423
+ if (!report.severity?.rating) {
424
+ throw new Error(`severity.rating not found for report ${report.id}.`);
425
+ }
426
+ }
427
+
428
+ return getHighestSeverityAnnouncement(content.reports);
429
+ }
430
+
366
431
  getSecurityPreReleaseTemplate() {
367
432
  return fs.readFileSync(
368
433
  new URL(
package/lib/session.js CHANGED
@@ -160,7 +160,7 @@ export default class Session {
160
160
  let sess;
161
161
  try {
162
162
  sess = this.session;
163
- } catch (err) {
163
+ } catch {
164
164
  return fs.rmSync(this.sessionPath, { recursive: true, force: true });
165
165
  }
166
166
 
@@ -345,8 +345,9 @@ export default class Session {
345
345
  }
346
346
 
347
347
  getStrayCommits(verbose) {
348
- const { upstream, branch } = this;
349
- const ref = `${upstream}/${branch}...HEAD`;
348
+ const { upstream, branch, cli } = this;
349
+ const base = cli.hasDetachedHEAD || `${upstream}/${branch}`;
350
+ const ref = `${base}...HEAD`;
350
351
  const gitCmd = verbose
351
352
  ? ['log', '--oneline', '--reverse', ref]
352
353
  : ['rev-list', '--reverse', ref];
package/lib/team_info.js CHANGED
@@ -76,7 +76,7 @@ TeamInfo.update = async function(cli, request, content) {
76
76
  const opening = `<!-- ncu-team-sync.team(${org}/${team}) -->`;
77
77
  const ending = '<!-- ncu-team-sync end -->';
78
78
  blocks.set(mapKey, `${opening}\n\n${teamData}\n\n${ending}`);
79
- };
79
+ }
80
80
  }
81
81
 
82
82
  if (blocks.size === 0) {
@@ -1,7 +1,6 @@
1
1
  import path from 'node:path';
2
2
 
3
3
  import {
4
- getNodeV8Version,
5
4
  filterForVersion,
6
5
  replaceGitignore,
7
6
  removeDirectory
@@ -18,8 +17,7 @@ export default function applyNodeChanges() {
18
17
  return {
19
18
  title: 'Apply Node-specific changes',
20
19
  task: async(ctx, task) => {
21
- const v8Version = await getNodeV8Version(ctx.nodeDir);
22
- const list = filterForVersion(nodeChanges, v8Version);
20
+ const list = filterForVersion(nodeChanges, ctx.newVersion);
23
21
  return task.newListr(list.map((change) => change.task()));
24
22
  }
25
23
  };
@@ -8,7 +8,7 @@ import { ListrEnquirerPromptAdapter } from '@listr2/prompt-adapter-enquirer';
8
8
 
9
9
  import { shortSha } from '../utils.js';
10
10
 
11
- import { getCurrentV8Version } from './common.js';
11
+ import { getV8Version } from './common.js';
12
12
  import { forceRunAsync } from '../run.js';
13
13
 
14
14
  export async function checkOptions(options) {
@@ -24,11 +24,11 @@ export async function checkOptions(options) {
24
24
  return true;
25
25
  }
26
26
  }
27
- };
27
+ }
28
28
 
29
29
  export function doBackport(options) {
30
30
  const todo = [
31
- getCurrentV8Version(),
31
+ getV8Version('current'),
32
32
  generatePatches()
33
33
  ];
34
34
 
@@ -54,7 +54,7 @@ export function doBackport(options) {
54
54
  return task.newListr(todo);
55
55
  }
56
56
  };
57
- };
57
+ }
58
58
 
59
59
  function commitSquashedBackport() {
60
60
  return {
@@ -77,7 +77,7 @@ function commitSquashedBackport() {
77
77
  await ctx.execGitNode('commit', ['-m', messageTitle, '-m', messageBody]);
78
78
  }
79
79
  };
80
- };
80
+ }
81
81
 
82
82
  const commitTask = (patch, extraArgs, trailers) => async(ctx) => {
83
83
  const messageTitle = formatMessageTitle([patch]);
@@ -261,7 +261,7 @@ async function applyPatch(ctx, task, patch, method = 'apply') {
261
261
  ['-p1', '--3way', '--directory=deps/v8'],
262
262
  patch.data /* input */
263
263
  );
264
- } catch (e) {
264
+ } catch {
265
265
  patch.hadConflicts = true;
266
266
  return task.prompt(ListrEnquirerPromptAdapter).run({
267
267
  type: 'input',
@@ -1,10 +1,7 @@
1
- import { getNodeV8Version } from './util.js';
2
-
3
1
  export default function commitUpdate() {
4
2
  return {
5
3
  title: 'Commit V8 update',
6
4
  task: async(ctx) => {
7
- const newV8Version = await getNodeV8Version(ctx.nodeDir);
8
5
  await ctx.execGitNode('add', ['deps/v8']);
9
6
  const moreArgs = [];
10
7
  let message;
@@ -15,12 +12,12 @@ export default function commitUpdate() {
15
12
  '-m',
16
13
  `Refs: https://github.com/v8/v8/compare/${prev}...${next}`
17
14
  );
18
- message = `deps: patch V8 to ${newV8Version}`;
15
+ message = `deps: patch V8 to ${ctx.newVersion}`;
19
16
  } else {
20
- message = `deps: update V8 to ${newV8Version}`;
17
+ message = `deps: update V8 to ${ctx.newVersion}`;
21
18
  }
22
19
  await ctx.execGitNode('commit', ['-m', message, ...moreArgs]);
23
20
  },
24
21
  skip: (ctx) => ctx.skipped
25
22
  };
26
- };
23
+ }
@@ -1,16 +1,39 @@
1
+ import assert from 'node:assert';
1
2
  import path from 'node:path';
2
3
  import { promises as fs } from 'node:fs';
3
4
 
4
5
  import { getNodeV8Version } from './util.js';
6
+ import { forceRunAsync } from '../run.js';
5
7
 
6
- export function getCurrentV8Version() {
8
+ export function getV8Version(label) {
7
9
  return {
8
- title: 'Get current V8 version',
10
+ title: `Get ${label} V8 version`,
9
11
  task: async(ctx) => {
10
- ctx.currentVersion = await getNodeV8Version(ctx.nodeDir);
12
+ ctx[`${label}Version`] = await getNodeV8Version(ctx.nodeDir);
11
13
  }
12
14
  };
13
- };
15
+ }
16
+
17
+ export function checkCargoAvailable() {
18
+ return {
19
+ title: 'Check Cargo exists in environment',
20
+ task: async(ctx) => {
21
+ try {
22
+ const output = await forceRunAsync(ctx.cargo, ['--version'], {
23
+ ignoreFailure: false,
24
+ captureStdout: true,
25
+ });
26
+ assert(output.startsWith('cargo'));
27
+ } catch (cause) {
28
+ let error = 'Unable to determine cargo version.';
29
+ if (ctx.cargo === 'cargo') {
30
+ error += '\nYou may need to specify the path to your cargo binary with `--cargo`.';
31
+ }
32
+ throw new Error(error, { cause });
33
+ }
34
+ }
35
+ };
36
+ }
14
37
 
15
38
  export async function checkCwd(ctx) {
16
39
  let isNode = false;
@@ -23,7 +46,7 @@ export async function checkCwd(ctx) {
23
46
  isNode = true;
24
47
  ctx.nodeMajorVersion = parseInt(match[1], 10);
25
48
  }
26
- } catch (e) {
49
+ } catch {
27
50
  // ignore
28
51
  }
29
52
  if (!isNode) {
@@ -32,4 +55,5 @@ export async function checkCwd(ctx) {
32
55
  `node-dir: ${ctx.nodeDir}`
33
56
  );
34
57
  }
35
- };
58
+ return ctx;
59
+ }
@@ -47,6 +47,14 @@ const highwayIgnore = `/third_party/highway/src/*
47
47
  const dragonboxIgnore = `/third_party/dragonbox/src/*
48
48
  !/third_party/dragonbox/src/include`;
49
49
 
50
+ const llvmLibcIgnore = `/third_party/llvm-libc/src/*
51
+ !/third_party/llvm-libc/src/hdr
52
+ !/third_party/llvm-libc/src/include
53
+ !/third_party/llvm-libc/src/shared
54
+ !/third_party/llvm-libc/src/src
55
+ /third_party/llvm-libc/src/src/*
56
+ !/third_party/llvm-libc/src/src/__support`;
57
+
50
58
  export const v8Deps = [
51
59
  {
52
60
  name: 'trace_event',
@@ -146,4 +154,18 @@ export const v8Deps = [
146
154
  },
147
155
  since: 138
148
156
  },
157
+ {
158
+ name: 'rust',
159
+ repo: 'third_party/rust',
160
+ since: 139
161
+ },
162
+ {
163
+ name: 'llvm-libc',
164
+ repo: 'third_party/llvm-libc/src',
165
+ gitignore: {
166
+ match: '/third_party/llvm-libc/src',
167
+ replace: llvmLibcIgnore
168
+ },
169
+ since: 150
170
+ },
149
171
  ];
@@ -6,7 +6,6 @@ import { forceRunAsync } from '../run.js';
6
6
  import {
7
7
  addToGitignore,
8
8
  filterForVersion,
9
- getNodeV8Version,
10
9
  removeDirectory,
11
10
  replaceGitignore,
12
11
  } from './util.js';
@@ -54,13 +53,12 @@ export default function updateV8Deps() {
54
53
  return {
55
54
  title: 'Update V8 DEPS',
56
55
  task: async(ctx, task) => {
57
- const newV8Version = await getNodeV8Version(ctx.nodeDir);
58
- const repoPrefix = newV8Version.majorMinor >= 86 ? '' : 'v8/';
56
+ const repoPrefix = ctx.newVersion.majorMinor >= 86 ? '' : 'v8/';
59
57
  const deps = filterForVersion(v8Deps.map((v8Dep) => ({
60
58
  ...v8Dep,
61
59
  repo: `${repoPrefix}${v8Dep.repo}`,
62
60
  path: v8Dep.repo
63
- })), newV8Version);
61
+ })), ctx.newVersion);
64
62
  if (deps.length === 0) return;
65
63
  const depsTable = await readDeps(ctx.nodeDir);
66
64
  const subtasks = [];
@@ -85,4 +83,4 @@ export default function updateV8Deps() {
85
83
  return task.newListr(subtasks, { concurrent: ctx.concurrent });
86
84
  }
87
85
  };
88
- };
86
+ }
@@ -1,20 +1,29 @@
1
1
  import { Listr } from 'listr2';
2
2
 
3
+ import { checkCargoAvailable } from './common.js';
3
4
  import { checkOptions, doBackport } from './backport.js';
4
5
  import updateVersionNumbers from './updateVersionNumbers.js';
5
6
  import commitUpdate from './commitUpdate.js';
6
7
  import majorUpdate from './majorUpdate.js';
7
8
  import minorUpdate from './minorUpdate.js';
8
9
  import updateDeps from './deps.js';
10
+ import updateCrates from './updateCrates.js';
9
11
  import updateV8Clone from './updateV8Clone.js';
10
12
 
11
13
  export function major(options) {
12
14
  const tasks = new Listr(
13
- [updateV8Clone(), majorUpdate(), commitUpdate(), updateVersionNumbers()],
15
+ [
16
+ checkCargoAvailable(),
17
+ updateV8Clone(),
18
+ majorUpdate(),
19
+ commitUpdate(),
20
+ updateCrates(),
21
+ updateVersionNumbers()
22
+ ],
14
23
  getOptions(options)
15
24
  );
16
25
  return tasks.run(options);
17
- };
26
+ }
18
27
 
19
28
  export function minor(options) {
20
29
  const tasks = new Listr(
@@ -22,7 +31,7 @@ export function minor(options) {
22
31
  getOptions(options)
23
32
  );
24
33
  return tasks.run(options);
25
- };
34
+ }
26
35
 
27
36
  export async function backport(options) {
28
37
  const shouldStop = await checkOptions(options);
@@ -33,7 +42,7 @@ export async function backport(options) {
33
42
  getOptions(options)
34
43
  );
35
44
  return tasks.run(options);
36
- };
45
+ }
37
46
 
38
47
  export async function deps(options) {
39
48
  const tasks = new Listr(
@@ -41,7 +50,7 @@ export async function deps(options) {
41
50
  getOptions(options)
42
51
  );
43
52
  return tasks.run(options);
44
- };
53
+ }
45
54
 
46
55
  /**
47
56
  * Get the listr2 options.