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

Improve patch release support #176

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions docs/platforms-release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,19 @@ Create and prepare your release branch by using `coho prepare-platform-release-b
3. Propagates version number from `--version` argument (or from `package.json` if there is no `--version` argument) to all other files (`VERSION` and similar [e.g. `build.gradle` for Android]) on the release branch `5.0.x`
4. Prepares `master` for future development already: It gives version (`package.json`, `VERSION` and similar) a minor bump and adds `-dev` (=> `5.1.0-dev`) again

Run the following command (make sure to replace the version below with what is listed inside `package.json`).
Run the following command (make sure to replace the version below with what is listed inside `package.json`) in case of release from the `master`:

coho prepare-platform-release-branch --version 5.0.0 -r android
coho prepare-platform-release-branch --version 7.2.0 -r android

or in case of release from another release branch:

coho prepare-platform-release-branch --version 7.1.1 -r android -b 7.1.x

Then ensure commits look okay on both branches

coho repo-status -r android -b master -b 5.0.x
coho repo-status -r android -b master -b 7.1.x

or use git tool to verify manually.

## Testing

Expand Down Expand Up @@ -355,25 +361,31 @@ Create a JIRA issue for it, and mark it as a blocker.

All good? Have another look at the changes:

coho repo-status -r android -b master -b 5.0.x
coho repo-status -r android -b master -b 7.1.x

If changes look right:

coho repo-push -r android -b master -b 5.0.x

This pushes the commits in both `master` and `5.0.x` (the release branch) to the remote.
This pushes the commits in both `master` and `7.1.x` (the release branch) to the remote.

### Tag and push tag

Before you tag, run this command:

coho tag-platform-release --version 5.0.0 -r android --pretend
coho tag-platform-release --version 7.1.0 -r android --pretend

Seems okay? Then execute it by running:

coho tag-platform-release --version 5.0.0 -r android
coho tag-platform-release --version 7.1.0 -r android

This command also tags `cordova-js` with `android-7.1.0` and pushes it.

To tag without automatic push:

coho tag-platform-release --version 7.1.0 -r android --tag-only

This command also tags `cordova-js` with `android-5.0.0` and pushes it.
and then manually push the new tags.

## Publish Release Candidate to `dist/dev`

Expand Down
4 changes: 4 additions & 0 deletions src/gitutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ exports.pendingChangesExist = function * () {
exports.gitCheckout = function * (branchName) {
var curBranch = yield gitutil.retrieveCurrentBranchName(true);
if (curBranch !== branchName) {
// EXTRA WORKAROUND SOLUTION for package.json,
// as needed for cordova-osx & Windows
// FUTURE TBD better solution for package.json?
yield executil.execHelper(executil.ARGS('git checkout -- package.json'));
return yield executil.execHelper(executil.ARGS('git checkout -q ', branchName));
}
};
Expand Down
98 changes: 68 additions & 30 deletions src/platform-release.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ function * updateCDVAvailabilityFile (version) {
fs.writeFileSync(iosFile, iosFileContents.join('\n'));
}

function * updateJsSnapshot (repo, version, commit) {
function * updateJsSnapshot (repo, version, commit, branch) {
function * ensureJsIsBuilt () {
var cordovaJsRepo = repoutil.getRepoById('js');
if (repo.id === 'blackberry') {
Expand All @@ -139,10 +139,19 @@ function * updateJsSnapshot (repo, version, commit) {
if (hasBuiltJs !== version) {
yield repoutil.forEachRepo([cordovaJsRepo], function * () {
yield gitutil.stashAndPop(cordovaJsRepo, function * () {
// git fetch and update master for cordovajs
yield repoupdate.updateRepos([cordovaJsRepo], ['master'], false);
yield gitutil.gitCheckout('master');
// git fetch and update master (or fetch other branch) for cordova-js
if (branch === 'master') {
yield repoupdate.updateRepos([cordovaJsRepo], [branch], false);
}
// EXTRA WORKAROUND SOLUTION for package.json,
// as needed for cordova-osx & Windows
// FUTURE TBD better solution for package.json?
yield executil.execHelper(executil.ARGS('git checkout -- package.json'));
yield executil.execHelper(executil.ARGS('git checkout -q ' + branch));
yield gitutil.gitCheckout(branch);
yield executil.execHelper(executil.ARGS('npm install'), false, true); // WORKAROUND PART 1 for local grunt issue in cordova-js
yield executil.execHelper(executil.ARGS('grunt compile:' + repo.id + ' --platformVersion=' + version), false, true);
shelljs.rm('-fr', 'node_modules'); // WORKAROUND PART 2 for local grunt issue in cordova-js
hasBuiltJs = version;
});
});
Expand Down Expand Up @@ -175,13 +184,16 @@ exports.createAndCopyCordovaJSCommand = function * () {
' 1. Generates a new cordova.js.\n' +
' 2. Replaces platform\'s cordova.js file.\n' +
'\n' +
'Usage: $0 copy-js -r platform')
'Usage: $0 copy-js -r platform [--js <cordova-js branch or tag name>]')
);

var repos = flagutil.computeReposFromFlag(argv.r);

var jsBranchName = argv.js ? argv.js : 'master';

yield repoutil.forEachRepo(repos, function * (repo) {
var version = yield handleVersion(repo, argv.version, false);
yield updateJsSnapshot(repo, version, false);
yield updateJsSnapshot(repo, version, false, jsBranchName);
});
};

Expand All @@ -197,64 +209,83 @@ exports.prepareReleaseBranchCommand = function * () {
'Command can also be used to update the JS snapshot after release \n' +
'branches have been created.\n' +
'\n' +
'Usage: $0 prepare-release-branch -r platform [--version=3.6.0]')
'Usage: $0 prepare-platform-release-branch -r platform [--version=3.6.0] [-b <platform branch name>] [--js <cordova-js branch or tag name>]')
);

var repos = flagutil.computeReposFromFlag(argv.r);

// XXX TBD ???:
var branchName = null;

var isOtherRepoBranch = !!argv.b;
var repoBranchName = isOtherRepoBranch ? argv.b : 'master';
var jsBranchName = argv.js ? argv.js : 'master';

// First - perform precondition checks.
yield repoupdate.updateRepos(repos, [], true);

yield repoutil.forEachRepo(repos, function * (repo) {
var platform = repo.id;
var version = yield handleVersion(repo, argv.version, true);
var branchName = versionutil.getReleaseBranchNameFromVersion(version);
var releaseBranchName = isOtherRepoBranch ? repoBranchName :
versionutil.getReleaseBranchNameFromVersion(version);

yield gitutil.stashAndPop(repo, function * () {
// git fetch + update master
yield repoupdate.updateRepos([repo], ['master'], false);
if (platform === 'ios') {
yield repoupdate.updateRepos([repo], [repoBranchName], false);

// Either create or pull down the branch.
if (yield gitutil.remoteBranchExists(repo, releaseBranchName)) {
print('Remote branch already exists for repo: ' + repo.repoName);
// Check out and rebase.
yield repoupdate.updateRepos([repo], [releaseBranchName], true);
yield gitutil.gitCheckout(releaseBranchName);
} else if (yield gitutil.localBranchExists(releaseBranchName)) {
yield executil.execHelper(executil.ARGS('git checkout ' + releaseBranchName));
} else if (isOtherRepoBranch) {
yield executil.execHelper(executil.ARGS('git checkout ' + repoBranchName));
} else {
yield gitutil.gitCheckout('master');
yield executil.execHelper(executil.ARGS('git checkout -b ' + releaseBranchName));
}

yield updateJsSnapshot(repo, version, true, jsBranchName);

if (platform === 'ios' && /\d$/.test(version)) {
// Updates version in CDVAvailability.h file
yield updateCDVAvailabilityFile(version);
// Git commit changes
if (yield gitutil.pendingChangesExist()) {
yield executil.execHelper(executil.ARGS('git commit -am', 'Added ' + version + ' to CDVAvailability.h (via coho).'));
}
}
// Either create or pull down the branch.
if (yield gitutil.remoteBranchExists(repo, branchName)) {
print('Remote branch already exists for repo: ' + repo.repoName);
// Check out and rebase.
yield repoupdate.updateRepos([repo], [branchName], true);
yield gitutil.gitCheckout(branchName);
} else if (yield gitutil.localBranchExists(branchName)) {
yield executil.execHelper(executil.ARGS('git checkout ' + branchName));
} else {
yield gitutil.gitCheckout('master');
yield executil.execHelper(executil.ARGS('git checkout -b ' + branchName));
}

yield updateJsSnapshot(repo, version, true);
print(repo.repoName + ': Setting VERSION to "' + version + '" on branch "' + branchName + '".');
print(repo.repoName + ': Setting VERSION to "' + version + '" on branch "' + releaseBranchName + '".');
yield versionutil.updateRepoVersion(repo, version);

// skip remaining steps for this repo if other repo branch was specified:
if (isOtherRepoBranch) return;

yield gitutil.gitCheckout('master');
var devVersion = createPlatformDevVersion(version);
print(repo.repoName + ': Setting VERSION to "' + devVersion + '" on branch "master".');
yield versionutil.updateRepoVersion(repo, devVersion);
yield updateJsSnapshot(repo, devVersion, true);
yield gitutil.gitCheckout(branchName);
yield updateJsSnapshot(repo, devVersion, true, jsBranchName);
yield gitutil.gitCheckout(releaseBranchName);
});
});
executil.reportGitPushResult(repos, ['master', branchName]);

// XXX TBD ???:
executil.reportGitPushResult(repos, [repoBranchName, branchName]);
};

function * tagJs (repo, version, pretend) {
function * tagJs (repo, version, pretend, tagOnly) {

function * execOrPretend (cmd) {
if (pretend) {
print('PRETENDING TO RUN: ' + cmd.join(' '));
} else if (tagOnly && cmd[1] === 'push') {
print('SKIP: ' + cmd.join(' '));
} else {
yield executil.execHelper(cmd);
}
Expand All @@ -281,23 +312,30 @@ exports.tagReleaseBranchCommand = function * (argv) {
var argv = configureReleaseCommandFlags(optimist // eslint-disable-line
.usage('Tags a release branches.\n' +
'\n' +
'Usage: $0 tag-release --version=2.8.0-rc1 -r platform')
'Usage: $0 tag-release --version=2.8.0-rc1 -r platform [--pretend] [--tag-only]')
.options('pretend', {
desc: 'Don\'t actually run git commands, just print out what would be run.',
type: 'boolean'
})
.options('tag-only', {
desc: 'Don\'t actually push to origin, just print out what would be pushed.',
type: 'boolean'
})
);
var repos = flagutil.computeReposFromFlag(argv.r);
var version = flagutil.validateVersionString(argv.version);
var pretend = argv.pretend;
var branchName = versionutil.getReleaseBranchNameFromVersion(version);
var tagOnly = argv['tag-only'];

// First - perform precondition checks.
yield repoupdate.updateRepos(repos, [], true);

function * execOrPretend (cmd) {
if (pretend) {
print('PRETENDING TO RUN: ' + cmd.join(' '));
} else if (tagOnly && cmd[1] === 'push') {
print('SKIP: ' + cmd.join(' '));
} else {
yield executil.execHelper(cmd);
}
Expand Down Expand Up @@ -329,7 +367,7 @@ exports.tagReleaseBranchCommand = function * (argv) {
} else {
print('Repo ' + repo.repoName + ' is already tagged.');
}
yield tagJs(repo, version, pretend);
yield tagJs(repo, version, pretend, tagOnly);

});
});
Expand Down
8 changes: 6 additions & 2 deletions src/versionutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ exports.updateRepoVersion = function * updateRepoVersion (repo, version, opts) {

// Update the package.json VERSION.
var packageFilePaths = repo.packageFilePaths || ['package.json'];
var pendingChangesExistInJSON = false;
if (fs.existsSync(packageFilePaths[0])) {
fs.readFile(packageFilePaths[0], {encoding: 'utf-8'}, function (err, data) {
if (err) throw err;
Expand All @@ -138,7 +139,8 @@ exports.updateRepoVersion = function * updateRepoVersion (repo, version, opts) {
// use 2 spaces indent similar to npm
fs.writeFileSync(packageFilePaths[0], JSON.stringify(packageJSON, null, 2) + '\n');
});
if (!(yield gitutil.pendingChangesExist())) {
pendingChangesExistInJSON = yield gitutil.pendingChangesExist();
if (!pendingChangesExistInJSON) {
apputil.print('package.json file was already up-to-date.');
}
} else {
Expand Down Expand Up @@ -170,6 +172,8 @@ exports.updateRepoVersion = function * updateRepoVersion (repo, version, opts) {

var commitChanges = !!(opts ? opts.commitChanges : true);
if (commitChanges && (yield gitutil.pendingChangesExist())) {
yield gitutil.commitChanges('Set VERSION to ' + version + ' (via coho)');
var versionDescription = pendingChangesExistInJSON ?
'version & VERSION' : 'VERSION';
yield gitutil.commitChanges('Set ' + versionDescription + ' to ' + version + ' (via coho)');
}
};