@gkalpak/ng-maintain-utils
Version:
A private collection of utilities for developing tools to help maintain (AngularJS-related) GitHub repositories.
180 lines (141 loc) • 5.32 kB
JavaScript
;
// Imports
let fs = require('fs');
let https = require('https');
// Imports - Local
let DiffHighlighter = require('./diff-highlighter');
let DiffHighlighter2 = require('./diff-highlighter2');
let Utils = require('./utils');
// Classes
class GitUtils {
// Constructor
constructor(cleanUper, utils) {
this._cleanUper = cleanUper;
this._utils = utils;
this._cleanUpTasks = {
abortAm: this._cleanUper.registerTask(
'Abort `git am`.',
() => this.abortAm().catch(() => {}))
};
}
// Methods - Public
abortAm() {
return this._utils.spawnAsPromised('git am --abort');
}
abortRebase() {
return this._utils.spawnAsPromised('git rebase --abort');
}
checkout(branch) {
return this._utils.spawnAsPromised(`git checkout ${branch}`);
}
clean(mode) {
if (!mode) {
mode = 'interactive';
}
let modeOpt = ((mode.length === 1) ? '-' : '--') + mode;
return this._utils.spawnAsPromised(`git clean ${modeOpt}`);
}
countCommitsSince(commit) {
return this._utils.execAsPromised(`git rev-list --count ${commit}..HEAD`).
then(response => parseInt(response.toString().trim(), 10));
}
createBranch(branch) {
return this._utils.spawnAsPromised(`git checkout -b ${branch}`);
}
deleteBranch(branch, force) {
// Git before v2.5.0 does not understand the `--delete --force` syntax. Use `-D` instead.
let deleteOpt = force ? '-D' : '--delete';
return this._utils.spawnAsPromised(`git branch ${deleteOpt} ${branch}`);
}
diff(commit, noColor) {
let colorOpt = noColor ? '--no-color' : '--color';
return this._utils.spawnAsPromised(`git diff ${colorOpt} ${commit}`);
}
diffWithHighlight(commit) {
let cmd1 = `git diff --no-color ${commit}`;
let cmd2 = 'less --no-init --raw-control-chars';
let dh = new DiffHighlighter();
return Promise.all([
this._utils.spawnAsPromised(cmd1, null, dh.getInputStream()),
this._utils.spawnAsPromised(cmd2, dh.getOutputStream())
]);
}
diffWithHighlight2(commit) {
let cmd1 = `git diff --no-color --word-diff=plain ${commit}`;
let cmd2 = 'less --no-init --raw-control-chars';
let dh = new DiffHighlighter2();
return Promise.all([
this._utils.spawnAsPromised(cmd1, null, dh.getInputStream()),
this._utils.spawnAsPromised(cmd2, dh.getOutputStream())
]);
}
getCommitMessage(commit) {
return this._utils.execAsPromised(`git show --no-patch --format=%B ${commit}`).
then(message => message.toString());
}
getLastCommitMessage() {
return this.getCommitMessage('HEAD');
}
log(oneline, count, noDecorate) {
let onelineOpt = oneline ? ' --oneline' : '';
let countOpt = count ? ` -${count}` : '';
let decorateOpt = noDecorate ? '--no-decorate' : '--decorate';
return this._utils.spawnAsPromised(`git log ${decorateOpt}${onelineOpt}${countOpt}`).
// `git log` has an exit code !== 0 if you exit before viewing all commits; ignore...
catch(() => {});
}
mergePullRequest(prUrl) {
// WARNING: Does not follow redirections :(
// To support redirection: this._utils.spawnAsPromised(`curl -L ${prUrl} | git am -3`)
return new Promise((resolve, reject) => {
let cb = res => this._cleanUper.
withTask(this._cleanUpTasks.abortAm, () => this._utils.spawnAsPromised('git am -3', res)).
then(resolve, reject);
https.
get(prUrl, cb).
on('error', reject);
});
}
pull(branch, rebase) {
let rebaseOpt = rebase ? ' --rebase' : '';
return this._utils.spawnAsPromised(`git pull${rebaseOpt} origin ${branch}`);
}
push(branch) {
return this._utils.spawnAsPromised(`git push origin ${branch}`);
}
rebase(commit, interactive) {
if (typeof commit === 'number') commit = `HEAD~${commit}`;
let interactiveOpt = interactive ? ' --interactive' : '';
return this._utils.spawnAsPromised(`git rebase${interactiveOpt} ${commit}`);
}
reset(commit, hard) {
let hardOpt = hard ? ' --hard' : '';
return this._utils.spawnAsPromised(`git reset${hardOpt} ${commit}`);
}
setLastCommitMessage(message) {
// Hack: The only cross-platform way I could come up with
// for programmatically setting multi-line commit messages
let tempFile = `.temp-commit-message_${Date.now()}.txt`;
let onSuccess = () => this.unlinkAsPromised(tempFile);
let onError = err => {
let finallyCb = () => Promise.reject(err);
return this.unlinkAsPromised(tempFile).then(finallyCb, finallyCb);
};
return Promise.resolve().
then(() => this.writeFileAsPromised(tempFile, message)).
then(() => this._utils.
spawnAsPromised(`git commit --amend --file=${tempFile}`).
then(onSuccess, onError));
}
updateLastCommitMessage(getNewMessage) {
return this.getLastCommitMessage().
then(oldMessage => getNewMessage(oldMessage)).
then(newMessage => this.setLastCommitMessage(newMessage));
}
}
GitUtils.DiffHighlighter = DiffHighlighter;
GitUtils.DiffHighlighter2 = DiffHighlighter2;
GitUtils.prototype.unlinkAsPromised = Utils.prototype.asPromised(fs.unlink, fs);
GitUtils.prototype.writeFileAsPromised = Utils.prototype.asPromised(fs.writeFile, fs);
// Exports
module.exports = GitUtils;