2
1
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2023-12-13 21:00:40 +01:00

🛠 Gulp setup (#7439)

refs #7427

With this PR, we'll get some development tooling magic:
`gulp setup`
Will update dependecies and submodules (if submodule branches are on master) for
currently chosen branches.

`gulp setup --force`
Will delete all dependencies and install them again, incl. submodules for
currently chosen branches.

`gulp setup --ghost some-branch --admin some-branch --casper some-branch`
Will checkout the branches for each repository.
Can also be used to checkout only selected branches e. g.
`gulp setup --admin some-branch`
Will leave the current branch for `ghost` and `casper`, but checkout the named
branch for admin. Will also install dependencies.

`gulp setup --admin pr/123 --ghost pr/1234 --casper pr/123`
Will fetch the named PR of the repository and checkout to this new branch.
Will also install dependencies. NOTE: This works only with an additional fetch line
in the .git/config file for each repository: `fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*`.
See https://dev.ghost.org/easy-git-pr-test/ for further information.

All the combinations above can be executed with the `--force` or `-f` flag, which
will delete the dependencies and install them again, but for the chosen branches.
This commit is contained in:
Aileen Nowak 2016-09-26 18:17:40 +02:00 committed by Katharina Irrgang
parent 7edc518d5a
commit 3ee7f5cdbd
2 changed files with 265 additions and 11 deletions

View file

@ -3,14 +3,55 @@ var gulp = require('gulp'),
nodemon = require('gulp-nodemon'),
shell = require('gulp-shell'),
chalk = require('chalk'),
paths,
nodemonServerInit;
runSequence = require('run-sequence'),
argv = require('minimist')(process.argv.slice(2)),
_ = require('lodash'),
exec = require('child_process').exec,
submodule = require('gulp-git-submodule'),
fs = require('fs'),
config,
gitBranches,
nodemonServerInit,
filterParams,
getGitBranch,
checkDirectoryExistance;
paths = {
server: 'core/server/',
client: 'core/client/'
// This config is used to store constant values to check against
// called options as well as the paths for each repository
config = {
ghost: {
type: 'string',
regex: /pr\/\d+/i,
path: 'core/server'
},
admin: {
type: 'string',
regex: /pr\/\d+/i,
path: 'core/client'
},
casper: {
type: 'string',
regex: /pr\/\d+/i,
path: 'content/themes/casper'
},
force: {
type: 'boolean'
},
f: {
type: 'boolean'
}
};
// gitBranches is used to store the currently chosen branch to checkout as well
// as the necessary shell command for `gulp setup`
gitBranches = {
ghost: {},
admin: {},
casper: {}
};
submodule.registerTasks(gulp);
nodemonServerInit = function () {
livereload.listen();
@ -18,16 +59,19 @@ nodemonServerInit = function () {
script: 'index.js',
ext: 'js,json,hbs',
watch: [
// TODO: these are the files we're watching. These need probably some
// adjustment as we go ahead with this.
'core/index.js',
paths.server + '**/*.js',
paths.server + '**/*.json',
paths.server + '**/*.hbs',
config.ghost.path + '**/*.js',
config.ghost.path + '**/*.json',
config.ghost.path + '**/*.hbs',
'core/built/assets/*.js'
],
ignore: [
'core/client/*',
'core/server/test/*'
]
],
verbose: true
}).on('restart', function () {
console.info(chalk.cyan('Restarting Ghost due to changes...'));
gulp.src('index.js')
@ -35,6 +79,122 @@ nodemonServerInit = function () {
});
};
// Filter against our config (checks the type and the allowed repos that can be
// used as parameters, e. b. `--admin`).
// Returns an Object which contains only the valid arguments as well as their value
filterParams = function (args) {
var filteredOptions = {};
_.forEach(args, function (key, value) {
key = typeof key === 'string' ? key.toLowerCase().trim() : key;
value = typeof value === 'string' ? value.toLowerCase().trim() : value;
if (config.hasOwnProperty(value)) {
if (config[value].type !== typeof key) {
console.info(chalk.red('Invalid usage of "--' + value + '" option.'));
return;
}
filteredOptions[value] = key;
} else {
if (value !== '_') { console.info(chalk.red('Invalid parameter "--' + value + '".')); }
return;
}
});
return filteredOptions;
};
// Creates the shell command to checkout the branch/pr and is verified against
// the regex in the config.
getGitBranch = function (branch, repo) {
if (branch && branch.match(config[repo].regex)) {
_.assign(gitBranches[repo], {
gitCommand: 'f() { git fetch && git checkout ' + branch + '; }; f',
branch: branch
});
} else if (branch) {
_.assign(gitBranches[repo], {
gitCommand: 'git fetch && git checkout ' + branch,
branch: branch
});
} else {
return null;
}
};
// Checks if a directory exists and returns true if so. This is needed to
// check, if the submodule directories exist.
checkDirectoryExistance = function (directory) {
try {
return fs.statSync(directory).isDirectory();
} catch (e) {
if (e.code === 'ENOENT') {
return false;
} else {
throw e;
}
}
};
// Delete all dependencies and installs npm modules again (necessary to make gulp
// work again 😛).
gulp.task('_FFS', shell.task(['rm -rf node_modules && rm -rf core/client/node_modules ' +
'&& rm -rf core/client/bower_components && npm cache clean ' +
'&& bower cache clean && npm install']));
gulp.task('_checkout_ghost', function (cb) {
exec(gitBranches.ghost.gitCommand, function (err, stdout, stderr) {
console.info(chalk.red(stderr));
cb(err);
});
});
gulp.task('_checkout_admin', function (cb) {
// Check first, if submodule exists and update it, if not.
if (!checkDirectoryExistance(config.admin.path)) {
exec('gulp submodules', function (err, stdout, stderr) {
console.info(chalk.red(stderr));
exec('cd ' + config.admin.path + ' && ' + gitBranches.admin.gitCommand, function (err, stdout, stderr) {
console.info(chalk.green(stdout));
console.info(chalk.red(stderr));
cb(err);
});
});
} else {
exec('cd ' + config.admin.path + ' && ' + gitBranches.admin.gitCommand, function (err, stdout, stderr) {
console.info(chalk.green(stdout));
console.info(chalk.red(stderr));
cb(err);
});
}
});
gulp.task('_checkout_casper', function (cb) {
// Check first, if submodule exists and update it, if not.
if (!checkDirectoryExistance(config.casper.path)) {
exec('gulp submodules', function (err, stdout, stderr) {
console.info(chalk.red(stderr));
exec('cd ' + config.casper.path + ' && ' + gitBranches.casper.gitCommand, function (err, stdout, stderr) {
console.info(chalk.green(stdout));
console.info(chalk.red(stderr));
cb(err);
});
});
} else {
exec('cd ' + config.casper.path + ' && ' + gitBranches.casper.gitCommand, function (err, stdout, stderr) {
console.info(chalk.green(stdout));
console.info(chalk.red(stderr));
cb(err);
});
}
});
gulp.task('_client_deps', shell.task(['npm install && bower install'], {
cwd: config.admin.path,
env: {
FORCE_COLOR: true
}
}));
// Starting the 🚗 to run the server only
// No client watch here.
gulp.task('server', function () {
@ -44,8 +204,99 @@ gulp.task('server', function () {
// Run `gulp dev` to enter development mode
// Filechanges in client will force a livereload
gulp.task('dev', ['server'], shell.task(['ember build --watch'], {
cwd: paths.client,
cwd: config.admin.path,
env: {
FORCE_COLOR: true // this is a fun little tidbit that will pass the colors from Ember to the main process
FORCE_COLOR: true
}
}));
// Update the submodules with gulp-git-submodule
// Will update only for these cases:
// 1. admin param is set to master (`--admin master`)
// 2. submodule doesn't exist, even if admin param is given
// Can be called directly, but will checkout the master branch
gulp.task('submodules', function (cb) {
var adminBranch = gitBranches.admin.branch || undefined,
casperBranch = gitBranches.casper.branch || undefined;
if ((!checkDirectoryExistance(config.admin.path) || adminBranch === 'master') ||
(!checkDirectoryExistance(config.casper.path) || casperBranch === 'master')) {
console.info(chalk.cyan('Updating submodules...'));
exec('gulp sm:install', function (err, stdout, stderr) {
console.info(chalk.red(stderr));
cb(err);
});
} else {
console.info(chalk.cyan('Nothing to update...'));
cb();
}
});
// Task to update dependencies for ghost and admin
gulp.task('deps', ['_client_deps'], shell.task(['npm install']));
// Task to make repositories ready for development. Can be used in mutliple ways:
//
// `gulp setup`
// Will update dependecies and submodules (if submodule branches are on master) for
// currently chosen branches.
//
// `gulp setup --force`
// Will delete all dependencies and install them again, incl. submodules for
// currently chosen branches.
//
// `gulp setup --ghost some-branch --admin some-branch --casper some-branch`
// Will checkout the branches for each repository.
// Can also be used to checkout only selected branches e. g.
// `gulp setup --admin some-branch`
// Will leave the current branch for `ghost` and `casper`, but checkout the named
// branch for admin. Will also install dependencies.
//
// `gulp setup --admin pr/123 --ghost pr/1234 --casper pr/123`
// Will fetch the named PR of the repository and checkout to this new branch.
// Will also install dependencies. NOTE: This works only with an additional fetch line
// in the .git/config file for each repository: `fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*`.
// See https://dev.ghost.org/easy-git-pr-test/ for further information.
//
// All the combinations above can be executed with the `--force` or `-f` flag, which
// will delete the dependencies and install them again, but for the chosen branches.
gulp.task('setup', function (done) {
var options = filterParams(argv) || {},
force = (options.force || options.f) || undefined;
if (options.ghost) {
getGitBranch(options.ghost, 'ghost');
runSequence(
'_checkout_ghost'
);
}
if (options.admin) {
getGitBranch(options.admin, 'admin');
runSequence(
'_checkout_admin'
);
}
if (options.casper) {
getGitBranch(options.casper, 'casper');
runSequence(
'_checkout_casper'
);
}
if (force) {
runSequence(
'submodules',
'_FFS',
'deps',
done
);
} else {
runSequence(
'submodules',
'deps',
done
);
}
});

View file

@ -99,14 +99,17 @@
"grunt-subgrunt": "1.2.0",
"grunt-update-submodules": "0.4.1",
"gulp": "3.9.1",
"gulp-git-submodule": "1.0.1",
"gulp-livereload": "3.8.1",
"gulp-nodemon": "2.1.0",
"gulp-shell": "0.5.2",
"istanbul": "0.4.5",
"matchdep": "1.0.1",
"minimist": "1.2.0",
"mocha": "3.0.2",
"nock": "8.0.0",
"rewire": "2.5.2",
"run-sequence": "1.2.2",
"should": "11.1.0",
"should-http": "0.0.4",
"sinon": "1.17.6",