From 1b8c11121f5927ebcb858992aaa0cf6bfacc090b Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 6 Dec 2018 11:00:10 -0800 Subject: [PATCH] chore: convert bump script to js (#15820) --- package-lock.json | 29 +++- package.json | 3 +- script/bump-version.js | 184 +++++++++++++++++++++++ script/bump-version.py | 219 ---------------------------- script/get-last-major-for-master.js | 12 +- script/lib/util.py | 79 ---------- script/lib/version-utils.js | 73 ++++++++++ script/prepare-release.js | 20 ++- script/upload.py | 2 +- spec/version-bump-spec.js | 80 ++++++++++ 10 files changed, 378 insertions(+), 323 deletions(-) create mode 100644 script/bump-version.js delete mode 100755 script/bump-version.py create mode 100644 script/lib/version-utils.js create mode 100644 spec/version-bump-spec.js diff --git a/package-lock.json b/package-lock.json index a17ccea67660..4965377ba6bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7972,6 +7972,17 @@ "find-up": "^1.0.0" } }, + "plist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", + "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", + "dev": true, + "requires": { + "base64-js": "^1.2.3", + "xmlbuilder": "^9.0.7", + "xmldom": "0.1.x" + } + }, "plur": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", @@ -9419,9 +9430,9 @@ "optional": true }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "dev": true }, "semver-diff": { @@ -12132,6 +12143,18 @@ "dev": true, "optional": true }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmldom": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", + "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", + "dev": true + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/package.json b/package.json index 2d164d8cafab..5da03af9d324 100644 --- a/package.json +++ b/package.json @@ -26,11 +26,12 @@ "node-fetch": "^2.1.2", "nugget": "^2.0.1", "octicons": "^7.3.0", + "plist": "^3.0.1", "recursive-readdir": "^2.2.2", "remark-cli": "^4.0.0", "remark-preset-lint-markdown-style-guide": "^2.1.1", "request": "^2.88.0", - "semver": "^5.5.0", + "semver": "^5.6.0", "serve": "^6.5.8", "standard-markdown": "^5.0.0", "sumchecker": "^2.0.2", diff --git a/script/bump-version.js b/script/bump-version.js new file mode 100644 index 000000000000..d7e66a509818 --- /dev/null +++ b/script/bump-version.js @@ -0,0 +1,184 @@ +#!/usr/bin/env node + +const { GitProcess } = require('dugite') +const utils = require('./lib/version-utils') +const plist = require('plist') +const fs = require('fs') +const semver = require('semver') +const path = require('path') +const { promisify } = require('util') +const minimist = require('minimist') + +const writeFile = promisify(fs.writeFile) +const readFile = promisify(fs.readFile) + +function parseCommandLine () { + let help + const opts = minimist(process.argv.slice(2), { + string: [ 'bump', 'version' ], + boolean: [ 'dryRun', 'help' ], + alias: { 'version': ['v'] }, + unknown: arg => { help = true } + }) + if (help || opts.help || !opts.bump) { + console.log(` + Bump release version number. Possible arguments:\n + --bump=patch to increment patch version\n + --version={version} to set version number directly\n + --dryRun to print the next version without updating files + Note that you can use both --bump and --stable simultaneously. + `) + process.exit(0) + } + return opts +} + +// run the script +async function main () { + const opts = parseCommandLine() + const currentVersion = await utils.getElectronVersion() + const version = await nextVersion(opts.bump, currentVersion) + + const parsed = semver.parse(version) + const components = { + major: parsed.major, + minor: parsed.minor, + patch: parsed.patch, + pre: parsed.prerelease + } + + // print would-be new version and exit early + if (opts.dryRun) { + console.log(`new version number would be: ${version}\n`) + return 0 + } + + // update all version-related files + await Promise.all([ + updateVersion(version), + updateInfoPlist(version), + updatePackageJSON(version), + updateVersionH(components), + updateWinRC(components) + ]) + + // commit all updated version-related files + await commitVersionBump(version) + + console.log(`Bumped to version: ${version}`) +} + +// get next version for release based on [nightly, beta, stable] +async function nextVersion (bumpType, version) { + if (utils.isNightly(version) || utils.isBeta(version)) { + switch (bumpType) { + case 'nightly': + version = await utils.nextNightly(version) + break + case 'beta': + version = await utils.nextBeta(version) + break + case 'stable': + version = semver.valid(semver.coerce(version)) + break + default: + throw new Error('Invalid bump type.') + } + } else if (utils.isStable(version)) { + switch (bumpType) { + case 'nightly': + version = utils.nextNightly(version) + break + case 'beta': + throw new Error('Cannot bump to beta from stable.') + case 'stable': + version = semver.inc(version, 'patch') + break + default: + throw new Error('Invalid bump type.') + } + } else { + throw new Error(`Invalid current version: ${version}`) + } + return version +} + +// update VERSION file with latest release info +async function updateVersion (version) { + const versionPath = path.resolve(__dirname, '..', 'VERSION') + await writeFile(versionPath, version, 'utf8') +} + +// update package metadata files with new version +async function updatePackageJSON (version) { + ['package.json', 'package-lock.json'].forEach(async fileName => { + const filePath = path.resolve(__dirname, '..', fileName) + const file = require(filePath) + file.version = version + await writeFile(filePath, JSON.stringify(file, null, 2)) + }) +} + +// update CFBundle version information and overwrite pre-existing file +// TODO(codebytere): provide these version fields at GN build time +async function updateInfoPlist (version) { + const filePath = path.resolve(__dirname, '..', 'atom', 'browser', 'resources', 'mac', 'Info.plist') + const file = plist.parse(await readFile(filePath, { encoding: 'utf8' })) + + file.CFBundleVersion = version + file.CFBundleShortVersionString = version + + await writeFile(filePath, plist.build(file)) +} + +// push bump commit to release branch +async function commitVersionBump (version) { + const gitDir = path.resolve(__dirname, '..') + const gitArgs = ['commit', '-a', '-m', `Bump v${version}`, '-n'] + await GitProcess.exec(gitArgs, gitDir) +} + +// updates atom_version.h file with new semver values +// TODO(codebytere): auto-generate this +async function updateVersionH (components) { + const filePath = path.resolve(__dirname, '..', 'atom', 'common', 'atom_version.h') + const data = await readFile(filePath, 'utf8') + const arr = data.split('\n') + const pre = components.pre != null ? `-${components.pre[0]}.${components.pre[1]}` : null + + arr.forEach((item, idx) => { + if (item.includes('#define ATOM_MAJOR_VERSION')) { + arr[idx] = `#define ATOM_MAJOR_VERSION ${components.major}` + arr[idx + 1] = `#define ATOM_MINOR_VERSION ${components.minor}` + arr[idx + 2] = `#define ATOM_PATCH_VERSION ${components.patch}` + arr[idx + 4] = pre ? `#define ATOM_PRE_RELEASE_VERSION ${pre}` : '// #define ATOM_PRE_RELEASE_VERSION' + } + }) + await writeFile(filePath, arr.join('\n')) +} + +// updates atom.rc file with new semver values +async function updateWinRC (components) { + const filePath = path.resolve(__dirname, '..', 'atom', 'browser', 'resources', 'win', 'atom.rc') + const data = await readFile(filePath, 'utf8') + const arr = data.split('\n') + arr.forEach((line, idx) => { + if (line.includes('FILEVERSION')) { + arr[idx] = ` FILEVERSION ${utils.makeVersion(components, ',', true)}` + arr[idx + 1] = ` PRODUCTVERSION ${utils.makeVersion(components, ',', true)}` + } else if (line.includes('FileVersion')) { + arr[idx] = ` VALUE "FileVersion", "${utils.makeVersion(components, '.')}"` + arr[idx + 5] = ` VALUE "ProductVersion", "${utils.makeVersion(components, '.')}"` + } + }) + await writeFile(filePath, arr.join('\n')) +} + +if (process.mainModule === module) { + main().catch((error) => { + console.error(error) + process.exit(1) + }) +} + +module.exports = { nextVersion } diff --git a/script/bump-version.py b/script/bump-version.py deleted file mode 100755 index 5268bde99034..000000000000 --- a/script/bump-version.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python - -import os -import re -import sys -import argparse - -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( - description='Bump version numbers. Must specify at least one of the three' - +' options:\n' - +' --bump=patch to increment patch version, or\n' - +' --stable to promote current beta to stable, or\n' - +' --version={version} to set version number directly\n' - +'Note that you can use both --bump and --stable ' - +'simultaneously.', - formatter_class=argparse.RawTextHelpFormatter - ) - parser.add_argument( - '--version', - default=None, - dest='new_version', - help='new version number' - ) - parser.add_argument( - '--bump', - action='store', - default=None, - dest='bump', - help='increment [stable | beta | nightly]' - ) - parser.add_argument( - '--dry-run', - action='store_true', - default= False, - dest='dry_run', - help='just to check that version number is correct' - ) - - 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': - version = get_next_beta(curr_version) - 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 is None and args.bump is None and not args.stable: - parser.print_help() - return 1 - - versions = clean_parse_version(version) - suffix = '' - if '-' in version: - suffix = '-' + version.split('-')[1] - versions[3] = parse_version(version)[3] - 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_version(version, suffix) - update_win_rc(version, versions, args.bump == "nightly") - update_version_h(versions, suffix) - update_info_plist(version) - update_package_json(version, suffix) - tag_version(version, suffix) - - 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' - versions[index] = str(int(versions[index]) + 1) - return versions - - -def update_version(version, suffix): - with open('VERSION', 'w') as f: - f.write(version + suffix) - - -def update_win_rc(version, versions, is_nightly_version): - pattern_fv = re.compile(' FILEVERSION [0-9,]+') - pattern_pv = re.compile(' PRODUCTVERSION [0-9,]+') - pattern_fvs = re.compile(' *VALUE "FileVersion", "[0-9.]+"') - pattern_pvs = re.compile(' *VALUE "ProductVersion", "[0-9.]+"') - - win_rc = os.path.join('atom', 'browser', 'resources', 'win', 'atom.rc') - with open(win_rc, 'r') as f: - lines = f.readlines() - - versions = [str(v) for v in versions] - for i in range(0, len(lines)): - line = lines[i] - if pattern_fv.match(line): - versions_64_bit = versions[::] - if is_nightly_version: - versions_64_bit[3] = '0' - lines[i] = ' FILEVERSION {0}\r\n'.format(','.join(versions_64_bit)) - elif pattern_pv.match(line): - lines[i] = ' PRODUCTVERSION {0}\r\n'.format(','.join(versions)) - elif pattern_fvs.match(line): - lines[i] = ' VALUE "FileVersion", "{0}"\r\n'.format(version) - elif pattern_pvs.match(line): - lines[i] = ' VALUE "ProductVersion", "{0}"\r\n'.format(version) - - with open(win_rc, 'w') as f: - f.write(''.join(lines)) - - -def update_version_h(versions, suffix): - version_h = os.path.join('atom', 'common', 'atom_version.h') - with open(version_h, 'r') as f: - lines = f.readlines() - - for i in range(0, len(lines)): - line = lines[i] - if 'ATOM_MAJOR_VERSION' in line: - lines[i] = '#define ATOM_MAJOR_VERSION {0}\n'.format(versions[0]) - lines[i + 1] = '#define ATOM_MINOR_VERSION {0}\n'.format(versions[1]) - lines[i + 2] = '#define ATOM_PATCH_VERSION {0}\n'.format(versions[2]) - - # We do +4 here to avoid the clang format comment - if (suffix): - lines[i + 4] = '#define ATOM_PRE_RELEASE_VERSION {0}\n'.format(suffix) - else: - lines[i + 4] = '// #define ATOM_PRE_RELEASE_VERSION\n' - - with open(version_h, 'w') as f: - f.write(''.join(lines)) - return - - -def update_info_plist(version): - info_plist = os.path.join('atom', 'browser', 'resources', 'mac', 'Info.plist') - with open(info_plist, 'r') as f: - lines = f.readlines() - - for i in range(0, len(lines)): - line = lines[i] - if 'CFBundleVersion' in line: - lines[i + 1] = ' {0}\n'.format(version) - if 'CFBundleShortVersionString' in line: - lines[i + 1] = ' {0}\n'.format(version) - - with open(info_plist, 'w') as f: - f.write(''.join(lines)) - - -def update_package_json(version, suffix): - metadata_json_files = ['package.json', 'package-lock.json'] - for json_file in metadata_json_files: - with open(json_file, 'r') as f: - lines = f.readlines() - - for i in range(0, len(lines)): - line = lines[i]; - if 'version' in line: - lines[i] = ' "version": "{0}",\n'.format(version + suffix) - break - - with open(json_file, 'w') as f: - f.write(''.join(lines)) - - -def tag_version(version, suffix): - execute([ - 'git', - 'commit', - '-a', - '-m', - 'Bump v{0}'.format(version + suffix), - '-n' - ]) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/script/get-last-major-for-master.js b/script/get-last-major-for-master.js index 3b0f20f48632..7e9cfd33910c 100644 --- a/script/get-last-major-for-master.js +++ b/script/get-last-major-for-master.js @@ -3,7 +3,7 @@ const path = require('path') const semver = require('semver') const gitDir = path.resolve(__dirname, '..') -async function determineNextMajorForMaster () { +async function getLastMajorForMaster () { let branchNames const result = await GitProcess.exec(['branch', '-a', '--remote', '--list', 'origin/[0-9]-[0-9]-x'], gitDir) if (result.exitCode === 0) { @@ -17,13 +17,7 @@ async function determineNextMajorForMaster () { 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) + return converted.reduce((v1, v2) => semver.gt(v1, v2) ? v1 : v2) } -determineNextMajorForMaster().then(console.info).catch((err) => { - console.error(err) - process.exit(1) -}) +module.exports = { getLastMajorForMaster } diff --git a/script/lib/util.py b/script/lib/util.py index 1c40efde9e19..f6d125f32794 100644 --- a/script/lib/util.py +++ b/script/lib/util.py @@ -217,85 +217,6 @@ def s3put(bucket, access_key, secret_key, prefix, key_prefix, files): def add_exec_bit(filename): os.chmod(filename, os.stat(filename).st_mode | stat.S_IEXEC) -def parse_version(version): - if version[0] == 'v': - version = version[1:] - - vs = version.split('.') - if len(vs) > 4: - return vs[0:4] - else: - return vs + ['0'] * (4 - len(vs)) - -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, minor, patch) = pv[0:3] - - 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 beta_tag_compare(tag1, tag2): - p1 = parse_version(tag1) - p2 = parse_version(tag2) - return int(p1[3]) - int(p2[3]) - -def get_next_beta(v): - pv = clean_parse_version(v) - tag_pattern = 'v' + pv[0] + '.' + pv[1] + '.' + pv[2] + '-beta.*' - tag_list = sorted(filter( - non_empty, - execute(['git', 'tag', '--list', '-l', tag_pattern]).strip().split('\n') - ), cmp=beta_tag_compare) - 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(pv[0] , pv[1], pv[2], 'beta.' + str(int(lv[3]) + 1)) - -def get_next_stable_from_pre(v): - pv = clean_parse_version(v) - (major, minor, patch) = pv[0:3] - return make_version(major, minor, patch) - -def get_next_stable_from_stable(v): - pv = clean_parse_version(v) - (major, minor, patch) = pv[0:3] - 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 - def get_out_dir(): out_dir = 'Debug' override = os.environ.get('ELECTRON_OUT_DIR') diff --git a/script/lib/version-utils.js b/script/lib/version-utils.js new file mode 100644 index 000000000000..439190ebc6cd --- /dev/null +++ b/script/lib/version-utils.js @@ -0,0 +1,73 @@ +const path = require('path') +const fs = require('fs') +const semver = require('semver') +const { getLastMajorForMaster } = require('../get-last-major-for-master') +const { GitProcess } = require('dugite') +const { promisify } = require('util') + +const readFile = promisify(fs.readFile) +const gitDir = path.resolve(__dirname, '..', '..') + +const getCurrentDate = () => { + const d = new Date() + const dd = `${d.getDate()}`.padStart(2, '0') + const mm = `${d.getMonth() + 1}`.padStart(2, '0') + const yyyy = d.getFullYear() + return `${yyyy}${mm}${dd}` +} + +const isNightly = v => v.includes('nightly') +const isBeta = v => v.includes('beta') +const isStable = v => { + const parsed = semver.parse(v) + return !!(parsed && parsed.prerelease.length === 0) +} + +const makeVersion = (components, delim, withPre = false) => { + let version = [components.major, components.minor, components.patch].join(delim) + if (withPre) { + version += `-${components.pre[0]}${delim}${components.pre[1]}` + } + return version +} + +async function nextBeta (v) { + const next = semver.coerce(semver.clean(v)) + + const tagBlob = await GitProcess.exec(['tag', '--list', '-l', `v${next}-beta.*`], gitDir) + const tags = tagBlob.stdout.split('\n').filter(e => e !== '') + tags.sort((t1, t2) => semver.gt(t1, t2)) + + // increment the latest existing beta tag or start at beta.1 if it's a new beta line + return tags.length === 0 ? semver.inc(next, 'beta', 'prerelease') : semver.inc(tags.pop(), 'prerelease') +} + +async function getElectronVersion () { + const versionPath = path.join(__dirname, '..', '..', 'VERSION') + const version = await readFile(versionPath, 'utf8') + return version.trim() +} + +async function nextNightly (v) { + let next = semver.valid(semver.coerce(v)) + const pre = `nightly.${getCurrentDate()}` + + const branch = await GitProcess.exec(['rev-parse', '--abbrev-ref', 'HEAD'], gitDir) + if (branch === 'master') { + next = semver.inc(await getLastMajorForMaster(), 'major') + } else if (isStable(v)) { + next = semver.inc(next, 'patch') + } + + return `${next}-${pre}` +} + +module.exports = { + isStable, + isBeta, + isNightly, + nextBeta, + makeVersion, + getElectronVersion, + nextNightly +} diff --git a/script/prepare-release.js b/script/prepare-release.js index 408f765fd3eb..def737430b73 100755 --- a/script/prepare-release.js +++ b/script/prepare-release.js @@ -13,8 +13,8 @@ const path = require('path') const readline = require('readline') const releaseNotesGenerator = require('./release-notes/index.js') const { getCurrentBranch } = require('./lib/utils.js') -const versionType = args._[0] -const targetRepo = versionType === 'nightly' ? 'nightlies' : 'electron' +const bumpType = args._[0] +const targetRepo = bumpType === 'nightly' ? 'nightlies' : 'electron' require('colors') const pass = '\u2713'.green @@ -23,8 +23,8 @@ const fail = '\u2717'.red // TODO (future) automatically determine version based on conventional commits // via conventional-recommended-bump -if (!versionType && !args.notesOnly) { - console.log(`Usage: prepare-release versionType [stable | beta | nightly]` + +if (!bumpType && !args.notesOnly) { + console.log(`Usage: prepare-release [stable | beta | nightly]` + ` (--stable) (--notesOnly) (--automaticRelease) (--branch)`) process.exit(1) } @@ -35,13 +35,11 @@ github.authenticate({ type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN }) async function getNewVersion (dryRun) { if (!dryRun) { - console.log(`Bumping for new "${versionType}" version.`) - } - const bumpScript = path.join(__dirname, 'bump-version.py') - const scriptArgs = [bumpScript, '--bump', versionType] - if (dryRun) { - scriptArgs.push('--dry-run') + console.log(`Bumping for new "${bumpType}" version.`) } + const bumpScript = path.join(__dirname, 'bump-version.js') + const scriptArgs = ['node', bumpScript, `--bump=${bumpType}`] + if (dryRun) scriptArgs.push('--dry-run') try { let bumpVersion = execSync(scriptArgs.join(' '), { encoding: 'UTF-8' }) bumpVersion = bumpVersion.substr(bumpVersion.indexOf(':') + 1).trim() @@ -57,7 +55,7 @@ async function getNewVersion (dryRun) { } async function getReleaseNotes (currentBranch) { - if (versionType === 'nightly') { + if (bumpType === 'nightly') { return 'Nightlies do not get release notes, please compare tags for info' } console.log(`Generating release notes for ${currentBranch}.`) diff --git a/script/upload.py b/script/upload.py index 7f5464206801..6dbdc9fccaa3 100755 --- a/script/upload.py +++ b/script/upload.py @@ -15,7 +15,7 @@ from io import StringIO from lib.config import PLATFORM, get_target_arch, get_env_var, s3_config, \ get_zip_name from lib.util import get_electron_branding, execute, get_electron_version, \ - parse_version, scoped_cwd, s3put, get_electron_exec, \ + scoped_cwd, s3put, get_electron_exec, \ get_out_dir, SRC_DIR diff --git a/spec/version-bump-spec.js b/spec/version-bump-spec.js new file mode 100644 index 000000000000..aae96e7a07fb --- /dev/null +++ b/spec/version-bump-spec.js @@ -0,0 +1,80 @@ +const { expect } = require('chai') +const { nextVersion } = require('../script/bump-version') + +describe('bump-version script', () => { + const nightlyPattern = /[0-9.]*(-nightly.(\d{4})(\d{2})(\d{2}))$/g + const betaPattern = /[0-9.]*(-beta[0-9.]*)/g + + it('bumps to nightly from stable', async () => { + const version = 'v2.0.0' + const next = await nextVersion('nightly', version) + const matches = next.match(nightlyPattern) + expect(matches).to.have.lengthOf(1) + }) + + it('bumps to nightly from beta', async () => { + const version = 'v2.0.0-beta.1' + const next = await nextVersion('nightly', version) + const matches = next.match(nightlyPattern) + expect(matches).to.have.lengthOf(1) + }) + + it('bumps to nightly from nightly', async () => { + const version = 'v2.0.0-nightly.19950901' + const next = await nextVersion('nightly', version) + const matches = next.match(nightlyPattern) + expect(matches).to.have.lengthOf(1) + }) + + it('throws error when bumping to beta from stable', () => { + const version = 'v2.0.0' + return expect( + nextVersion('beta', version) + ).to.be.rejectedWith('Cannot bump to beta from stable.') + }) + + it('bumps to beta from nightly', async () => { + const version = 'v2.0.0-nightly.19950901' + const next = await nextVersion('beta', version) + const matches = next.match(betaPattern) + expect(matches).to.have.lengthOf(1) + }) + + it('bumps to beta from beta', async () => { + const version = 'v2.0.0-beta.8' + const next = await nextVersion('beta', version) + expect(next).to.equal('2.0.0-beta.9') + }) + + it('bumps to stable from beta', async () => { + const version = 'v2.0.0-beta.1' + const next = await nextVersion('stable', version) + expect(next).to.equal('2.0.0') + }) + + it('bumps to stable from stable', async () => { + const version = 'v2.0.0' + const next = await nextVersion('stable', version) + expect(next).to.equal('2.0.1') + }) + + it('bumps to stable from nightly', async () => { + const version = 'v2.0.0-nightly.19950901' + const next = await nextVersion('stable', version) + expect(next).to.equal('2.0.0') + }) + + it('throws on an invalid version', () => { + const version = 'vI.AM.INVALID' + return expect( + nextVersion('beta', version) + ).to.be.rejectedWith(`Invalid current version: ${version}`) + }) + + it('throws on an invalid bump type', () => { + const version = 'v2.0.0' + return expect( + nextVersion('WRONG', version) + ).to.be.rejectedWith('Invalid bump type.') + }) +})