1+ import auth from '../../lib/auth.js' ;
12import CLI from '../../lib/cli.js' ;
23import ReleasePreparation from '../../lib/prepare_release.js' ;
4+ import ReleasePromotion from '../../lib/promote_release.js' ;
5+ import TeamInfo from '../../lib/team_info.js' ;
6+ import Request from '../../lib/request.js' ;
37import { runPromise } from '../../lib/run.js' ;
48
5- export const command = 'release [newVersion |options]' ;
9+ export const command = 'release [prid |options]' ;
610export const describe = 'Manage an in-progress release or start a new one.' ;
711
812const PREPARE = 'prepare' ;
913const PROMOTE = 'promote' ;
14+ const RELEASERS = 'releasers' ;
1015
1116const releaseOptions = {
17+ filterLabel : {
18+ describe : 'Labels separated by "," to filter security PRs' ,
19+ type : 'string'
20+ } ,
21+ 'gpg-sign' : {
22+ describe : 'GPG-sign commits, will be passed to the git process' ,
23+ alias : 'S'
24+ } ,
25+ newVersion : {
26+ describe : 'Version number of the release to be prepared' ,
27+ type : 'string'
28+ } ,
1229 prepare : {
1330 describe : 'Prepare a new release of Node.js' ,
1431 type : 'boolean'
@@ -21,14 +38,16 @@ const releaseOptions = {
2138 describe : 'Default relase date when --prepare is used. It must be YYYY-MM-DD' ,
2239 type : 'string'
2340 } ,
41+ run : {
42+ describe : 'Run steps that involve touching more than the local clone, ' +
43+ 'including `git push` commands. Might not work if a passphrase ' +
44+ 'required to push to the remote clone.' ,
45+ type : 'boolean'
46+ } ,
2447 security : {
2548 describe : 'Demarcate the new security release as a security release' ,
2649 type : 'boolean'
2750 } ,
28- filterLabel : {
29- describe : 'Labels separated by "," to filter security PRs' ,
30- type : 'string'
31- } ,
3251 skipBranchDiff : {
3352 describe : 'Skips the initial branch-diff check when preparing releases' ,
3453 type : 'boolean'
@@ -49,11 +68,16 @@ let yargsInstance;
4968export function builder ( yargs ) {
5069 yargsInstance = yargs ;
5170 return yargs
52- . options ( releaseOptions ) . positional ( 'newVersion' , {
53- describe : 'Version number of the release to be prepared or promoted'
71+ . options ( releaseOptions ) . positional ( 'prid' , {
72+ describe : 'PR number or URL of the release proposal to be promoted' ,
73+ type : 'string'
5474 } )
55- . example ( 'git node release --prepare 1.2.3' ,
56- 'Prepare a release of Node.js tagged v1.2.3' )
75+ . example ( 'git node release --prepare --security' ,
76+ 'Prepare a new security release of Node.js with auto-determined version' )
77+ . example ( 'git node release --prepare --newVersion=1.2.3' ,
78+ 'Prepare a new release of Node.js tagged v1.2.3' )
79+ . example ( 'git node release --promote 12345' ,
80+ 'Promote a prepared release of Node.js with PR #12345' )
5781 . example ( 'git node --prepare --startLTS' ,
5882 'Prepare the first LTS release' ) ;
5983}
@@ -88,17 +112,21 @@ function release(state, argv) {
88112}
89113
90114async function main ( state , argv , cli , dir ) {
115+ const prID = / ^ (?: h t t p s : \/ \/ g i t h u b \. c o m \/ n o d e j s \/ n o d e \/ p u l l \/ ) ? ( \d + ) $ / . exec ( argv . prid ) ;
116+ if ( prID ) {
117+ argv . prid = Number ( prID [ 1 ] ) ;
118+ }
91119 if ( state === PREPARE ) {
92- const prep = new ReleasePreparation ( argv , cli , dir ) ;
120+ const release = new ReleasePreparation ( argv , cli , dir ) ;
93121
94- await prep . prepareLocalBranch ( ) ;
122+ await release . prepareLocalBranch ( ) ;
95123
96- if ( prep . warnForWrongBranch ( ) ) return ;
124+ if ( release . warnForWrongBranch ( ) ) return ;
97125
98126 // If the new version was automatically calculated, confirm it.
99127 if ( ! argv . newVersion ) {
100128 const create = await cli . prompt (
101- `Create release with new version ${ prep . newVersion } ?` ,
129+ `Create release with new version ${ release . newVersion } ?` ,
102130 { defaultAnswer : true } ) ;
103131
104132 if ( ! create ) {
@@ -107,8 +135,30 @@ async function main(state, argv, cli, dir) {
107135 }
108136 }
109137
110- return prep . prepare ( ) ;
138+ return release . prepare ( ) ;
111139 } else if ( state === PROMOTE ) {
112- // TODO(codebytere): implement release promotion.
140+ const credentials = await auth ( { github : true } ) ;
141+ const request = new Request ( credentials ) ;
142+ const release = new ReleasePromotion ( argv , request , cli , dir ) ;
143+
144+ cli . startSpinner ( 'Verifying Releaser status' ) ;
145+ const info = new TeamInfo ( cli , request , 'nodejs' , RELEASERS ) ;
146+
147+ const releasers = await info . getMembers ( ) ;
148+ if ( release . username === undefined ) {
149+ cli . stopSpinner ( 'Failed to verify Releaser status' ) ;
150+ cli . info (
151+ 'Username was undefined - do you have your .ncurc set up correctly?' ) ;
152+ return ;
153+ } else if ( releasers . every ( r => r . login !== release . username ) ) {
154+ cli . stopSpinner ( `${ release . username } is not a Releaser` , 'failed' ) ;
155+ if ( ! argv . dryRun ) {
156+ throw new Error ( 'aborted' ) ;
157+ }
158+ } else {
159+ cli . stopSpinner ( `${ release . username } is a Releaser` ) ;
160+ }
161+
162+ return release . promote ( ) ;
113163 }
114164}
0 commit comments