| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  | #!/usr/bin/env node
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-19 11:48:13 -07:00
										 |  |  | if (!process.env.CI) require('dotenv-safe').load() | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  | require('colors') | 
					
						
							| 
									
										
										
										
											2018-05-14 17:21:51 -04:00
										 |  |  | const args = require('minimist')(process.argv.slice(2), { | 
					
						
							|  |  |  |   boolean: ['automaticRelease', 'notesOnly', 'stable'] | 
					
						
							|  |  |  | }) | 
					
						
							| 
									
										
										
										
											2017-11-17 15:13:30 -05:00
										 |  |  | const ciReleaseBuild = require('./ci-release-build') | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  | const { execSync } = require('child_process') | 
					
						
							|  |  |  | const fail = '\u2717'.red | 
					
						
							| 
									
										
										
										
											2018-02-12 11:01:50 -05:00
										 |  |  | const { GitProcess } = require('dugite') | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  | const GitHub = require('github') | 
					
						
							|  |  |  | const pass = '\u2713'.green | 
					
						
							|  |  |  | const path = require('path') | 
					
						
							| 
									
										
										
										
											2018-01-31 16:40:38 -07:00
										 |  |  | const readline = require('readline') | 
					
						
							| 
									
										
										
										
											2018-11-06 14:06:11 -06:00
										 |  |  | const releaseNotesGenerator = require('./release-notes/index.js') | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  | const versionType = args._[0] | 
					
						
							| 
									
										
										
										
											2018-08-16 09:12:06 -07:00
										 |  |  | const targetRepo = versionType === 'nightly' ? 'nightlies' : 'electron' | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TODO (future) automatically determine version based on conventional commits
 | 
					
						
							|  |  |  | // via conventional-recommended-bump
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if (!versionType && !args.notesOnly) { | 
					
						
							| 
									
										
										
										
											2018-08-17 10:42:45 -07:00
										 |  |  |   console.log(`Usage: prepare-release versionType [stable | beta | nightly]` + | 
					
						
							| 
									
										
										
										
											2018-05-14 17:21:51 -04:00
										 |  |  |      ` (--stable) (--notesOnly) (--automaticRelease) (--branch)`) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   process.exit(1) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const github = new GitHub() | 
					
						
							|  |  |  | const gitDir = path.resolve(__dirname, '..') | 
					
						
							| 
									
										
										
										
											2018-09-14 02:10:51 +10:00
										 |  |  | github.authenticate({ type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN }) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 08:57:12 -07:00
										 |  |  | async function getNewVersion (dryRun) { | 
					
						
							| 
									
										
										
										
											2018-08-20 08:17:47 -07:00
										 |  |  |   if (!dryRun) { | 
					
						
							|  |  |  |     console.log(`Bumping for new "${versionType}" version.`) | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |   const bumpScript = path.join(__dirname, 'bump-version.py') | 
					
						
							|  |  |  |   const scriptArgs = [bumpScript, '--bump', versionType] | 
					
						
							| 
									
										
										
										
											2018-01-31 16:40:38 -07:00
										 |  |  |   if (dryRun) { | 
					
						
							|  |  |  |     scriptArgs.push('--dry-run') | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   try { | 
					
						
							| 
									
										
										
										
											2018-09-14 02:10:51 +10:00
										 |  |  |     let bumpVersion = execSync(scriptArgs.join(' '), { encoding: 'UTF-8' }) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |     bumpVersion = bumpVersion.substr(bumpVersion.indexOf(':') + 1).trim() | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |     const newVersion = `v${bumpVersion}` | 
					
						
							| 
									
										
										
										
											2018-01-31 16:40:38 -07:00
										 |  |  |     if (!dryRun) { | 
					
						
							|  |  |  |       console.log(`${pass} Successfully bumped version to ${newVersion}`) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |     return newVersion | 
					
						
							|  |  |  |   } catch (err) { | 
					
						
							|  |  |  |     console.log(`${fail} Could not bump version, error was:`, err) | 
					
						
							| 
									
										
										
										
											2018-08-16 08:57:12 -07:00
										 |  |  |     throw err | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function getCurrentBranch (gitDir) { | 
					
						
							|  |  |  |   console.log(`Determining current git branch`) | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |   const gitArgs = ['rev-parse', '--abbrev-ref', 'HEAD'] | 
					
						
							|  |  |  |   const branchDetails = await GitProcess.exec(gitArgs, gitDir) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   if (branchDetails.exitCode === 0) { | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |     const currentBranch = branchDetails.stdout.trim() | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |     console.log(`${pass} Successfully determined current git branch is ` + | 
					
						
							|  |  |  |       `${currentBranch}`) | 
					
						
							|  |  |  |     return currentBranch | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |     const error = GitProcess.parseError(branchDetails.stderr) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |     console.log(`${fail} Could not get details for the current branch,
 | 
					
						
							|  |  |  |       error was ${branchDetails.stderr}`, error)
 | 
					
						
							|  |  |  |     process.exit(1) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function getReleaseNotes (currentBranch) { | 
					
						
							| 
									
										
										
										
											2018-08-16 08:57:12 -07:00
										 |  |  |   if (versionType === 'nightly') { | 
					
						
							|  |  |  |     return 'Nightlies do not get release notes, please compare tags for info' | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   console.log(`Generating release notes for ${currentBranch}.`) | 
					
						
							| 
									
										
										
										
											2018-11-06 14:06:11 -06:00
										 |  |  |   const releaseNotes = await releaseNotesGenerator(currentBranch) | 
					
						
							|  |  |  |   if (releaseNotes.warning) { | 
					
						
							|  |  |  |     console.warn(releaseNotes.warning) | 
					
						
							| 
									
										
										
										
											2018-05-14 17:21:51 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   return releaseNotes | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function createRelease (branchToTarget, isBeta) { | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |   const releaseNotes = await getReleaseNotes(branchToTarget) | 
					
						
							|  |  |  |   const newVersion = await getNewVersion() | 
					
						
							| 
									
										
										
										
											2018-02-12 11:01:50 -05:00
										 |  |  |   await tagRelease(newVersion) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   const githubOpts = { | 
					
						
							|  |  |  |     owner: 'electron', | 
					
						
							| 
									
										
										
										
											2018-08-16 09:12:06 -07:00
										 |  |  |     repo: targetRepo | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   } | 
					
						
							|  |  |  |   console.log(`Checking for existing draft release.`) | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |   const releases = await github.repos.getReleases(githubOpts) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |     .catch(err => { | 
					
						
							| 
									
										
										
										
											2018-11-27 23:12:01 -05:00
										 |  |  |       console.log(`${fail} Could not get releases. Error was: `, err) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |     }) | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |   const drafts = releases.data.filter(release => release.draft && | 
					
						
							| 
									
										
										
										
											2018-01-30 17:35:16 -07:00
										 |  |  |     release.tag_name === newVersion) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   if (drafts.length > 0) { | 
					
						
							|  |  |  |     console.log(`${fail} Aborting because draft release for
 | 
					
						
							| 
									
										
										
										
											2017-11-06 16:11:34 -05:00
										 |  |  |       ${drafts[0].tag_name} already exists.`)
 | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |     process.exit(1) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   console.log(`${pass} A draft release does not exist; creating one.`) | 
					
						
							|  |  |  |   githubOpts.draft = true | 
					
						
							|  |  |  |   githubOpts.name = `electron ${newVersion}` | 
					
						
							|  |  |  |   if (isBeta) { | 
					
						
							| 
									
										
										
										
											2018-08-17 10:42:45 -07:00
										 |  |  |     if (newVersion.indexOf('nightly') > 0) { | 
					
						
							| 
									
										
										
										
											2018-08-16 09:28:17 -07:00
										 |  |  |       githubOpts.body = `Note: This is a nightly release.  Please file new issues ` + | 
					
						
							| 
									
										
										
										
											2018-08-16 09:12:06 -07:00
										 |  |  |         `for any bugs you find in it.\n \n This release is published to npm ` + | 
					
						
							| 
									
										
										
										
											2018-08-16 09:28:17 -07:00
										 |  |  |         `under the nightly tag and can be installed via npm install electron@nightly, ` + | 
					
						
							| 
									
										
										
										
											2018-11-06 14:06:11 -06:00
										 |  |  |         `or npm i electron@${newVersion.substr(1)}.\n \n ${releaseNotes.text}` | 
					
						
							| 
									
										
										
										
											2018-08-16 09:12:06 -07:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2018-08-16 09:28:17 -07:00
										 |  |  |       githubOpts.body = `Note: This is a beta release.  Please file new issues ` + | 
					
						
							| 
									
										
										
										
											2018-08-16 09:12:06 -07:00
										 |  |  |         `for any bugs you find in it.\n \n This release is published to npm ` + | 
					
						
							| 
									
										
										
										
											2018-08-16 09:28:17 -07:00
										 |  |  |         `under the beta tag and can be installed via npm install electron@beta, ` + | 
					
						
							| 
									
										
										
										
											2018-11-06 14:06:11 -06:00
										 |  |  |         `or npm i electron@${newVersion.substr(1)}.\n \n ${releaseNotes.text}` | 
					
						
							| 
									
										
										
										
											2018-08-16 09:12:06 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |     githubOpts.name = `${githubOpts.name}` | 
					
						
							|  |  |  |     githubOpts.prerelease = true | 
					
						
							| 
									
										
										
										
											2018-01-31 16:40:38 -07:00
										 |  |  |   } else { | 
					
						
							|  |  |  |     githubOpts.body = releaseNotes | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   } | 
					
						
							|  |  |  |   githubOpts.tag_name = newVersion | 
					
						
							| 
									
										
										
										
											2018-08-18 09:21:38 -07:00
										 |  |  |   githubOpts.target_commitish = newVersion.indexOf('nightly') !== -1 ? 'master' : branchToTarget | 
					
						
							| 
									
										
										
										
											2018-11-27 23:12:01 -05:00
										 |  |  |   const release = await github.repos.createRelease(githubOpts) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |     .catch(err => { | 
					
						
							|  |  |  |       console.log(`${fail} Error creating new release: `, err) | 
					
						
							|  |  |  |       process.exit(1) | 
					
						
							|  |  |  |     }) | 
					
						
							| 
									
										
										
										
											2018-11-27 23:12:01 -05:00
										 |  |  |   console.log(`Release has been created with id: ${release.id}.`) | 
					
						
							|  |  |  |   console.log(`${pass} Draft release for ${newVersion} successful.`) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-14 17:21:51 -04:00
										 |  |  | async function pushRelease (branch) { | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |   const pushDetails = await GitProcess.exec(['push', 'origin', `HEAD:${branch}`, '--follow-tags'], gitDir) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   if (pushDetails.exitCode === 0) { | 
					
						
							| 
									
										
										
										
											2018-02-12 11:01:50 -05:00
										 |  |  |     console.log(`${pass} Successfully pushed the release.  Wait for ` + | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |       `release builds to finish before running "npm run release".`) | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2018-02-12 11:01:50 -05:00
										 |  |  |     console.log(`${fail} Error pushing the release: ` + | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |         `${pushDetails.stderr}`) | 
					
						
							|  |  |  |     process.exit(1) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-12 11:01:50 -05:00
										 |  |  | async function runReleaseBuilds (branch) { | 
					
						
							|  |  |  |   await ciReleaseBuild(branch, { | 
					
						
							| 
									
										
										
										
											2018-05-14 17:21:51 -04:00
										 |  |  |     ghRelease: true, | 
					
						
							|  |  |  |     automaticRelease: args.automaticRelease | 
					
						
							| 
									
										
										
										
											2017-11-17 15:13:30 -05:00
										 |  |  |   }) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-12 11:01:50 -05:00
										 |  |  | async function tagRelease (version) { | 
					
						
							|  |  |  |   console.log(`Tagging release ${version}.`) | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |   const checkoutDetails = await GitProcess.exec([ 'tag', '-a', '-m', version, version ], gitDir) | 
					
						
							| 
									
										
										
										
											2018-02-12 11:01:50 -05:00
										 |  |  |   if (checkoutDetails.exitCode === 0) { | 
					
						
							|  |  |  |     console.log(`${pass} Successfully tagged ${version}.`) | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     console.log(`${fail} Error tagging ${version}: ` + | 
					
						
							|  |  |  |       `${checkoutDetails.stderr}`) | 
					
						
							|  |  |  |     process.exit(1) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-31 16:40:38 -07:00
										 |  |  | async function verifyNewVersion () { | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |   const newVersion = await getNewVersion(true) | 
					
						
							| 
									
										
										
										
											2018-05-14 17:21:51 -04:00
										 |  |  |   let response | 
					
						
							|  |  |  |   if (args.automaticRelease) { | 
					
						
							|  |  |  |     response = 'y' | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     response = await promptForVersion(newVersion) | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-01-31 16:40:38 -07:00
										 |  |  |   if (response.match(/^y/i)) { | 
					
						
							|  |  |  |     console.log(`${pass} Starting release of ${newVersion}`) | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     console.log(`${fail} Aborting release of ${newVersion}`) | 
					
						
							|  |  |  |     process.exit() | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function promptForVersion (version) { | 
					
						
							|  |  |  |   return new Promise((resolve, reject) => { | 
					
						
							|  |  |  |     const rl = readline.createInterface({ | 
					
						
							|  |  |  |       input: process.stdin, | 
					
						
							|  |  |  |       output: process.stdout | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     rl.question(`Do you want to create the release ${version.green} (y/N)? `, (answer) => { | 
					
						
							|  |  |  |       rl.close() | 
					
						
							|  |  |  |       resolve(answer) | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-18 17:36:16 -07:00
										 |  |  | // function to determine if there have been commits to master since the last release
 | 
					
						
							|  |  |  | async function changesToRelease () { | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |   const lastCommitWasRelease = new RegExp(`^Bump v[0-9.]*(-beta[0-9.]*)?(-nightly[0-9.]*)?$`, 'g') | 
					
						
							|  |  |  |   const lastCommit = await GitProcess.exec(['log', '-n', '1', `--pretty=format:'%s'`], gitDir) | 
					
						
							| 
									
										
										
										
											2018-08-18 17:36:16 -07:00
										 |  |  |   return !lastCommitWasRelease.test(lastCommit.stdout) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  | async function prepareRelease (isBeta, notesOnly) { | 
					
						
							| 
									
										
										
										
											2018-08-20 08:17:47 -07:00
										 |  |  |   if (args.dryRun) { | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |     const newVersion = await getNewVersion(true) | 
					
						
							| 
									
										
										
										
											2018-08-20 08:17:47 -07:00
										 |  |  |     console.log(newVersion) | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2018-08-20 08:17:47 -07:00
										 |  |  |     const currentBranch = (args.branch) ? args.branch : await getCurrentBranch(gitDir) | 
					
						
							|  |  |  |     if (notesOnly) { | 
					
						
							| 
									
										
										
										
											2018-10-02 03:56:31 +02:00
										 |  |  |       const releaseNotes = await getReleaseNotes(currentBranch) | 
					
						
							| 
									
										
										
										
											2018-11-06 14:06:11 -06:00
										 |  |  |       console.log(`Draft release notes are: \n${releaseNotes.text}`) | 
					
						
							| 
									
										
										
										
											2018-08-18 17:36:16 -07:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2018-08-20 08:17:47 -07:00
										 |  |  |       const changes = await changesToRelease(currentBranch) | 
					
						
							|  |  |  |       if (changes) { | 
					
						
							|  |  |  |         await verifyNewVersion() | 
					
						
							|  |  |  |         await createRelease(currentBranch, isBeta) | 
					
						
							|  |  |  |         await pushRelease(currentBranch) | 
					
						
							|  |  |  |         await runReleaseBuilds(currentBranch) | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         console.log(`There are no new changes to this branch since the last release, aborting release.`) | 
					
						
							|  |  |  |         process.exit(1) | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-08-18 17:36:16 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-23 11:02:50 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | prepareRelease(!args.stable, args.notesOnly) |