You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2017/01/18 02:26:27 UTC
cordova-coho git commit: first few steps for automating a bunch of
plugins releasing.
Repository: cordova-coho
Updated Branches:
refs/heads/plugins-releaser [created] 4cf47953f
first few steps for automating a bunch of plugins releasing.
Project: http://git-wip-us.apache.org/repos/asf/cordova-coho/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-coho/commit/4cf47953
Tree: http://git-wip-us.apache.org/repos/asf/cordova-coho/tree/4cf47953
Diff: http://git-wip-us.apache.org/repos/asf/cordova-coho/diff/4cf47953
Branch: refs/heads/plugins-releaser
Commit: 4cf47953f90f7c93cf5c751ea59e76e5080cdda8
Parents: 75cac48
Author: filmaj <ma...@gmail.com>
Authored: Tue Jan 17 18:26:08 2017 -0800
Committer: filmaj <ma...@gmail.com>
Committed: Tue Jan 17 18:26:08 2017 -0800
----------------------------------------------------------------------
package.json | 4 +-
src/main.js | 4 +-
src/plugin-release.js | 548 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 553 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-coho/blob/4cf47953/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index a1f41cf..4d68629 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,9 @@
"q": "~0.9",
"request": "^2.69.0",
"semver": "^4.2.0",
- "shelljs": "0.1.4"
+ "shelljs": "0.1.4",
+ "jira-client": "4.2.0",
+ "inquirer": "2.0.0"
},
"devDependencies": {
"nsp": ">=2.0.1",
http://git-wip-us.apache.org/repos/asf/cordova-coho/blob/4cf47953/src/main.js
----------------------------------------------------------------------
diff --git a/src/main.js b/src/main.js
index 7cdd3f4..b01996e 100644
--- a/src/main.js
+++ b/src/main.js
@@ -67,11 +67,11 @@ module.exports = function() {
entryPoint: lazyRequire('./list-repos')
}];
var releaseCommands = [{
- name: 'prepare-release-branch',
+ name: 'prepare-platform-release-branch',
desc: 'Branches, updates JS, updates VERSION. Safe to run multiple times.',
entryPoint: lazyRequire('./platform-release', 'prepareReleaseBranchCommand')
}, {
- name: 'tag-release',
+ name: 'tag-platform-release',
desc: 'Tags repos for a release.',
entryPoint: lazyRequire('./platform-release', 'tagReleaseBranchCommand')
}, {
http://git-wip-us.apache.org/repos/asf/cordova-coho/blob/4cf47953/src/plugin-release.js
----------------------------------------------------------------------
diff --git a/src/plugin-release.js b/src/plugin-release.js
new file mode 100644
index 0000000..9ac1a07
--- /dev/null
+++ b/src/plugin-release.js
@@ -0,0 +1,548 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+var path = require('path');
+var fs = require('fs');
+var util = require('util');
+var optimist = require('optimist');
+var shelljs = require('shelljs');
+var apputil = require('./apputil');
+var executil = require('./executil');
+var flagutil = require('./flagutil');
+var gitutil = require('./gitutil');
+var repoutil = require('./repoutil');
+var repoupdate = require('./repo-update');
+var versionutil = require('./versionutil');
+var jira_client = require('jira-client');
+var inquirer = require('inquirer');
+var print = apputil.print;
+
+/*
+ * Pseudo code for plugin automation:
+ * 1. Who are you? --> this is the release manager. Can we use JIRA for this?
+ */
+var jira; // issues.apache.org jira client object
+var you; // store label for the user here
+var jira_user; // store ref to jira project user
+var cordova_project; // store ref to jira project for Cordova
+var plugins_release_issue; // store ref to jira issue tracking release.
+var jira_issue_types; // store ref to all issue types supported by our JIRA instance
+var jira_task_issue; // store ref to the "task" issue type
+
+console.log('Hi! So you want to do a plugins release, do you?');
+console.log('Let\'s start with your JIRA credentials - this system will be interacting with Apache\'s JIRA instance (issues.apache.org) often.');
+inquirer.prompt([{
+ type: 'input',
+ name: 'username',
+ message: 'Please enter your JIRA username'
+},{
+ type: 'password',
+ name: 'password',
+ message: 'Please enter your JIRA password'
+}]).then(function(answers) {
+ var username = answers.username;
+ you = username;
+ var password = answers.password;
+ jira = new jira_client({
+ protocol: 'https',
+ host: 'issues.apache.org',
+ base: 'jira',
+ apiVersion: '2',
+ strictSSL: true,
+ username: username,
+ password: password
+ });
+ return jira.getCurrentUser();
+}).then(function(user) {
+ jira_user = user;
+ you = user.displayName || you; // either use JIRA display name, or username
+ console.log('Hey', you, '!');
+ console.log('Welcome. Let me pull some data from JIRA first...');
+ return jira.listProjects();
+}).then(function(projects) {
+ // Find the Apache Cordova (CB) project in Apache's JIRA
+ for (var i = 0; i < projects.length; i++) {
+ var project = projects[i];
+ if (project.key == 'CB') {
+ cordova_project = project;
+ break;
+ }
+ }
+ return jira.listIssueTypes();
+}).then(function(issue_types) {
+ jira_issue_types = issue_types;
+ for (var i = 0; i < issue_types.length; i++) {
+ var it = issue_types[i];
+ if (it.name == 'Task') {
+ jira_task_issue = it;
+ }
+ }
+ /*
+ * 2. Are your gpg keys in place? maybe basic validation
+ */
+ inquirer.prompt({
+ type: 'confirm',
+ name: 'gpg',
+ message: 'Are your GPG keys in place?'
+ }).then(function(answer) {
+ if (answer.gpg) {
+ console.log('Great! Let\'s keep going.');
+ return inquirer.prompt({
+ type: 'confirm',
+ name: 'discuss',
+ message: 'Did you start a "[DISCUSS] Plugins release" thread on the Cordova mailing list?'
+ });
+ } else {
+ console.error('You should get your GPG keys sorted out first!');
+ console.warn('Follow the instructions here, then come back and try again :)');
+ console.warn('https://github.com/apache/cordova-coho/blob/master/docs/setting-up-gpg.md');
+ process.exit(2);
+ }
+ }).then(function(answer) {
+ /* 3. Y/N did you start a "[DISCUSS] Plugins release" thread on the mailing list?
+ * - Bonus: Can we parse the mailing list for this?
+ */
+ if (answer.discuss) {
+ console.log('Nice! Way to keep everyone in the loop!');
+ return inquirer.prompt({
+ type: 'confirm',
+ name: 'jira',
+ message: 'Is there a JIRA issue filed for the plugins release? (i.e. "Plugins Release, <recent date>") - if not, I will create one for you.'
+ });
+ } else {
+ console.error('You definitely need to have a discussion about the plugins release on the mailing list first. Go do that!');
+ process.exit(3);
+
+ }
+ }).then(function(answer) {
+ /* 4. Ask for JIRA issue, or, Create JIRA issue; check docs/plugins-release-process.md for details
+ * - lets refer to this JIRA issue as $JIRA from here on out.
+ * - BONUS: COMMENT to this JIRA issue for each "top-level" step below that is completed.
+ */
+ if (answer.jira) {
+ return inquirer.prompt({
+ type: 'input',
+ name: 'jira',
+ message: 'What is the JIRA issue number for your plugins release? Please provide a number. (i.e. CB-XXXXX)',
+ validate: function(input) {
+ var done = this.async();
+ if (typeof input !== 'number') {
+ done('You need to provide a number!');
+ return;
+ }
+ var cb_issue = 'CB-' + input;
+ jira.findIssue(cb_issue).then(function(issue) {
+ done(null, issue);
+ }, function(err) {
+ done('Error finding issue ' + cb_issue);
+ });
+ }
+ }).catch(function(err) {
+ console.error(err);
+ process.exit(3);
+ });
+ } else {
+ console.warn('OK, no problem. I will create one for you now! Hang tight...');
+ var date = (new Date()).toDateString();
+ var new_issue = {
+ "fields": {
+ "project": {
+ "id": cordova_project.id
+ },
+ "summary": "Plugins Release, " + date,
+ "description": "Following steps at https://github.com/apache/cordova-coho/blob/master/docs/plugins-release-process.md",
+ "assignee": {
+ "name": jira_user.name
+ },
+ "issuetype": {
+ "id": jira_task_issue.id
+ },
+ }
+ }
+ return jira.addNewIssue(new_issue).then(function(issue) {
+ return issue;
+ }, function(err) {
+ console.error('There was a problem creating the JIRA issue!', err);
+ process.exit(4);
+ });
+ }
+ }).then(function(jira_issue) {
+ console.log('Sweet, our Plugins Release JIRA issue is ' + jira_issue.key + ' (https://issues.apache.org/jira/browse/' + jira_issue.key + ')!');
+ plugins_release_issue = jira_issue;
+ /* Time for step 5: update the repos. */
+ });
+},function(auth_err) {
+ var keys = Object.keys(auth_err);
+ console.error('ERROR! There was a problem connecting to JIRA, received a', auth_err.statusCode, 'status code.');
+ process.exit(1);
+});
+/* 6. ask user if they have a specific list of plugins to release, OR, auto-identify which plugins have changes. if auto-identifying, ask user to confirm at end. if wrong, ask user to manually input.
+ * 7. ensure license headers are present everywhere.
+ * 8. ensure all dependencies and subdependencies have apache-compatible licenses.
+ * 9. update plugin versions + release notes.
+ * - for each plugin, remove the `-dev` suffix in plugin.xml, package.json, and plugin.xml of `tests/` subdirectory (if exists)
+ * - each plugin needs a version bump.
+ * - the plugin may already have an acceptably-bumped verison. perhaps grab latest-published version of plugin from npm and compare to version in source as a hint to RM
+ * - how to determine if patch, minor or major? show changes to each plugin and then prompt Release Manager for a decision?
+ * - reuse coho 'update release notes' command
+ * - what's the average case? just a patch bump? perhaps, for each plugin, show release notes and let RM override version beyond patch bump if RM believes it is necessary?
+ * - while reviewing changes for version bump, this is probably the right time to aggregate release notes. once aggregated, write them out to RELEASENOTES.md
+ * - commit changes to versions and release notes together with description '$JIRA Updated version and release notes for release $v'
+ * - tag each plugin repo with $v
+ * 10. Create release branch. wtf is going on here?
+ * 11. Increment plugin versions back on the master branch to include -dev.. i think?
+ * 12. Push tags, release branch, and master branch changes.
+ * 13. Publish to apache svn:
+ * - repo-clone the dist and dist/dev svn repos
+ * - create-archive -r $ACTIVE --dest cordova-dist-dev/$JIRA
+ * - "manually double check version numbers are correct on the file names"
+ * - verify-archive cordova-dist-dev/$JIRA/*.tgz
+ * - upload by running `svn` commands.
+ * 14. Dump instructions only? Prepare blog post - perhaps can dump out release notes-based blog content.
+ * - this apparently ends up as a .md file in cordova-docs. perhaps can dump this as a shell of a file into the cordova-docs repo? maybe even auto-branch the docs repo in prep for a PR?
+ * 15. Dump instructions only? Start a vote thread.
+ * 16. Bonus: separate script to 'approve' a plugins release, which would:
+ * - publish the artifacts to dist/ in apache
+ * - "tell apache about the release" which has a TODO to write a helper to POST the request appropriately.
+ * - publish to npm
+ * - push 'permanent release tags' (for apache) to git
+ * - issue cordova-docs blog post PR (only if we auto-branch in cordova-docs repo, as per step 14)
+ * - dump instructions only? post an ANNOUNCE thread to ML.
+ * - close $JIRA issue
+ */
+
+/*
+ * TODO: Need ability to serialize process of plugins release - save state of the process at any point.
+ */
+
+// TODO: what is shared between plugin-release and platform-release helpers? factor out into util/lib/whatever helper modules
+
+/*
+function createPlatformDevVersion(version) {
+ // e.g. "3.1.0" -> "3.2.0-dev".
+ // e.g. "3.1.2-0.8.0-rc2" -> "3.2.0-0.8.0-dev".
+ version = version.replace(/-rc.*$/, '');
+ var parts = version.split('.');
+ parts[1] = String(+parts[1] + 1);
+ var cliSafeParts = parts[2].split('-');
+ cliSafeParts[0] = '0';
+ parts[2] = cliSafeParts.join('-');
+ return parts.join('.') + '-dev';
+}
+
+function getVersionBranchName(version) {
+ if (/-dev$/.test(version)) {
+ return 'master';
+ }
+ return version.replace(/\d+(-?rc\d)?$/, 'x');
+}
+
+function cpAndLog(src, dest) {
+ print('Coping File:', src, '->', dest);
+ // Throws upon failure.
+ shelljs.cp('-f', src, dest);
+ if (shelljs.error()) {
+ apputil.fatal('Copy failed.');
+ }
+}
+*/
+
+/*
+ * A function that handles version if it is defined or undefined
+ *
+ * @param {String} repo current repo
+ * @param {String|undefined} ver current version that can be defined or undefined
+ * @param {String|undefined} validate current version that can be defined or undefined
+ *
+ * @return {String} version Returns the calculated version
+ *
+ */
+
+function *handleVersion(repo,ver,validate) {
+ var platform = repo.id;
+ var version = ver || undefined;
+
+ if (version === undefined) {
+ yield repoutil.forEachRepo([repo], function*() {
+ // Grabbing version from platformPackageJson
+ var platformPackage = path.join(process.cwd(), 'package.json');
+ var platformPackageJson = require(platformPackage);
+ if(validate === true) {
+ version = flagutil.validateVersionString(platformPackageJson.version);
+ } else {
+ version = platformPackageJson.version;
+ }
+ });
+ }
+ return version;
+}
+
+function configureReleaseCommandFlags(opt) {
+ var opt = flagutil.registerRepoFlag(opt)
+ opt = opt
+ .options('version', {
+ desc: 'The version to use for the branch. Must match the pattern #.#.#[-rc#]'
+ });
+ opt = flagutil.registerHelpFlag(opt);
+ argv = opt.argv;
+
+ if (argv.h) {
+ optimist.showHelp();
+ process.exit(1);
+ }
+
+ return argv;
+}
+
+var hasBuiltJs = '';
+
+//Adds the version to CDVAvailability.h for iOS
+function *updateCDVAvailabilityFile(version) {
+ var iosFile = path.join(process.cwd(), 'CordovaLib', 'Classes', 'Public','CDVAvailability.h');
+ var iosFileContents = fs.readFileSync(iosFile, 'utf8');
+ iosFileContents = iosFileContents.split('\n');
+
+ var lineNumberToInsertLine = iosFileContents.indexOf('/* coho:next-version,insert-before */');
+ var lineNumberToReplaceLine = iosFileContents.indexOf(' /* coho:next-version-min-required,replace-after */') + 2;
+
+ var versionNumberUnderscores = version.split('.').join('_');
+ var versionNumberZeroes = version.split('.').join('0');
+
+ var lineToAdd = util.format('#define __CORDOVA_%s %s', versionNumberUnderscores, versionNumberZeroes);
+ var lineToReplace = util.format(' #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_%s', versionNumberUnderscores);
+
+ if(iosFileContents[lineNumberToInsertLine - 1] === lineToAdd) {
+ print('Version already exists in CDVAvailability.h');
+ lineNumberToReplaceLine = lineNumberToReplaceLine - 1;
+ } else {
+ iosFileContents.splice(lineNumberToInsertLine, 0, lineToAdd);
+ }
+
+ iosFileContents[lineNumberToReplaceLine] = lineToReplace;
+
+ fs.writeFileSync(iosFile, iosFileContents.join('\n'));
+}
+
+function *updateJsSnapshot(repo, version, commit) {
+ function *ensureJsIsBuilt() {
+ var cordovaJsRepo = repoutil.getRepoById('js');
+ if (repo.id === 'blackberry') {
+ repo.id = 'blackberry10';
+ }
+ 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');
+ yield executil.execHelper(executil.ARGS('grunt compile:' +repo.id + ' --platformVersion='+version));
+ hasBuiltJs = version;
+ });
+ });
+ }
+ }
+
+ if (repoutil.repoGroups.platform.indexOf(repo) == -1) {
+ return;
+ }
+
+ if (repo.cordovaJsPaths) {
+ yield ensureJsIsBuilt();
+ repo.cordovaJsPaths.forEach(function(jsPath) {
+ var src = path.join('..', 'cordova-js', 'pkg', repo.cordovaJsSrcName || ('cordova.' + repo.id + '.js'));
+ cpAndLog(src, jsPath);
+ });
+ if(commit === true) {
+ if (yield gitutil.pendingChangesExist()) {
+ yield executil.execHelper(executil.ARGS('git commit -am', 'Update JS snapshot to version ' + version + ' (via coho)'));
+ }
+ }
+ } else if (repoutil.repoGroups.all.indexOf(repo) != -1) {
+ print('*** DO NOT KNOW HOW TO UPDATE cordova.js FOR THIS REPO ***');
+ }
+}
+
+exports.createAndCopyCordovaJSCommand = function*() {
+ var argv = configureReleaseCommandFlags(optimist
+ .usage('Generates and copies an updated cordova.js to the specified platform. It does the following:\n' +
+ ' 1. Generates a new cordova.js.\n' +
+ ' 2. Replaces platform\'s cordova.js file.\n' +
+ '\n' +
+ 'Usage: $0 copy-js -r platform')
+ );
+
+ var repos = flagutil.computeReposFromFlag(argv.r);
+ yield repoutil.forEachRepo(repos, function*(repo) {
+ var version = yield handleVersion(repo, argv.version, false);
+ yield updateJsSnapshot(repo,version, false);
+ });
+}
+
+exports.prepareReleaseBranchCommand = function*() {
+ var argv = configureReleaseCommandFlags(optimist
+ .usage('Prepares release branches but does not create tags. This includes:\n' +
+ ' 1. Creating the branch if it doesn\'t already exist\n' +
+ ' 2. Generates and updates the cordova.js snapshot and VERSION file from master.\n' +
+ '\n' +
+ 'Command is safe to run multiple times, and can be run for the purpose\n' +
+ 'of checking out existing release branches.\n' +
+ '\n' +
+ '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]')
+ );
+
+ var repos = flagutil.computeReposFromFlag(argv.r);
+ var branchName = null;
+
+ // 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 = getVersionBranchName(version);
+
+ yield gitutil.stashAndPop(repo, function*() {
+ // git fetch + update master
+ yield repoupdate.updateRepos([repo], ['master'], false);
+ if (platform === 'ios') {
+ // 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 + '".');
+ yield versionutil.updateRepoVersion(repo, version);
+
+ 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);
+ });
+ });
+ executil.reportGitPushResult(repos, ['master', branchName]);
+}
+
+function *tagJs(repo, version, pretend) {
+
+ function *execOrPretend(cmd) {
+ if (pretend) {
+ print('PRETENDING TO RUN: ' + cmd.join(' '));
+ } else {
+ yield executil.execHelper(cmd);
+ }
+ }
+ //tag cordova.js platform-version
+ var cordovaJsRepo = repoutil.getRepoById('js');
+ yield repoutil.forEachRepo([cordovaJsRepo], function*() {
+ yield gitutil.stashAndPop(cordovaJsRepo, function*() {
+ // git fetch
+ yield repoupdate.updateRepos([cordovaJsRepo], ['master'], false);
+
+ var tagName = repo.id + '-' + version;
+ if (yield gitutil.tagExists(tagName)) {
+ yield execOrPretend(executil.ARGS('git tag ' + tagName + ' --force'));
+ } else {
+ yield execOrPretend(executil.ARGS('git tag ' + tagName));
+ }
+ yield execOrPretend(executil.ARGS('git push ' + repo.remoteName + ' refs/tags/' + tagName));
+ });
+ });
+}
+
+exports.tagReleaseBranchCommand = function*(argv) {
+ var argv = configureReleaseCommandFlags(optimist
+ .usage('Tags a release branches.\n' +
+ '\n' +
+ 'Usage: $0 tag-release --version=2.8.0-rc1 -r platform')
+ .options('pretend', {
+ desc: 'Don\'t actually run git commands, just print out what would be run.',
+ type: 'boolean'
+ })
+ );
+ var repos = flagutil.computeReposFromFlag(argv.r);
+ var version = flagutil.validateVersionString(argv.version);
+ var pretend = argv.pretend;
+ var branchName = getVersionBranchName(version);
+
+ // First - perform precondition checks.
+ yield repoupdate.updateRepos(repos, [], true);
+
+ function *execOrPretend(cmd) {
+ if (pretend) {
+ print('PRETENDING TO RUN: ' + cmd.join(' '));
+ } else {
+ yield executil.execHelper(cmd);
+ }
+ }
+ yield repoutil.forEachRepo(repos, function*(repo) {
+ yield gitutil.stashAndPop(repo, function*() {
+ // git fetch.
+ yield repoupdate.updateRepos([repo], [], false);
+
+ if (yield gitutil.remoteBranchExists(repo, branchName)) {
+ print('Remote branch already exists for repo: ' + repo.repoName);
+ yield gitutil.gitCheckout(branchName);
+ } else {
+ apputil.fatal('Release branch does not exist for repo ' + repo.repoName);
+ }
+
+ // git merge
+ yield repoupdate.updateRepos([repo], [branchName], true);
+
+ // Create/update the tag.
+ var tagName = yield gitutil.retrieveCurrentTagName();
+ if (tagName != version) {
+ if (yield gitutil.tagExists(version)) {
+ yield execOrPretend(executil.ARGS('git tag ' + version + ' --force'));
+ } else {
+ yield execOrPretend(executil.ARGS('git tag ' + version));
+ }
+ yield execOrPretend(executil.ARGS('git push ' + repo.remoteName + ' ' + branchName + ' refs/tags/' + version));
+ } else {
+ print('Repo ' + repo.repoName + ' is already tagged.');
+ }
+ yield tagJs(repo, version, pretend);
+
+ });
+ });
+
+ print('');
+ print('All work complete.');
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org