@node-core/utils 5.10.0 → 5.12.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/bin/git-node.js CHANGED
@@ -27,4 +27,6 @@ Promise.all(commandFiles.map(importCommand)).then((commands) => {
27
27
  .epilogue(epilogue)
28
28
  .help('help')
29
29
  .parse();
30
+ }).catch((err) => {
31
+ throw err;
30
32
  });
package/bin/ncu-ci.js CHANGED
@@ -115,9 +115,9 @@ const args = yargs(hideBin(process.argv))
115
115
  type: 'number'
116
116
  })
117
117
  .positional('certify-safe', {
118
- describe: 'If not provided, the command will reject PRs that have ' +
119
- 'been pushed since the last review',
120
- type: 'boolean'
118
+ describe: 'SHA of the commit that is expected to be at the tip of the PR head. ' +
119
+ 'If not provided, the command will use the SHA of the last approved commit.',
120
+ type: 'string'
121
121
  })
122
122
  .option('owner', {
123
123
  default: '',
@@ -90,5 +90,6 @@ export function handler(argv) {
90
90
  if (status === false) {
91
91
  throw new Error(IGNORE);
92
92
  }
93
+ return undefined;
93
94
  }));
94
95
  }
@@ -112,9 +112,10 @@ function release(state, argv) {
112
112
  }
113
113
 
114
114
  async function main(state, argv, cli, dir) {
115
- const prID = /^(?:https:\/\/github\.com\/nodejs\/node\/pull\/)?(\d+)$/.exec(argv.prid);
115
+ const prID = /^(?:https:\/\/github\.com\/nodejs(-private)?\/node\1\/pull\/)?(\d+)$/.exec(argv.prid);
116
116
  if (prID) {
117
- argv.prid = Number(prID[1]);
117
+ if (prID[1]) argv.security = true;
118
+ argv.prid = Number(prID[2]);
118
119
  }
119
120
  if (state === PREPARE) {
120
121
  const release = new ReleasePreparation(argv, cli, dir);
@@ -20,10 +20,10 @@ class Health {
20
20
  formatAsMarkdown() {
21
21
  const { success, pending, aborted, failed, unstable, count } = this;
22
22
  const rate = `${(success / (count - pending - aborted) * 100).toFixed(2)}%`;
23
- // eslint-disable-next-line max-len
24
- let result = '| UTC Time | RUNNING | SUCCESS | UNSTABLE | ABORTED | FAILURE | Green Rate |\n';
25
- // eslint-disable-next-line max-len
26
- result += '| ---------------- | ------- | ------- | -------- | ------- | ------- | ---------- |\n';
23
+ let result =
24
+ '| UTC Time | RUNNING | SUCCESS | UNSTABLE | ABORTED | FAILURE | Green Rate |\n';
25
+ result +=
26
+ '| ---------------- | ------- | ------- | -------- | ------- | ------- | ---------- |\n';
27
27
  const time = new Date().toISOString().slice(0, 16).replace('T', ' ');
28
28
  result += `| ${time} | ${pad(pending, 7)} | ${pad(success, 8)}|`;
29
29
  result += ` ${pad(unstable, 8)} | ${pad(aborted, 7)} | ${pad(failed, 7)} |`;
@@ -76,6 +76,8 @@ export class TestBuild extends Job {
76
76
  return result;
77
77
  }
78
78
  }
79
+
80
+ return undefined;
79
81
  }
80
82
 
81
83
  get commit() {
@@ -204,7 +204,6 @@ const FAILURE_FILTERS = [{
204
204
  context: { index: 0, contextBefore: 0, contextAfter: 0 }
205
205
  }, {
206
206
  pattern:
207
- // eslint-disable-next-line max-len
208
207
  /error: Your local changes to the following files[\s\S]+Failed to merge in the changes./g,
209
208
  context: { index: 0, contextBefore: 0, contextAfter: 0 }
210
209
  }, {
package/lib/ci/run_ci.js CHANGED
@@ -27,7 +27,7 @@ export class RunPRJob {
27
27
  this.certifySafe =
28
28
  certifySafe ||
29
29
  Promise.all([this.prData.getReviews(), this.prData.getPR()]).then(() =>
30
- new PRChecker(cli, this.prData, request, {}).checkCommitsAfterReviewOrLabel()
30
+ (this.certifySafe = new PRChecker(cli, this.prData, request, {}).getApprovedTipOfHead())
31
31
  );
32
32
  }
33
33
 
@@ -45,6 +45,7 @@ export class RunPRJob {
45
45
  payload.append('json', JSON.stringify({
46
46
  parameter: [
47
47
  { name: 'CERTIFY_SAFE', value: 'on' },
48
+ { name: 'COMMIT_SHA_CHECK', value: this.certifySafe },
48
49
  { name: 'TARGET_GITHUB_ORG', value: this.owner },
49
50
  { name: 'TARGET_REPO_NAME', value: this.repo },
50
51
  { name: 'PR_ID', value: this.prid },
package/lib/cli.js CHANGED
@@ -81,6 +81,7 @@ export default class CLI {
81
81
  return defaultAnswer;
82
82
  }
83
83
 
84
+ // eslint-disable-next-line import/namespace -- Plugin can't validate computed reference here
84
85
  const answer = await inquirer[questionType]({
85
86
  message: question,
86
87
  default: defaultAnswer
@@ -105,7 +105,6 @@ function parseCollaborators(readme, cli) {
105
105
 
106
106
  // We also assume that TSC & TSC Emeriti are also listed as collaborators
107
107
  CONTACT_RE.lastIndex = tscIndex;
108
- // eslint-disable-next-line no-cond-assign
109
108
  while ((m = CONTACT_RE.exec(readme)) && CONTACT_RE.lastIndex < tscrIndex) {
110
109
  const login = m[1].toLowerCase();
111
110
  const user = new Collaborator(m[1], m[2], m[3], TSC);
@@ -113,7 +112,6 @@ function parseCollaborators(readme, cli) {
113
112
  }
114
113
 
115
114
  CONTACT_RE.lastIndex = clIndex;
116
- // eslint-disable-next-line no-cond-assign
117
115
  while ((m = CONTACT_RE.exec(readme)) &&
118
116
  CONTACT_RE.lastIndex < cleIndex) {
119
117
  const login = m[1].toLowerCase();
package/lib/pr_checker.js CHANGED
@@ -524,38 +524,17 @@ export default class PRChecker {
524
524
  return true;
525
525
  }
526
526
 
527
- async checkCommitsAfterReviewOrLabel() {
528
- if (this.checkCommitsAfterReview()) return true;
529
-
530
- await Promise.all([this.data.getLabeledEvents(), this.data.getCollaborators()]);
531
-
532
- const {
533
- cli, data, pr
534
- } = this;
535
-
536
- const { updatedAt } = pr.timelineItems;
537
- const requestCiLabels = data.labeledEvents.findLast(
538
- ({ createdAt, label: { name } }) => name === 'request-ci' && createdAt > updatedAt
539
- );
540
- if (requestCiLabels == null) return false;
541
-
542
- const { actor: { login } } = requestCiLabels;
543
- const collaborators = Array.from(data.collaborators.values(),
544
- (c) => c.login.toLowerCase());
545
- if (collaborators.includes(login.toLowerCase())) {
546
- cli.info('request-ci label was added by a Collaborator after the last push event.');
547
- return true;
548
- }
549
-
550
- return false;
551
- }
552
-
553
- checkCommitsAfterReview() {
527
+ getApprovedTipOfHead() {
554
528
  const {
555
529
  commits, reviews, cli, argv
556
530
  } = this;
557
531
  const { maxCommits } = argv;
558
532
 
533
+ if (commits.length === 0) {
534
+ cli.warn('No commits found');
535
+ return false;
536
+ }
537
+
559
538
  const reviewIndex = reviews.findLastIndex(
560
539
  review => review.authorCanPushToRepository && review.state === 'APPROVED'
561
540
  );
@@ -565,45 +544,32 @@ export default class PRChecker {
565
544
  return false;
566
545
  }
567
546
 
568
- const reviewDate = reviews[reviewIndex].publishedAt;
569
-
570
- const afterCommits = [];
571
- commits.forEach((commit) => {
572
- commit = commit.commit;
573
- if (commit.committedDate > reviewDate) {
574
- afterCommits.push(commit);
575
- }
576
- });
577
-
578
- const totalCommits = afterCommits.length;
579
- if (totalCommits === 0 && this.pr.timelineItems.updatedAt > reviewDate) {
580
- // Some commits were pushed, but all the commits have a commit date prior
581
- // to the last review. It means that either that a long time elapsed
582
- // between the commit and the push, or that the clock on the dev machine
583
- // is wrong, or the commit date was forged.
584
- cli.warn('Something was pushed to the Pull Request branch since the last approving review.');
585
- return false;
586
- }
547
+ const reviewedCommitIndex = commits
548
+ .findLastIndex(({ commit }) => commit.oid === reviews[reviewIndex].commit.oid);
587
549
 
588
- if (totalCommits > 0) {
550
+ if (reviewedCommitIndex !== commits.length - 1) {
589
551
  cli.warn('Commits were pushed since the last approving review:');
590
- const sliceLength = maxCommits === 0 ? totalCommits : -maxCommits;
591
- afterCommits.slice(sliceLength)
592
- .forEach(commit => {
552
+ commits.slice(Math.max(reviewedCommitIndex + 1, commits.length - maxCommits))
553
+ .forEach(({ commit }) => {
593
554
  cli.warn(`- ${commit.messageHeadline}`);
594
555
  });
595
556
 
557
+ const totalCommits = commits.length - reviewedCommitIndex - 1;
596
558
  if (totalCommits > maxCommits) {
597
559
  const infoMsg = '...(use `' +
598
- `--max-commits ${totalCommits}` +
599
- '` to see the full list of commits)';
560
+ `--max-commits ${totalCommits}` +
561
+ '` to see the full list of commits)';
600
562
  cli.warn(infoMsg);
601
563
  }
602
564
 
603
565
  return false;
604
566
  }
605
567
 
606
- return true;
568
+ return reviews[reviewIndex].commit.oid;
569
+ }
570
+
571
+ checkCommitsAfterReview() {
572
+ return !!this.getApprovedTipOfHead();
607
573
  }
608
574
 
609
575
  checkMergeableState() {
package/lib/pr_data.js CHANGED
@@ -5,7 +5,6 @@ import {
5
5
  } from './user_status.js';
6
6
 
7
7
  // lib/queries/*.gql file names
8
- const LABELED_EVENTS_QUERY = 'PRLabeledEvents';
9
8
  const PR_QUERY = 'PR';
10
9
  const REVIEWS_QUERY = 'Reviews';
11
10
  const COMMENTS_QUERY = 'PRComments';
@@ -34,7 +33,6 @@ export default class PRData {
34
33
  this.comments = [];
35
34
  this.commits = [];
36
35
  this.reviewers = [];
37
- this.labeledEvents = [];
38
36
  }
39
37
 
40
38
  getThread() {
@@ -92,14 +90,6 @@ export default class PRData {
92
90
  ]);
93
91
  }
94
92
 
95
- async getLabeledEvents() {
96
- const { prid, owner, repo, cli, request, prStr } = this;
97
- const vars = { prid, owner, repo };
98
- cli.updateSpinner(`Getting labels from ${prStr}`);
99
- this.labeledEvents = (await request.gql(LABELED_EVENTS_QUERY, vars))
100
- .repository.pullRequest.timelineItems.nodes;
101
- }
102
-
103
93
  async getComments() {
104
94
  const { prid, owner, repo, cli, request, prStr } = this;
105
95
  const vars = { prid, owner, repo };
@@ -40,7 +40,7 @@ export default class ReleasePreparation extends Session {
40
40
  const { cli } = this;
41
41
 
42
42
  cli.warn(`PR#${pr.number} - ${pr.title} is not 'MERGEABLE'.
43
- So, it will be skipped. Status: ${pr.mergeable}`);
43
+ Status: ${pr.mergeable}`);
44
44
  }
45
45
 
46
46
  async getOpenPRs(filterLabels) {
@@ -66,7 +66,6 @@ export default class ReleasePreparation extends Session {
66
66
  for (const pr of prs) {
67
67
  if (pr.mergeable !== 'MERGEABLE') {
68
68
  this.warnForNonMergeablePR(pr);
69
- continue;
70
69
  }
71
70
  const cp = new CherryPick(pr.number, this.dir, cli, {
72
71
  owner: this.owner,
@@ -93,9 +92,9 @@ export default class ReleasePreparation extends Session {
93
92
  } = this;
94
93
 
95
94
  // Create new proposal branch.
96
- cli.startSpinner(`Creating new proposal branch for ${newVersion}`);
95
+ cli.startSpinner(`Switching to proposal branch for ${newVersion}`);
97
96
  const proposalBranch = await this.createProposalBranch(releaseBranch);
98
- cli.stopSpinner(`Created new proposal branch for ${newVersion}`);
97
+ cli.stopSpinner(`Switched to proposal branch for ${newVersion}`);
99
98
 
100
99
  const success = await this.cherryPickSecurityPRs(filterLabels);
101
100
  if (!success) {
@@ -201,9 +200,9 @@ export default class ReleasePreparation extends Session {
201
200
  }
202
201
 
203
202
  // Create new proposal branch.
204
- cli.startSpinner(`Creating new proposal branch for ${newVersion}`);
203
+ cli.startSpinner(`Switching to proposal branch for ${newVersion}`);
205
204
  await this.createProposalBranch();
206
- cli.stopSpinner(`Created new proposal branch for ${newVersion}`);
205
+ cli.stopSpinner(`Switched to proposal branch for ${newVersion}`);
207
206
 
208
207
  if (this.isLTSTransition) {
209
208
  // For releases transitioning into LTS, fetch the new code name.
@@ -482,11 +481,14 @@ export default class ReleasePreparation extends Session {
482
481
  const data = await fs.readFile(majorChangelogPath, 'utf8');
483
482
  const arr = data.split('\n');
484
483
  const allCommits = this.getChangelog();
485
- const notableChanges = await this.getBranchDiff({ onlyNotableChanges: true });
484
+ const notableChanges = await this.getBranchDiff({
485
+ onlyNotableChanges: true,
486
+ format: isSecurityRelease ? 'messageonly' : 'markdown',
487
+ });
486
488
  let releaseHeader = `## ${date}, Version ${newVersion}` +
487
489
  ` ${releaseInfo}, @${username}\n`;
488
490
  if (isSecurityRelease) {
489
- releaseHeader += '\nThis is a security release.';
491
+ releaseHeader += '\nThis is a security release.\n';
490
492
  }
491
493
 
492
494
  const topHeader =
@@ -541,7 +543,7 @@ export default class ReleasePreparation extends Session {
541
543
 
542
544
  await runAsync('git', [
543
545
  'checkout',
544
- '-b',
546
+ '-B',
545
547
  proposalBranch,
546
548
  base
547
549
  ]);
@@ -620,7 +622,7 @@ export default class ReleasePreparation extends Session {
620
622
 
621
623
  const notableChanges = await this.getBranchDiff({
622
624
  onlyNotableChanges: true,
623
- format: 'plaintext'
625
+ format: isSecurityRelease ? 'messageonly' : 'plaintext'
624
626
  });
625
627
  messageBody.push('Notable changes:\n\n');
626
628
  if (isLTSTransition) {
@@ -52,24 +52,27 @@ export default class PrepareSecurityRelease extends SecurityRelease {
52
52
  await this.closeAndRequestDisclosure(vulnerabilityJSON.reports);
53
53
 
54
54
  this.cli.info('Closing pull requests');
55
- // For now, close the ones with vN.x label
56
- await this.closePRWithLabel(this.getAffectedVersions(vulnerabilityJSON));
55
+ // For now, close the ones with Security Release label
56
+ await this.closePRWithLabel('Security Release');
57
57
 
58
- const updateFolder = this.cli.prompt(
59
- // eslint-disable-next-line max-len
60
- `Would you like to update the next-security-release folder to ${vulnerabilityJSON.releaseDate}?`,
58
+ const updateFolder = await this.cli.prompt(
59
+ `Would you like to update the next-security-release folder to ${
60
+ vulnerabilityJSON.releaseDate}?`,
61
61
  { defaultAnswer: true });
62
62
  if (updateFolder) {
63
- const newFolder = this.updateReleaseFolder(vulnerabilityJSON.releaseDate);
63
+ this.updateReleaseFolder(
64
+ vulnerabilityJSON.releaseDate.replaceAll('/', '-')
65
+ );
66
+ const securityReleaseFolder = path.join(process.cwd(), 'security-release');
64
67
  commitAndPushVulnerabilitiesJSON(
65
- newFolder,
68
+ securityReleaseFolder,
66
69
  'chore: change next-security-release folder',
67
70
  { cli: this.cli, repository: this.repository }
68
71
  );
69
72
  }
70
73
  this.cli.info(`Merge pull request with:
71
74
  - git checkout main
72
- - git merge --squash ${NEXT_SECURITY_RELEASE_BRANCH}
75
+ - git merge ${NEXT_SECURITY_RELEASE_BRANCH} --no-ff -m "chore: add latest security release"
73
76
  - git push origin main`);
74
77
  this.cli.ok('Done!');
75
78
  }
@@ -306,16 +309,17 @@ export default class PrepareSecurityRelease extends SecurityRelease {
306
309
  labels = [labels];
307
310
  }
308
311
 
309
- const url = 'https://github.com/nodejs-private/node-private/pulls';
312
+ const url = 'https://github.com/nodejs-private/node-private/pull';
310
313
  this.cli.startSpinner('Closing GitHub Pull Requests...');
311
314
  // At this point, GitHub does not provide filters through their REST API
312
- const prs = this.req.getPullRequest(url);
315
+ const prs = await this.req.getPullRequest(url);
313
316
  for (const pr of prs) {
314
- if (pr.labels.some((l) => labels.includes(l))) {
315
- this.cli.updateSpinner(`Closing Pull Request: ${pr.id}`);
316
- await this.req.closePullRequest(pr.id);
317
+ if (pr.labels.some((l) => labels.includes(l.name))) {
318
+ this.cli.updateSpinner(`Closing Pull Request: ${pr.number}`);
319
+ await this.req.closePullRequest(pr.number,
320
+ { owner: 'nodejs-private', repo: 'node-private' });
317
321
  }
318
322
  }
319
- this.cli.startSpinner('Closed GitHub Pull Requests.');
323
+ this.cli.stopSpinner('Closed GitHub Pull Requests.');
320
324
  }
321
325
  }
@@ -19,6 +19,10 @@ export default class ReleasePromotion extends Session {
19
19
  constructor(argv, req, cli, dir) {
20
20
  super(cli, dir, argv.prid);
21
21
  this.req = req;
22
+ if (argv.security) {
23
+ this.config.owner = 'nodejs-private';
24
+ this.config.repo = 'node-private';
25
+ }
22
26
  this.dryRun = !argv.run;
23
27
  this.isLTS = false;
24
28
  this.ltsCodename = '';
@@ -226,20 +230,28 @@ export default class ReleasePromotion extends Session {
226
230
 
227
231
  async verifyTagSignature() {
228
232
  const { cli, version } = this;
229
- const [needle, haystack] = await Promise.all([forceRunAsync(
233
+ const verifyTagPattern = /gpg:[^\n]+\ngpg:\s+using RSA key ([^\n]+)\ngpg:\s+issuer "([^"]+)"\ngpg:\s+Good signature from "([^<]+) <\2>"/;
234
+ const [verifyTagOutput, haystack] = await Promise.all([forceRunAsync(
230
235
  'git', ['--no-pager',
231
- 'log', '-1',
232
- `refs/tags/v${version}`,
233
- '--format=* **%an** <<%ae>>\n `%GF`'
234
- ], { captureStdout: true }), fs.readFile('README.md')]);
235
- if (haystack.includes(needle)) {
236
- return;
236
+ 'verify-tag',
237
+ `v${version}`
238
+ ], { ignoreFailure: false, captureStderr: true }), fs.readFile('README.md')]);
239
+ const match = verifyTagPattern.exec(verifyTagOutput);
240
+ if (match == null) {
241
+ cli.warn('git was not able to verify the tag:');
242
+ cli.info(verifyTagOutput);
243
+ } else {
244
+ const [, keyID, email, name] = match;
245
+ const needle = `* **${name}** <<${email}>>\n ${'`'}${keyID}${'`'}`;
246
+ if (haystack.includes(needle)) {
247
+ return;
248
+ }
249
+ cli.warn('Tag was signed with an undocumented identity/key pair!');
250
+ cli.info('Expected to find the following entry in the README:');
251
+ cli.info(needle);
252
+ cli.info('If you are using a subkey, it might be OK.');
237
253
  }
238
- cli.warn('Tag was signed with an undocumented identity/key pair!');
239
- cli.info('Expected to find the following entry in the README:');
240
- cli.info(needle);
241
- cli.info('If you are using a subkey, it might be OK.');
242
- cli.info(`Otherwise consider removing the tag (git tag -d v${version
254
+ cli.info(`If that doesn't sound right, consider removing the tag (git tag -d v${version
243
255
  }), check your local config, and start the process over.`);
244
256
  if (!await cli.prompt('Do you want to proceed anyway?', { defaultAnswer: false })) {
245
257
  throw new Error('Aborted');
@@ -383,7 +395,6 @@ export default class ReleasePromotion extends Session {
383
395
  { cause: err }
384
396
  );
385
397
  }
386
- await forceRunAsync('git', ['tag', '--verify', `v${version}`], { ignoreFailure: false });
387
398
  this.cli.info('Using the existing tag');
388
399
  }
389
400
  }
@@ -391,7 +402,7 @@ export default class ReleasePromotion extends Session {
391
402
  // Set up the branch so that nightly builds are produced with the next
392
403
  // version number and a pre-release tag.
393
404
  async setupForNextRelease() {
394
- const { versionComponents, prid } = this;
405
+ const { versionComponents, prid, owner, repo } = this;
395
406
 
396
407
  // Update node_version.h for next patch release.
397
408
  const filePath = path.resolve('src', 'node_version.h');
@@ -422,7 +433,7 @@ export default class ReleasePromotion extends Session {
422
433
  '-m',
423
434
  `Working on ${workingOnVersion}`,
424
435
  '-m',
425
- `PR-URL: https://github.com/nodejs/node/pull/${prid}`
436
+ `PR-URL: https://github.com/${owner}/${repo}/pull/${prid}`
426
437
  ], { ignoreFailure: false });
427
438
  const workingOnNewReleaseCommit = await forceRunAsync('git', ['rev-parse', 'HEAD'],
428
439
  { ignoreFailure: false, captureStdout: true });
@@ -23,9 +23,6 @@ query PR($prid: Int!, $owner: String!, $repo: String!) {
23
23
  path
24
24
  }
25
25
  },
26
- timelineItems(itemTypes: [HEAD_REF_FORCE_PUSHED_EVENT, PULL_REQUEST_COMMIT]) {
27
- updatedAt
28
- },
29
26
  title,
30
27
  baseRefName,
31
28
  headRefName,
@@ -21,12 +21,10 @@ export function getStartLTSBlurb({ date, ltsCodename, versionComponents }) {
21
21
  const eol = eolDate.toLocaleString('en-US', dateFormat);
22
22
  const { major } = versionComponents;
23
23
  return [
24
- /* eslint-disable max-len */
25
24
  `This release marks the transition of Node.js ${major}.x into Long Term Support (LTS)`,
26
25
  `with the codename '${ltsCodename}'. The ${major}.x release line now moves into "Active LTS"`,
27
26
  `and will remain so until ${mainStart}. After that time, it will move into`,
28
27
  `"Maintenance" until end of life in ${eol}.`
29
- /* eslint-enable */
30
28
  ].join('\n');
31
29
  }
32
30
 
package/lib/request.js CHANGED
@@ -109,14 +109,15 @@ export default class Request {
109
109
  return this.json(url, options);
110
110
  }
111
111
 
112
- async closePullRequest({ owner, repo }) {
113
- const url = `https://api.github.com/repos/${owner}/${repo}/pulls`;
112
+ async closePullRequest(id, { owner, repo }) {
113
+ const url = `https://api.github.com/repos/${owner}/${repo}/pulls/${id}`;
114
114
  const options = {
115
115
  method: 'POST',
116
116
  headers: {
117
117
  Authorization: `Basic ${this.credentials.github}`,
118
118
  'User-Agent': 'node-core-utils',
119
- Accept: 'application/vnd.github+json'
119
+ Accept: 'application/vnd.github+json',
120
+ 'Content-Type': 'application/json'
120
121
  },
121
122
  body: JSON.stringify({
122
123
  state: 'closed'
@@ -230,7 +231,8 @@ export default class Request {
230
231
  headers: {
231
232
  Authorization: `Basic ${this.credentials.h1}`,
232
233
  'User-Agent': 'node-core-utils',
233
- Accept: 'application/json'
234
+ Accept: 'application/json',
235
+ 'Content-Type': 'application/json'
234
236
  },
235
237
  body: JSON.stringify({
236
238
  data: {
@@ -252,11 +254,13 @@ export default class Request {
252
254
  headers: {
253
255
  Authorization: `Basic ${this.credentials.h1}`,
254
256
  'User-Agent': 'node-core-utils',
255
- Accept: 'application/json'
257
+ Accept: 'application/json',
258
+ 'Content-Type': 'application/json'
256
259
  },
257
260
  body: JSON.stringify({
258
261
  data: {
259
262
  attributes: {
263
+ message: 'Requesting disclosure',
260
264
  // default to limited version
261
265
  substate: 'no-content'
262
266
  }
package/lib/run.js CHANGED
@@ -12,14 +12,19 @@ function runAsyncBase(cmd, args, {
12
12
  ignoreFailure = true,
13
13
  spawnArgs,
14
14
  input,
15
+ captureStderr = false,
15
16
  captureStdout = false
16
17
  } = {}) {
17
18
  if (cmd instanceof URL) {
18
19
  cmd = fileURLToPath(cmd);
19
20
  }
20
21
  let stdio = 'inherit';
21
- if (captureStdout || input != null) {
22
- stdio = [input == null ? 'inherit' : 'pipe', captureStdout ? 'pipe' : 'inherit', 'inherit'];
22
+ if (captureStderr || captureStdout || input != null) {
23
+ stdio = [
24
+ input == null ? 'inherit' : 'pipe',
25
+ captureStdout ? 'pipe' : 'inherit',
26
+ captureStderr ? 'pipe' : 'inherit'
27
+ ];
23
28
  }
24
29
  return new Promise((resolve, reject) => {
25
30
  const opt = Object.assign({
@@ -30,6 +35,12 @@ function runAsyncBase(cmd, args, {
30
35
  debuglog('[Spawn]', `${cmd} ${(args || []).join(' ')}`, opt);
31
36
  }
32
37
  const child = spawn(cmd, args, opt);
38
+ let stderr;
39
+ if (!captureStdout && captureStderr) {
40
+ stderr = '';
41
+ child.stderr.setEncoding('utf8');
42
+ child.stderr.on('data', (chunk) => { stderr += chunk; });
43
+ }
33
44
  let stdout;
34
45
  if (captureStdout) {
35
46
  stdout = '';
@@ -51,7 +62,7 @@ function runAsyncBase(cmd, args, {
51
62
  stdout = stdout.split(/\r?\n/g);
52
63
  if (stdout[stdout.length - 1] === '') stdout.pop();
53
64
  }
54
- return resolve(stdout);
65
+ return resolve(stdout ?? stderr);
55
66
  });
56
67
  if (input != null) child.stdin.end(input);
57
68
  });
@@ -236,7 +236,7 @@ export class SecurityRelease {
236
236
  updateReleaseFolder(releaseDate) {
237
237
  const folder = path.join(process.cwd(),
238
238
  NEXT_SECURITY_RELEASE_FOLDER);
239
- const newFolder = path.join(process.cwd(), releaseDate);
239
+ const newFolder = path.join(process.cwd(), 'security-release', releaseDate);
240
240
  fs.renameSync(folder, newFolder);
241
241
  return newFolder;
242
242
  }
package/lib/team_info.js CHANGED
@@ -67,7 +67,6 @@ TeamInfo.update = async function(cli, request, content) {
67
67
 
68
68
  const blocks = new Map();
69
69
  let m;
70
- // eslint-disable-next-line no-cond-assign
71
70
  while ((m = RE.exec(content))) {
72
71
  const [, org, team] = m;
73
72
  const mapKey = key(org, team);
@@ -127,5 +127,11 @@ export const v8Deps = [
127
127
  replace: highwayIgnore
128
128
  },
129
129
  since: 134
130
+ },
131
+ {
132
+ name: 'simdutf',
133
+ repo: 'third_party/simdutf',
134
+ gitignore: '!/third_party/simdutf',
135
+ since: 134
130
136
  }
131
137
  ];
@@ -119,7 +119,6 @@ function updateV8Deps() {
119
119
  path: v8Dep.repo
120
120
  })), newV8Version);
121
121
  if (deps.length === 0) return;
122
- /* eslint-disable no-await-in-loop */
123
122
  for (const dep of deps) {
124
123
  if (dep.gitignore) {
125
124
  if (typeof dep.gitignore === 'string') {
@@ -132,7 +131,6 @@ function updateV8Deps() {
132
131
  const thePath = path.join(ctx.nodeDir, 'deps/v8', dep.path);
133
132
  await fetchFromGit(thePath, repo, commit);
134
133
  }
135
- /* eslint-enable */
136
134
  }
137
135
  };
138
136
  }
@@ -10,6 +10,7 @@ import {
10
10
  getEditor, isGhAvailable
11
11
  } from './utils.js';
12
12
 
13
+ // eslint-disable-next-line import/no-unresolved
13
14
  import voteUsingGit from '@node-core/caritat/voteUsingGit';
14
15
  import * as yaml from 'js-yaml';
15
16
 
@@ -97,7 +98,7 @@ export default class VotingSession extends Session {
97
98
  cp.stdin.end(share);
98
99
  const [code] = await Promise.race([
99
100
  once(cp, 'exit'),
100
- once(cp, 'error').then((er) => Promise.reject(er))
101
+ once(cp, 'error').then((er) => { throw er; })
101
102
  ]);
102
103
  if (code !== 0) throw new Error('failed', { cause: code });
103
104
  return Buffer.concat(await stdout);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-core/utils",
3
- "version": "5.10.0",
3
+ "version": "5.12.0",
4
4
  "description": "Utilities for Node.js core collaborators",
5
5
  "type": "module",
6
6
  "engines": {
@@ -40,7 +40,7 @@
40
40
  "@pkgjs/nv": "^0.2.2",
41
41
  "branch-diff": "^3.1.1",
42
42
  "chalk": "^5.4.1",
43
- "changelog-maker": "^4.3.1",
43
+ "changelog-maker": "^4.3.2",
44
44
  "cheerio": "^1.0.0",
45
45
  "clipboardy": "^4.0.0",
46
46
  "core-validate-commit": "^4.1.0",
@@ -53,18 +53,21 @@
53
53
  "log-symbols": "^7.0.0",
54
54
  "ora": "^8.1.1",
55
55
  "replace-in-file": "^8.3.0",
56
- "undici": "^7.2.2",
56
+ "semver": "^7.6.3",
57
+ "undici": "^7.3.0",
57
58
  "which": "^5.0.0",
58
59
  "yargs": "^17.7.2"
59
60
  },
60
61
  "devDependencies": {
62
+ "@eslint/js": "^9.19.0",
61
63
  "@reporters/github": "^1.7.2",
62
64
  "c8": "^10.1.3",
63
- "eslint": "^8.57.1",
64
- "eslint-config-standard": "^17.1.0",
65
+ "eslint": "^9.19.0",
65
66
  "eslint-plugin-import": "^2.31.0",
66
- "eslint-plugin-n": "^16.6.2",
67
- "eslint-plugin-promise": "^6.6.0",
67
+ "eslint-plugin-n": "^17.15.1",
68
+ "eslint-plugin-promise": "^7.2.1",
69
+ "globals": "^15.14.0",
70
+ "neostandard": "^0.12.0",
68
71
  "sinon": "^19.0.2"
69
72
  }
70
73
  }
@@ -1,19 +0,0 @@
1
- query PRLabeledEvents($prid: Int!, $owner: String!, $repo: String!, $after: String) {
2
- repository(owner: $owner, name: $repo) {
3
- pullRequest(number: $prid) {
4
- timelineItems(itemTypes: LABELED_EVENT, after: $after, last: 100) {
5
- nodes {
6
- ... on LabeledEvent {
7
- actor {
8
- login
9
- }
10
- label {
11
- name
12
- }
13
- createdAt
14
- }
15
- }
16
- }
17
- }
18
- }
19
- }