|
|
|
"use strict";
|
|
|
|
|
|
|
|
var NodeGit = require("nodegit"),
|
|
|
|
Promise = require('bluebird'),
|
|
|
|
path = require('path'),
|
|
|
|
os = require('os'),
|
|
|
|
fs = Promise.promisifyAll(require("fs")),
|
|
|
|
_ = require('lodash');
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Git Model
|
|
|
|
*/
|
|
|
|
module.exports = {
|
|
|
|
|
|
|
|
_git: null,
|
|
|
|
_repo: {
|
|
|
|
path: '',
|
|
|
|
branch: 'master',
|
|
|
|
exists: false,
|
|
|
|
inst: null,
|
|
|
|
sync: true
|
|
|
|
},
|
|
|
|
_opts: {
|
|
|
|
clone: {},
|
|
|
|
push: {}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize Git model
|
|
|
|
*
|
|
|
|
* @param {Object} appconfig The application config
|
|
|
|
* @return {Object} Git model instance
|
|
|
|
*/
|
|
|
|
init(appconfig) {
|
|
|
|
|
|
|
|
let self = this;
|
|
|
|
|
|
|
|
//-> Build repository path
|
|
|
|
|
|
|
|
if(_.isEmpty(appconfig.git.path) || appconfig.git.path === 'auto') {
|
|
|
|
self._repo.path = path.join(ROOTPATH, 'repo');
|
|
|
|
} else {
|
|
|
|
self._repo.path = appconfig.git.path;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-> Initialize repository
|
|
|
|
|
|
|
|
self._initRepo(appconfig).then((repo) => {
|
|
|
|
self._repo.inst = repo;
|
|
|
|
|
|
|
|
if(self._repo.sync) {
|
|
|
|
self.resync();
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize Git repository
|
|
|
|
*
|
|
|
|
* @param {Object} appconfig The application config
|
|
|
|
* @return {Object} Promise
|
|
|
|
*/
|
|
|
|
_initRepo(appconfig) {
|
|
|
|
|
|
|
|
let self = this;
|
|
|
|
|
|
|
|
winston.info('[GIT] Initializing Git repository...');
|
|
|
|
|
|
|
|
//-> Check if path is accessible
|
|
|
|
|
|
|
|
return fs.mkdirAsync(self._repo.path).catch((err) => {
|
|
|
|
if(err.code !== 'EEXIST') {
|
|
|
|
winston.error('Invalid Git repository path or missing permissions.');
|
|
|
|
}
|
|
|
|
}).then(() => {
|
|
|
|
|
|
|
|
//-> Check if path already contains a git working folder
|
|
|
|
|
|
|
|
return fs.statAsync(path.join(self._repo.path, '.git')).then((stat) => {
|
|
|
|
self._repo.exists = stat.isDirectory();
|
|
|
|
}).catch((err) => {
|
|
|
|
self._repo.exists = false;
|
|
|
|
});
|
|
|
|
|
|
|
|
}).then(() => {
|
|
|
|
|
|
|
|
//-> Init repository
|
|
|
|
|
|
|
|
let repoInitOperation = null;
|
|
|
|
self._repo.branch = appconfig.git.branch;
|
|
|
|
self._repo.sync = appconfig.git.remote;
|
|
|
|
self._opts.clone = self._generateCloneOptions(appconfig);
|
|
|
|
self._opts.push = self._generatePushOptions(appconfig);
|
|
|
|
|
|
|
|
if(self._repo.exists) {
|
|
|
|
|
|
|
|
winston.info('[GIT] Using existing repository...');
|
|
|
|
repoInitOperation = NodeGit.Repository.open(self._repo.path);
|
|
|
|
|
|
|
|
} else if(appconfig.git.remote) {
|
|
|
|
|
|
|
|
winston.info('[GIT] Cloning remote repository for first time...');
|
|
|
|
repoInitOperation = NodeGit.Clone(appconfig.git.url, self._repo.path, self._opts.clone);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
winston.info('[GIT] Using offline local repository...');
|
|
|
|
repoInitOperation = NodeGit.Repository.init(self._repo.path, 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return repoInitOperation;
|
|
|
|
|
|
|
|
}).catch((err) => {
|
|
|
|
winston.error('Unable to open or clone Git repository!');
|
|
|
|
winston.error(err);
|
|
|
|
}).then((repo) => {
|
|
|
|
|
|
|
|
if(self._repo.sync) {
|
|
|
|
NodeGit.Remote.setPushurl(repo, 'origin', appconfig.git.url);
|
|
|
|
}
|
|
|
|
|
|
|
|
return repo;
|
|
|
|
|
|
|
|
winston.info('[GIT] Git repository is now ready.');
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate Clone Options object
|
|
|
|
*
|
|
|
|
* @param {Object} appconfig The application configuration
|
|
|
|
* @return {Object} CloneOptions object
|
|
|
|
*/
|
|
|
|
_generateCloneOptions(appconfig) {
|
|
|
|
|
|
|
|
let cloneOptions = new NodeGit.CloneOptions();
|
|
|
|
cloneOptions.fetchOpts = this._generateFetchOptions(appconfig);
|
|
|
|
return cloneOptions;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
_generateFetchOptions(appconfig) {
|
|
|
|
|
|
|
|
let fetchOptions = new NodeGit.FetchOptions();
|
|
|
|
fetchOptions.callbacks = this._generateRemoteCallbacks(appconfig);
|
|
|
|
return fetchOptions;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
_generatePushOptions(appconfig) {
|
|
|
|
|
|
|
|
let pushOptions = new NodeGit.PushOptions();
|
|
|
|
pushOptions.callbacks = this._generateRemoteCallbacks(appconfig);
|
|
|
|
return pushOptions;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
_generateRemoteCallbacks(appconfig) {
|
|
|
|
|
|
|
|
let remoteCallbacks = new NodeGit.RemoteCallbacks();
|
|
|
|
let credFunc = this._generateCredentials(appconfig);
|
|
|
|
remoteCallbacks.credentials = () => { return credFunc; };
|
|
|
|
|
|
|
|
if(os.type() === 'Darwin') {
|
|
|
|
remoteCallbacks.certificateCheck = () => { return 1; }; // Bug in OS X, bypass certs check workaround
|
|
|
|
}
|
|
|
|
|
|
|
|
return remoteCallbacks;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
_generateCredentials(appconfig) {
|
|
|
|
|
|
|
|
let cred = null;
|
|
|
|
switch(appconfig.git.auth.type) {
|
|
|
|
case 'basic':
|
|
|
|
cred = NodeGit.Cred.userpassPlaintextNew(
|
|
|
|
appconfig.git.auth.user,
|
|
|
|
appconfig.git.auth.pass
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
case 'oauth':
|
|
|
|
cred = NodeGit.Cred.userpassPlaintextNew(
|
|
|
|
appconfig.git.auth.token,
|
|
|
|
"x-oauth-basic"
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
case 'ssh':
|
|
|
|
cred = NodeGit.Cred.sshKeyNew(
|
|
|
|
appconfig.git.auth.user,
|
|
|
|
appconfig.git.auth.publickey,
|
|
|
|
appconfig.git.auth.privatekey,
|
|
|
|
appconfig.git.auth.passphrase
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cred = NodeGit.Cred.defaultNew();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cred;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
resync() {
|
|
|
|
|
|
|
|
let self = this;
|
|
|
|
|
|
|
|
// Fetch
|
|
|
|
|
|
|
|
return self._repo.inst.fetch('origin', self._opts.clone.fetchOpts)
|
|
|
|
.catch((err) => {
|
|
|
|
winston.error('Unable to fetch from git origin!' + err);
|
|
|
|
})
|
|
|
|
|
|
|
|
// Merge
|
|
|
|
|
|
|
|
.then(() => {
|
|
|
|
return self._repo.inst.mergeBranches(self._repo.branch, 'origin/' + self._repo.branch);
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
winston.error('Unable to merge from remote head!' + err);
|
|
|
|
})
|
|
|
|
|
|
|
|
// Push
|
|
|
|
|
|
|
|
.then(() => {
|
|
|
|
return self._repo.inst.getRemote('origin').then((remote) => {
|
|
|
|
self._repo.inst.getStatus().then(function(arrayStatusFile) {
|
|
|
|
console.log(arrayStatusFile[0].status());
|
|
|
|
});
|
|
|
|
/*remote.push( ["refs/heads/master:refs/heads/master"], self._opts.push ).then((errNum) => {
|
|
|
|
console.log('DUDE' + errNum);
|
|
|
|
}).catch((err) => {
|
|
|
|
console.log(err);
|
|
|
|
});*/
|
|
|
|
});
|
|
|
|
}).catch((err) => {
|
|
|
|
winston.error('Unable to push to git origin!' + err);
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|