Allow committer details to be set per-user

This commit is contained in:
Nick O'Leary
2017-12-04 11:42:44 +00:00
parent 14c48253f6
commit 94eeaeb8d3
16 changed files with 639 additions and 366 deletions

View File

@@ -51,9 +51,9 @@ Project.prototype.load = function () {
}
this.credentialSecret = projectSettings.credentialSecret;
this.git = projectSettings.git || { user:{} };
this.remote = projectSettings.remote;
console.log("LOADED",this.git);
// this.paths.flowFile = fspath.join(this.path,"flow.json");
// this.paths.credentialsFile = fspath.join(this.path,"flow_cred.json");
@@ -103,12 +103,7 @@ Project.prototype.load = function () {
// project.paths.credentialsFile = fspath.join(project.path,"flow_cred.json");
// }
promises.push(gitTools.getRemotes(project.path).then(function(remotes) {
project.remotes = remotes;
}));
promises.push(gitTools.getBranchInfo(project.path).then(function(branches) {
project.branches = branches;
}));
promises.push(project.loadRemotes());
return when.settle(promises).then(function() {
return project;
@@ -116,7 +111,51 @@ Project.prototype.load = function () {
});
};
Project.prototype.update = function (data) {
Project.prototype.loadRemotes = function() {
var project = this;
return gitTools.getRemotes(project.path).then(function(remotes) {
project.remotes = remotes;
}).then(function() {
return project.loadBranches();
}).then(function() {
var allRemotes = Object.keys(project.remotes);
var match = "";
allRemotes.forEach(function(remote) {
if (project.branches.remote.indexOf(remote) === 0 && match.length < remote.length) {
match = remote;
}
});
project.currentRemote = project.parseRemoteBranch(project.branches.remote).remote;
});
}
Project.prototype.parseRemoteBranch = function (remoteBranch) {
if (!remoteBranch) {
return {}
}
var project = this;
var allRemotes = Object.keys(project.remotes);
var match = "";
allRemotes.forEach(function(remote) {
if (remoteBranch.indexOf(remote) === 0 && match.length < remote.length) {
match = remote;
}
});
return {
remote: match,
branch: remoteBranch.substring(match.length+1)
}
};
Project.prototype.loadBranches = function() {
var project = this;
return gitTools.getBranchInfo(project.path).then(function(branches) {
project.branches = branches;
});
}
Project.prototype.update = function (user, data) {
var promises = [];
var project = this;
@@ -172,13 +211,63 @@ Project.prototype.update = function (data) {
savePackage = true;
this.package.description = data.summary;
}
if (data.hasOwnProperty('remote')) {
for (var remote in data.remote) {
if (data.remote.hasOwnProperty(remote)) {
authCache.set(project.name,remote,data.remote[remote]);
// if (data.hasOwnProperty('remote')) {
// // TODO: this MUST move under 'git'
// for (var remote in data.remote) {
// if (data.remote.hasOwnProperty(remote)) {
// authCache.set(project.name,remote,data.remote[remote]);
// }
// }
// }
if (data.hasOwnProperty('git')) {
if (data.git.hasOwnProperty('user')) {
var username;
if (!user) {
username = "_";
} else {
username = user.username;
}
globalProjectSettings.projects[this.name].git = globalProjectSettings.projects[this.name].git || {};
globalProjectSettings.projects[this.name].git.user = globalProjectSettings.projects[this.name].git.user || {};
globalProjectSettings.projects[this.name].git.user[username] = {
name: data.git.user.name,
email: data.git.user.email
}
this.git.user[username] = {
name: data.git.user.name,
email: data.git.user.email
}
saveSettings = true;
}
if (data.git.hasOwnProperty('remotes')) {
var remoteNames = Object.keys(data.git.remotes);
var remotesChanged = false;
var modifyRemotesPromise = when.resolve();
remoteNames.forEach(function(name) {
if (data.git.remotes[name].removed) {
remotesChanged = true;
modifyRemotesPromise = modifyRemotesPromise.then(function() { gitTools.removeRemote(project.path,name) });
} else {
if (data.git.remotes[name].url) {
remotesChanged = true;
modifyRemotesPromise = modifyRemotesPromise.then(function() { gitTools.addRemote(project.path,name,data.git.remotes[name])});
}
if (data.git.remotes[name].username && data.git.remotes[name].password) {
var url = data.git.remotes[name].url || project.remotes[name].fetch;
authCache.set(project.name,url,data.git.remotes[name]);
}
}
})
if (remotesChanged) {
modifyRemotesPromise = modifyRemotesPromise.then(function() {
return project.loadRemotes();
});
promises.push(modifyRemotesPromise);
}
}
}
if (data.hasOwnProperty('files')) {
this.package['node-red'] = this.package['node-red'] || { settings: {}};
if (data.files.hasOwnProperty('flow') && this.package['node-red'].settings.flowFile !== data.files.flow) {
@@ -223,8 +312,15 @@ Project.prototype.stageFile = function(file) {
Project.prototype.unstageFile = function(file) {
return gitTools.unstageFile(this.path,file);
}
Project.prototype.commit = function(options) {
return gitTools.commit(this.path,options.message);
Project.prototype.commit = function(user, options) {
var username;
if (!user) {
username = "_";
} else {
username = user.username;
}
var gitUser = this.git.user[username];
return gitTools.commit(this.path,options.message,gitUser);
}
Project.prototype.getFileDiff = function(file,type) {
return gitTools.getFileDiff(this.path,file,type);
@@ -247,8 +343,17 @@ Project.prototype.status = function() {
var self = this;
var fetchPromise;
if (this.remote) {
fetchPromise = gitTools.fetch(this.path,authCache.get(this.name,'origin'));
if (this.remotes) {
fetchPromise = gitTools.getRemoteBranch(self.path).then(function(remoteBranch) {
var allRemotes = Object.keys(self.remotes);
var match = "";
allRemotes.forEach(function(remote) {
if (remoteBranch.indexOf(remote) === 0 && match.length < remote.length) {
match = remote;
}
})
return self.fetch(match);
});
} else {
fetchPromise = when.resolve();
}
@@ -267,6 +372,7 @@ Project.prototype.status = function() {
self.branches.remote = result.branches.remote;
if (fetchError) {
result.branches.remoteError = {
remote: fetchError.remote,
code: fetchError.code
}
}
@@ -283,17 +389,19 @@ Project.prototype.status = function() {
};
Project.prototype.push = function (remoteBranchName,setRemote) {
return gitTools.push(this.path, remoteBranchName, setRemote, authCache.get(this.name,'origin'));
var remote = this.parseRemoteBranch(remoteBranchName);
return gitTools.push(this.path, remote.remote || this.currentRemote,remote.branch, setRemote, authCache.get(this.name,this.remotes[this.currentRemote].fetch));
};
Project.prototype.pull = function (remoteBranchName,setRemote) {
var self = this;
if (setRemote) {
return gitTools.setUpstream(this.path, remoteBranchName).then(function() {
return gitTools.pull(self.path, null, authCache.get(self.name,'origin'));
return gitTools.pull(self.path, null, null, authCache.get(self.name,this.remotes[this.currentRemote].fetch));
})
} else {
return gitTools.pull(this.path, remoteBranchName, authCache.get(this.name,'origin'));
var remote = this.parseRemoteBranch(remoteBranchName);
return gitTools.pull(this.path, remote.remote, remote.branch, authCache.get(this.name,this.remotes[this.currentRemote].fetch));
}
};
@@ -342,18 +450,41 @@ Project.prototype.abortMerge = function () {
return gitTools.abortMerge(this.path);
};
Project.prototype.getBranches = function (remote) {
Project.prototype.getBranches = function (isRemote) {
var self = this;
var fetchPromise;
if (remote) {
fetchPromise = gitTools.fetch(this.path,authCache.get(this.name,'origin'))
if (isRemote) {
fetchPromise = self.fetch();
} else {
fetchPromise = when.resolve();
}
return fetchPromise.then(function() {
return gitTools.getBranches(self.path,remote);
return gitTools.getBranches(self.path,isRemote);
});
};
Project.prototype.fetch = function(remoteName) {
var project = this;
if (remoteName) {
return gitTools.fetch(project.path,remoteName,authCache.get(project.name,project.remotes[remoteName].fetch)).catch(function(err) {
err.remote = remoteName;
throw err;
})
} else {
var remotes = Object.keys(this.remotes);
var promise = when.resolve();
remotes.forEach(function(remote) {
promise = promise.then(function() {
return gitTools.fetch(project.path,remote,authCache.get(project.name,project.remotes[remote].fetch))
}).catch(function(err) {
err.remote = remote;
throw err;
})
});
return promise;
}
}
Project.prototype.setBranch = function (branchName, isCreate) {
var self = this;
return gitTools.checkoutBranch(this.path, branchName, isCreate).then(function() {
@@ -402,8 +533,10 @@ Project.prototype.toJSON = function () {
flow: this.paths.flowFile,
credentials: this.paths.credentialsFile
},
remotes: this.remotes,
branches: this.branches
git: {
remotes: this.remotes,
branches: this.branches
}
}
};
@@ -438,7 +571,7 @@ function createProjectDirectory(project) {
return fs.ensureDir(projectPath);
}
function createDefaultProject(project) {
function createDefaultProject(user, project) {
var projectPath = fspath.join(projectsDir,project.name);
// Create a basic skeleton of a project
return gitTools.initRepo(projectPath).then(function() {
@@ -502,7 +635,7 @@ function checkProjectFiles(project) {
});
}
function createProject(metadata) {
function createProject(user, metadata) {
var project = metadata.name;
return when.promise(function(resolve,reject) {
var projectPath = fspath.join(projectsDir,project);
@@ -518,23 +651,20 @@ function createProject(metadata) {
if (metadata.hasOwnProperty('credentialSecret')) {
projects.projects[project].credentialSecret = metadata.credentialSecret;
}
if (metadata.remote) {
projects.projects[project].remote = metadata.remote;
}
return settings.set('projects',projects);
}).then(function() {
if (metadata.remote) {
if (metadata.git && metadata.git.remotes && metadata.git.remotes.origin) {
var originRemote = metadata.git.remotes.origin;
var auth;
if (metadata.remote.hasOwnProperty("username") && metadata.remote.hasOwnProperty("password")) {
authCache.set(project,'origin',{ // TODO: hardcoded remote name
username: metadata.remote.username,
password: metadata.remote.password
if (originRemote.hasOwnProperty("username") && originRemote.hasOwnProperty("password")) {
authCache.set(project,originRemote.url,{ // TODO: hardcoded remote name
username: originRemote.username,
password: originRemote.password
}
);
auth = authCache.get(project,'origin');
auth = authCache.get(project,originRemote.url);
}
return gitTools.clone(metadata.remote,auth,projectPath).then(function(result) {
return gitTools.clone(originRemote,auth,projectPath).then(function(result) {
// Check this is a valid project
// If it is empty
// - if 'populate' flag is set, call populateProject
@@ -554,7 +684,7 @@ function createProject(metadata) {
});
})
} else {
createDefaultProject(metadata).then(function() { resolve(getProject(project))}).catch(reject);
createDefaultProject(user, metadata).then(function() { resolve(getProject(project))}).catch(reject);
}
}).catch(reject);
})

View File

@@ -25,15 +25,13 @@ module.exports = {
delete authCache[project];
},
set: function(project,remote,auth) {
if (authCache.hasOwnProperty(project)) {
authCache[project][remote] = auth;
} else {
authCache[project] = {
remote: auth
}
}
console.log("AuthCache.set",remote,auth);
authCache[project] = authCache[project]||{};
authCache[project][remote] = auth;
// console.log(JSON.stringify(authCache,'',4));
},
get: function(project,remote) {
console.log("AuthCache.get",remote,authCache[project]&&authCache[project][remote]);
if (authCache.hasOwnProperty(project)) {
return authCache[project][remote];
}

View File

@@ -37,7 +37,6 @@ function getListenPath() {
var ResponseServer = function(auth) {
return new Promise(function(resolve, reject) {
server = net.createServer(function(connection) {
// Stop accepting new connections
connection.setEncoding('utf8');
var parts = [];
connection.on('data', function(data) {
@@ -46,6 +45,7 @@ var ResponseServer = function(auth) {
parts.push(data.substring(0, m));
data = data.substring(m);
var line = parts.join("");
console.log("LINE",line);
parts = [];
if (line==='Username') {
connection.end(auth.username);

View File

@@ -311,6 +311,15 @@ function getBranchStatus(cwd,remoteBranch) {
})
}
function addRemote(cwd,name,options) {
var args = ["remote","add",name,options.url]
return runGitCommand(args,cwd);
}
function removeRemote(cwd,name) {
var args = ["remote","remove",name];
return runGitCommand(args,cwd);
}
module.exports = {
init: function(_settings,_runtime) {
log = _runtime.log
@@ -322,12 +331,11 @@ module.exports = {
var args = ["branch","--set-upstream-to",remoteBranch];
return runGitCommand(args,cwd);
},
pull: function(cwd,remoteBranch,auth) {
pull: function(cwd,remote,branch,auth) {
var args = ["pull"];
var m = /^(.*?)\/(.*)$/.exec(remoteBranch);
if (m) {
args.push(m[1]);
args.push(m[2])
if (remote && branch) {
args.push(remote);
args.push(branch);
}
var promise;
if (auth) {
@@ -348,17 +356,16 @@ module.exports = {
throw err;
});
},
push: function(cwd,remoteBranch,setUpstream, auth) {
push: function(cwd,remote,branch,setUpstream, auth) {
var args = ["push"];
var m = /^(.*?)\/(.*)$/.exec(remoteBranch);
if (m) {
if (branch) {
if (setUpstream) {
args.push("-u");
}
args.push(m[1]);
args.push("HEAD:"+m[2]);
args.push(remote);
args.push("HEAD:"+branch);
} else {
args.push("origin");
args.push(remote);
}
args.push("--porcelain");
var promise;
@@ -419,9 +426,16 @@ module.exports = {
}
return runGitCommand(args,cwd);
},
commit: function(cwd, message) {
commit: function(cwd, message, gitUser) {
var args = ["commit","-m",message];
return runGitCommand(args,cwd);
var env;
if (gitUser && gitUser['name'] && gitUser['email']) {
args.unshift('user.name="'+gitUser['name']+'"');
args.unshift('-c');
args.unshift('user.email="'+gitUser['email']+'"');
args.unshift('-c');
}
return runGitCommand(args,cwd,env);
},
getFileDiff(cwd,file,type) {
var args = ["diff"];
@@ -433,8 +447,8 @@ module.exports = {
args.push(file);
return runGitCommand(args,cwd);
},
fetch: function(cwd,auth) {
var args = ["fetch"];
fetch: function(cwd,remote,auth) {
var args = ["fetch",remote];
if (auth) {
return runGitCommandWithAuth(args,cwd,auth);
} else {
@@ -474,6 +488,9 @@ module.exports = {
return runGitCommand(['merge','--abort'],cwd);
},
getRemotes: getRemotes,
getRemoteBranch: function(cwd) {
return runGitCommand(['rev-parse','--abbrev-ref','--symbolic-full-name','@{u}'],cwd)
},
getBranches: getBranches,
getBranchInfo: getBranchInfo,
checkoutBranch: function(cwd, branchName, isCreate) {
@@ -484,5 +501,7 @@ module.exports = {
args.push(branchName);
return runGitCommand(args,cwd);
},
getBranchStatus: getBranchStatus
getBranchStatus: getBranchStatus,
addRemote: addRemote,
removeRemote: removeRemote
}

View File

@@ -96,6 +96,11 @@ function init(_settings, _runtime) {
}
}
function getUserGitSettings(user) {
var userSettings = settings.getUserSettings(user)||{};
return userSettings.git;
}
function getBackupFilename(filename) {
var ffName = fspath.basename(filename);
var ffDir = fspath.dirname(filename);
@@ -113,10 +118,27 @@ function loadProject(name) {
})
}
function getProject(name) {
function listProjects(user) {
return Projects.list();
}
function getProject(user, name) {
checkActiveProject(name);
//return when.resolve(activeProject.info);
return Projects.get(name);
var username;
if (!user) {
username = "_";
} else {
username = user.username;
}
return Projects.get(name).then(function(project) {
var result = project.toJSON();
var projectSettings = settings.get("projects").projects;
if (projectSettings[name].git && projectSettings[name].git.user[username]) {
result.git.user = projectSettings[name].git.user[username];
}
return result;
});
}
function checkActiveProject(project) {
@@ -125,78 +147,78 @@ function checkActiveProject(project) {
throw new Error("Cannot operate on inactive project wanted:"+project+" current:"+(activeProject&&activeProject.name));
}
}
function getFiles(project) {
function getFiles(user, project) {
checkActiveProject(project);
return activeProject.getFiles();
}
function stageFile(project,file) {
function stageFile(user, project,file) {
checkActiveProject(project);
return activeProject.stageFile(file);
}
function unstageFile(project,file) {
function unstageFile(user, project,file) {
checkActiveProject(project);
return activeProject.unstageFile(file);
}
function commit(project,options) {
function commit(user, project,options) {
checkActiveProject(project);
return activeProject.commit(options);
return activeProject.commit(user, options);
}
function getFileDiff(project,file,type) {
function getFileDiff(user, project,file,type) {
checkActiveProject(project);
return activeProject.getFileDiff(file,type);
}
function getCommits(project,options) {
function getCommits(user, project,options) {
checkActiveProject(project);
return activeProject.getCommits(options);
}
function getCommit(project,sha) {
function getCommit(user, project,sha) {
checkActiveProject(project);
return activeProject.getCommit(sha);
}
function getFile(project,filePath,sha) {
function getFile(user, project,filePath,sha) {
checkActiveProject(project);
return activeProject.getFile(filePath,sha);
}
function push(project,remoteBranchName,setRemote) {
function push(user, project,remoteBranchName,setRemote) {
checkActiveProject(project);
return activeProject.push(remoteBranchName,setRemote);
}
function pull(project,remoteBranchName,setRemote) {
function pull(user, project,remoteBranchName,setRemote) {
checkActiveProject(project);
return activeProject.pull(remoteBranchName,setRemote).then(function() {
return reloadActiveProject("pull");
});
}
function getStatus(project) {
function getStatus(user, project) {
checkActiveProject(project);
return activeProject.status();
}
function resolveMerge(project,file,resolution) {
function resolveMerge(user, project,file,resolution) {
checkActiveProject(project);
return activeProject.resolveMerge(file,resolution);
}
function abortMerge(project) {
function abortMerge(user, project) {
checkActiveProject(project);
return activeProject.abortMerge().then(function() {
return reloadActiveProject("abort-merge")
});
}
function getBranches(project,remote) {
function getBranches(user, project,isRemote) {
checkActiveProject(project);
return activeProject.getBranches(remote);
return activeProject.getBranches(isRemote);
}
function setBranch(project,branchName,isCreate) {
function setBranch(user, project,branchName,isCreate) {
checkActiveProject(project);
return activeProject.setBranch(branchName,isCreate).then(function() {
return reloadActiveProject("change-branch");
});
}
function getBranchStatus(project,branchName) {
function getBranchStatus(user, project,branchName) {
checkActiveProject(project);
return activeProject.getBranchStatus(branchName);
}
function getActiveProject() {
function getActiveProject(user) {
return activeProject;
}
@@ -212,14 +234,15 @@ function reloadActiveProject(action) {
});
});
}
function createProject(metadata) {
return Projects.create(metadata).then(function(p) {
return setActiveProject(p.name);
function createProject(user, metadata) {
// var userSettings = getUserGitSettings(user);
return Projects.create(null,metadata).then(function(p) {
return setActiveProject(user, p.name);
}).then(function() {
return getProject(metadata.name);
return getProject(user, metadata.name);
})
}
function setActiveProject(projectName) {
function setActiveProject(user, projectName) {
return loadProject(projectName).then(function(project) {
var globalProjectSettings = settings.get("projects");
globalProjectSettings.activeProject = project.name;
@@ -234,7 +257,7 @@ function setActiveProject(projectName) {
})
});
}
function updateProject(project,data) {
function updateProject(user, project, data) {
if (!activeProject || activeProject.name !== project) {
// TODO standardise
throw new Error("Cannot update inactive project");
@@ -243,7 +266,7 @@ function updateProject(project,data) {
var isReset = data.resetCredentialSecret;
var wasInvalid = activeProject.credentialSecretInvalid;
return activeProject.update(data).then(function(result) {
return activeProject.update(user,data).then(function(result) {
if (result.flowFilesChanged) {
flowsFullPath = activeProject.getFlowFile();
@@ -371,7 +394,7 @@ function saveCredentials(credentials) {
module.exports = {
init: init,
listProjects: Projects.list,
listProjects: listProjects,
getActiveProject: getActiveProject,
setActiveProject: setActiveProject,
getProject: getProject,