1
1
'use strict'
2
2
3
- /* eslint-disable no-console */
4
-
5
3
// TODO: Support major versions.
6
4
7
- const { execSync } = require ( 'child_process' )
8
5
const fs = require ( 'fs' )
6
+ const os = require ( 'os' )
9
7
const path = require ( 'path' )
8
+ const { capture, checkpoint, exit, fatal, success, run } = require ( './helpers/terminal' )
9
+ const { checkBranchDiff, checkGitHub, checkGit } = require ( './helpers/requirements' )
10
10
11
- // Helpers for colored output.
12
- const log = msg => console . log ( msg )
13
- const success = msg => console . log ( `\x1b[32m${ msg } \x1b[0m` )
14
- const error = msg => console . log ( `\x1b[31m${ msg } \x1b[0m` )
15
- const whisper = msg => console . log ( `\x1b[90m${ msg } \x1b[0m` )
11
+ checkGit ( )
12
+ checkBranchDiff ( )
16
13
17
- const currentBranch = capture ( 'git branch --show-current' )
18
14
const releaseLine = process . argv [ 2 ]
19
15
20
16
// Validate release line argument.
21
17
if ( ! releaseLine || releaseLine === 'help' || releaseLine === '--help' ) {
22
- log ( 'Usage: node scripts/release/proposal <release-line> [release-type]' )
23
- process . exit ( 0 )
18
+ exit ( 'Usage: node scripts/release/proposal <release-line> [release-type]' )
24
19
} else if ( ! releaseLine ?. match ( / ^ \d + $ / ) ) {
25
- error ( 'Invalid release line. Must be a whole number.' )
26
- process . exit ( 1 )
20
+ fatal ( 'Invalid release line. Must be a whole number.' )
27
21
}
28
22
29
23
// Make sure the release branch is up to date to prepare for new proposal.
@@ -36,20 +30,21 @@ const diffCmd = [
36
30
'branch-diff' ,
37
31
'--user DataDog' ,
38
32
'--repo dd-trace-js' ,
39
- isActivePatch ( )
40
- ? `--exclude-label=semver-major,semver-minor,dont-land-on-v${ releaseLine } .x`
41
- : `--exclude-label=semver-major,dont-land-on-v${ releaseLine } .x`
33
+ `--exclude-label=semver-major,dont-land-on-v${ releaseLine } .x`
42
34
] . join ( ' ' )
43
35
44
- // Determine the new version.
45
- const [ lastMajor , lastMinor , lastPatch ] = require ( '../../package.json' ) . version . split ( '.' ) . map ( Number )
46
- const lineDiff = capture ( `${ diffCmd } v${ releaseLine } .x master` )
36
+ // Determine the new version and release notes location .
37
+ const [ , lastMinor , lastPatch ] = require ( '../../package.json' ) . version . split ( '.' ) . map ( Number )
38
+ const lineDiff = capture ( `${ diffCmd } --markdown=true v${ releaseLine } .x master` )
47
39
const newVersion = lineDiff . includes ( 'SEMVER-MINOR' )
48
40
? `${ releaseLine } .${ lastMinor + 1 } .0`
49
41
: `${ releaseLine } .${ lastMinor } .${ lastPatch + 1 } `
42
+ const notesDir = path . join ( os . tmpdir ( ) , 'release_notes' )
43
+ const notesFile = path . join ( notesDir , `${ newVersion } .md` )
50
44
51
- // Checkout new branch and output new changes .
45
+ // Checkout new or existing branch .
52
46
run ( `git checkout v${ newVersion } -proposal || git checkout -b v${ newVersion } -proposal` )
47
+ run ( `git remote show origin | grep v${ newVersion } && git pull || exit 0` )
53
48
54
49
// Get the hashes of the last version and the commits to add.
55
50
const lastCommit = capture ( 'git log -1 --pretty=%B' ) . trim ( )
@@ -69,60 +64,38 @@ if (proposalDiff) {
69
64
try {
70
65
run ( `echo "${ proposalDiff } " | xargs git cherry-pick` )
71
66
} catch ( err ) {
72
- error ( 'Cherry-pick failed. Resolve the conflicts and run `git cherry-pick --continue` to continue.' )
73
- error ( 'When all conflicts have been resolved, run this script again.' )
74
- process . exit ( 1 )
67
+ fatal (
68
+ 'Cherry-pick failed. Resolve the conflicts and run `git cherry-pick --continue` to continue.' ,
69
+ 'When all conflicts have been resolved, run this script again.'
70
+ )
75
71
}
76
72
}
77
73
78
74
// Update package.json with new version.
79
- run ( `npm version --git-tag-version=false ${ newVersion } ` )
75
+ run ( `npm version --allow-same-version -- git-tag-version=false ${ newVersion } ` )
80
76
run ( `git commit -uno -m v${ newVersion } package.json || exit 0` )
81
77
82
- ready ( )
78
+ // Write release notes to a file that can be copied to the GitHub release.
79
+ fs . mkdirSync ( notesDir , { recursive : true } )
80
+ fs . writeFileSync ( notesFile , lineDiff )
83
81
84
- // Check if current branch is already an active patch proposal branch to avoid
85
- // creating a new minor proposal branch if new minor commits are added to the
86
- // main branch during a existing patch release.
87
- function isActivePatch ( ) {
88
- const currentMatch = currentBranch . match ( / ^ ( \d + ) \. ( \d + ) \. ( \d + ) - p r o p o s a l $ / )
82
+ success ( 'Release proposal is ready.' )
83
+ success ( `Changelog at ${ os . tmpdir ( ) } /release_notes/${ newVersion } .md` )
89
84
90
- if ( currentMatch ) {
91
- const [ major , minor , patch ] = currentMatch . slice ( 1 ) . map ( Number )
85
+ // Stop and ask the user if they want to proceed with pushing everything upstream.
86
+ checkpoint ( 'Push the release upstream and create/update PR?' )
92
87
93
- if ( major === lastMajor && minor === lastMinor && patch > lastPatch ) {
94
- return true
95
- }
96
- }
88
+ checkGitHub ( )
97
89
98
- return false
99
- }
90
+ run ( 'git push -f -u origin HEAD' )
100
91
101
- // Output a command to the terminal and execute it .
102
- function run ( cmd ) {
103
- whisper ( `> ${ cmd } `)
104
-
105
- const output = execSync ( cmd , { } ) . toString ( )
106
-
107
- log ( output )
92
+ // Create or edit the PR. This will also automatically output a link to the PR .
93
+ try {
94
+ run ( `gh pr create -d -B v ${ releaseLine } .x -t "v ${ newVersion } proposal" -F ${ notesFile } `)
95
+ } catch ( e ) {
96
+ // PR already exists so update instead.
97
+ // TODO: Keep existing non-release-notes PR description if there is one.
98
+ run ( `gh pr edit -F " ${ notesFile } "` )
108
99
}
109
100
110
- // Run a command and capture its output to return it to the caller.
111
- function capture ( cmd ) {
112
- return execSync ( cmd , { } ) . toString ( )
113
- }
114
-
115
- // Write release notes to a file that can be copied to the GitHub release.
116
- function ready ( ) {
117
- const notesDir = path . join ( __dirname , '..' , '..' , '.github' , 'release_notes' )
118
- const notesFile = path . join ( notesDir , `${ newVersion } .md` )
119
- const lineDiff = capture ( `${ diffCmd } --markdown=true v${ releaseLine } .x master` )
120
-
121
- fs . mkdirSync ( notesDir , { recursive : true } )
122
- fs . writeFileSync ( notesFile , lineDiff )
123
-
124
- success ( 'Release proposal is ready.' )
125
- success ( `Changelog at .github/release_notes/${ newVersion } .md` )
126
-
127
- process . exit ( 0 )
128
- }
101
+ success ( 'Release PR is ready.' )
0 commit comments