blob: 30b213484ac055462c0fc0d990c62831c49db63e [file] [log] [blame]
/*
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.
*/
const apputil = require('./apputil');
const optimist = require('optimist');
const flagutil = require('./flagutil');
const repoutil = require('./repoutil');
const repoupdate = require('./repo-update');
const retrieveSha = require('./retrieve-sha');
const npmpublish = require('./npm-publish');
const versionutil = require('./versionutil');
const gitutil = require('./gitutil');
const fs = require('fs');
const path = require('path');
const repoclone = require('./repo-clone');
module.exports = function * (argv) {
/** Specifies the default repos to build nightlies for */
const DEFAULT_NIGHTLY_REPOS = ['cli', 'lib', 'fetch', 'common', 'create', 'coho'];
let opt = flagutil.registerHelpFlag(optimist);
opt = flagutil.registerRepoFlag(opt);
argv = opt
.usage('Publish CLI & LIB to NPM under nightly tag. \n' +
'Cordova platform add uses latest commits to the platforms. \n' +
'Usage: $0 nightly'
)
.options('pretend', {
desc: 'Don\'t actually publish to npm, just print what would be run.',
type: 'boolean'
})
.default({ r: DEFAULT_NIGHTLY_REPOS })
.argv;
if (argv.h) {
optimist.showHelp();
process.exit(1);
}
// Clone and update Repos
yield prepareRepos(argv.r);
const reposToBuild = flagutil.computeReposFromFlag(argv.r, { includeModules: true });
// Get updated nightly versions for all repos
/** @type {Object} A map of repo.id and a short SHA for every repo to build */
const VERSIONS = yield retrieveVersions(reposToBuild);
// Update version in package.json and other respective files for every repo
// and update dependencies to use nightly versions of packages to be released
yield repoutil.forEachRepo(reposToBuild, function * (repo) {
apputil.print('Updating ' + repo.id + ' version to ' + VERSIONS[repo.id]);
yield versionutil.updateRepoVersion(repo, VERSIONS[repo.id], { commitChanges: false });
updateRepoDependencies(repo, VERSIONS);
});
// Pin nightly versions of platforms
if (reposToBuild.some(function (repo) { return repo.id === 'lib'; })) {
apputil.print('Updating platforms pinned versions...');
versionutil.updatePlatformsConfig(VERSIONS);
}
const options = {};
options.tag = 'nightly';
options.pretend = argv.pretend;
options.r = reposToBuild.map(function (repo) { return repo.id; });
// publish to npm under nightly tag
yield npmpublish.publishTag(options);
};
function * prepareRepos (repoNames) {
// Clone and update required repos
apputil.print('Cloning and updating required repositories...');
const reposToClone = flagutil.computeReposFromFlag(['tools'].concat(repoNames));
yield repoclone.cloneRepos(reposToClone, /* silent= */true);
yield repoupdate.updateRepos(reposToClone, /* silent= */true);
// Remove local changes and sync up with remote master
apputil.print('Resetting repositories to "master" branches...');
const reposToUpdate = flagutil.computeReposFromFlag(repoNames);
yield repoutil.forEachRepo(reposToUpdate, function * () {
yield gitutil.gitClean();
yield gitutil.resetFromOrigin();
});
}
/**
* Updates current repo dependencies with versions, supplied in dependencies object
* @param {Object} repo Current repo which dependencies need to be updated
* @param {Object<String, String>} dependencies Map of package's id's and nightly versions
*/
function updateRepoDependencies (repo, dependencies) {
const packageJSONPath = path.join(process.cwd(), 'package.json');
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath));
// Let's iterate through repos we're going to release
// eslint-disable-next-line array-callback-return
Object.keys(dependencies).map(function (dependencyId) {
const repo = repoutil.getRepoById(dependencyId);
const packageId = repo.packageName || repo.repoName;
if (packageJSON.dependencies[packageId]) {
// If current repo has dependency that points to one of packages, we're going
// to release, update that dependency's version to nightly
apputil.print('Updating ' + packageId + ' dependency version to ' + dependencies[dependencyId]);
packageJSON.dependencies[packageId] = dependencies[dependencyId];
}
});
fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON, null, 2) + '\n', 'utf8');
}
/**
* Generates suffix for appending to nightly package version
* based on current date and SHA string.
* @param SHA {String} String to use to generate nightly version
* @returns {String} A newly generated nightly suffix
*/
function getNightlySuffix (SHA) {
const currentDate = new Date();
// converts "2023-05-09T18:20:32.730Z" to "20230509182032730"
const dateTime = currentDate.toISOString().replace(/[T|Z\-:.]/g, '');
// @see https://semver.org/#spec-item-10
// Example: -nightly+20230509182032730.sha.8d2286c9
return `-nightly+${dateTime}.sha.${SHA}`;
}
/**
* Generates map of repo.id -> nightly version based on current
* date and SHA of current revision of repository
* @param {Object[]} repos An array of cordova repos
* @returns {Object} Mapped object
*/
function * retrieveVersions (repos) {
const SHAJSON = yield retrieveSha(repos);
return Object.keys(SHAJSON).reduce(function (result, repoId) {
const repoPath = repoutil.getRepoDir(repoutil.getRepoById(repoId));
const oldVersion = require(path.join(repoPath, 'package.json')).version;
result[repoId] = versionutil.removeDev(oldVersion) + getNightlySuffix(SHAJSON[repoId]);
return result;
}, {});
}