mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Handle cloning a bare repository
This commit is contained in:
parent
6013e186ed
commit
1d7ae300e2
@ -97,17 +97,50 @@
|
|||||||
}
|
}
|
||||||
if (msg.text) {
|
if (msg.text) {
|
||||||
var text = RED._(msg.text,{default:msg.text});
|
var text = RED._(msg.text,{default:msg.text});
|
||||||
|
var options = {
|
||||||
|
type: msg.type,
|
||||||
|
fixed: msg.timeout === undefined,
|
||||||
|
timeout: msg.timeout
|
||||||
|
}
|
||||||
if (notificationId === "runtime-state") {
|
if (notificationId === "runtime-state") {
|
||||||
if (msg.error === "credentials_load_failed") {
|
if (msg.error === "credentials_load_failed") {
|
||||||
// TODO: NLS
|
options.buttons = [
|
||||||
text += '<p><a href="#" onclick="RED.projects.showCredentialsPrompt(); return false;">'+'Setup credentials'+'</a></p>';
|
{
|
||||||
|
text: "Setup credentials",
|
||||||
|
click: function() {
|
||||||
|
RED.projects.showCredentialsPrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
} else if (msg.error === "missing_flow_file") {
|
} else if (msg.error === "missing_flow_file") {
|
||||||
// TODO: NLS
|
options.buttons = [
|
||||||
text += '<p><a href="#" onclick="RED.projects.showFilesPrompt(); return false;">'+'Setup project files'+'</a></p>';
|
{
|
||||||
|
text: "Setup project files",
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].close();
|
||||||
|
RED.projects.showFilesPrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
} else if (msg.error === "project_empty") {
|
||||||
|
options.buttons = [
|
||||||
|
{
|
||||||
|
text: "No thanks",
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].close();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: "Create default project files",
|
||||||
|
click: function() {
|
||||||
|
persistentNotifications[notificationId].close();
|
||||||
|
RED.projects.createDefaultFileSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!persistentNotifications.hasOwnProperty(notificationId)) {
|
if (!persistentNotifications.hasOwnProperty(notificationId)) {
|
||||||
persistentNotifications[notificationId] = RED.notify(text,msg.type,msg.timeout === undefined,msg.timeout);
|
persistentNotifications[notificationId] = RED.notify(text,options);
|
||||||
} else {
|
} else {
|
||||||
persistentNotifications[notificationId].update(text,msg.timeout);
|
persistentNotifications[notificationId].update(text,msg.timeout);
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,10 @@ RED.notify = (function() {
|
|||||||
n.close = (function() {
|
n.close = (function() {
|
||||||
var nn = n;
|
var nn = n;
|
||||||
return function() {
|
return function() {
|
||||||
|
if (nn.closed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nn.closed = true;
|
||||||
currentNotifications.splice(currentNotifications.indexOf(nn),1);
|
currentNotifications.splice(currentNotifications.indexOf(nn),1);
|
||||||
$(nn).slideUp(300, function() {
|
$(nn).slideUp(300, function() {
|
||||||
nn.parentNode.removeChild(nn);
|
nn.parentNode.removeChild(nn);
|
||||||
|
@ -83,7 +83,7 @@ RED.projects = (function() {
|
|||||||
migrateProjectHeader.appendTo(container);
|
migrateProjectHeader.appendTo(container);
|
||||||
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
|
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
|
||||||
|
|
||||||
$('<p>').text("Step 1 : Setup your version control client").appendTo(body);
|
$('<p>').text("Setup your version control client").appendTo(body);
|
||||||
$('<p>').text("Node-RED uses the open source tool Git for version control. It tracks changes to your project files and lets you push them to remote repositories.").appendTo(body);
|
$('<p>').text("Node-RED uses the open source tool Git for version control. It tracks changes to your project files and lets you push them to remote repositories.").appendTo(body);
|
||||||
$('<p>').text("When you commit a set of changes, Git records who made the changes with a username and email address. The Username can be anything you want - it does not need to be your real name.").appendTo(body);
|
$('<p>').text("When you commit a set of changes, Git records who made the changes with a username and email address. The Username can be anything you want - it does not need to be your real name.").appendTo(body);
|
||||||
$('<p>').text("If your Git client is already configured, you can skip this step.").appendTo(body);
|
$('<p>').text("If your Git client is already configured, you can skip this step.").appendTo(body);
|
||||||
@ -139,25 +139,24 @@ RED.projects = (function() {
|
|||||||
migrateProjectHeader.appendTo(container);
|
migrateProjectHeader.appendTo(container);
|
||||||
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
|
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
|
||||||
|
|
||||||
$('<p>').text("Step 2 : Create your project").appendTo(body);
|
$('<p>').text("Create your project").appendTo(body);
|
||||||
$('<p>').text("A project contains your flow files, a README file, a package.json file and a settings file. It makes it much easier to share your flows with others and to collaborate on them.").appendTo(body);
|
$('<p>').text("A project is maintained as a Git repository. It makes it much easier to share your flows with others and to collaborate on them.").appendTo(body);
|
||||||
$('<p>').text("You can create multiple projects and quickly switch between them from the editor.").appendTo(body);
|
$('<p>').text("You can create multiple projects and quickly switch between them from the editor.").appendTo(body);
|
||||||
$('<p>').text("To begin, your project needs a name and an optional description.").appendTo(body);
|
$('<p>').text("To begin, your project needs a name and an optional description.").appendTo(body);
|
||||||
|
|
||||||
var validateForm = function() {
|
var validateForm = function() {
|
||||||
var projectName = projectNameInput.val();
|
var projectName = projectNameInput.val();
|
||||||
var valid = true;
|
var valid = true;
|
||||||
|
var projectNameValid = /^[a-zA-Z0-9\-_]+$/.test(projectName);
|
||||||
if (projectNameInputChanged) {
|
if (projectNameInputChanged) {
|
||||||
projectNameStatus.empty();
|
projectNameStatus.empty();
|
||||||
if (!/^[a-zA-Z0-9\-_]+$/.test(projectName)) {
|
if (!projectNameValid) {
|
||||||
projectNameInput.addClass("input-error");
|
projectNameInput.addClass("input-error");
|
||||||
$('<i style="margin-top: 8px;" class="fa fa-exclamation-triangle"></i>').appendTo(projectNameStatus);
|
$('<i style="margin-top: 8px;" class="fa fa-exclamation-triangle"></i>').appendTo(projectNameStatus);
|
||||||
projectNameValid = false;
|
|
||||||
valid = false;
|
valid = false;
|
||||||
} else {
|
} else {
|
||||||
projectNameInput.removeClass("input-error");
|
projectNameInput.removeClass("input-error");
|
||||||
$('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus);
|
$('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus);
|
||||||
projectNameValid = true;
|
|
||||||
}
|
}
|
||||||
projectNameLastChecked = projectName;
|
projectNameLastChecked = projectName;
|
||||||
}
|
}
|
||||||
@ -206,6 +205,7 @@ RED.projects = (function() {
|
|||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
projectNameInput.focus();
|
projectNameInput.focus();
|
||||||
|
validateForm();
|
||||||
},50);
|
},50);
|
||||||
return container;
|
return container;
|
||||||
},
|
},
|
||||||
@ -224,14 +224,112 @@ RED.projects = (function() {
|
|||||||
click: function() {
|
click: function() {
|
||||||
createProjectOptions.name = projectNameInput.val();
|
createProjectOptions.name = projectNameInput.val();
|
||||||
createProjectOptions.summary = projectSummaryInput.val();
|
createProjectOptions.summary = projectSummaryInput.val();
|
||||||
createProjectOptions.files = { migrateFiles: true };
|
show('default-files');
|
||||||
show('encryption-config');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
})(),
|
})(),
|
||||||
|
'default-files': (function() {
|
||||||
|
var projectFlowFileInput;
|
||||||
|
var projectCredentialFileInput;
|
||||||
|
return {
|
||||||
|
content: function(options) {
|
||||||
|
var container = $('<div class="projects-dialog-screen-start"></div>');
|
||||||
|
migrateProjectHeader.appendTo(container);
|
||||||
|
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
|
||||||
|
|
||||||
|
$('<p>').text("Create your project files").appendTo(body);
|
||||||
|
$('<p>').text("A project contains your flow files, a README file, a package.json file and a settings file.").appendTo(body);
|
||||||
|
$('<p>').text("It can contain any other files you want to maintain in the Git repository.").appendTo(body);
|
||||||
|
if (!options.existingProject) {
|
||||||
|
$('<p>').text("Your existing flow and credential files will be copied into the project.").appendTo(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
var validateForm = function() {
|
||||||
|
var valid = true;
|
||||||
|
var flowFile = projectFlowFileInput.val();
|
||||||
|
if (flowFile === "" || !/\.json$/.test(flowFile)) {
|
||||||
|
valid = false;
|
||||||
|
if (!projectFlowFileInput.hasClass("input-error")) {
|
||||||
|
projectFlowFileInput.addClass("input-error");
|
||||||
|
projectFlowFileInput.next().empty().append('<i style="margin-top: 8px;" class="fa fa-exclamation-triangle"></i>');
|
||||||
|
}
|
||||||
|
projectCredentialFileInput.text("");
|
||||||
|
if (!projectCredentialFileInput.hasClass("input-error")) {
|
||||||
|
projectCredentialFileInput.addClass("input-error");
|
||||||
|
projectCredentialFileInput.next().empty().append('<i style="margin-top: 8px;" class="fa fa-exclamation-triangle"></i>');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (projectFlowFileInput.hasClass("input-error")) {
|
||||||
|
projectFlowFileInput.removeClass("input-error");
|
||||||
|
projectFlowFileInput.next().empty();
|
||||||
|
}
|
||||||
|
if (projectCredentialFileInput.hasClass("input-error")) {
|
||||||
|
projectCredentialFileInput.removeClass("input-error");
|
||||||
|
projectCredentialFileInput.next().empty();
|
||||||
|
}
|
||||||
|
projectCredentialFileInput.text(flowFile.substring(0,flowFile.length-5)+"_cred.json");
|
||||||
|
}
|
||||||
|
$("#projects-dialog-create-default-files").prop('disabled',!valid).toggleClass('disabled ui-button-disabled ui-state-disabled',!valid);
|
||||||
|
}
|
||||||
|
var row = $('<div class="form-row"></div>').appendTo(body);
|
||||||
|
$('<label for="projects-dialog-screen-create-project-file">Flow file</label>').appendTo(row);
|
||||||
|
var subrow = $('<div style="position:relative;"></div>').appendTo(row);
|
||||||
|
var defaultFlowFile = (createProjectOptions.files &&createProjectOptions.files.flow) || RED.settings.files.flow||"flow.json";
|
||||||
|
projectFlowFileInput = $('<input id="projects-dialog-screen-create-project-file" type="text">').val(defaultFlowFile)
|
||||||
|
.on("change keyup paste",validateForm)
|
||||||
|
.appendTo(subrow);
|
||||||
|
$('<div class="projects-dialog-screen-input-status"></div>').appendTo(subrow);
|
||||||
|
$('<label class="projects-edit-form-sublabel"><small>*.json</small></label>').appendTo(row);
|
||||||
|
|
||||||
|
var defaultCredentialsFile = (createProjectOptions.files &&createProjectOptions.files.credentials) || RED.settings.files.credentials||"flow_cred.json";
|
||||||
|
row = $('<div class="form-row"></div>').appendTo(body);
|
||||||
|
$('<label for="projects-dialog-screen-create-project-credfile">Credentials file</label>').appendTo(row);
|
||||||
|
subrow = $('<div style="position:relative;"></div>').appendTo(row);
|
||||||
|
projectCredentialFileInput = $('<div style="width: 100%" class="uneditable-input" id="projects-dialog-screen-create-project-credentials">').text(defaultCredentialsFile)
|
||||||
|
.appendTo(subrow);
|
||||||
|
$('<div class="projects-dialog-screen-input-status"></div>').appendTo(subrow);
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
projectFlowFileInput.focus();
|
||||||
|
validateForm();
|
||||||
|
},50);
|
||||||
|
|
||||||
|
return container;
|
||||||
|
},
|
||||||
|
buttons: function(options) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
// id: "clipboard-dialog-cancel",
|
||||||
|
text: options.existingProject?"Cancel":"Back",
|
||||||
|
click: function() {
|
||||||
|
if (options.existingProject) {
|
||||||
|
$(this).dialog('close');
|
||||||
|
} else {
|
||||||
|
show('project-details',options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "projects-dialog-create-default-files",
|
||||||
|
text: "Next", // TODO: nls
|
||||||
|
class: "primary",
|
||||||
|
click: function() {
|
||||||
|
createProjectOptions.files = {
|
||||||
|
flow: projectFlowFileInput.val(),
|
||||||
|
credentials: projectCredentialFileInput.text()
|
||||||
|
}
|
||||||
|
if (!options.existingProject) {
|
||||||
|
createProjectOptions.migrateFiles = true;
|
||||||
|
}
|
||||||
|
show('encryption-config',options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(),
|
||||||
'encryption-config': (function() {
|
'encryption-config': (function() {
|
||||||
var emptyProjectCredentialInput;
|
var emptyProjectCredentialInput;
|
||||||
return {
|
return {
|
||||||
@ -241,20 +339,23 @@ RED.projects = (function() {
|
|||||||
migrateProjectHeader.appendTo(container);
|
migrateProjectHeader.appendTo(container);
|
||||||
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
|
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
|
||||||
|
|
||||||
$('<p>').text("Step 3 : Setup encryption of your credentials file").appendTo(body);
|
$('<p>').text("Setup encryption of your credentials file").appendTo(body);
|
||||||
// $('<p>').text("Your flow credentials file can be encrypted to keep its contents secure.").appendTo(body);
|
if (options.existingProject) {
|
||||||
|
$('<p>').text("Your flow credentials file can be encrypted to keep its contents secure.").appendTo(body);
|
||||||
if (RED.settings.flowEncryptionType === 'disabled') {
|
|
||||||
$('<p>').text("Your flow credentials file is not currently encrypted.").appendTo(body);
|
|
||||||
$('<p>').text("That means its contents, such as passwords and access tokens, can be read by anyone with access to the file.").appendTo(body);
|
|
||||||
$('<p>').text("If you want to store these credentials in a public Git repository, you must encrypt them by providing a secret key phrase.").appendTo(body);
|
$('<p>').text("If you want to store these credentials in a public Git repository, you must encrypt them by providing a secret key phrase.").appendTo(body);
|
||||||
} else {
|
} else {
|
||||||
if (RED.settings.flowEncryptionType === 'user') {
|
if (RED.settings.flowEncryptionType === 'disabled') {
|
||||||
$('<p>').text("Your flow credentials file is currently encrypted using the credentialSecret property from your settings file as the key.").appendTo(body);
|
$('<p>').text("Your flow credentials file is not currently encrypted.").appendTo(body);
|
||||||
} else if (RED.settings.flowEncryptionType === 'system') {
|
$('<p>').text("That means its contents, such as passwords and access tokens, can be read by anyone with access to the file.").appendTo(body);
|
||||||
$('<p>').text("Your flow credentials file is currently encrypted using a system-generated secret as the key. You should provide a new secret key for this project.").appendTo(body);
|
$('<p>').text("If you want to store these credentials in a public Git repository, you must encrypt them by providing a secret key phrase.").appendTo(body);
|
||||||
|
} else {
|
||||||
|
if (RED.settings.flowEncryptionType === 'user') {
|
||||||
|
$('<p>').text("Your flow credentials file is currently encrypted using the credentialSecret property from your settings file as the key.").appendTo(body);
|
||||||
|
} else if (RED.settings.flowEncryptionType === 'system') {
|
||||||
|
$('<p>').text("Your flow credentials file is currently encrypted using a system-generated secret as the key. You should provide a new secret key for this project.").appendTo(body);
|
||||||
|
}
|
||||||
|
$('<p>').text("The secret will be copied into the settings for your new project. You can then manage the secret within the editor.").appendTo(body);
|
||||||
}
|
}
|
||||||
$('<p>').text("The secret will be copied into the settings for your new project. You can then manage the secret within the editor.").appendTo(body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// var row = $('<div class="form-row"></div>').appendTo(body);
|
// var row = $('<div class="form-row"></div>').appendTo(body);
|
||||||
@ -356,75 +457,89 @@ RED.projects = (function() {
|
|||||||
|
|
||||||
return container;
|
return container;
|
||||||
},
|
},
|
||||||
buttons: [
|
buttons: function(options) {
|
||||||
{
|
return [
|
||||||
// id: "clipboard-dialog-cancel",
|
{
|
||||||
text: "Back",
|
// id: "clipboard-dialog-cancel",
|
||||||
click: function() {
|
text: "Back",
|
||||||
show('project-details');
|
click: function() {
|
||||||
}
|
show('default-files',options);
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "projects-dialog-create-encryption",
|
|
||||||
text: "Create project", // TODO: nls
|
|
||||||
class: "primary disabled",
|
|
||||||
disabled: true,
|
|
||||||
click: function() {
|
|
||||||
var encryptionState = $("input[name=projects-encryption-type]:checked").val();
|
|
||||||
if (encryptionState === 'enabled') {
|
|
||||||
var encryptionKeyType = $("input[name=projects-encryption-key]:checked").val();
|
|
||||||
if (encryptionKeyType === 'custom') {
|
|
||||||
createProjectOptions.credentialSecret = emptyProjectCredentialInput.val();
|
|
||||||
} else {
|
|
||||||
// If 'use existing', leave createProjectOptions.credentialSecret blank
|
|
||||||
// - that will trigger it to use the existing key
|
|
||||||
// TODO: this option should be disabled if encryption is disabled
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Disabled encryption by explicitly setting credSec to false
|
|
||||||
createProjectOptions.credentialSecret = false;
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "projects-dialog-create-encryption",
|
||||||
|
text: options.existingProject?"Create project files":"Create project", // TODO: nls
|
||||||
|
class: "primary disabled",
|
||||||
|
disabled: true,
|
||||||
|
click: function() {
|
||||||
|
var encryptionState = $("input[name=projects-encryption-type]:checked").val();
|
||||||
|
if (encryptionState === 'enabled') {
|
||||||
|
var encryptionKeyType = $("input[name=projects-encryption-key]:checked").val();
|
||||||
|
if (encryptionKeyType === 'custom') {
|
||||||
|
createProjectOptions.credentialSecret = emptyProjectCredentialInput.val();
|
||||||
|
} else {
|
||||||
|
// If 'use existing', leave createProjectOptions.credentialSecret blank
|
||||||
|
// - that will trigger it to use the existing key
|
||||||
|
// TODO: this option should be disabled if encryption is disabled
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Disabled encryption by explicitly setting credSec to false
|
||||||
|
createProjectOptions.credentialSecret = false;
|
||||||
|
}
|
||||||
|
RED.deploy.setDeployInflight(true);
|
||||||
|
RED.projects.settings.switchProject(createProjectOptions.name);
|
||||||
|
|
||||||
RED.deploy.setDeployInflight(true);
|
var method = "POST";
|
||||||
RED.projects.settings.switchProject(createProjectOptions.name);
|
var url = "projects";
|
||||||
|
|
||||||
sendRequest({
|
if (options.existingProject) {
|
||||||
url: "projects",
|
createProjectOptions.initialise = true;
|
||||||
type: "POST",
|
method = "PUT";
|
||||||
requireCleanWorkspace: true,
|
url = "projects/"+activeProject.name;
|
||||||
handleAuthFail: false,
|
}
|
||||||
responses: {
|
var self = this;
|
||||||
200: function(data) {
|
sendRequest({
|
||||||
createProjectOptions = {};
|
url: url,
|
||||||
show('create-success');
|
type: method,
|
||||||
},
|
requireCleanWorkspace: true,
|
||||||
400: {
|
handleAuthFail: false,
|
||||||
'project_exists': function(error) {
|
responses: {
|
||||||
console.log("already exists");
|
200: function(data) {
|
||||||
|
createProjectOptions = {};
|
||||||
|
if (options.existingProject) {
|
||||||
|
$( self ).dialog( "close" );
|
||||||
|
} else {
|
||||||
|
show('create-success');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'git_error': function(error) {
|
400: {
|
||||||
console.log("git error",error);
|
'project_exists': function(error) {
|
||||||
},
|
console.log("already exists");
|
||||||
'git_connection_failed': function(error) {
|
},
|
||||||
projectRepoInput.addClass("input-error");
|
'git_error': function(error) {
|
||||||
},
|
console.log("git error",error);
|
||||||
'git_auth_failed': function(error) {
|
},
|
||||||
projectRepoUserInput.addClass("input-error");
|
'git_connection_failed': function(error) {
|
||||||
projectRepoPasswordInput.addClass("input-error");
|
projectRepoInput.addClass("input-error");
|
||||||
// getRepoAuthDetails(req);
|
},
|
||||||
console.log("git auth error",error);
|
'git_auth_failed': function(error) {
|
||||||
},
|
projectRepoUserInput.addClass("input-error");
|
||||||
'unexpected_error': function(error) {
|
projectRepoPasswordInput.addClass("input-error");
|
||||||
console.log("unexpected_error",error)
|
// getRepoAuthDetails(req);
|
||||||
|
console.log("git auth error",error);
|
||||||
|
},
|
||||||
|
'unexpected_error': function(error) {
|
||||||
|
console.log("unexpected_error",error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},createProjectOptions).always(function() {
|
||||||
},createProjectOptions).always(function() {
|
RED.deploy.setDeployInflight(false);
|
||||||
RED.deploy.setDeployInflight(false);
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
];
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
'create-success': {
|
'create-success': {
|
||||||
@ -437,10 +552,10 @@ RED.projects = (function() {
|
|||||||
$('<p>').text("You have successfully created your first project!").appendTo(body);
|
$('<p>').text("You have successfully created your first project!").appendTo(body);
|
||||||
$('<p>').text("You can now continue to use Node-RED just as you always have.").appendTo(body);
|
$('<p>').text("You can now continue to use Node-RED just as you always have.").appendTo(body);
|
||||||
$('<p>').text("The 'info' tab in the sidebar shows you what your current active project is. "+
|
$('<p>').text("The 'info' tab in the sidebar shows you what your current active project is. "+
|
||||||
"The button next to the name can be used to access the project settings view.").appendTo(body);
|
"The button next to the name can be used to access the project settings view.").appendTo(body);
|
||||||
$('<p>').text("The new 'history' tab in the sidebar can be used to view files that have changed "+
|
$('<p>').text("The 'history' tab in the sidebar can be used to view files that have changed "+
|
||||||
"in your project and to commit them. It shows you a complete history of your commits and "+
|
"in your project and to commit them. It shows you a complete history of your commits and "+
|
||||||
"allows you to push your changes to a remote repository.").appendTo(body);
|
"allows you to push your changes to a remote repository.").appendTo(body);
|
||||||
|
|
||||||
return container;
|
return container;
|
||||||
},
|
},
|
||||||
@ -537,18 +652,15 @@ RED.projects = (function() {
|
|||||||
}
|
}
|
||||||
if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(repo)) {
|
if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(repo)) {
|
||||||
$(".projects-dialog-screen-create-row-creds").hide();
|
$(".projects-dialog-screen-create-row-creds").hide();
|
||||||
$(".projects-dialog-screen-create-row-passphrase").show();
|
|
||||||
$(".projects-dialog-screen-create-row-sshkey").show();
|
$(".projects-dialog-screen-create-row-sshkey").show();
|
||||||
// if ( !getSelectedSSHKey(projectRepoSSHKeySelect) ) {
|
// if ( !getSelectedSSHKey(projectRepoSSHKeySelect) ) {
|
||||||
// valid = false;
|
// valid = false;
|
||||||
// }
|
// }
|
||||||
} else if (/^https?:\/\//.test(repo)) {
|
} else if (/^https?:\/\//.test(repo)) {
|
||||||
$(".projects-dialog-screen-create-row-creds").show();
|
$(".projects-dialog-screen-create-row-creds").show();
|
||||||
$(".projects-dialog-screen-create-row-passphrase").hide();
|
|
||||||
$(".projects-dialog-screen-create-row-sshkey").hide();
|
$(".projects-dialog-screen-create-row-sshkey").hide();
|
||||||
} else {
|
} else {
|
||||||
$(".projects-dialog-screen-create-row-creds").show();
|
$(".projects-dialog-screen-create-row-creds").show();
|
||||||
$(".projects-dialog-screen-create-row-passphrase").hide();
|
|
||||||
$(".projects-dialog-screen-create-row-sshkey").hide();
|
$(".projects-dialog-screen-create-row-sshkey").hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,9 +869,9 @@ RED.projects = (function() {
|
|||||||
projectRepoPasswordInput = $('<input id="projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
|
projectRepoPasswordInput = $('<input id="projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
|
||||||
|
|
||||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').hide().appendTo(container);
|
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').hide().appendTo(container);
|
||||||
|
subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
|
||||||
$('<label for="projects-dialog-screen-create-project-repo-passphrase">SSH Key</label>').appendTo(row);
|
$('<label for="projects-dialog-screen-create-project-repo-passphrase">SSH Key</label>').appendTo(subrow);
|
||||||
projectRepoSSHKeySelect = $("<select>").appendTo(row);
|
projectRepoSSHKeySelect = $("<select>",{style:"width: 100%"}).appendTo(subrow);
|
||||||
|
|
||||||
$.getJSON("settings/user/keys", function(data) {
|
$.getJSON("settings/user/keys", function(data) {
|
||||||
var count = 0;
|
var count = 0;
|
||||||
@ -773,20 +885,9 @@ RED.projects = (function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-passphrase"></div>').hide().appendTo(container);
|
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
|
||||||
$('<label for="projects-dialog-screen-create-project-repo-passphrase">SSH key passphrase</label>').appendTo(row);
|
$('<label for="projects-dialog-screen-create-project-repo-passphrase">Passphrase</label>').appendTo(subrow);
|
||||||
projectRepoPassphrase = $('<input id="projects-dialog-screen-create-project-repo-passphrase" type="password" style="width: calc(100% - 250px);"></input>').appendTo(row);
|
projectRepoPassphrase = $('<input id="projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow);
|
||||||
|
|
||||||
// row = $('<div style="width: calc(50% - 10px); display:inline-block;" class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').hide().appendTo(container);
|
|
||||||
// $('<label for="projects-dialog-screen-create-project-repo-remote-name">Remote name</label>').appendTo(row);
|
|
||||||
// projectRepoRemoteName = $('<input id="projects-dialog-screen-create-project-repo-remote-name" type="text" style="width: 100%;"></input>').val("origin").appendTo(row);
|
|
||||||
//
|
|
||||||
// row = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;" class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').hide().appendTo(container);
|
|
||||||
// $('<label for="projects-dialog-screen-create-project-repo-branch">Branch</label>').appendTo(row);
|
|
||||||
// projectRepoBranch = $('<input id="projects-dialog-screen-create-project-repo-branch" type="text"></input>').val('master').appendTo(row);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// // Secret - clone
|
// // Secret - clone
|
||||||
// row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
|
// row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
|
||||||
@ -905,6 +1006,10 @@ RED.projects = (function() {
|
|||||||
projectRepoPassphrase.addClass("input-error");
|
projectRepoPassphrase.addClass("input-error");
|
||||||
console.log("git auth error",error);
|
console.log("git auth error",error);
|
||||||
},
|
},
|
||||||
|
'project_empty': function(error) {
|
||||||
|
// This is handled via a runtime notification.
|
||||||
|
dialog.dialog("close");
|
||||||
|
},
|
||||||
'unexpected_error': function(error) {
|
'unexpected_error': function(error) {
|
||||||
console.log("unexpected_error",error)
|
console.log("unexpected_error",error)
|
||||||
}
|
}
|
||||||
@ -996,15 +1101,12 @@ RED.projects = (function() {
|
|||||||
class: "primary disabled",
|
class: "primary disabled",
|
||||||
disabled: true,
|
disabled: true,
|
||||||
click: function() {
|
click: function() {
|
||||||
|
dialog.dialog( "close" );
|
||||||
switchProject(selectedProject.name,function(err,data) {
|
switchProject(selectedProject.name,function(err,data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.error === 'credentials_load_failed') {
|
if (err.error !== 'credentials_load_failed') {
|
||||||
dialog.dialog( "close" );
|
|
||||||
} else {
|
|
||||||
console.log("unexpected_error",err)
|
console.log("unexpected_error",err)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
dialog.dialog( "close" );
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1109,7 +1211,11 @@ RED.projects = (function() {
|
|||||||
var container = screen.content(options);
|
var container = screen.content(options);
|
||||||
|
|
||||||
dialogBody.empty();
|
dialogBody.empty();
|
||||||
dialog.dialog('option','buttons',screen.buttons);
|
var buttons = screen.buttons;
|
||||||
|
if (typeof buttons === 'function') {
|
||||||
|
buttons = buttons(options);
|
||||||
|
}
|
||||||
|
dialog.dialog('option','buttons',buttons);
|
||||||
dialogBody.append(container);
|
dialogBody.append(container);
|
||||||
dialog.dialog('option','title',screen.title||"");
|
dialog.dialog('option','title',screen.title||"");
|
||||||
dialog.dialog("open");
|
dialog.dialog("open");
|
||||||
@ -1258,7 +1364,7 @@ RED.projects = (function() {
|
|||||||
count++;
|
count++;
|
||||||
});
|
});
|
||||||
if (count === 0) {
|
if (count === 0) {
|
||||||
// projectRepoSSHKeySelect
|
//TODO: handle no keys yet setup
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
row = $('<div class="form-row"></div>').appendTo(message);
|
row = $('<div class="form-row"></div>').appendTo(message);
|
||||||
@ -1520,6 +1626,38 @@ RED.projects = (function() {
|
|||||||
// initSidebar();
|
// initSidebar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createDefaultFileSet() {
|
||||||
|
if (!activeProject) {
|
||||||
|
throw new Error("Cannot create default file set without an active project");
|
||||||
|
} else if (!activeProject.empty) {
|
||||||
|
throw new Error("Cannot create default file set on a non-empty project");
|
||||||
|
}
|
||||||
|
createProjectOptions = {};
|
||||||
|
show('default-files',{existingProject: true});
|
||||||
|
// var payload = {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// RED.deploy.setDeployInflight(true);
|
||||||
|
// utils.sendRequest({
|
||||||
|
// url: "projects/"+activeProject.name,
|
||||||
|
// type: "PUT",
|
||||||
|
// responses: {
|
||||||
|
// 0: function(error) {},
|
||||||
|
// 200: function(data) {
|
||||||
|
// activeProject = data;
|
||||||
|
// RED.sidebar.versionControl.refresh(true);
|
||||||
|
// },
|
||||||
|
// 400: {
|
||||||
|
// 'unexpected_error': function(error) {
|
||||||
|
// console.log(error);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// },payload).always(function() {
|
||||||
|
// RED.deploy.setDeployInflight(false);
|
||||||
|
// });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function refresh(done) {
|
function refresh(done) {
|
||||||
$.getJSON("projects",function(data) {
|
$.getJSON("projects",function(data) {
|
||||||
@ -1546,6 +1684,7 @@ RED.projects = (function() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
|
_show: show,
|
||||||
showStartup: function() {
|
showStartup: function() {
|
||||||
show('welcome');
|
show('welcome');
|
||||||
},
|
},
|
||||||
@ -1568,6 +1707,7 @@ RED.projects = (function() {
|
|||||||
showFilesPrompt: function() { //TODO: rename this function
|
showFilesPrompt: function() { //TODO: rename this function
|
||||||
RED.projects.settings.show('settings');
|
RED.projects.settings.show('settings');
|
||||||
},
|
},
|
||||||
|
createDefaultFileSet: createDefaultFileSet,
|
||||||
// showSidebar: showSidebar,
|
// showSidebar: showSidebar,
|
||||||
refresh: refresh,
|
refresh: refresh,
|
||||||
editProject: function() {
|
editProject: function() {
|
||||||
|
@ -1191,7 +1191,7 @@ RED.sidebar.versionControl = (function() {
|
|||||||
var commitsBehind = result.commits.behind || 0;
|
var commitsBehind = result.commits.behind || 0;
|
||||||
|
|
||||||
if (activeProject.git.hasOwnProperty('remotes')) {
|
if (activeProject.git.hasOwnProperty('remotes')) {
|
||||||
if (result.branches.hasOwnProperty("remoteError")) {
|
if (result.branches.hasOwnProperty("remoteError") && result.branches.remoteError.code !== 'git_remote_gone') {
|
||||||
$("#sidebar-version-control-repo-status-auth-issue").show();
|
$("#sidebar-version-control-repo-status-auth-issue").show();
|
||||||
$("#sidebar-version-control-repo-status-stats").hide();
|
$("#sidebar-version-control-repo-status-stats").hide();
|
||||||
$('#sidebar-version-control-repo-branch').attr('disabled',true);
|
$('#sidebar-version-control-repo-branch').attr('disabled',true);
|
||||||
|
@ -160,7 +160,7 @@
|
|||||||
}
|
}
|
||||||
#full-shade {
|
#full-shade {
|
||||||
@include shade;
|
@include shade;
|
||||||
z-index: 101;
|
z-index: 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-form,#dialog-form, #node-config-dialog-edit-form {
|
.dialog-form,#dialog-form, #node-config-dialog-edit-form {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
#notifications {
|
#notifications {
|
||||||
z-index: 101;
|
z-index: 100;
|
||||||
width: 500px;
|
width: 500px;
|
||||||
margin-left: -250px;
|
margin-left: -250px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
@ -86,7 +86,8 @@
|
|||||||
"missing-types": "Flows stopped due to missing node types. Check logs for details.",
|
"missing-types": "Flows stopped due to missing node types. Check logs for details.",
|
||||||
"restartRequired": "Node-RED must be restarted to enable upgraded modules",
|
"restartRequired": "Node-RED must be restarted to enable upgraded modules",
|
||||||
"credentials_load_failed": "Flows stopped due to missing or invalid credentialSecret",
|
"credentials_load_failed": "Flows stopped due to missing or invalid credentialSecret",
|
||||||
"missing_flow_file": "Could not find the project flow file"
|
"missing_flow_file": "Could not find the project flow file",
|
||||||
|
"project_empty": "<p>The project repository is empty.</p><p>Do you want to create a default set of project files?<br/>Otherwise, you will have to manually add files to the project outside of the editor.</p>"
|
||||||
},
|
},
|
||||||
|
|
||||||
"error": "<strong>Error</strong>: __message__",
|
"error": "<strong>Error</strong>: __message__",
|
||||||
|
@ -90,6 +90,17 @@ module.exports = {
|
|||||||
} else {
|
} else {
|
||||||
res.redirect(303,req.baseUrl + '/'+ req.params.id);
|
res.redirect(303,req.baseUrl + '/'+ req.params.id);
|
||||||
}
|
}
|
||||||
|
} else if (req.body.initialise) {
|
||||||
|
// Initialised set when creating default files for an empty repo
|
||||||
|
runtime.storage.projects.initialiseProject(req.user, req.params.id, req.body).then(function() {
|
||||||
|
res.redirect(303,req.baseUrl + '/'+ req.params.id);
|
||||||
|
}).catch(function(err) {
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
|
})
|
||||||
} else if (req.body.hasOwnProperty('credentialSecret') ||
|
} else if (req.body.hasOwnProperty('credentialSecret') ||
|
||||||
req.body.hasOwnProperty('description') ||
|
req.body.hasOwnProperty('description') ||
|
||||||
req.body.hasOwnProperty('dependencies')||
|
req.body.hasOwnProperty('dependencies')||
|
||||||
@ -145,8 +156,11 @@ module.exports = {
|
|||||||
res.status(404).end();
|
res.status(404).end();
|
||||||
}
|
}
|
||||||
}).catch(function(err) {
|
}).catch(function(err) {
|
||||||
console.log(err.stack);
|
if (err.code) {
|
||||||
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -154,12 +168,15 @@ module.exports = {
|
|||||||
// Project file listing
|
// Project file listing
|
||||||
app.get("/:id/files", needsPermission("projects.read"), function(req,res) {
|
app.get("/:id/files", needsPermission("projects.read"), function(req,res) {
|
||||||
runtime.storage.projects.getFiles(req.user, req.params.id).then(function(data) {
|
runtime.storage.projects.getFiles(req.user, req.params.id).then(function(data) {
|
||||||
console.log("TODO: REMOVE /:id/files as /:id/status is better!")
|
// console.log("TODO: REMOVE /:id/files as /:id/status is better!")
|
||||||
res.json(data);
|
res.json(data);
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
console.log(err.stack);
|
if (err.code) {
|
||||||
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -48,6 +48,16 @@ module.exports = {
|
|||||||
safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {};
|
safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {};
|
||||||
safeSettings.editorTheme.palette.editable = false;
|
safeSettings.editorTheme.palette.editable = false;
|
||||||
}
|
}
|
||||||
|
if (runtime.storage.projects) {
|
||||||
|
var activeProject = runtime.storage.projects.getActiveProject();
|
||||||
|
if (activeProject) {
|
||||||
|
safeSettings.project = activeProject;
|
||||||
|
}
|
||||||
|
safeSettings.files = {
|
||||||
|
flow: runtime.storage.projects.getFlowFilename(),
|
||||||
|
credentials: runtime.storage.projects.getCredentialsFilename()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType();
|
safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType();
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ function Project(name) {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
this.path = fspath.join(projectsDir,name);
|
this.path = fspath.join(projectsDir,name);
|
||||||
this.paths = {};
|
this.paths = {};
|
||||||
|
this.files = {};
|
||||||
this.auth = {origin:{}};
|
this.auth = {origin:{}};
|
||||||
|
|
||||||
this.missingFiles = [];
|
this.missingFiles = [];
|
||||||
@ -111,6 +112,44 @@ Project.prototype.load = function () {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Project.prototype.initialise = function(user,data) {
|
||||||
|
var project = this;
|
||||||
|
if (!this.empty) {
|
||||||
|
throw new Error("Cannot initialise non-empty project");
|
||||||
|
}
|
||||||
|
var files = Object.keys(defaultFileSet);
|
||||||
|
var promises = [];
|
||||||
|
|
||||||
|
if (data.hasOwnProperty('credentialSecret')) {
|
||||||
|
var projects = settings.get('projects');
|
||||||
|
projects.projects[project.name] = projects.projects[project.name] || {};
|
||||||
|
projects.projects[project.name].credentialSecret = data.credentialSecret;
|
||||||
|
promises.push(settings.set('projects',projects));
|
||||||
|
}
|
||||||
|
|
||||||
|
project.files.flow = data.files.flow;
|
||||||
|
project.files.credentials = data.files.credentials;
|
||||||
|
var flowFilePath = fspath.join(project.path,project.files.flow);
|
||||||
|
var credsFilePath = getCredentialsFilename(flowFilePath);
|
||||||
|
promises.push(util.writeFile(flowFilePath,"[]"));
|
||||||
|
promises.push(util.writeFile(credsFilePath,"{}"));
|
||||||
|
files.push(project.files.flow);
|
||||||
|
files.push(project.files.credentials);
|
||||||
|
for (var file in defaultFileSet) {
|
||||||
|
if (defaultFileSet.hasOwnProperty(file)) {
|
||||||
|
promises.push(util.writeFile(fspath.join(project.path,file),defaultFileSet[file](project)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return when.all(promises).then(function() {
|
||||||
|
return gitTools.stageFile(project.path,files);
|
||||||
|
}).then(function() {
|
||||||
|
return gitTools.commit(project.path,"Create project files");
|
||||||
|
}).then(function() {
|
||||||
|
return project.load()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Project.prototype.loadRemotes = function() {
|
Project.prototype.loadRemotes = function() {
|
||||||
var project = this;
|
var project = this;
|
||||||
return gitTools.getRemotes(project.path).then(function(remotes) {
|
return gitTools.getRemotes(project.path).then(function(remotes) {
|
||||||
@ -154,8 +193,15 @@ Project.prototype.loadBranches = function() {
|
|||||||
var project = this;
|
var project = this;
|
||||||
return gitTools.getBranchInfo(project.path).then(function(branches) {
|
return gitTools.getBranchInfo(project.path).then(function(branches) {
|
||||||
project.branches = branches;
|
project.branches = branches;
|
||||||
|
project.empty = project.branches.empty;
|
||||||
|
delete project.branches.empty;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Project.prototype.isEmpty = function () {
|
||||||
|
return this.empty;
|
||||||
|
};
|
||||||
|
|
||||||
Project.prototype.update = function (user, data) {
|
Project.prototype.update = function (user, data) {
|
||||||
var username;
|
var username;
|
||||||
if (!user) {
|
if (!user) {
|
||||||
@ -297,7 +343,12 @@ Project.prototype.update = function (user, data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Project.prototype.getFiles = function () {
|
Project.prototype.getFiles = function () {
|
||||||
return gitTools.getFiles(this.path);
|
return gitTools.getFiles(this.path).catch(function(err) {
|
||||||
|
if (/ambiguous argument/.test(err.message)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
Project.prototype.stageFile = function(file) {
|
Project.prototype.stageFile = function(file) {
|
||||||
return gitTools.stageFile(this.path,file);
|
return gitTools.stageFile(this.path,file);
|
||||||
@ -319,7 +370,16 @@ Project.prototype.getFileDiff = function(file,type) {
|
|||||||
return gitTools.getFileDiff(this.path,file,type);
|
return gitTools.getFileDiff(this.path,file,type);
|
||||||
}
|
}
|
||||||
Project.prototype.getCommits = function(options) {
|
Project.prototype.getCommits = function(options) {
|
||||||
return gitTools.getCommits(this.path,options);
|
return gitTools.getCommits(this.path,options).catch(function(err) {
|
||||||
|
if (/ambiguous argument/.test(err.message) || /does not have any commits yet/.test(err.message)) {
|
||||||
|
return {
|
||||||
|
count:0,
|
||||||
|
commits:[],
|
||||||
|
total: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Project.prototype.getCommit = function(sha) {
|
Project.prototype.getCommit = function(sha) {
|
||||||
return gitTools.getCommit(this.path,sha);
|
return gitTools.getCommit(this.path,sha);
|
||||||
@ -373,20 +433,29 @@ Project.prototype.status = function(user) {
|
|||||||
}
|
}
|
||||||
self.branches.local = result.branches.local;
|
self.branches.local = result.branches.local;
|
||||||
self.branches.remote = result.branches.remote;
|
self.branches.remote = result.branches.remote;
|
||||||
if (fetchError) {
|
if (fetchError && !/ambiguous argument/.test(fetchError.message)) {
|
||||||
result.branches.remoteError = {
|
result.branches.remoteError = {
|
||||||
remote: fetchError.remote,
|
remote: fetchError.remote,
|
||||||
code: fetchError.code
|
code: fetchError.code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
}).catch(function(err) {
|
||||||
|
if (/ambiguous argument/.test(err.message)) {
|
||||||
|
return {
|
||||||
|
files:{},
|
||||||
|
commits:{total:0},
|
||||||
|
branches:{}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return fetchPromise.then(completeStatus).catch(function(e) {
|
return fetchPromise.then(completeStatus).catch(function(e) {
|
||||||
if (e.code !== 'git_auth_failed') {
|
// if (e.code !== 'git_auth_failed') {
|
||||||
console.log("Fetch failed");
|
// console.log("Fetch failed");
|
||||||
console.log(e);
|
// console.log(e);
|
||||||
}
|
// }
|
||||||
return completeStatus(e);
|
return completeStatus(e);
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
@ -600,6 +669,7 @@ Project.prototype.toJSON = function () {
|
|||||||
summary: this.package.description,
|
summary: this.package.description,
|
||||||
description: this.description,
|
description: this.description,
|
||||||
dependencies: this.package.dependencies||{},
|
dependencies: this.package.dependencies||{},
|
||||||
|
empty: this.empty,
|
||||||
settings: {
|
settings: {
|
||||||
credentialsEncrypted: (typeof this.credentialSecret === "string"),
|
credentialsEncrypted: (typeof this.credentialSecret === "string"),
|
||||||
credentialSecretInvalid: this.credentialSecretInvalid
|
credentialSecretInvalid: this.credentialSecretInvalid
|
||||||
@ -663,15 +733,15 @@ function createDefaultProject(user, project) {
|
|||||||
var credsFilePath;
|
var credsFilePath;
|
||||||
|
|
||||||
if (project.files.migrateFiles) {
|
if (project.files.migrateFiles) {
|
||||||
var baseFlowFileName = fspath.basename(project.files.flow);
|
var baseFlowFileName = project.files.flow || fspath.basename(project.files.oldFlow);
|
||||||
var baseCredentialFileName = fspath.basename(project.files.credentials);
|
var baseCredentialFileName = project.files.credentials || fspath.basename(project.files.oldCredentials);
|
||||||
files.push(baseFlowFileName);
|
files.push(baseFlowFileName);
|
||||||
files.push(baseCredentialFileName);
|
files.push(baseCredentialFileName);
|
||||||
flowFilePath = fspath.join(projectPath,baseFlowFileName);
|
flowFilePath = fspath.join(projectPath,baseFlowFileName);
|
||||||
credsFilePath = fspath.join(projectPath,baseCredentialFileName);
|
credsFilePath = fspath.join(projectPath,baseCredentialFileName);
|
||||||
log.trace("Migrating "+project.files.flow+" to "+flowFilePath);
|
log.trace("Migrating "+project.files.oldFlow+" to "+flowFilePath);
|
||||||
log.trace("Migrating "+project.files.credentials+" to "+credsFilePath);
|
log.trace("Migrating "+project.files.oldCredentials+" to "+credsFilePath);
|
||||||
promises.push(fs.copy(project.files.flow,flowFilePath));
|
promises.push(fs.copy(project.files.oldFlow,flowFilePath));
|
||||||
runtime.nodes.setCredentialSecret(project.credentialSecret);
|
runtime.nodes.setCredentialSecret(project.credentialSecret);
|
||||||
promises.push(runtime.nodes.exportCredentials().then(function(creds) {
|
promises.push(runtime.nodes.exportCredentials().then(function(creds) {
|
||||||
var credentialData;
|
var credentialData;
|
||||||
@ -769,7 +839,6 @@ function createProject(user, metadata) {
|
|||||||
if (metadata.git && metadata.git.remotes && metadata.git.remotes.origin) {
|
if (metadata.git && metadata.git.remotes && metadata.git.remotes.origin) {
|
||||||
var originRemote = metadata.git.remotes.origin;
|
var originRemote = metadata.git.remotes.origin;
|
||||||
var auth;
|
var auth;
|
||||||
console.log('originRemote:', originRemote);
|
|
||||||
if (originRemote.hasOwnProperty("username") && originRemote.hasOwnProperty("password")) {
|
if (originRemote.hasOwnProperty("username") && originRemote.hasOwnProperty("password")) {
|
||||||
authCache.set(project,originRemote.url,username,{ // TODO: hardcoded remote name
|
authCache.set(project,originRemote.url,username,{ // TODO: hardcoded remote name
|
||||||
username: originRemote.username,
|
username: originRemote.username,
|
||||||
@ -799,7 +868,18 @@ function createProject(user, metadata) {
|
|||||||
// console.log("checkProjectFiles");
|
// console.log("checkProjectFiles");
|
||||||
// console.log(results);
|
// console.log(results);
|
||||||
// });
|
// });
|
||||||
|
// return gitTools.getFiles(projectPath).then(function() {
|
||||||
|
// // It wasn't an empty repository.
|
||||||
|
// // TODO: check for required files - checkProjectFiles
|
||||||
|
//
|
||||||
|
// }).catch(function(err) {
|
||||||
|
// if (/ambiguous argument/.test(err.message)) {
|
||||||
|
// // Empty repository
|
||||||
|
// err.code = "project_empty";
|
||||||
|
// err.message = "Project is empty";
|
||||||
|
// }
|
||||||
|
// throw err;
|
||||||
|
// });
|
||||||
resolve(getProject(project));
|
resolve(getProject(project));
|
||||||
}).catch(function(error) {
|
}).catch(function(error) {
|
||||||
fs.remove(projectPath,function() {
|
fs.remove(projectPath,function() {
|
||||||
|
@ -121,20 +121,17 @@ function getBranchInfo(localRepo) {
|
|||||||
return runGitCommand(["status","--porcelain","-b"],localRepo).then(function(output) {
|
return runGitCommand(["status","--porcelain","-b"],localRepo).then(function(output) {
|
||||||
var lines = output.split("\n");
|
var lines = output.split("\n");
|
||||||
var unknownDirs = [];
|
var unknownDirs = [];
|
||||||
var branchLineRE = /^## (.+?)($|\.\.\.(.+?)($| \[(ahead (\d+))?.*?(behind (\d+))?\]))/m;
|
var branchLineRE = /^## (No commits yet on )?(.+?)($|\.\.\.(.+?)($| \[(ahead (\d+))?.*?(behind (\d+))?\]))/m;
|
||||||
var m = branchLineRE.exec(output);
|
var m = branchLineRE.exec(output);
|
||||||
var result = {}; //commits:{}};
|
var result = {}; //commits:{}};
|
||||||
if (m) {
|
if (m) {
|
||||||
result.local = m[1];
|
if (m[1]) {
|
||||||
if (m[3]) {
|
result.empty = true;
|
||||||
result.remote = m[3];
|
}
|
||||||
|
result.local = m[2];
|
||||||
|
if (m[4]) {
|
||||||
|
result.remote = m[4];
|
||||||
}
|
}
|
||||||
// if (m[6] !== undefined) {
|
|
||||||
// result.commits.ahead = parseInt(m[6]);
|
|
||||||
// }
|
|
||||||
// if (m[8] !== undefined) {
|
|
||||||
// result.commits.behind = parseInt(m[8]);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
@ -177,7 +174,7 @@ function getStatus(localRepo) {
|
|||||||
return runGitCommand(["status","--porcelain","-b"],localRepo).then(function(output) {
|
return runGitCommand(["status","--porcelain","-b"],localRepo).then(function(output) {
|
||||||
var lines = output.split("\n");
|
var lines = output.split("\n");
|
||||||
var unknownDirs = [];
|
var unknownDirs = [];
|
||||||
var branchLineRE = /^## (.+?)($|\.\.\.(.+?)($| \[(ahead (\d+))?.*?(behind (\d+))?\]))/;
|
var branchLineRE = /^## (.+?)(?:$|\.\.\.(.+?)(?:$| \[(?:(?:ahead (\d+)(?:,\s*)?)?(?:behind (\d+))?|(gone))\]))/;
|
||||||
lines.forEach(function(line) {
|
lines.forEach(function(line) {
|
||||||
if (line==="") {
|
if (line==="") {
|
||||||
return;
|
return;
|
||||||
@ -186,16 +183,22 @@ function getStatus(localRepo) {
|
|||||||
var m = branchLineRE.exec(line);
|
var m = branchLineRE.exec(line);
|
||||||
if (m) {
|
if (m) {
|
||||||
result.branches.local = m[1];
|
result.branches.local = m[1];
|
||||||
if (m[3]) {
|
if (m[2]) {
|
||||||
result.branches.remote = m[3];
|
result.branches.remote = m[2];
|
||||||
result.commits.ahead = 0;
|
result.commits.ahead = 0;
|
||||||
result.commits.behind = 0;
|
result.commits.behind = 0;
|
||||||
}
|
}
|
||||||
if (m[6] !== undefined) {
|
if (m[3] !== undefined) {
|
||||||
result.commits.ahead = parseInt(m[6]);
|
result.commits.ahead = parseInt(m[3]);
|
||||||
}
|
}
|
||||||
if (m[8] !== undefined) {
|
if (m[4] !== undefined) {
|
||||||
result.commits.behind = parseInt(m[8]);
|
result.commits.behind = parseInt(m[4]);
|
||||||
|
}
|
||||||
|
if (m[5] !== undefined) {
|
||||||
|
result.commits.ahead = result.commits.total;
|
||||||
|
result.branches.remoteError = {
|
||||||
|
code: "git_remote_gone"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -303,8 +303,15 @@ function createProject(user, metadata) {
|
|||||||
if (!metadata.hasOwnProperty('credentialSecret')) {
|
if (!metadata.hasOwnProperty('credentialSecret')) {
|
||||||
metadata.credentialSecret = currentEncryptionKey;
|
metadata.credentialSecret = currentEncryptionKey;
|
||||||
}
|
}
|
||||||
metadata.files.flow = flowsFullPath;
|
if (!metadata.files.flow) {
|
||||||
metadata.files.credentials = credentialsFile;
|
metadata.files.flow = fspath.basename(flowsFullPath);
|
||||||
|
}
|
||||||
|
if (!metadata.files.credentials) {
|
||||||
|
metadata.files.credentials = fspath.basename(credentialsFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.files.oldFlow = flowsFullPath;
|
||||||
|
metadata.files.oldCredentials = credentialsFile;
|
||||||
metadata.files.credentialSecret = currentEncryptionKey;
|
metadata.files.credentialSecret = currentEncryptionKey;
|
||||||
}
|
}
|
||||||
return Projects.create(null,metadata).then(function(p) {
|
return Projects.create(null,metadata).then(function(p) {
|
||||||
@ -327,6 +334,21 @@ function setActiveProject(user, projectName) {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initialiseProject(user, project, data) {
|
||||||
|
if (!activeProject || activeProject.name !== project) {
|
||||||
|
// TODO standardise
|
||||||
|
throw new Error("Cannot initialise inactive project");
|
||||||
|
}
|
||||||
|
return activeProject.initialise(user,data).then(function(result) {
|
||||||
|
flowsFullPath = activeProject.getFlowFile();
|
||||||
|
flowsFileBackup = activeProject.getFlowFileBackup();
|
||||||
|
credentialsFile = activeProject.getCredentialsFile();
|
||||||
|
credentialsFileBackup = activeProject.getCredentialsFileBackup();
|
||||||
|
runtime.nodes.setCredentialSecret(activeProject.credentialSecret);
|
||||||
|
return reloadActiveProject("updated");
|
||||||
|
});
|
||||||
|
}
|
||||||
function updateProject(user, project, data) {
|
function updateProject(user, project, data) {
|
||||||
if (!activeProject || activeProject.name !== project) {
|
if (!activeProject || activeProject.name !== project) {
|
||||||
// TODO standardise
|
// TODO standardise
|
||||||
@ -414,9 +436,16 @@ function getFlows() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (activeProject) {
|
if (activeProject) {
|
||||||
|
var error;
|
||||||
|
if (activeProject.isEmpty()) {
|
||||||
|
log.warn("Project repository is empty");
|
||||||
|
error = new Error("Project repository is empty");
|
||||||
|
error.code = "project_empty";
|
||||||
|
return when.reject(error);
|
||||||
|
}
|
||||||
if (!activeProject.getFlowFile()) {
|
if (!activeProject.getFlowFile()) {
|
||||||
log.warn("NLS: project has no flow file");
|
log.warn("Project has no flow file");
|
||||||
var error = new Error("NLS: project has no flow file");
|
error = new Error("Project has no flow file");
|
||||||
error.code = "missing_flow_file";
|
error.code = "missing_flow_file";
|
||||||
return when.reject(error);
|
return when.reject(error);
|
||||||
}
|
}
|
||||||
@ -466,6 +495,16 @@ function saveCredentials(credentials) {
|
|||||||
return util.writeFile(credentialsFile, credentialData);
|
return util.writeFile(credentialsFile, credentialData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFlowFilename() {
|
||||||
|
if (flowsFullPath) {
|
||||||
|
return fspath.basename(flowsFullPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getCredentialsFilename() {
|
||||||
|
if (flowsFullPath) {
|
||||||
|
return fspath.basename(credentialsFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init: init,
|
init: init,
|
||||||
@ -475,6 +514,7 @@ module.exports = {
|
|||||||
getProject: getProject,
|
getProject: getProject,
|
||||||
deleteProject: deleteProject,
|
deleteProject: deleteProject,
|
||||||
createProject: createProject,
|
createProject: createProject,
|
||||||
|
initialiseProject: initialiseProject,
|
||||||
updateProject: updateProject,
|
updateProject: updateProject,
|
||||||
getFiles: getFiles,
|
getFiles: getFiles,
|
||||||
getFile: getFile,
|
getFile: getFile,
|
||||||
@ -498,6 +538,8 @@ module.exports = {
|
|||||||
addRemote: addRemote,
|
addRemote: addRemote,
|
||||||
removeRemote: removeRemote,
|
removeRemote: removeRemote,
|
||||||
updateRemote: updateRemote,
|
updateRemote: updateRemote,
|
||||||
|
getFlowFilename: getFlowFilename,
|
||||||
|
getCredentialsFilename: getCredentialsFilename,
|
||||||
|
|
||||||
getFlows: getFlows,
|
getFlows: getFlows,
|
||||||
saveFlows: saveFlows,
|
saveFlows: saveFlows,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user