Skip to content

Commit

Permalink
[BUGFIX] Centralize build versioning info
Browse files Browse the repository at this point in the history
Make BUILD_TYPE only affect published buildType if on master so we don't
accidentally publish from lts/release branches over the current beta or
release.

Only use a tag as version if it is parseable by semver.

The build-for-publishing script uses git info instead of travis env.
  • Loading branch information
krisselden committed Jul 14, 2018
1 parent 14cb285 commit bd0e1a3
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 53 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Expand Up @@ -139,6 +139,7 @@ module.exports = {
// matches node-land files that aren't shipped to consumers (allows using Node 6+ features)
files: [
'broccoli/**/*.js',
'tests/node/**/*.js',
'ember-cli-build.js',
'rollup.config.js',
'd8-runner.js',
Expand Down
18 changes: 10 additions & 8 deletions bin/build-for-publishing.js
Expand Up @@ -4,7 +4,7 @@
const fs = require('fs');
const path = require('path');
const execa = require('execa');
const VERSION = require('../broccoli/version').VERSION;
const buildInfo = require('../broccoli/build-info').buildInfo();

function exec(command, args) {
// eslint-disable-next-line
Expand All @@ -23,9 +23,11 @@ function updatePackageJSONVersion() {

let pkgContents = fs.readFileSync(packageJSONPath, { encoding: 'utf-8' });
let pkg = JSON.parse(pkgContents);
if (!pkg._originalVersion) {
pkg._originalVersion = pkg.version;
}
pkg._versionPreviouslyCalculated = true;
pkg._originalVersion = pkg.version;
pkg.version = VERSION;
pkg.version = buildInfo.version;
fs.writeFileSync(packageJSONPath, JSON.stringify(pkg, null, 2), {
encoding: 'utf-8',
});
Expand All @@ -44,7 +46,7 @@ function updateDocumentationVersion() {

let contents = fs.readFileSync(docsPath, { encoding: 'utf-8' });
let docs = JSON.parse(contents);
docs.project.version = VERSION;
docs.project.version = buildInfo.version;
fs.writeFileSync(docsPath, JSON.stringify(docs, null, 2), {
encoding: 'utf-8',
});
Expand All @@ -69,10 +71,10 @@ Promise.resolve()
.then(() => {
// generate build-metadata.json
const metadata = {
version: VERSION,
buildType: process.env.BUILD_TYPE,
SHA: process.env.TRAVIS_COMMIT,
assetPath: `/${process.env.BUILD_TYPE}/shas/${process.env.TRAVIS_COMMIT}.tgz`,
version: buildInfo.version,
buildType: buildInfo.channel,
SHA: buildInfo.sha,
assetPath: `/${buildInfo.channel}/shas/${buildInfo.sha}.tgz`,
};
fs.writeFileSync('build-metadata.json', JSON.stringify(metadata, null, 2), {
encoding: 'utf-8',
Expand Down
20 changes: 8 additions & 12 deletions bin/publish_to_s3.js
@@ -1,3 +1,7 @@
'use strict';

const buildInfo = require('../broccoli/build-info').buildInfo();

// To invoke this from the commandline you need the following to env vars to exist:
//
// S3_BUCKET_NAME
Expand All @@ -12,21 +16,13 @@
// ```sh
// ./bin/publish_to_s3.js
// ```
var S3Publisher = require('ember-publisher');
var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js');
const S3Publisher = require('ember-publisher');
const configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js');

var publisher = new S3Publisher({ projectConfigPath: configPath });
let publisher = new S3Publisher({ projectConfigPath: configPath });

publisher.currentBranch = function() {
return (
process.env.BUILD_TYPE ||
{
master: 'canary',
beta: 'beta',
release: 'release',
'lts-2-4': 'lts-2-4',
}[this.CURRENT_BRANCH]
);
return buildInfo.channel;
};

publisher.publish();
162 changes: 162 additions & 0 deletions broccoli/build-info.js
@@ -0,0 +1,162 @@
'use strict';
const fs = require('fs');
const path = require('path');
const gitRepoInfo = require('git-repo-info');
const semver = require('semver');

const NON_SEMVER_IDENTIFIER = /[^0-9A-Za-z-]/g;

/** @type {BuildInfo} */
let cached;

/**
* @param {Options=} options
* @returns {BuildInfo}
*/
function buildInfo(options) {
if (!options && cached) {
return cached;
}
let root = (options && options.root) || path.resolve(__dirname, '..');
let packageVersion = (options && options.packageVersion) || readPackageVersion(root);
let gitInfo = (options && options.gitInfo) || buildGitInfo(root);
let buildInfo = buildFromParts(packageVersion, gitInfo);
if (!options) {
cached = buildInfo;
}
return buildInfo;
}

/**
* @param {string} root
* @returns {GitInfo}
*/
function buildGitInfo(root) {
let info = gitRepoInfo(root);
return {
sha: process.env.TRAVIS_COMMIT || info.sha,
branch: process.env.TRAVIS_BRANCH || info.branch,
tag: process.env.TRAVIS_TAG || info.tag,
};
}

/**
* @typedef {Object} GitInfo
* @property {string} sha
* @property {string=} branch
* @property {string=} tag
*/

/**
* @typedef {Object} Options
* @property {string=} root
* @property {string=} packageVersion
* @property {GitInfo=} gitInfo
*/

/**
* @typedef {Object} BuildInfo
* @property {string=} tag
* @property {string=} branch
* @property {string} sha
* @property {string} shortSha
* @property {string=} channel
* @property {string} packageVersion
* @property {string=} tagVersion
* @property {string} version
*/

/**
* Build info object from parts.
* @param {string} packageVersion
* @param {GitInfo} gitInfo
* @returns {BuildInfo}
*/
function buildFromParts(packageVersion, gitInfo) {
// Travis builds are always detached
let { tag, branch, sha } = gitInfo;

let tagVersion = parseTagVersion(tag);
let shortSha = sha.slice(0, 8);
let channel =
branch === 'master'
? process.env.BUILD_TYPE === 'alpha' ? 'alpha' : 'canary'
: branch && escapeSemVerIdentifier(branch);
let version = tagVersion || buildVersion(packageVersion, shortSha, channel);

return {
tag,
branch,
sha,
shortSha,
channel,
packageVersion,
tagVersion,
version,
};
}

/**
* Read package version.
* @param {string} root
* @returns {string}
*/
function readPackageVersion(root) {
let pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
// use _originalVersion if present if we've already mutated it
return pkg._originalVersion || pkg.version;
}

/**
* @param {string} tag
*/
function parseTagVersion(tag) {
try {
return tag && semver.parse(tag).version;
} catch (e) {
return;
}
}

/**
* @param {string} txt
*/
function escapeSemVerIdentifier(txt) {
return txt.replace(NON_SEMVER_IDENTIFIER, '-');
}

/**
* @param {string} packageVersion
* @param {string} sha
* @param {string=} channel
*/
function buildVersion(packageVersion, sha, channel) {
let base = semver.parse(packageVersion);
let major = base.major;
let minor = base.minor;
let patch = base.patch;
let suffix = '';
suffix += toSuffix('-', base.prerelease, channel);
suffix += toSuffix('+', base.build, sha);
return `${major}.${minor}.${patch}${suffix}`;
}

/**
* @param {string} delim
* @param {string[]} identifiers
* @param {string=} identifier
*/
function toSuffix(delim, identifiers, identifier) {
if (identifier) {
identifiers = identifiers.concat([identifier]);
}
if (identifiers.length > 0) {
return delim + identifiers.join('.');
}
return '';
}

module.exports.buildInfo = buildInfo;
module.exports.buildFromParts = buildFromParts;
module.exports.buildVersion = buildVersion;
module.exports.parseTagVersion = parseTagVersion;
35 changes: 2 additions & 33 deletions broccoli/version.js
@@ -1,36 +1,5 @@
'use strict';

const getGitInfo = require('git-repo-info');
const path = require('path');
const buildInfo = require('../broccoli/build-info').buildInfo();

module.exports.VERSION = (() => {
let info = getGitInfo(path.resolve(__dirname, '..'));
// if the current commit _is_ a tagged commit, use the tag as the version
// number
if (info.tag) {
return info.tag.replace(/^v/, '');
}

let pkg = require('../package');
// if `_versionPreviouslyCalculated` is set the `package.json` version string
// _already_ includes the branch, sha, etc (from bin/build-for-publishing.js)
// so just use it directly
if (pkg._versionPreviouslyCalculated) {
return pkg.version;
}

// otherwise build the version number up of:
//
// * actual package.json version string
// * current "build type" or branch name (in CI this is generally not
// present, but it is very useful for local / testing builds)
// * the sha for the commit
let packageVersion = pkg.version;
let sha = info.sha || '';
let suffix = process.env.BUILD_TYPE || info.branch;
// * remove illegal non-alphanumeric characters from branch name.
suffix = suffix && suffix.replace(/[^a-zA-Z\d\s-]/g, '-');
let metadata = sha.slice(0, 8);

return `${packageVersion}${suffix ? '-' + suffix : ''}+${metadata}`;
})();
module.exports.VERSION = buildInfo.version;

0 comments on commit bd0e1a3

Please sign in to comment.