@node-core/utils 5.7.0 → 5.8.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.
@@ -29,8 +29,8 @@ const securityOptions = {
29
29
  type: 'string'
30
30
  },
31
31
  'pre-release': {
32
- describe: 'Create the pre-release announcement',
33
- type: 'boolean'
32
+ describe: 'Create the pre-release announcement to the given nodejs.org folder',
33
+ type: 'string'
34
34
  },
35
35
  'notify-pre-release': {
36
36
  describe: 'Notify the community about the security release',
@@ -41,8 +41,8 @@ const securityOptions = {
41
41
  type: 'boolean'
42
42
  },
43
43
  'post-release': {
44
- describe: 'Create the post-release announcement',
45
- type: 'boolean'
44
+ describe: 'Create the post-release announcement to the given nodejs.org folder',
45
+ type: 'string'
46
46
  },
47
47
  cleanup: {
48
48
  describe: 'cleanup the security release.',
@@ -73,7 +73,7 @@ export function builder(yargs) {
73
73
  'git node security --remove-report=H1-ID',
74
74
  'Removes the Hackerone report based on ID provided from vulnerabilities.json'
75
75
  ).example(
76
- 'git node security --pre-release',
76
+ 'git node security --pre-release="../nodejs.org/"',
77
77
  'Create the pre-release announcement on the Nodejs.org repo'
78
78
  ).example(
79
79
  'git node security --notify-pre-release',
@@ -83,7 +83,7 @@ export function builder(yargs) {
83
83
  'Request CVEs for a security release of Node.js based on' +
84
84
  ' the next-security-release/vulnerabilities.json'
85
85
  ).example(
86
- 'git node security --post-release',
86
+ 'git node security --post-release="../nodejs.org/"',
87
87
  'Create the post-release announcement on the Nodejs.org repo'
88
88
  ).example(
89
89
  'git node security --cleanup',
@@ -149,11 +149,12 @@ async function updateReleaseDate(argv) {
149
149
  return update.updateReleaseDate(releaseDate);
150
150
  }
151
151
 
152
- async function createPreRelease() {
152
+ async function createPreRelease(argv) {
153
+ const nodejsOrgFolder = argv['pre-release'];
153
154
  const logStream = process.stdout.isTTY ? process.stdout : process.stderr;
154
155
  const cli = new CLI(logStream);
155
156
  const preRelease = new SecurityBlog(cli);
156
- return preRelease.createPreRelease();
157
+ return preRelease.createPreRelease(nodejsOrgFolder);
157
158
  }
158
159
 
159
160
  async function requestCVEs() {
@@ -163,11 +164,12 @@ async function requestCVEs() {
163
164
  return hackerOneCve.requestCVEs();
164
165
  }
165
166
 
166
- async function createPostRelease() {
167
+ async function createPostRelease(argv) {
168
+ const nodejsOrgFolder = argv['post-release'];
167
169
  const logStream = process.stdout.isTTY ? process.stdout : process.stderr;
168
170
  const cli = new CLI(logStream);
169
171
  const blog = new SecurityBlog(cli);
170
- return blog.createPostRelease();
172
+ return blog.createPostRelease(nodejsOrgFolder);
171
173
  }
172
174
 
173
175
  async function startSecurityRelease() {
@@ -367,6 +367,16 @@ export default class ReleasePreparation extends Session {
367
367
  runSync('git', ['fetch', this.upstream, 'tag', '-n', tagName]);
368
368
  this.cli.stopSpinner(`Tag fetched: ${tagName}`);
369
369
  }
370
+ try {
371
+ if (runSync('git', ['describe', '--abbrev=0', '--tags']).trim() !== tagName) {
372
+ this.cli.warn(`${tagName} is not the closest tag`);
373
+ }
374
+ } catch {
375
+ this.cli.startSpinner(`${tagName} is unreachable from the current HEAD`);
376
+ runSync('git', ['fetch', '--shallow-exclude', tagName, this.upstream, this.branch]);
377
+ runSync('git', ['fetch', '--deepen=1', this.upstream, this.branch]);
378
+ this.cli.stopSpinner('Local clone unshallowed');
379
+ }
370
380
  return tagName;
371
381
  }
372
382
 
@@ -11,12 +11,10 @@ import {
11
11
  import auth from './auth.js';
12
12
  import Request from './request.js';
13
13
 
14
- const kChanged = Symbol('changed');
15
-
16
14
  export default class SecurityBlog extends SecurityRelease {
17
15
  req;
18
16
 
19
- async createPreRelease() {
17
+ async createPreRelease(nodejsOrgFolder) {
20
18
  const { cli } = this;
21
19
 
22
20
  // checkout on security release branch
@@ -45,14 +43,32 @@ export default class SecurityBlog extends SecurityRelease {
45
43
  };
46
44
  const month = releaseDate.toLocaleString('en-US', { month: 'long' }).toLowerCase();
47
45
  const year = releaseDate.getFullYear();
48
- const fileName = `${month}-${year}-security-releases.md`;
46
+ const fileName = `${month}-${year}-security-releases`;
47
+ const fileNameExt = fileName + '.md';
49
48
  const preRelease = this.buildPreRelease(template, data);
50
- const file = path.join(process.cwd(), fileName);
49
+
50
+ const pathToBlogPosts = 'apps/site/pages/en/blog/release';
51
+ const pathToBannerJson = 'apps/site/site.json';
52
+
53
+ const file = path.resolve(process.cwd(), nodejsOrgFolder, pathToBlogPosts, fileNameExt);
54
+ const site = path.resolve(process.cwd(), nodejsOrgFolder, pathToBannerJson);
55
+
56
+ const endDate = new Date(data.annoucementDate);
57
+ endDate.setDate(endDate.getDate() + 7);
58
+
59
+ this.updateWebsiteBanner(site, {
60
+ startDate: data.annoucementDate,
61
+ endDate: endDate.toISOString(),
62
+ text: `New security releases to be made available ${data.releaseDate}`,
63
+ link: `https://nodejs.org/en/blog/vulnerability/${fileName}`,
64
+ type: 'warning'
65
+ });
66
+
51
67
  fs.writeFileSync(file, preRelease);
52
- cli.ok(`Pre-release announcement file created at ${file}`);
68
+ cli.ok(`Announcement file created and banner has been updated. Folder: ${nodejsOrgFolder}`);
53
69
  }
54
70
 
55
- async createPostRelease() {
71
+ async createPostRelease(nodejsOrgFolder) {
56
72
  const { cli } = this;
57
73
  const credentials = await auth({
58
74
  github: true,
@@ -65,7 +81,7 @@ export default class SecurityBlog extends SecurityRelease {
65
81
  checkoutOnSecurityReleaseBranch(cli, this.repository);
66
82
 
67
83
  // read vulnerabilities JSON file
68
- const content = this.readVulnerabilitiesJSON(cli);
84
+ const content = this.readVulnerabilitiesJSON();
69
85
  if (!content.releaseDate) {
70
86
  cli.error('Release date is not set in vulnerabilities.json,' +
71
87
  ' run `git node security --update-date=YYYY/MM/DD` to set the release date.');
@@ -76,47 +92,54 @@ export default class SecurityBlog extends SecurityRelease {
76
92
  const releaseDate = new Date(content.releaseDate);
77
93
  const template = this.getSecurityPostReleaseTemplate();
78
94
  const data = {
79
- // TODO: read from pre-sec-release
80
- annoucementDate: await this.getAnnouncementDate(cli),
95
+ annoucementDate: releaseDate.toISOString(),
81
96
  releaseDate: this.formatReleaseDate(releaseDate),
82
97
  affectedVersions: this.getAffectedVersions(content),
83
98
  vulnerabilities: this.getVulnerabilities(content),
84
99
  slug: this.getSlug(releaseDate),
85
- author: await this.promptAuthor(cli),
100
+ author: 'The Node.js Project',
86
101
  dependencyUpdates: content.dependencies
87
102
  };
88
- const postReleaseContent = await this.buildPostRelease(template, data, content);
89
103
 
90
- const pathPreRelease = await this.promptExistingPreRelease(cli);
91
- // read the existing pre-release announcement
92
- let preReleaseContent = fs.readFileSync(pathPreRelease, 'utf-8');
104
+ const pathToBlogPosts = path.resolve(nodejsOrgFolder, 'apps/site/pages/en/blog/release');
105
+ const pathToBannerJson = path.resolve(nodejsOrgFolder, 'apps/site/site.json');
106
+
107
+ const preReleasePath = path.resolve(pathToBlogPosts, data.slug + '.md');
108
+ let preReleaseContent = this.findExistingPreRelease(preReleasePath);
109
+ if (!preReleaseContent) {
110
+ cli.error(`Existing pre-release not found! Path: ${preReleasePath} `);
111
+ process.exit(1);
112
+ }
113
+
114
+ const postReleaseContent = await this.buildPostRelease(template, data, content);
93
115
  // cut the part before summary
94
116
  const preSummary = preReleaseContent.indexOf('# Summary');
95
117
  if (preSummary !== -1) {
96
118
  preReleaseContent = preReleaseContent.substring(preSummary);
97
119
  }
98
-
99
120
  const updatedContent = postReleaseContent + preReleaseContent;
100
121
 
101
- fs.writeFileSync(pathPreRelease, updatedContent);
102
- cli.ok(`Post-release announcement file updated at ${pathPreRelease}`);
122
+ const endDate = new Date(data.annoucementDate);
123
+ endDate.setDate(endDate.getDate() + 7);
124
+ const month = releaseDate.toLocaleString('en-US', { month: 'long' });
125
+ const capitalizedMonth = month[0].toUpperCase() + month.slice(1);
103
126
 
104
- // if the vulnerabilities.json has been changed, update the file
105
- if (!content[kChanged]) return;
106
- this.updateVulnerabilitiesJSON(content);
107
- }
127
+ this.updateWebsiteBanner(pathToBannerJson, {
128
+ startDate: releaseDate,
129
+ endDate,
130
+ text: `${capitalizedMonth} Security Release is available`
131
+ });
108
132
 
109
- async promptExistingPreRelease(cli) {
110
- const pathPreRelease = await cli.prompt(
111
- 'Please provide the path of the existing pre-release announcement:', {
112
- questionType: 'input',
113
- defaultAnswer: ''
114
- });
133
+ fs.writeFileSync(preReleasePath, updatedContent);
134
+ cli.ok(`Announcement file and banner has been updated. Folder: ${nodejsOrgFolder}`);
135
+ }
115
136
 
116
- if (!pathPreRelease || !fs.existsSync(path.resolve(pathPreRelease))) {
117
- return this.promptExistingPreRelease(cli);
137
+ findExistingPreRelease(filepath) {
138
+ if (!fs.existsSync(filepath)) {
139
+ return null;
118
140
  }
119
- return pathPreRelease;
141
+
142
+ return fs.readFileSync(filepath, 'utf-8');
120
143
  }
121
144
 
122
145
  promptAuthor(cli) {
@@ -127,6 +150,20 @@ export default class SecurityBlog extends SecurityRelease {
127
150
  });
128
151
  }
129
152
 
153
+ updateWebsiteBanner(siteJsonPath, content) {
154
+ const siteJson = JSON.parse(fs.readFileSync(siteJsonPath));
155
+
156
+ const currentValue = siteJson.websiteBanners.index;
157
+ siteJson.websiteBanners.index = {
158
+ startDate: content.startDate ?? currentValue.startDate,
159
+ endDate: content.endDate ?? currentValue.endDate,
160
+ text: content.text ?? currentValue.text,
161
+ link: content.link ?? currentValue.link,
162
+ type: content.type ?? currentValue.type
163
+ };
164
+ fs.writeFileSync(siteJsonPath, JSON.stringify(siteJson, null, 2));
165
+ }
166
+
130
167
  formatReleaseDate(releaseDate) {
131
168
  const options = {
132
169
  weekday: 'long',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-core/utils",
3
- "version": "5.7.0",
3
+ "version": "5.8.0",
4
4
  "description": "Utilities for Node.js core collaborators",
5
5
  "type": "module",
6
6
  "engines": {