123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- var fs = require('graceful-fs');
- var path = require('path');
- var Q = require('q');
- var semver = require('semver');
- var mout = require('mout');
- var rimraf = require('rimraf');
- var mkdirp = require('mkdirp');
- var chalk = require('chalk');
- var cmd = require('../lib/util/cmd');
- var packages = require('./packages.json');
- var nopt = require('nopt');
- var options = nopt({
- 'force': Boolean
- }, {
- 'f': '--force'
- });
- var env = {
- 'GIT_AUTHOR_DATE': 'Sun Apr 7 22:13:13 2013 +0000',
- 'GIT_AUTHOR_NAME': 'André Cruz',
- 'GIT_AUTHOR_EMAIL': 'amdfcruz@gmail.com',
- 'GIT_COMMITTER_DATE': 'Sun Apr 7 22:13:13 2013 +0000',
- 'GIT_COMMITTER_NAME': 'André Cruz',
- 'GIT_COMMITTER_EMAIL': 'amdfcruz@gmail.com'
- };
- // Preserve the original environment
- mout.object.mixIn(env, process.env);
- function ensurePackage(dir) {
- var promise;
- // If force is specified, delete folder
- if (options.force) {
- promise = Q.nfcall(rimraf, dir)
- .then(function () {
- throw new Error();
- });
- // Otherwise check if .git is already created
- } else {
- promise = Q.nfcall(fs.stat, path.join(dir, '.git'));
- }
- // Only create if stat failed
- return promise.fail(function () {
- // Create dir
- return Q.nfcall(mkdirp, dir)
- // Init git repo
- .then(cmd.bind(null, 'git', ['init'], { cwd: dir }))
- // Create dummy file
- .then(function () {
- return Q.nfcall(fs.writeFile, path.join(dir, '.master'), 'based on master');
- })
- // Stage files
- .then(cmd.bind(null, 'git', ['add', '-A'], { cwd: dir }))
- // Commit
- // Note that we force a specific date and author so that the same
- // commit-sha's are always equal
- // These commit-sha's are used internally in tests!
- .then(function () {
- return cmd('git', ['commit', '-m"Initial commit."'], {
- cwd: dir,
- env: env
- });
- })
- .then(function () {
- return dir;
- });
- });
- }
- function checkRelease(dir, release) {
- if (semver.valid(release)) {
- return cmd('git', ['tag', '-l'], { cwd: dir })
- .spread(function (stdout) {
- return stdout.split(/\s*\r*\n\s*/).some(function (tag) {
- return semver.clean(tag) === release;
- });
- });
- }
- return cmd('git', ['branch', '--list'], { cwd: dir })
- .spread(function (stdout) {
- return stdout.split(/\s*\r*\n\s*/).some(function (branch) {
- branch = branch.trim().replace(/^\*?\s*/, '');
- return branch === release;
- });
- });
- }
- function createRelease(dir, release, files) {
- var branch = semver.valid(release) ? 'branch-' + release : release;
- // Checkout master
- return cmd('git', ['checkout', 'master', '-f'], { cwd: dir })
- // Attempt to delete branch, ignoring the error
- .then(function () {
- return cmd('git', ['branch', '-D', branch], { cwd: dir })
- .fail(function () {});
- })
- // Checkout based on master
- .then(cmd.bind(null, 'git', ['checkout', '-b', branch, 'master'], { cwd: dir }))
- // Create files
- .then(function () {
- var promise;
- var promises = [];
- mout.object.forOwn(files, function (contents, name) {
- name = path.join(dir, name);
- // Convert contents to JSON if they are not a string
- if (typeof contents !== 'string') {
- contents = JSON.stringify(contents, null, ' ');
- }
- promise = Q.nfcall(mkdirp, path.dirname(name))
- .then(function () {
- return Q.nfcall(fs.writeFile, name, contents);
- });
- promises.push(promise);
- });
- // Delete dummy .master file that is present on the master branch
- promise = Q.nfcall(fs.unlink, path.join(dir, '.master'));
- promises.push(promise);
- return Q.all(promises);
- })
- // Stage files
- .then(cmd.bind(null, 'git', ['add', '-A'], { cwd: dir }))
- // Commit
- // Note that we force a specific date and author so that the same
- // commit-sha's are always equal
- // These commit-sha's are used internally in tests!
- .then(function () {
- return cmd('git', ['commit', '-m"Commit for ' + branch + '."'], {
- cwd: dir,
- env: env
- });
- })
- // Tag
- .then(function () {
- if (!semver.valid(release)) {
- return;
- }
- return cmd('git', ['tag', '-f', release], { cwd: dir })
- // Delete branch (not necessary anymore)
- .then(cmd.bind(null, 'git', ['checkout', 'master', '-f'], { cwd: dir }))
- .then(cmd.bind(null, 'git', ['branch', '-D', branch], { cwd: dir }));
- });
- }
- var promises = [];
- // Process packages.json
- mout.object.forOwn(packages, function (pkg, name) {
- var promise;
- var dir = path.join(__dirname, 'assets', name);
- // Ensure package is created
- promise = ensurePackage(dir);
- promise = promise.fail(function (err) {
- console.log('Failed to create ' + name);
- console.log(err.message);
- });
- mout.object.forOwn(pkg, function (files, release) {
- // Check if the release already exists
- promise = promise.then(checkRelease.bind(null, dir, release))
- .then(function (exists) {
- // Skip it if already created
- if (exists) {
- return console.log(chalk.cyan('> ') + 'Package ' + name + '#' + release + ' already created');
- }
- // Create it based on the metadata
- return createRelease(dir, release, files)
- .then(function () {
- console.log(chalk.green('> ') + 'Package ' + name + '#' + release + ' successfully created');
- });
- })
- .fail(function (err) {
- console.log(chalk.red('> ') + 'Failed to create ' + name + '#' + release);
- console.log(err.message.trim());
- if (err.details) {
- console.log(err.details.trim());
- }
- console.log(err.stack);
- });
- });
- promises.push(promise);
- });
- Q.allSettled(promises, function (results) {
- results.forEach(function (result) {
- if (result.state !== 'fulfilled') {
- process.exit(1);
- }
- });
- });
|