Merge pull request #11903 from electron/update-release-for2

Change release process for 2.0
This commit is contained in:
John Kleinschmidt 2018-02-12 16:52:41 -05:00 committed by GitHub
commit 546bd6da5e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 24 additions and 164 deletions

View file

@ -167,27 +167,10 @@ This release is published to [npm](https://www.npmjs.com/package/electron) under
1. You can run `npm run release -- --validateRelease` to verify that all of the 1. You can run `npm run release -- --validateRelease` to verify that all of the
required files have been created for the release. required files have been created for the release.
## Merge temporary branch
Once the release builds have finished, merge the `release` branch back into
the source release branch using the `merge-release` script.
If the branch cannot be successfully merged back this script will automatically
rebase the `release` branch and push the changes which will trigger the release
builds again, which means you will need to wait for the release builds to run
again before proceeding.
### Merging back into master
```sh
npm run merge-release -- master
```
### Merging back into old release branch
```sh
npm run merge-release -- 1-7-x
```
## Publish the release ## Publish the release
Once the merge has finished successfully, run the `release` script Once the release builds have finished, run the `release` script
via `npm run release` to finish the release process. This script will do the via `npm run release` to finish the release process. This script will do the
following: following:
1. Build the project to validate that the correct version number is being released. 1. Build the project to validate that the correct version number is being released.

View file

@ -55,7 +55,6 @@
"lint-js-in-markdown": "standard-markdown docs", "lint-js-in-markdown": "standard-markdown docs",
"create-api-json": "electron-docs-linter docs --outfile=out/electron-api.json --version=$npm_package_version", "create-api-json": "electron-docs-linter docs --outfile=out/electron-api.json --version=$npm_package_version",
"create-typescript-definitions": "npm run create-api-json && electron-typescript-definitions --in=out/electron-api.json --out=out/electron.d.ts", "create-typescript-definitions": "npm run create-api-json && electron-typescript-definitions --in=out/electron-api.json --out=out/electron.d.ts",
"merge-release": "node ./script/merge-release.js",
"mock-release": "node ./script/ci-release-build.js", "mock-release": "node ./script/ci-release-build.js",
"preinstall": "node -e 'process.exit(0)'", "preinstall": "node -e 'process.exit(0)'",
"publish-to-npm": "node ./script/publish-to-npm.js", "publish-to-npm": "node ./script/publish-to-npm.js",

View file

@ -1,116 +0,0 @@
#!/usr/bin/env node
require('colors')
const assert = require('assert')
const branchToRelease = process.argv[2]
const fail = '\u2717'.red
const { GitProcess, GitError } = require('dugite')
const pass = '\u2713'.green
const path = require('path')
const pkg = require('../package.json')
assert(process.env.ELECTRON_GITHUB_TOKEN, 'ELECTRON_GITHUB_TOKEN not found in environment')
if (!branchToRelease) {
console.log(`Usage: merge-release branch`)
process.exit(1)
}
const gitDir = path.resolve(__dirname, '..')
async function callGit (args, errorMessage, successMessage) {
let gitResult = await GitProcess.exec(args, gitDir)
if (gitResult.exitCode === 0) {
console.log(`${pass} ${successMessage}`)
return true
} else {
console.log(`${fail} ${errorMessage} ${gitResult.stderr}`)
process.exit(1)
}
}
async function checkoutBranch (branchName) {
console.log(`Checking out ${branchName}.`)
let errorMessage = `Error checking out branch ${branchName}:`
let successMessage = `Successfully checked out branch ${branchName}.`
return callGit(['checkout', branchName], errorMessage, successMessage)
}
async function commitMerge () {
console.log(`Committing the merge for v${pkg.version}`)
let errorMessage = `Error committing merge:`
let successMessage = `Successfully committed the merge for v${pkg.version}`
let gitArgs = ['commit', '-m', `v${pkg.version}`]
return callGit(gitArgs, errorMessage, successMessage)
}
async function mergeReleaseIntoBranch (branchName) {
console.log(`Merging release branch into ${branchName}.`)
let mergeArgs = ['merge', 'release', '--squash']
let mergeDetails = await GitProcess.exec(mergeArgs, gitDir)
if (mergeDetails.exitCode === 0) {
return true
} else {
const error = GitProcess.parseError(mergeDetails.stderr)
if (error === GitError.MergeConflicts) {
console.log(`${fail} Could not merge release branch into ${branchName} ` +
`due to merge conflicts.`)
return false
} else {
console.log(`${fail} Could not merge release branch into ${branchName} ` +
`due to an error: ${mergeDetails.stderr}.`)
process.exit(1)
}
}
}
async function pushBranch (branchName) {
console.log(`Pushing branch ${branchName}.`)
let pushArgs = ['push', 'origin', branchName]
let errorMessage = `Could not push branch ${branchName} due to an error:`
let successMessage = `Successfully pushed branch ${branchName}.`
return callGit(pushArgs, errorMessage, successMessage)
}
async function pull () {
console.log(`Performing a git pull`)
let errorMessage = `Could not pull due to an error:`
let successMessage = `Successfully performed a git pull`
return callGit(['pull'], errorMessage, successMessage)
}
async function rebase (targetBranch) {
console.log(`Rebasing release branch from ${targetBranch}`)
let errorMessage = `Could not rebase due to an error:`
let successMessage = `Successfully rebased release branch from ` +
`${targetBranch}`
return callGit(['rebase', targetBranch], errorMessage, successMessage)
}
async function mergeRelease () {
await checkoutBranch(branchToRelease)
let mergeSuccess = await mergeReleaseIntoBranch(branchToRelease)
if (mergeSuccess) {
console.log(`${pass} Successfully merged release branch into ` +
`${branchToRelease}.`)
await commitMerge()
let pushSuccess = await pushBranch(branchToRelease)
if (pushSuccess) {
console.log(`${pass} Success!!! ${branchToRelease} now has the latest release!`)
}
} else {
console.log(`Trying rebase of ${branchToRelease} into release branch.`)
await pull()
await checkoutBranch('release')
let rebaseResult = await rebase(branchToRelease)
if (rebaseResult) {
let pushResult = pushBranch('HEAD')
if (pushResult) {
console.log(`Rebase of ${branchToRelease} into release branch was ` +
`successful. Let release builds run and then try this step again.`)
}
// Exit as failure so release doesn't continue
process.exit(1)
}
}
}
mergeRelease()

View file

@ -6,7 +6,7 @@ const assert = require('assert')
const ciReleaseBuild = require('./ci-release-build') const ciReleaseBuild = require('./ci-release-build')
const { execSync } = require('child_process') const { execSync } = require('child_process')
const fail = '\u2717'.red const fail = '\u2717'.red
const { GitProcess, GitError } = require('dugite') const { GitProcess } = require('dugite')
const GitHub = require('github') const GitHub = require('github')
const pass = '\u2713'.green const pass = '\u2713'.green
const path = require('path') const path = require('path')
@ -28,24 +28,6 @@ const github = new GitHub()
const gitDir = path.resolve(__dirname, '..') const gitDir = path.resolve(__dirname, '..')
github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN}) github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
async function createReleaseBranch () {
console.log(`Creating release branch.`)
let checkoutDetails = await GitProcess.exec([ 'checkout', '-b', 'release' ], gitDir)
if (checkoutDetails.exitCode === 0) {
console.log(`${pass} Successfully created the release branch.`)
} else {
const error = GitProcess.parseError(checkoutDetails.stderr)
if (error === GitError.BranchAlreadyExists) {
console.log(`${fail} Release branch already exists, aborting prepare ` +
`release process.`)
} else {
console.log(`${fail} Error creating release branch: ` +
`${checkoutDetails.stderr}`)
}
process.exit(1)
}
}
function getNewVersion (dryRun) { function getNewVersion (dryRun) {
console.log(`Bumping for new "${versionType}" version.`) console.log(`Bumping for new "${versionType}" version.`)
let bumpScript = path.join(__dirname, 'bump-version.py') let bumpScript = path.join(__dirname, 'bump-version.py')
@ -98,7 +80,7 @@ async function getReleaseNotes (currentBranch) {
console.log(`Checking for commits from ${pkg.version} to ${currentBranch}`) console.log(`Checking for commits from ${pkg.version} to ${currentBranch}`)
let commitComparison = await github.repos.compareCommits(githubOpts) let commitComparison = await github.repos.compareCommits(githubOpts)
.catch(err => { .catch(err => {
console.log(`{$fail} Error checking for commits from ${pkg.version} to ` + console.log(`${fail} Error checking for commits from ${pkg.version} to ` +
`${currentBranch}`, err) `${currentBranch}`, err)
process.exit(1) process.exit(1)
}) })
@ -116,6 +98,7 @@ async function getReleaseNotes (currentBranch) {
async function createRelease (branchToTarget, isBeta) { async function createRelease (branchToTarget, isBeta) {
let releaseNotes = await getReleaseNotes(branchToTarget) let releaseNotes = await getReleaseNotes(branchToTarget)
let newVersion = getNewVersion() let newVersion = getNewVersion()
await tagRelease(newVersion)
const githubOpts = { const githubOpts = {
owner: 'electron', owner: 'electron',
repo: 'electron' repo: 'electron'
@ -156,25 +139,37 @@ async function createRelease (branchToTarget, isBeta) {
} }
async function pushRelease () { async function pushRelease () {
let pushDetails = await GitProcess.exec(['push', 'origin', 'HEAD'], gitDir) let pushDetails = await GitProcess.exec(['push', 'origin', 'HEAD', '--follow-tags'], gitDir)
if (pushDetails.exitCode === 0) { if (pushDetails.exitCode === 0) {
console.log(`${pass} Successfully pushed the release branch. Wait for ` + console.log(`${pass} Successfully pushed the release. Wait for ` +
`release builds to finish before running "npm run release".`) `release builds to finish before running "npm run release".`)
} else { } else {
console.log(`${fail} Error pushing the release branch: ` + console.log(`${fail} Error pushing the release: ` +
`${pushDetails.stderr}`) `${pushDetails.stderr}`)
process.exit(1) process.exit(1)
} }
} }
async function runReleaseBuilds () { async function runReleaseBuilds (branch) {
await ciReleaseBuild('release', { await ciReleaseBuild(branch, {
ghRelease: true ghRelease: true
}) })
} }
async function tagRelease (version) {
console.log(`Tagging release ${version}.`)
let checkoutDetails = await GitProcess.exec([ 'tag', '-a', '-m', version, version ], gitDir)
if (checkoutDetails.exitCode === 0) {
console.log(`${pass} Successfully tagged ${version}.`)
} else {
console.log(`${fail} Error tagging ${version}: ` +
`${checkoutDetails.stderr}`)
process.exit(1)
}
}
async function verifyNewVersion () { async function verifyNewVersion () {
let newVersion = await getNewVersion(true) let newVersion = getNewVersion(true)
let response = await promptForVersion(newVersion) let response = await promptForVersion(newVersion)
if (response.match(/^y/i)) { if (response.match(/^y/i)) {
console.log(`${pass} Starting release of ${newVersion}`) console.log(`${pass} Starting release of ${newVersion}`)
@ -204,10 +199,9 @@ async function prepareRelease (isBeta, notesOnly) {
console.log(`Draft release notes are: ${releaseNotes}`) console.log(`Draft release notes are: ${releaseNotes}`)
} else { } else {
await verifyNewVersion() await verifyNewVersion()
await createReleaseBranch()
await createRelease(currentBranch, isBeta) await createRelease(currentBranch, isBeta)
await pushRelease() await pushRelease()
await runReleaseBuilds() await runReleaseBuilds(currentBranch)
} }
} }

View file

@ -50,7 +50,7 @@ new Promise((resolve, reject) => {
tempDir = dirPath tempDir = dirPath
// copy files from `/npm` to temp directory // copy files from `/npm` to temp directory
files.forEach((name) => { files.forEach((name) => {
const noThirdSegment = name === 'README.md' || 'LICENSE' const noThirdSegment = name === 'README.md' || name === 'LICENSE'
fs.writeFileSync( fs.writeFileSync(
path.join(tempDir, name), path.join(tempDir, name),
fs.readFileSync(path.join(__dirname, '..', noThirdSegment ? '' : 'npm', name)) fs.readFileSync(path.join(__dirname, '..', noThirdSegment ? '' : 'npm', name))