@node-core/utils 5.16.2 → 6.1.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/README.md +34 -26
- package/bin/ncu-config.js +24 -5
- package/components/git/release.js +8 -2
- package/components/git/v8.js +22 -2
- package/lib/auth.js +63 -40
- package/lib/cherry_pick.js +12 -2
- package/lib/config.js +76 -12
- package/lib/landing_session.js +35 -8
- package/lib/pr_checker.js +18 -18
- package/lib/prepare_release.js +52 -3
- package/lib/promote_release.js +39 -24
- package/lib/session.js +19 -7
- package/lib/update-v8/deps.js +88 -0
- package/lib/update-v8/index.js +9 -0
- package/lib/update-v8/majorUpdate.js +1 -68
- package/lib/update-v8/util.js +7 -2
- package/lib/update_security_release.js +14 -4
- package/lib/verbosity.js +3 -0
- package/lib/voting_session.js +0 -1
- package/npm-shrinkwrap.json +422 -321
- package/package.json +7 -7
package/lib/prepare_release.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { promises as fs, existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
|
|
4
4
|
import semver from 'semver';
|
|
5
5
|
import { replaceInFile } from 'replace-in-file';
|
|
@@ -21,7 +21,11 @@ const isWindows = process.platform === 'win32';
|
|
|
21
21
|
export default class ReleasePreparation extends Session {
|
|
22
22
|
constructor(argv, cli, dir) {
|
|
23
23
|
super(cli, dir);
|
|
24
|
-
|
|
24
|
+
// argv.security can be either:
|
|
25
|
+
// - true (boolean) if --security was used without parameter
|
|
26
|
+
// - string if --security=path was used
|
|
27
|
+
this.isSecurityRelease = !!argv.security;
|
|
28
|
+
this.securityReleaseRepo = typeof argv.security === 'string' ? argv.security : null;
|
|
25
29
|
this.isLTS = false;
|
|
26
30
|
this.isLTSTransition = argv.startLTS;
|
|
27
31
|
this.runBranchDiff = !argv.skipBranchDiff;
|
|
@@ -63,17 +67,62 @@ export default class ReleasePreparation extends Session {
|
|
|
63
67
|
return false;
|
|
64
68
|
}
|
|
65
69
|
|
|
70
|
+
const vulnCveMap = new Map();
|
|
71
|
+
if (this.isSecurityRelease && this.securityReleaseRepo) {
|
|
72
|
+
const vulnPath = path.join(
|
|
73
|
+
this.securityReleaseRepo,
|
|
74
|
+
'security-release',
|
|
75
|
+
'next-security-release',
|
|
76
|
+
'vulnerabilities.json'
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
if (!existsSync(vulnPath)) {
|
|
80
|
+
cli.error(`vulnerabilities.json not found at ${vulnPath}. ` +
|
|
81
|
+
'Skipping CVE auto-population.');
|
|
82
|
+
cli.warn('PRs will require manual CVE-ID entry.');
|
|
83
|
+
} else {
|
|
84
|
+
try {
|
|
85
|
+
cli.startSpinner(`Reading vulnerabilities.json from ${vulnPath}..`);
|
|
86
|
+
const vulnData = JSON.parse(readFileSync(vulnPath, 'utf-8'));
|
|
87
|
+
cli.stopSpinner(`Done reading vulnerabilities.json from ${vulnPath}`);
|
|
88
|
+
|
|
89
|
+
if (vulnData.reports && Array.isArray(vulnData.reports)) {
|
|
90
|
+
vulnData.reports.forEach(report => {
|
|
91
|
+
if (report.prURL && report.cveIds && report.cveIds.length > 0) {
|
|
92
|
+
vulnCveMap.set(report.prURL, report.cveIds);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
cli.ok(`Loaded ${vulnCveMap.size} CVE mappings from vulnerabilities.json`);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
cli.error(`Failed to read vulnerabilities.json: ${err.message}`);
|
|
99
|
+
cli.warn('Continuing without CVE auto-population.');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
66
104
|
for (const pr of prs) {
|
|
67
105
|
if (pr.mergeable !== 'MERGEABLE') {
|
|
68
106
|
this.warnForNonMergeablePR(pr);
|
|
69
107
|
}
|
|
108
|
+
|
|
109
|
+
// Look up CVE-IDs from vulnerabilities.json
|
|
110
|
+
const prUrl = `https://github.com/${this.owner}/${this.repo}/pull/${pr.number}`;
|
|
111
|
+
const cveIds = vulnCveMap.get(prUrl);
|
|
112
|
+
|
|
113
|
+
if (!cveIds || cveIds.length === 0) {
|
|
114
|
+
cli.warn(`No CVE-IDs found in vulnerabilities.json for ${prUrl}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
70
117
|
const cp = new CherryPick(pr.number, this.dir, cli, {
|
|
71
118
|
owner: this.owner,
|
|
72
119
|
repo: this.repo,
|
|
73
120
|
gpgSign: this.gpgSign,
|
|
74
121
|
upstream: this.isSecurityRelease ? `https://${this.username}:${this.config.token}@github.com/${this.owner}/${this.repo}.git` : this.upstream,
|
|
75
122
|
lint: false,
|
|
76
|
-
includeCVE: true
|
|
123
|
+
includeCVE: true,
|
|
124
|
+
cveIds: cveIds || null,
|
|
125
|
+
vulnCveMap
|
|
77
126
|
});
|
|
78
127
|
const success = await cp.start();
|
|
79
128
|
if (!success) {
|
package/lib/promote_release.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { pipeline } from 'node:stream/promises';
|
|
3
5
|
import semver from 'semver';
|
|
4
6
|
import * as gst from 'git-secure-tag';
|
|
5
7
|
|
|
@@ -196,31 +198,44 @@ export default class ReleasePromotion extends Session {
|
|
|
196
198
|
|
|
197
199
|
async verifyTagSignature(version) {
|
|
198
200
|
const { cli } = this;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
201
|
+
|
|
202
|
+
cli.startSpinner('Downloading active releasers keyring from nodejs/release-keys...');
|
|
203
|
+
const [keyRingStream, [GNUPGHOME, keyRingFd]] = await Promise.all([
|
|
204
|
+
fetch('https://github.com/nodejs/release-keys/raw/HEAD/gpg-only-active-keys/pubring.kbx'),
|
|
205
|
+
fs.mkdtemp(path.join(tmpdir(), 'ncu-'))
|
|
206
|
+
.then(async d => [d, await fs.open(path.join(d, 'pubring.kbx'), 'w')]),
|
|
207
|
+
]);
|
|
208
|
+
if (!keyRingStream.ok) throw new Error('Failed to download keyring', { cause: keyRingStream });
|
|
209
|
+
await pipeline(keyRingStream.body, keyRingFd.createWriteStream());
|
|
210
|
+
cli.stopSpinner('Active releasers keyring stored in temp directory');
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
await forceRunAsync(
|
|
214
|
+
'git', ['--no-pager',
|
|
215
|
+
'verify-tag',
|
|
216
|
+
`v${version}`
|
|
217
|
+
], {
|
|
218
|
+
ignoreFailure: false,
|
|
219
|
+
spawnArgs: { env: { ...process.env, GNUPGHOME } },
|
|
220
|
+
});
|
|
221
|
+
cli.ok('git tag signature verified');
|
|
222
|
+
} catch (cause) {
|
|
223
|
+
cli.error('git was not able to verify the tag');
|
|
224
|
+
cli.warn('This means that either the tag was signed with the wrong key,');
|
|
225
|
+
cli.warn('or that nodejs/release-keys contains outdated information.');
|
|
226
|
+
cli.warn('The release should not proceed.');
|
|
227
|
+
if (!await cli.prompt('Do you want to proceed anyway?', { defaultAnswer: false })) {
|
|
228
|
+
if (await cli.prompt('Do you want to delete the local tag?')) {
|
|
229
|
+
await forceRunAsync('git', ['tag', '-d', `v${version}`]);
|
|
230
|
+
} else {
|
|
231
|
+
cli.info(`Run 'git tag -d v${version}' to remove the local tag.`);
|
|
232
|
+
}
|
|
233
|
+
throw new Error('Aborted', { cause });
|
|
214
234
|
}
|
|
215
|
-
|
|
216
|
-
cli.
|
|
217
|
-
|
|
218
|
-
cli.
|
|
219
|
-
}
|
|
220
|
-
cli.info(`If that doesn't sound right, consider removing the tag (git tag -d v${version
|
|
221
|
-
}), check your local config, and start the process over.`);
|
|
222
|
-
if (!await cli.prompt('Do you want to proceed anyway?', { defaultAnswer: false })) {
|
|
223
|
-
throw new Error('Aborted');
|
|
235
|
+
} finally {
|
|
236
|
+
cli.startSpinner('Cleaning up temp files');
|
|
237
|
+
await fs.rm(GNUPGHOME, { force: true, recursive: true });
|
|
238
|
+
cli.stopSpinner('Temp files removed');
|
|
224
239
|
}
|
|
225
240
|
}
|
|
226
241
|
|
package/lib/session.js
CHANGED
|
@@ -19,7 +19,7 @@ export default class Session {
|
|
|
19
19
|
this.cli = cli;
|
|
20
20
|
this.dir = dir;
|
|
21
21
|
this.prid = prid;
|
|
22
|
-
this.config =
|
|
22
|
+
this.config = getMergedConfig(this.dir, undefined, argv);
|
|
23
23
|
this.gpgSign = argv?.['gpg-sign']
|
|
24
24
|
? (argv['gpg-sign'] === true ? ['-S'] : ['-S', argv['gpg-sign']])
|
|
25
25
|
: [];
|
|
@@ -126,7 +126,12 @@ export default class Session {
|
|
|
126
126
|
writeJson(this.sessionPath, {
|
|
127
127
|
state: STARTED,
|
|
128
128
|
prid: this.prid,
|
|
129
|
-
|
|
129
|
+
// Filter out getters, those are likely encrypted data we don't need on the session.
|
|
130
|
+
config: Object.entries(Object.getOwnPropertyDescriptors(this.config))
|
|
131
|
+
.reduce((pv, [key, desc]) => {
|
|
132
|
+
if (Object.hasOwn(desc, 'value')) pv[key] = desc.value;
|
|
133
|
+
return pv;
|
|
134
|
+
}, { __proto__: null }),
|
|
130
135
|
});
|
|
131
136
|
}
|
|
132
137
|
|
|
@@ -382,12 +387,19 @@ export default class Session {
|
|
|
382
387
|
cli.setExitCode(1);
|
|
383
388
|
}
|
|
384
389
|
if (!upstream) {
|
|
385
|
-
cli.warn('You have not told git-node
|
|
390
|
+
cli.warn('You have not told git-node what remote name you are trying to land commits on.');
|
|
386
391
|
cli.separator();
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
392
|
+
const remoteName = runSync('git', ['remote', '-v'])
|
|
393
|
+
.match(/^(\S+)\s+(?:https:\/\/github\.com\/|git@github\.com:)nodejs\/node\.git \(\S+\)\r?$/m)?.[1];
|
|
394
|
+
cli.info(remoteName
|
|
395
|
+
? `You likely want to run the following:\n\n $ ncu-config set upstream ${remoteName}`
|
|
396
|
+
: 'The expected repository does not seem to appear in your local config.\n' +
|
|
397
|
+
'1. First, add the Node.js core repository as a remote:\n' +
|
|
398
|
+
' $ git remote add upstream https://github.com/nodejs/node.git\n\n' +
|
|
399
|
+
'2. Then, tell git-node to use this remote for syncing:\n' +
|
|
400
|
+
' $ ncu-config set upstream upstream\n\n' +
|
|
401
|
+
'Note: Using "upstream" is recommended, but you can use any remote name.\n' +
|
|
402
|
+
'For security reasons, you need to add the remote manually.');
|
|
391
403
|
cli.separator();
|
|
392
404
|
cli.setExitCode(1);
|
|
393
405
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import { chromiumGit, v8Deps } from './constants.js';
|
|
5
|
+
import { forceRunAsync } from '../run.js';
|
|
6
|
+
import {
|
|
7
|
+
addToGitignore,
|
|
8
|
+
filterForVersion,
|
|
9
|
+
getNodeV8Version,
|
|
10
|
+
removeDirectory,
|
|
11
|
+
replaceGitignore,
|
|
12
|
+
} from './util.js';
|
|
13
|
+
|
|
14
|
+
async function fetchFromGit(cwd, repo, commit) {
|
|
15
|
+
await removeDirectory(cwd);
|
|
16
|
+
await fs.mkdir(cwd, { recursive: true });
|
|
17
|
+
await exec('init');
|
|
18
|
+
await exec('remote', 'add', 'origin', repo);
|
|
19
|
+
await exec('fetch', 'origin', commit);
|
|
20
|
+
await exec('reset', '--hard', 'FETCH_HEAD');
|
|
21
|
+
await removeDirectory(path.join(cwd, '.git'));
|
|
22
|
+
|
|
23
|
+
function exec(...options) {
|
|
24
|
+
return forceRunAsync('git', options, {
|
|
25
|
+
ignoreFailure: false,
|
|
26
|
+
spawnArgs: { cwd, stdio: 'ignore' }
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function readDeps(nodeDir) {
|
|
32
|
+
const depsStr = await fs.readFile(path.join(nodeDir, 'deps/v8/DEPS'), 'utf8');
|
|
33
|
+
const start = depsStr.indexOf('deps = {');
|
|
34
|
+
const end = depsStr.indexOf('\n}', start) + 2;
|
|
35
|
+
const depsDeclaration = depsStr.substring(start, end).replace(/^ *#.*/gm, '');
|
|
36
|
+
const Var = () => chromiumGit; // eslint-disable-line no-unused-vars
|
|
37
|
+
let deps;
|
|
38
|
+
eval(depsDeclaration); // eslint-disable-line no-eval
|
|
39
|
+
return deps;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function lookupDep(depsTable, depName) {
|
|
43
|
+
const dep = depsTable[depName];
|
|
44
|
+
if (!dep) {
|
|
45
|
+
throw new Error(`V8 dep "${depName}" not found in DEPS file`);
|
|
46
|
+
}
|
|
47
|
+
if (typeof dep === 'object') {
|
|
48
|
+
return dep.url.split('@');
|
|
49
|
+
}
|
|
50
|
+
return dep.split('@');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default function updateV8Deps() {
|
|
54
|
+
return {
|
|
55
|
+
title: 'Update V8 DEPS',
|
|
56
|
+
task: async(ctx, task) => {
|
|
57
|
+
const newV8Version = await getNodeV8Version(ctx.nodeDir);
|
|
58
|
+
const repoPrefix = newV8Version.majorMinor >= 86 ? '' : 'v8/';
|
|
59
|
+
const deps = filterForVersion(v8Deps.map((v8Dep) => ({
|
|
60
|
+
...v8Dep,
|
|
61
|
+
repo: `${repoPrefix}${v8Dep.repo}`,
|
|
62
|
+
path: v8Dep.repo
|
|
63
|
+
})), newV8Version);
|
|
64
|
+
if (deps.length === 0) return;
|
|
65
|
+
const depsTable = await readDeps(ctx.nodeDir);
|
|
66
|
+
const subtasks = [];
|
|
67
|
+
for (const dep of deps) {
|
|
68
|
+
// Update .gitignore sequentially to avoid races
|
|
69
|
+
if (dep.gitignore) {
|
|
70
|
+
if (typeof dep.gitignore === 'string') {
|
|
71
|
+
await addToGitignore(ctx.nodeDir, dep.gitignore);
|
|
72
|
+
} else {
|
|
73
|
+
await replaceGitignore(ctx.nodeDir, dep.gitignore);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
subtasks.push({
|
|
77
|
+
title: `Update ${dep.path}`,
|
|
78
|
+
task: async(ctx) => {
|
|
79
|
+
const [repo, commit] = await lookupDep(depsTable, dep.repo);
|
|
80
|
+
const thePath = path.join(ctx.nodeDir, 'deps/v8', dep.path);
|
|
81
|
+
await fetchFromGit(thePath, repo, commit);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return task.newListr(subtasks, { concurrent: ctx.concurrent });
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
};
|
package/lib/update-v8/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import updateVersionNumbers from './updateVersionNumbers.js';
|
|
|
5
5
|
import commitUpdate from './commitUpdate.js';
|
|
6
6
|
import majorUpdate from './majorUpdate.js';
|
|
7
7
|
import minorUpdate from './minorUpdate.js';
|
|
8
|
+
import updateDeps from './deps.js';
|
|
8
9
|
import updateV8Clone from './updateV8Clone.js';
|
|
9
10
|
|
|
10
11
|
export function major(options) {
|
|
@@ -34,6 +35,14 @@ export async function backport(options) {
|
|
|
34
35
|
return tasks.run(options);
|
|
35
36
|
};
|
|
36
37
|
|
|
38
|
+
export async function deps(options) {
|
|
39
|
+
const tasks = new Listr(
|
|
40
|
+
[updateDeps()],
|
|
41
|
+
getOptions(options)
|
|
42
|
+
);
|
|
43
|
+
return tasks.run(options);
|
|
44
|
+
};
|
|
45
|
+
|
|
37
46
|
/**
|
|
38
47
|
* Get the listr2 options.
|
|
39
48
|
* @param {{ verbose?: boolean }} options The original options.
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { promises as fs } from 'node:fs';
|
|
3
2
|
|
|
4
3
|
import { getCurrentV8Version } from './common.js';
|
|
4
|
+
import updateV8Deps from './deps.js';
|
|
5
5
|
import {
|
|
6
|
-
getNodeV8Version,
|
|
7
|
-
filterForVersion,
|
|
8
|
-
addToGitignore,
|
|
9
|
-
replaceGitignore,
|
|
10
6
|
removeDirectory,
|
|
11
7
|
isVersionString
|
|
12
8
|
} from './util.js';
|
|
13
9
|
import applyNodeChanges from './applyNodeChanges.js';
|
|
14
|
-
import { chromiumGit, v8Deps } from './constants.js';
|
|
15
10
|
import { forceRunAsync } from '../run.js';
|
|
16
11
|
|
|
17
12
|
export default function majorUpdate() {
|
|
@@ -106,65 +101,3 @@ function addDepsV8() {
|
|
|
106
101
|
})
|
|
107
102
|
};
|
|
108
103
|
}
|
|
109
|
-
|
|
110
|
-
function updateV8Deps() {
|
|
111
|
-
return {
|
|
112
|
-
title: 'Update V8 DEPS',
|
|
113
|
-
task: async(ctx) => {
|
|
114
|
-
const newV8Version = await getNodeV8Version(ctx.nodeDir);
|
|
115
|
-
const repoPrefix = newV8Version.majorMinor >= 86 ? '' : 'v8/';
|
|
116
|
-
const deps = filterForVersion(v8Deps.map((v8Dep) => ({
|
|
117
|
-
...v8Dep,
|
|
118
|
-
repo: `${repoPrefix}${v8Dep.repo}`,
|
|
119
|
-
path: v8Dep.repo
|
|
120
|
-
})), newV8Version);
|
|
121
|
-
if (deps.length === 0) return;
|
|
122
|
-
for (const dep of deps) {
|
|
123
|
-
if (dep.gitignore) {
|
|
124
|
-
if (typeof dep.gitignore === 'string') {
|
|
125
|
-
await addToGitignore(ctx.nodeDir, dep.gitignore);
|
|
126
|
-
} else {
|
|
127
|
-
await replaceGitignore(ctx.nodeDir, dep.gitignore);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
const [repo, commit] = await readDeps(ctx.nodeDir, dep.repo);
|
|
131
|
-
const thePath = path.join(ctx.nodeDir, 'deps/v8', dep.path);
|
|
132
|
-
await fetchFromGit(thePath, repo, commit);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function readDeps(nodeDir, depName) {
|
|
139
|
-
const depsStr = await fs.readFile(path.join(nodeDir, 'deps/v8/DEPS'), 'utf8');
|
|
140
|
-
const start = depsStr.indexOf('deps = {');
|
|
141
|
-
const end = depsStr.indexOf('\n}', start) + 2;
|
|
142
|
-
const depsDeclaration = depsStr.substring(start, end).replace(/^ *#.*/gm, '');
|
|
143
|
-
const Var = () => chromiumGit; // eslint-disable-line no-unused-vars
|
|
144
|
-
let deps;
|
|
145
|
-
eval(depsDeclaration); // eslint-disable-line no-eval
|
|
146
|
-
const dep = deps[depName];
|
|
147
|
-
if (!dep) {
|
|
148
|
-
throw new Error(`V8 dep "${depName}" not found in DEPS file`);
|
|
149
|
-
}
|
|
150
|
-
if (typeof dep === 'object') {
|
|
151
|
-
return dep.url.split('@');
|
|
152
|
-
}
|
|
153
|
-
return dep.split('@');
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async function fetchFromGit(cwd, repo, commit) {
|
|
157
|
-
await fs.mkdir(cwd, { recursive: true });
|
|
158
|
-
await exec('init');
|
|
159
|
-
await exec('remote', 'add', 'origin', repo);
|
|
160
|
-
await exec('fetch', 'origin', commit);
|
|
161
|
-
await exec('reset', '--hard', 'FETCH_HEAD');
|
|
162
|
-
await removeDirectory(path.join(cwd, '.git'));
|
|
163
|
-
|
|
164
|
-
function exec(...options) {
|
|
165
|
-
return forceRunAsync('git', options, {
|
|
166
|
-
ignoreFailure: false,
|
|
167
|
-
spawnArgs: { cwd, stdio: 'ignore' }
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
package/lib/update-v8/util.js
CHANGED
|
@@ -37,13 +37,18 @@ export function filterForVersion(list, version) {
|
|
|
37
37
|
|
|
38
38
|
export async function addToGitignore(nodeDir, value) {
|
|
39
39
|
const gitignorePath = path.join(nodeDir, 'deps/v8/.gitignore');
|
|
40
|
-
await fs.
|
|
40
|
+
const gitignore = await fs.readFile(gitignorePath, 'utf8');
|
|
41
|
+
if (!gitignore.includes(value)) {
|
|
42
|
+
await fs.appendFile(gitignorePath, `${value}\n`);
|
|
43
|
+
}
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
export async function replaceGitignore(nodeDir, options) {
|
|
44
47
|
const gitignorePath = path.join(nodeDir, 'deps/v8/.gitignore');
|
|
45
48
|
let gitignore = await fs.readFile(gitignorePath, 'utf8');
|
|
46
|
-
|
|
49
|
+
if (!gitignore.includes(options.replace)) {
|
|
50
|
+
gitignore = gitignore.replace(options.match, options.replace);
|
|
51
|
+
}
|
|
47
52
|
await fs.writeFile(gitignorePath, gitignore);
|
|
48
53
|
}
|
|
49
54
|
|
|
@@ -12,6 +12,7 @@ import fs from 'node:fs';
|
|
|
12
12
|
import auth from './auth.js';
|
|
13
13
|
import Request from './request.js';
|
|
14
14
|
import nv from '@pkgjs/nv';
|
|
15
|
+
import semver from 'semver';
|
|
15
16
|
|
|
16
17
|
export default class UpdateSecurityRelease extends SecurityRelease {
|
|
17
18
|
async sync() {
|
|
@@ -268,17 +269,26 @@ Summary: ${summary}\n`,
|
|
|
268
269
|
async calculateVersions(affectedVersions, supportedVersions) {
|
|
269
270
|
const h1AffectedVersions = [];
|
|
270
271
|
const patchedVersions = [];
|
|
272
|
+
let isPatchRelease = true;
|
|
271
273
|
for (const affectedVersion of affectedVersions) {
|
|
272
|
-
const
|
|
273
|
-
const latest = supportedVersions.find((v) => v.major === Number(
|
|
274
|
+
const affectedMajor = affectedVersion.split('.')[0];
|
|
275
|
+
const latest = supportedVersions.find((v) => v.major === Number(affectedMajor)).version;
|
|
274
276
|
const version = await this.cli.prompt(
|
|
275
277
|
`What is the affected version (<=) for release line ${affectedVersion}?`,
|
|
276
278
|
{ questionType: 'input', defaultAnswer: latest });
|
|
277
279
|
|
|
278
|
-
const nextPatchVersion =
|
|
280
|
+
const nextPatchVersion = semver.inc(version, 'patch');
|
|
281
|
+
const nextMinorVersion = semver.inc(version, 'minor');
|
|
279
282
|
const patchedVersion = await this.cli.prompt(
|
|
280
283
|
`What is the patched version (>=) for release line ${affectedVersion}?`,
|
|
281
|
-
{
|
|
284
|
+
{
|
|
285
|
+
questionType: 'input',
|
|
286
|
+
defaultAnswer: isPatchRelease ? nextPatchVersion : nextMinorVersion
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
if (patchedVersion !== nextPatchVersion) {
|
|
290
|
+
isPatchRelease = false; // is a minor release
|
|
291
|
+
}
|
|
282
292
|
|
|
283
293
|
patchedVersions.push(patchedVersion);
|
|
284
294
|
h1AffectedVersions.push({
|
package/lib/verbosity.js
CHANGED