Browse Source

chore: allow nightlies from release branches (#14157)

* chore: allow nightlies from release branches

* keep current version from beta to nightly

* move version bump logic to bump-versi.py
Shelley Vohr 6 years ago
parent
commit
6861c10183
4 changed files with 143 additions and 81 deletions
  1. 45 37
      script/bump-version.py
  2. 29 0
      script/get-last-major-for-master.js
  3. 65 0
      script/lib/util.py
  4. 4 44
      script/prepare-release.js

+ 45 - 37
script/bump-version.py

@@ -5,12 +5,12 @@ import re
 import sys
 import argparse
 
-from lib.util import execute, get_electron_version, parse_version, scoped_cwd
-
+from lib.util import execute, get_electron_version, parse_version, scoped_cwd, \
+is_nightly, is_beta, is_stable, get_next_nightly, get_next_beta, \
+get_next_stable_from_pre, get_next_stable_from_stable, clean_parse_version
 
 SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
 
-
 def main():
 
   parser = argparse.ArgumentParser(
@@ -34,14 +34,7 @@ def main():
     action='store',
     default=None,
     dest='bump',
-    help='increment [major | minor | patch | beta]'
-  )
-  parser.add_argument(
-    '--stable',
-    action='store_true',
-    default= False,
-    dest='stable',
-    help='promote to stable (i.e. remove `-beta.x` suffix)'
+    help='increment [stable | beta | nightly]'
   )
   parser.add_argument(
     '--dry-run',
@@ -52,43 +45,55 @@ def main():
   )
 
   args = parser.parse_args()
+  curr_version = get_electron_version()
+
+  if args.bump not in ['stable', 'beta', 'nightly']:
+    raise Exception('bump must be set to either stable, beta or nightly')
+
+  if is_nightly(curr_version):
+    if args.bump == 'nightly':
+      version = get_next_nightly(curr_version)
+    elif args.bump == 'beta':
+      version = get_next_beta(curr_version)
+    elif args.bump == 'stable':
+      version = get_next_stable_from_pre(curr_version)
+    else:
+      not_reached()
+  elif is_beta(curr_version):
+    if args.bump == 'nightly':
+      version = get_next_nightly(curr_version)
+    elif args.bump == 'beta':
+      version = get_next_beta(curr_version)
+    elif args.bump == 'stable':
+      version = get_next_stable_from_pre(curr_version)
+    else:
+      not_reached()
+  elif is_stable(curr_version):
+    if args.bump == 'nightly':
+      version = get_next_nightly(curr_version)
+    elif args.bump == 'beta':
+      raise Exception("You can\'t bump to a beta from stable")
+    elif args.bump == 'stable':
+      version = get_next_stable_from_stable(curr_version)
+    else:
+      not_reached()
+  else:
+    raise Exception("Invalid current version: " + curr_version)
 
   if args.new_version == None and args.bump == None and args.stable == False:
     parser.print_help()
     return 1
 
-  increments = ['major', 'minor', 'patch', 'beta']
-
-  curr_version = get_electron_version()
-  versions = parse_version(re.sub('-beta', '', curr_version))
-
-  if args.bump in increments:
-    versions = increase_version(versions, increments.index(args.bump))
-    if versions[3] == '0':
-      # beta starts at 1
-      versions = increase_version(versions, increments.index('beta'))
-
-  if args.stable == True:
-    versions[3] = '0'
-
-  if args.new_version != None:
-    clean_version = re.sub('-beta', '', args.new_version)
-    clean_version = re.sub('-nightly', '', clean_version)
-    versions = parse_version(clean_version)
-
-  version = '.'.join(versions[:3])
+  versions = clean_parse_version(version)
   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 '-' in version:
+    suffix = '-' + version.split('-')[1]
+  version = version.split('-')[0]
 
   if args.dry_run:
     print 'new version number would be: {0}\n'.format(version + suffix)
     return 0
 
-
   with scoped_cwd(SOURCE_ROOT):
     update_electron_gyp(version, suffix)
     update_win_rc(version, versions)
@@ -99,6 +104,9 @@ def main():
 
   print 'Bumped to version: {0}'.format(version + suffix)
 
+def not_reached():
+  raise Exception('Unreachable code was reached')
+
 def increase_version(versions, index):
   for i in range(index + 1, 4):
     versions[i] = '0'

+ 29 - 0
script/get-last-major-for-master.js

@@ -0,0 +1,29 @@
+const { GitProcess } = require('dugite')
+const path = require('path')
+const semver = require('semver')
+const gitDir = path.resolve(__dirname, '..')
+
+async function determineNextMajorForMaster () {
+  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)
+}
+
+determineNextMajorForMaster().then(console.info).catch((err) => {
+  console.error(err)
+  process.exit(1)
+})

+ 65 - 0
script/lib/util.py

@@ -2,6 +2,7 @@
 
 import atexit
 import contextlib
+import datetime
 import errno
 import platform
 import re
@@ -293,3 +294,67 @@ def update_node_modules(dirname, env=None):
         pass
     else:
       execute_stdout(args, env)
+
+def clean_parse_version(v):
+  return parse_version(v.split("-")[0])        
+
+def is_stable(v):
+  return len(v.split(".")) == 3    
+
+def is_beta(v):
+  return 'beta' in v
+
+def is_nightly(v):
+  return 'nightly' in v
+
+def get_nightly_date():
+  return datetime.datetime.today().strftime('%Y%m%d')
+
+def get_last_major():
+  return execute(['node', 'script/get-last-major-for-master.js'])
+
+def get_next_nightly(v):
+  pv = clean_parse_version(v)
+  major = pv[0]; minor = pv[1]; patch = pv[2]
+
+  if (is_stable(v)):
+    patch = str(int(pv[2]) + 1)
+
+  if execute(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) == "master":
+    major = str(get_last_major() + 1)
+    minor = '0'
+    patch = '0'
+
+  pre = 'nightly.' + get_nightly_date()
+  return make_version(major, minor, patch, pre)
+
+def non_empty(thing):
+  return thing.strip() != ''
+
+def get_next_beta(v):
+  pv = clean_parse_version(v)
+  tag_pattern = 'v' + pv[0] + '.' + pv[1] + '.' + pv[2] + '-beta.*'
+  tag_list = filter(
+    non_empty,
+    execute(['git', 'tag', '--list', '-l', tag_pattern]).strip().split('\n')
+  )
+  if len(tag_list) == 0:
+    return make_version(pv[0] , pv[1],  pv[2], 'beta.1')
+
+  lv = parse_version(tag_list[-1])
+  return make_version(lv[0] , lv[1],  lv[2], str(int(lv[3]) + 1))
+
+def get_next_stable_from_pre(v):
+  pv = clean_parse_version(v)
+  major = pv[0]; minor = pv[1]; patch = pv[2]
+  return make_version(major, minor, patch)
+
+def get_next_stable_from_stable(v):
+  pv = clean_parse_version(v)
+  major = pv[0]; minor = pv[1]; patch = pv[2]
+  return make_version(major, minor, str(int(patch) + 1))
+
+def make_version(major, minor, patch, pre = None):
+  if pre is None:
+    return major + '.' + minor + '.' + patch
+  return major + "." + minor + "." + patch + '-' + pre

+ 4 - 44
script/prepare-release.js

@@ -14,7 +14,6 @@ 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]
 const targetRepo = versionType === 'nightly' ? 'nightlies' : 'electron'
 
@@ -22,7 +21,7 @@ const targetRepo = versionType === 'nightly' ? 'nightlies' : 'electron'
 // via conventional-recommended-bump
 
 if (!versionType && !args.notesOnly) {
-  console.log(`Usage: prepare-release versionType [major | minor | patch | beta | nightly]` +
+  console.log(`Usage: prepare-release versionType [stable | beta | nightly]` +
      ` (--stable) (--notesOnly) (--automaticRelease) (--branch)`)
   process.exit(1)
 }
@@ -35,9 +34,7 @@ async function getNewVersion (dryRun) {
   console.log(`Bumping for new "${versionType}" version.`)
   let bumpScript = path.join(__dirname, 'bump-version.py')
   let scriptArgs = [bumpScript]
-  if (versionType === 'nightly') {
-    scriptArgs.push(`--version ${await determineNextNightly(await getCurrentBranch())}`)
-  } else {
+  if (args.bump) {
     scriptArgs.push(`--bump ${versionType}`)
   }
   if (args.stable) {
@@ -60,43 +57,6 @@ async function getNewVersion (dryRun) {
   }
 }
 
-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']
@@ -205,7 +165,7 @@ async function createRelease (branchToTarget, isBeta) {
   githubOpts.draft = true
   githubOpts.name = `electron ${newVersion}`
   if (isBeta) {
-    if (versionType === 'nightly') {
+    if (newVersion.indexOf('nightly') > 0) {
       githubOpts.body = `Note: This is a nightly release.  Please file new issues ` +
         `for any bugs you find in it.\n \n This release is published to npm ` +
         `under the nightly tag and can be installed via npm install electron@nightly, ` +
@@ -293,7 +253,7 @@ async function promptForVersion (version) {
 
 async function prepareRelease (isBeta, notesOnly) {
   if (args.automaticRelease && (pkg.version.indexOf('beta') === -1 ||
-      versionType !== 'beta') && versionType !== 'nightly') {
+      versionType !== 'beta') && versionType !== 'nightly' && versionType !== 'stable') {
     console.log(`${fail} Automatic release is only supported for beta and nightly releases`)
     process.exit(1)
   }