Browse Source

chore: introduce concept of nightly builds to release scripts (#14130)

* chore: introduce concept of nightly builds to release scripts

* build: publish nightly releases to dedicated repo
Shelley Vohr 6 years ago
parent
commit
b9afc68c35

+ 17 - 3
script/bump-version.py

@@ -72,10 +72,17 @@ def main():
     versions[3] = '0'
 
   if args.new_version != None:
-    versions = parse_version(re.sub('-beta', '', args.new_version))
+    clean_version = re.sub('-beta', '', args.new_version)
+    clean_version = re.sub('-nightly', '', clean_version)
+    versions = parse_version(clean_version)
 
   version = '.'.join(versions[:3])
-  suffix = '' if versions[3] == '0' else '-beta.' + versions[3]
+  suffix = ''
+
+  if args.new_version != None and '-nightly' in args.new_version:
+    suffix = '-nightly.' + versions[3]
+  elif versions[3] != '0':
+    suffix = '-beta.' + versions[3]
 
   if args.dry_run:
     print 'new version number would be: {0}\n'.format(version + suffix)
@@ -192,7 +199,14 @@ def update_package_json(version, suffix):
 
 
 def tag_version(version, suffix):
-  execute(['git', 'commit', '-a', '-m', 'Bump v{0}'.format(version + suffix)])
+  execute([
+    'git',
+    'commit',
+    '-a',
+    '-m',
+    'Bump v{0}'.format(version + suffix),
+    '-n'
+  ])
 
 
 if __name__ == '__main__':

+ 1 - 1
script/find-release.js

@@ -14,7 +14,7 @@ async function findRelease () {
   github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
   let releases = await github.repos.getReleases({
     owner: 'electron',
-    repo: 'electron'
+    repo: version.indexOf('nightly') > 0 ? 'nightlies' : 'electron'
   })
   let targetRelease = releases.data.find(release => {
     return release.tag_name === version

+ 54 - 7
script/prepare-release.js

@@ -14,13 +14,14 @@ const pass = '\u2713'.green
 const path = require('path')
 const pkg = require('../package.json')
 const readline = require('readline')
+const semver = require('semver')
 const versionType = args._[0]
 
 // TODO (future) automatically determine version based on conventional commits
 // via conventional-recommended-bump
 
 if (!versionType && !args.notesOnly) {
-  console.log(`Usage: prepare-release versionType [major | minor | patch | beta]` +
+  console.log(`Usage: prepare-release versionType [major | minor | patch | beta | nightly]` +
      ` (--stable) (--notesOnly) (--automaticRelease) (--branch)`)
   process.exit(1)
 }
@@ -29,10 +30,15 @@ const github = new GitHub()
 const gitDir = path.resolve(__dirname, '..')
 github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
 
-function getNewVersion (dryRun) {
+async function getNewVersion (dryRun) {
   console.log(`Bumping for new "${versionType}" version.`)
   let bumpScript = path.join(__dirname, 'bump-version.py')
-  let scriptArgs = [bumpScript, `--bump ${versionType}`]
+  let scriptArgs = [bumpScript]
+  if (versionType === 'nightly') {
+    scriptArgs.push(`--version ${await determineNextNightly(await getCurrentBranch())}`)
+  } else {
+    scriptArgs.push(`--bump ${versionType}`)
+  }
   if (args.stable) {
     scriptArgs.push('--stable')
   }
@@ -49,9 +55,47 @@ function getNewVersion (dryRun) {
     return newVersion
   } catch (err) {
     console.log(`${fail} Could not bump version, error was:`, err)
+    throw err
   }
 }
 
+async function determineNextNightly (currentBranch) {
+  const twoPad = (n) => n < 10 ? `0${n}` : `${n}`
+  const d = new Date()
+  const date = `${d.getFullYear()}${twoPad(d.getMonth() + 1)}${twoPad(d.getDate())}`
+
+  let version
+
+  if (currentBranch === 'master') {
+    version = await determineNextNightlyForMaster()
+  }
+  if (!version) {
+    throw new Error(`not yet implemented for release branch: ${currentBranch}`)
+  }
+
+  return `${version}-nightly.${date}`
+}
+
+async function determineNextNightlyForMaster () {
+  let branchNames
+  let result = await GitProcess.exec(['branch', '-a', '--remote', '--list', 'origin/[0-9]-[0-9]-x'], gitDir)
+  if (result.exitCode === 0) {
+    branchNames = result.stdout.trim().split('\n')
+    const filtered = branchNames.map(b => b.replace('origin/', ''))
+    return getNextReleaseBranch(filtered)
+  } else {
+    throw new Error('Release branches could not be fetched.')
+  }
+}
+
+function getNextReleaseBranch (branches) {
+  const converted = branches.map(b => b.replace(/-/g, '.').replace('x', '0'))
+  const next = converted.reduce((v1, v2) => {
+    return semver.gt(v1, v2) ? v1 : v2
+  })
+  return `${parseInt(next.split('.')[0], 10) + 1}.0.0`
+}
+
 async function getCurrentBranch (gitDir) {
   console.log(`Determining current git branch`)
   let gitArgs = ['rev-parse', '--abbrev-ref', 'HEAD']
@@ -70,6 +114,9 @@ async function getCurrentBranch (gitDir) {
 }
 
 async function getReleaseNotes (currentBranch) {
+  if (versionType === 'nightly') {
+    return 'Nightlies do not get release notes, please compare tags for info'
+  }
   console.log(`Generating release notes for ${currentBranch}.`)
   let githubOpts = {
     owner: 'electron',
@@ -135,7 +182,7 @@ async function getReleaseNotes (currentBranch) {
 
 async function createRelease (branchToTarget, isBeta) {
   let releaseNotes = await getReleaseNotes(branchToTarget)
-  let newVersion = getNewVersion()
+  let newVersion = await getNewVersion()
   await tagRelease(newVersion)
   const githubOpts = {
     owner: 'electron',
@@ -208,7 +255,7 @@ async function tagRelease (version) {
 }
 
 async function verifyNewVersion () {
-  let newVersion = getNewVersion(true)
+  let newVersion = await getNewVersion(true)
   let response
   if (args.automaticRelease) {
     response = 'y'
@@ -238,8 +285,8 @@ async function promptForVersion (version) {
 
 async function prepareRelease (isBeta, notesOnly) {
   if (args.automaticRelease && (pkg.version.indexOf('beta') === -1 ||
-      versionType !== 'beta')) {
-    console.log(`${fail} Automatic release is only supported for beta releases`)
+      versionType !== 'beta') && versionType !== 'nightly') {
+    console.log(`${fail} Automatic release is only supported for beta and nightly releases`)
     process.exit(1)
   }
   let currentBranch

+ 1 - 1
script/publish-to-npm.js

@@ -68,7 +68,7 @@ new Promise((resolve, reject) => {
 
   return github.repos.getReleases({
     owner: 'electron',
-    repo: 'electron'
+    repo: rootPackageJson.version.indexOf('nightly') > 0 ? 'nightlies' : 'electron'
   })
 })
 .then((releases) => {

+ 6 - 5
script/release.js

@@ -16,6 +16,7 @@ const fail = '\u2717'.red
 const sumchecker = require('sumchecker')
 const temp = require('temp').track()
 const { URL } = require('url')
+const targetRepo = pkgVersion.indexOf('nightly') > 0 ? 'nightlies' : 'electron'
 let failureCount = 0
 
 const github = new GitHub({
@@ -24,7 +25,7 @@ const github = new GitHub({
 github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
 
 async function getDraftRelease (version, skipValidation) {
-  let releaseInfo = await github.repos.getReleases({owner: 'electron', repo: 'electron'})
+  let releaseInfo = await github.repos.getReleases({owner: 'electron', repo: targetRepo})
   let drafts
   let versionToCheck
   if (version) {
@@ -197,7 +198,7 @@ async function createReleaseShasums (release) {
     console.log(`${fileName} already exists on GitHub; deleting before creating new file.`)
     await github.repos.deleteAsset({
       owner: 'electron',
-      repo: 'electron',
+      repo: targetRepo,
       id: existingAssets[0].id
     }).catch(err => {
       console.log(`${fail} Error deleting ${fileName} on GitHub:`, err)
@@ -216,7 +217,7 @@ async function createReleaseShasums (release) {
 async function uploadShasumFile (filePath, fileName, release) {
   let githubOpts = {
     owner: 'electron',
-    repo: 'electron',
+    repo: targetRepo,
     id: release.id,
     filePath,
     name: fileName
@@ -251,7 +252,7 @@ function saveShaSumFile (checksums, fileName) {
 async function publishRelease (release) {
   let githubOpts = {
     owner: 'electron',
-    repo: 'electron',
+    repo: targetRepo,
     id: release.id,
     tag_name: release.tag_name,
     draft: false
@@ -305,7 +306,7 @@ async function verifyAssets (release) {
   let downloadDir = await makeTempDir()
   let githubOpts = {
     owner: 'electron',
-    repo: 'electron',
+    repo: targetRepo,
     headers: {
       Accept: 'application/octet-stream'
     }

+ 6 - 3
script/upload-to-github.js

@@ -4,17 +4,20 @@ const GitHub = require('github')
 const github = new GitHub()
 github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
 
-if (process.argv.length < 5) {
+if (process.argv.length < 6) {
   console.log('Usage: upload-to-github filePath fileName releaseId')
   process.exit(1)
 }
 let filePath = process.argv[2]
 let fileName = process.argv[3]
 let releaseId = process.argv[4]
+let releaseVersion = process.argv[5]
+
+const targetRepo = releaseVersion.indexOf('nightly') > 0 ? 'nightlies' : 'electron'
 
 let githubOpts = {
   owner: 'electron',
-  repo: 'electron',
+  repo: targetRepo,
   id: releaseId,
   filePath: filePath,
   name: fileName
@@ -36,7 +39,7 @@ function uploadToGitHub () {
           console.log(`${fileName} already exists; will delete before retrying upload.`)
           github.repos.deleteAsset({
             owner: 'electron',
-            repo: 'electron',
+            repo: targetRepo,
             id: existingAssets[0].id
           }).then(uploadToGitHub).catch(uploadToGitHub)
         } else {

+ 4 - 3
script/upload.py

@@ -165,17 +165,18 @@ def upload_electron(release, file_path, args):
     return
 
   # Upload the file.
-  upload_io_to_github(release, filename, file_path)
+  upload_io_to_github(release, filename, file_path, args.version)
 
   # Upload the checksum file.
   upload_sha256_checksum(args.version, file_path)
 
 
-def upload_io_to_github(release, filename, filepath):
+def upload_io_to_github(release, filename, filepath, version):
   print 'Uploading %s to Github' % \
       (filename)
   script_path = os.path.join(SOURCE_ROOT, 'script', 'upload-to-github.js')
-  execute(['node', script_path, filepath, filename, str(release['id'])])
+  execute(['node', script_path, filepath, filename, str(release['id']),
+          version])
 
 
 def upload_sha256_checksum(version, file_path, key_prefix=None):