Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breaking: separate releases into "generate" and "publish" phase #27

Merged
merged 5 commits into from
Oct 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var ReleaseOps = require("../lib/release-ops");

/*
* Usage:
* $ eslint-prerelease beta
* $ eslint-generate-prerelease beta
*/
var args = process.argv.slice(2),
prereleaseId = (args.length ? args[0] : null);
Expand All @@ -32,5 +32,4 @@ if (!prereleaseId) {
process.exit(1); // eslint-disable-line no-process-exit
}

var releaseInfo = ReleaseOps.release(prereleaseId);
ReleaseOps.publishReleaseToGitHub(releaseInfo);
ReleaseOps.generateRelease(prereleaseId);
7 changes: 3 additions & 4 deletions bin/eslint-ci-release.js → bin/eslint-generate-release.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env node

/**
* @fileoverview Main CLI that is run via the eslint-ci-release command.
* @fileoverview Main CLI that is run via the eslint-generate-release command.
* @author Nicholas C. Zakas
* @copyright jQuery Foundation and other contributors, https://jquery.org/
* MIT License
Expand All @@ -21,8 +21,7 @@ var ReleaseOps = require("../lib/release-ops");

/*
* Usage:
* $ eslint-ci-release
* $ eslint-generate-release
*/

var releaseInfo = ReleaseOps.release(null, true);
ReleaseOps.publishReleaseToGitHub(releaseInfo);
ReleaseOps.generateRelease();
29 changes: 0 additions & 29 deletions bin/eslint-gh-release.js

This file was deleted.

4 changes: 2 additions & 2 deletions bin/eslint-release.js → bin/eslint-publish-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var ReleaseOps = require("../lib/release-ops");

/*
* Usage:
* $ eslint-release
* $ eslint-publish-release
*/

ReleaseOps.release();
ReleaseOps.publishRelease();
201 changes: 56 additions & 145 deletions lib/release-ops.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ var fs = require("fs"),
shelljs = require("shelljs"),
semver = require("semver"),
GitHub = require("github-api"),
// checker = require("npm-license"),
dateformat = require("dateformat"),
ShellOps = require("./shell-ops");

Expand All @@ -40,11 +39,10 @@ function getPackageInfo() {

/**
* Run before a release to validate that the project is setup correctly.
* @param {boolean} [ciRelease] Set to true to indicate this is a CI release.
* @returns {void}
* @private
*/
function validateSetup(ciRelease) {
function validateSetup() {
if (!shelljs.test("-f", "package.json")) {
console.error("Missing package.json file");
ShellOps.exit(1);
Expand All @@ -56,23 +54,24 @@ function validateSetup(ciRelease) {
ShellOps.exit(1);
}

// special checks for CI release
if (ciRelease) {
// check repository field
if (!pkg.repository) {
console.error("Missing 'repository' in package.json");
ShellOps.exit(1);
} else if (!/^[\w\-]+\/[\w\-]+$/.test(pkg.repository)) {
console.error("The 'repository' field must be in the format 'foo/bar' in package.json");
ShellOps.exit(1);
}

// check repository field
if (!pkg.repository) {
console.error("Missing 'repository' in package.json");
ShellOps.exit(1);
} else if (!/^[\w\-]+\/[\w\-]+$/.test(pkg.repository)) {
console.error("The 'repository' field must be in the format 'foo/bar' in package.json");
ShellOps.exit(1);
}
// check NPM_TOKEN
if (!process.env.NPM_TOKEN) {
console.error("Missing NPM_TOKEN environment variable");
ShellOps.exit(1);
}

// check NPM_TOKEN
if (!process.env.NPM_TOKEN) {
console.error("Missing NPM_TOKEN environment variable");
ShellOps.exit(1);
}
if (!process.env.ESLINT_GITHUB_TOKEN) {
console.error("Missing ESLINT_GITHUB_TOKEN environment variable");
ShellOps.exit(1);
}
}

Expand Down Expand Up @@ -111,63 +110,6 @@ function getVersionTags() {
}, []).sort(semver.compare);
}

// TODO: Make this async
/**
* Validates the licenses of all dependencies are valid open source licenses.
* @returns {void}
* @private
*/
// function checkLicenses() {

// /**
// * Check if a dependency is eligible to be used by us
// * @param {object} dependency dependency to check
// * @returns {boolean} true if we have permission
// * @private
// */
// function isPermissible(dependency) {
// var licenses = dependency.licenses;

// if (Array.isArray(licenses)) {
// return licenses.some(function(license) {
// return isPermissible({
// name: dependency.name,
// licenses: license
// });
// });
// }

// return OPEN_SOURCE_LICENSES.some(function(license) {
// return license.test(licenses);
// });
// }

// console.log("Validating licenses");

// checker.init({
// start: process.cwd()
// }, function(deps) {
// var impermissible = Object.keys(deps).map(function(dependency) {
// return {
// name: dependency,
// licenses: deps[dependency].licenses
// };
// }).filter(function(dependency) {
// return !isPermissible(dependency);
// });

// if (impermissible.length) {
// impermissible.forEach(function(dependency) {
// console.error("%s license for %s is impermissible.",
// dependency.licenses,
// dependency.name
// );
// });
// ShellOps.exit(1);
// }
// });
// }

/**
* Extracts data from a commit log in the format --pretty=format:"* %h %s (%an)\n%b".
* @param {string[]} logs Output from git log command.
Expand Down Expand Up @@ -345,28 +287,11 @@ function writeChangelog(releaseInfo) {
* Creates a release version tag and pushes to origin and npm.
* @param {string} [prereleaseId] The prerelease ID (alpha, beta, rc, etc.).
* Only include when doing a prerelease.
* @param {boolean} [ciRelease] Indicates that the release is being done by the
* CI and so shouldn't push back to Git (this will be handled by CI itself).
* @returns {Object} The information about the release.
*/
function release(prereleaseId, ciRelease) {
function generateRelease(prereleaseId) {

validateSetup(ciRelease);

// CI release doesn't need to clear node_modules because it installs clean
if (!ciRelease) {
console.log("Updating dependencies (this may take a while)");
shelljs.rm("-rf", "node_modules");
ShellOps.execSilent("npm install --silent");
}

// necessary so later "npm install" will install the same versions
// console.log("Shrinkwrapping dependencies");
// ShellOps.execSilent("npm shrinkwrap");

// TODO: Make this work
// console.log("Checking licenses");
// checkLicenses();
validateSetup();

console.log("Running tests");
ShellOps.execSilent("npm test");
Expand All @@ -379,20 +304,13 @@ function release(prereleaseId, ciRelease) {
console.log("Generating changelog");
writeChangelog(releaseInfo);

// console.log("Updating bundled dependencies");
// ShellOps.exec("bundle-dependencies update");

console.log("Committing to git");
ShellOps.exec("git add CHANGELOG.md");
ShellOps.exec("git commit -m \"Build: changelog update for " + releaseInfo.version + "\"");

console.log("Generating %s", releaseInfo.version);
ShellOps.execSilent("npm version " + releaseInfo.version);

// push all the things
console.log("Publishing to git");
ShellOps.exec("git push origin master --tags");

console.log("Fixing line endings");
getPackageInfo().files.filter(function(dirPath) {
return fs.lstatSync(dirPath).isDirectory();
Expand All @@ -402,42 +320,10 @@ function release(prereleaseId, ciRelease) {
}
});

// NOTE: eslint-release dependencies are no longer available starting here

// console.log("Fixing dependencies for bundle");
// shelljs.rm("-rf", "node_modules");
// ShellOps.execSilent("npm install --production");

if (ciRelease) {

// CI release needs a .npmrc file to work properly - token is read from environment
console.log("Writing .npmrc file");
fs.writeFileSync(".npmrc", "//registry.npmjs.org/:_authToken=${NPM_TOKEN}");
}

// if there's a prerelease ID, publish under "next" tag
console.log("Publishing to npm");
if (prereleaseId) {
ShellOps.exec("npm publish --tag next");
} else {
ShellOps.exec("npm publish");
}

// undo any differences
if (!ciRelease) {
ShellOps.exec("git reset");
ShellOps.exec("git clean -f");
}

// restore development environment
// ShellOps.exec("npm install");

// NOTE: eslint-release dependencies are once again available after here

// delete shrinkwrap file
// shelljs.rm("npm-shrinkwrap.json");

return releaseInfo;
// Release needs a .npmrc file to work properly - token is read from environment
console.log("Writing .npmrc file");
fs.writeFileSync(".npmrc", "//registry.npmjs.org/:_authToken=${NPM_TOKEN}");
fs.writeFileSync(".eslint-release-info.json", JSON.stringify(releaseInfo, null, 4));
}

/**
Expand All @@ -448,11 +334,6 @@ function release(prereleaseId, ciRelease) {
*/
function publishReleaseToGitHub(releaseInfo) {

if (!process.env.ESLINT_GITHUB_TOKEN) {
console.error("Missing ESLINT_GITHUB_TOKEN environment variable");
ShellOps.exit(1);
}

var repoParts = releaseInfo.repository.split("/"),
gh = new GitHub({ token: process.env.ESLINT_GITHUB_TOKEN }),
repo = gh.getRepo(repoParts[0], repoParts[1]),
Expand All @@ -473,15 +354,45 @@ function publishReleaseToGitHub(releaseInfo) {

}

/**
* Push the commit and git tags, publish to npm, and publish a changelog to GitHub release notes.
* @returns {Object} the information about the release.
*/
function publishRelease() {
validateSetup();
var releaseInfo = JSON.parse(fs.readFileSync(".eslint-release-info.json", "utf8"));

// if there's a prerelease ID, publish under "next" tag
console.log("Publishing to npm");

var command = "npm publish";
if (semver.prerelease(releaseInfo.version)) {
command += " --tag next";
}

if (process.env.NPM_OTP && /^\d+$/.test(process.env.NPM_OTP)) {
command += "--otp=" + process.env.NPM_OTP;
}

ShellOps.exec(command);

console.log("Publishing to git");
ShellOps.exec("git push origin master --tags");

publishReleaseToGitHub(releaseInfo);

return releaseInfo;
}

//------------------------------------------------------------------------------
// Public API
//------------------------------------------------------------------------------

module.exports = {
getPrereleaseVersion: getPrereleaseVersion,
release: release,
generateRelease: generateRelease,
publishRelease: publishRelease,
calculateReleaseInfo: calculateReleaseInfo,
calculateReleaseFromGitLogs: calculateReleaseFromGitLogs,
writeChangelog: writeChangelog,
publishReleaseToGitHub: publishReleaseToGitHub
writeChangelog: writeChangelog
};
1 change: 1 addition & 0 deletions lib/shell-ops.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ module.exports = {
* @private
*/
exec: function(cmd) {
console.log("+ " + cmd);
var result = this.execSilent(cmd);
console.log(result);
},
Expand Down