From a988e6e78fbc6f558a17c8f33d121efea9a95869 Mon Sep 17 00:00:00 2001 From: Thomas Berger Date: Thu, 9 Aug 2018 15:08:58 +0200 Subject: [PATCH 01/21] wip --- install.js | 446 +++++++++++++++++++++--------------------- lib/installHelpers.js | 57 +++++- 2 files changed, 281 insertions(+), 222 deletions(-) diff --git a/install.js b/install.js index 39ae5de5e2..1f5a11619d 100644 --- a/install.js +++ b/install.js @@ -25,248 +25,252 @@ var superUser = false; // from user input var configResults; -// we need the framework version for the config items, so let's go -installHelpers.getLatestFrameworkVersion(function(error, latestFrameworkTag) { - if(error) { - return handleError(error, 1, 'Failed to get the latest framework version. Check package.json.'); - } - inputData = { - useConfigJSON: { - name: 'useJSON', - description: 'Use existing config values? y/N', - type: 'string', - before: installHelpers.inputHelpers.toBoolean, - default: 'N' - }, - startInstall: { - name: 'install', - description: 'Continue? Y/n', - type: 'string', - before: installHelpers.inputHelpers.toBoolean, - default: 'Y' - }, - server: [ - { - name: 'serverPort', - type: 'number', - description: 'Server port', - pattern: installHelpers.inputHelpers.numberValidator, - default: 5000 - }, - { - name: 'serverName', - type: 'string', - description: 'Server name', - default: 'localhost' - }, - { - name: 'dbHost', - type: 'string', - description: 'Database host', - default: 'localhost' - }, - { - name: 'dbName', - type: 'string', - description: 'Master database name', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'adapt-tenant-master' - }, - { - name: 'dbPort', - type: 'number', - description: 'Database server port', - pattern: installHelpers.inputHelpers.numberValidator, - default: 27017 - }, - { - name: 'dbUser', - type: 'string', - description: 'Database server user', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: '' - }, - { - name: 'dbPass', - type: 'string', - description: 'Database server password', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: '' - }, - { - name: 'dbAuthSource', - type: 'string', - description: 'Database server authentication database', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'admin' - }, - { - name: 'dataRoot', - type: 'string', - description: 'Data directory path', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'data' - }, - { - name: 'sessionSecret', - type: 'string', - description: 'Session secret (value used when saving session cookie data)', - pattern: /^.+$/, - default: 'your-session-secret' - }, - { - name: 'authoringToolRepository', - type: 'string', - description: "Git repository URL to be used for the authoring tool source code", - default: 'https://github.com/adaptlearning/adapt_authoring.git' - }, - { - name: 'frameworkRepository', +installHelpers.checkPrerequisites(function(error) { + exit(0); + installHelpers.getLatestFrameworkVersion(function(error, latestFrameworkTag) { + if(error) { + return handleError(error, 1, 'Failed to get the latest framework version. Check package.json.'); + } + inputData = { + useConfigJSON: { + name: 'useJSON', + description: 'Use existing config values? y/N', type: 'string', - description: "Git repository URL to be used for the framework source code", - default: 'https://github.com/adaptlearning/adapt_framework.git' + before: installHelpers.inputHelpers.toBoolean, + default: 'N' }, - { - name: 'frameworkRevision', - type: 'string', - description: 'Specific git revision to be used for the framework. Accepts any valid revision type (e.g. branch/tag/commit)', - default: 'tags/' + latestFrameworkTag - } - ], - features: { - ffmpeg: { - name: 'useffmpeg', + startInstall: { + name: 'install', + description: 'Continue? Y/n', type: 'string', - description: "Are you using ffmpeg? y/N", before: installHelpers.inputHelpers.toBoolean, - default: 'N' + default: 'Y' }, - smtp: { - confirm: { - name: 'useSmtp', + server: [ + { + name: 'serverPort', + type: 'number', + description: 'Server port', + pattern: installHelpers.inputHelpers.numberValidator, + default: 5000 + }, + { + name: 'serverName', type: 'string', - description: "Will you be using an SMTP server? (used for sending emails) y/N", - before: installHelpers.inputHelpers.toBoolean, - default: 'N' + description: 'Server name', + default: 'localhost' + }, + { + name: 'dbHost', + type: 'string', + description: 'Database host', + default: 'localhost' + }, + { + name: 'dbName', + type: 'string', + description: 'Master database name', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'adapt-tenant-master' + }, + { + name: 'dbPort', + type: 'number', + description: 'Database server port', + pattern: installHelpers.inputHelpers.numberValidator, + default: 27017 + }, + { + name: 'dbUser', + type: 'string', + description: 'Database server user', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: '' + }, + { + name: 'dbPass', + type: 'string', + description: 'Database server password', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: '' + }, + { + name: 'dbAuthSource', + type: 'string', + description: 'Database server authentication database', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'admin' + }, + { + name: 'dataRoot', + type: 'string', + description: 'Data directory path', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'data' + }, + { + name: 'sessionSecret', + type: 'string', + description: 'Session secret (value used when saving session cookie data)', + pattern: /^.+$/, + default: 'your-session-secret' + }, + { + name: 'authoringToolRepository', + type: 'string', + description: "Git repository URL to be used for the authoring tool source code", + default: 'https://github.com/adaptlearning/adapt_authoring.git' }, - confirmConnectionUrl: { - name: 'useSmtpConnectionUrl', + { + name: 'frameworkRepository', + type: 'string', + description: "Git repository URL to be used for the framework source code", + default: 'https://github.com/adaptlearning/adapt_framework.git' + }, + { + name: 'frameworkRevision', + type: 'string', + description: 'Specific git revision to be used for the framework. Accepts any valid revision type (e.g. branch/tag/commit)', + default: 'tags/' + latestFrameworkTag + } + ], + features: { + ffmpeg: { + name: 'useffmpeg', type: 'string', - description: "Will you use a URL to connect to your smtp Server y/N", + description: "Are you using ffmpeg? y/N", before: installHelpers.inputHelpers.toBoolean, default: 'N' }, - configure: [ - { - name: 'fromAddress', + smtp: { + confirm: { + name: 'useSmtp', type: 'string', - description: "Sender email address", - default: '', + description: "Will you be using an SMTP server? (used for sending emails) y/N", + before: installHelpers.inputHelpers.toBoolean, + default: 'N' }, - { - name: 'rootUrl', + confirmConnectionUrl: { + name: 'useSmtpConnectionUrl', type: 'string', - description: "The url this install will be accessible from", - default: '' // set using default server options - } - ], - configureService: [ - { - name: 'smtpService', - type: 'string', - description: "Which SMTP service (if any) will be used? (see https://github.com/andris9/nodemailer-wellknown#supported-services for a list of supported services.)", - default: 'none', - }, - { - name: 'smtpUsername', - type: 'string', - description: "SMTP username", - default: '', + description: "Will you use a URL to connect to your smtp Server y/N", + before: installHelpers.inputHelpers.toBoolean, + default: 'N' }, - { - name: 'smtpPassword', - type: 'string', - description: "SMTP password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - default: '', - before: installHelpers.inputHelpers.passwordBefore - } - ], - configureConnectionUrl: [ - { - name: 'smtpConnectionUrl', - type: 'string', - description: "Custom connection URL: smtps://user%40gmail.com:pass@smtp.gmail.com/?pool=true", - default: 'none', - } - ] - } - }, - tenant: [ - { - name: 'masterTenantName', - type: 'string', - description: "Set a unique name for your tenant", - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'master' - }, - { - name: 'masterTenantDisplayName', - type: 'string', - description: 'Set the display name for your tenant', - default: 'Master' - } - ], - tenantDelete: { - name: "confirm", - description: "Continue? (Y/n)", - before: installHelpers.inputHelpers.toBoolean, - default: "Y" - }, - superUser: [ - { - name: 'suEmail', - type: 'string', - description: "Email address", - required: true + configure: [ + { + name: 'fromAddress', + type: 'string', + description: "Sender email address", + default: '', + }, + { + name: 'rootUrl', + type: 'string', + description: "The url this install will be accessible from", + default: '' // set using default server options + } + ], + configureService: [ + { + name: 'smtpService', + type: 'string', + description: "Which SMTP service (if any) will be used? (see https://github.com/andris9/nodemailer-wellknown#supported-services for a list of supported services.)", + default: 'none', + }, + { + name: 'smtpUsername', + type: 'string', + description: "SMTP username", + default: '', + }, + { + name: 'smtpPassword', + type: 'string', + description: "SMTP password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + default: '', + before: installHelpers.inputHelpers.passwordBefore + } + ], + configureConnectionUrl: [ + { + name: 'smtpConnectionUrl', + type: 'string', + description: "Custom connection URL: smtps://user%40gmail.com:pass@smtp.gmail.com/?pool=true", + default: 'none', + } + ] + } }, - { - name: 'suPassword', - type: 'string', - description: "Password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - required: true, - before: installHelpers.inputHelpers.passwordBefore + tenant: [ + { + name: 'masterTenantName', + type: 'string', + description: "Set a unique name for your tenant", + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'master' + }, + { + name: 'masterTenantDisplayName', + type: 'string', + description: 'Set the display name for your tenant', + default: 'Master' + } + ], + tenantDelete: { + name: "confirm", + description: "Continue? (Y/n)", + before: installHelpers.inputHelpers.toBoolean, + default: "Y" }, - { - name: 'suRetypePassword', - type: 'string', - description: "Confirm Password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - required: true, - before: installHelpers.inputHelpers.passwordBefore - } - ] - }; - if(!IS_INTERACTIVE) { - return start(); - } - console.log(''); - if(!fs.existsSync('conf/config.json')) { - fs.ensureDirSync('conf'); - return start(); - } - console.log('Found an existing config.json file. Do you want to use the values in this file during install?'); - installHelpers.getInput(inputData.useConfigJSON, function(result) { + superUser: [ + { + name: 'suEmail', + type: 'string', + description: "Email address", + required: true + }, + { + name: 'suPassword', + type: 'string', + description: "Password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + required: true, + before: installHelpers.inputHelpers.passwordBefore + }, + { + name: 'suRetypePassword', + type: 'string', + description: "Confirm Password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + required: true, + before: installHelpers.inputHelpers.passwordBefore + } + ] + }; + if(!IS_INTERACTIVE) { + return start(); + } console.log(''); - USE_CONFIG = result.useJSON; - start(); + if(!fs.existsSync('conf/config.json')) { + fs.ensureDirSync('conf'); + return start(); + } + console.log('Found an existing config.json file. Do you want to use the values in this file during install?'); + installHelpers.getInput(inputData.useConfigJSON, function(result) { + console.log(''); + USE_CONFIG = result.useJSON; + start(); + }); }); }); +// we need the framework version for the config items, so let's go + function generatePromptOverrides() { if(USE_CONFIG) { var configJson = require('./conf/config.json'); diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 7bc9fc7ef9..8ad2d5a589 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -62,7 +62,8 @@ var exports = module.exports = { updateFramework, updateFrameworkPlugins, updateAuthoring, - buildAuthoring + buildAuthoring, + checkPrerequisites }; function exit(code, msg, preCallback) { @@ -578,3 +579,57 @@ function error(msg) { function isSilent() { return process.env.SILENT; } + +function checkPrerequisites(callback) { + const result = { + errors: [], + warnings: [] + }; + + async.applyEach([ + checkGitInstalled, + checkGruntCliInstalled, + checkGithubConnection, + checkLocalMongoDbConnection + ], result, function(error, results) { + debugger; + }) +} + +function checkGitInstalled(result, gitCb) { + execCommand('git --version', {}, function(error, stdOut) { + if (error) { + result.errors.push(new Error('git must be installed')); + } + gitCb(); + }); +} + +function checkGruntCliInstalled(result, gruntCb) { + execCommand('grunt --version', {}, function(error, stdOut) { + if (error) { + result.errors.push(new Error('grunt-cli must be installed')); + } + gruntCb(); + }); +} + +function checkGithubConnection(result, githubCb) { + const url = 'https://api.github.com/'; + request({ + headers: { + 'User-Agent': DEFAULT_USER_AGENT + }, + uri: url, + method: 'GET' + }, function(error, response) { + if (error) { + result.errors.push(new Error(`Failed to´connect to ${url}`)); + } + githubCb(); + }); +} + +function checkLocalMongoDbConnection(result, callback) { + callback(null); +} From 659f303bf98d6d1b6077f13f99b45f0d512b6c69 Mon Sep 17 00:00:00 2001 From: Thomas Berger Date: Tue, 14 Aug 2018 10:09:34 +0200 Subject: [PATCH 02/21] check required dependencies for installation: - git - grunt-cli - github-api connection warn if local mongo-db not found --- install.js | 5 ++++- lib/installHelpers.js | 28 +++++++++++++++++++++------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/install.js b/install.js index 1f5a11619d..22bf5a2345 100644 --- a/install.js +++ b/install.js @@ -26,7 +26,10 @@ var superUser = false; var configResults; installHelpers.checkPrerequisites(function(error) { - exit(0); + if(error) { + return handleError(error, 1, 'Not all required pre-requisites fulfilled. Please check install guides.'); + } + installHelpers.getLatestFrameworkVersion(function(error, latestFrameworkTag) { if(error) { return handleError(error, 1, 'Failed to get the latest framework version. Check package.json.'); diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 8ad2d5a589..1c047e983b 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -580,6 +580,10 @@ function isSilent() { return process.env.SILENT; } +/** +* Manually collect all misisng prerequisites +* Therefore we do not pass error to async-callbacks as this would exit the process +*/ function checkPrerequisites(callback) { const result = { errors: [], @@ -591,15 +595,20 @@ function checkPrerequisites(callback) { checkGruntCliInstalled, checkGithubConnection, checkLocalMongoDbConnection - ], result, function(error, results) { - debugger; - }) + ], result, function(error) { + if (error) return callback(error); + if (result.errors.length) { + return callback(new Error(result.errors.join(', '))); + } + console.log(result.warnings.join('\n')); + return callback(null); + }); } function checkGitInstalled(result, gitCb) { execCommand('git --version', {}, function(error, stdOut) { if (error) { - result.errors.push(new Error('git must be installed')); + result.errors.push('git must be installed'); } gitCb(); }); @@ -608,7 +617,7 @@ function checkGitInstalled(result, gitCb) { function checkGruntCliInstalled(result, gruntCb) { execCommand('grunt --version', {}, function(error, stdOut) { if (error) { - result.errors.push(new Error('grunt-cli must be installed')); + result.errors.push('grunt-cli must be installed'); } gruntCb(); }); @@ -624,12 +633,17 @@ function checkGithubConnection(result, githubCb) { method: 'GET' }, function(error, response) { if (error) { - result.errors.push(new Error(`Failed to´connect to ${url}`)); + result.errors.push(`Failed to´connect to ${url}`); } githubCb(); }); } function checkLocalMongoDbConnection(result, callback) { - callback(null); + execCommand('mongod --version', {}, function(error, stdOut) { + if (error) { + result.warnings.push('MongoDB was not found locally. Please install it locally or connect to a remote.'); + } + callback(); + }) } From 4472fbe6625deb34e306ad8ae3230482e64f9323 Mon Sep 17 00:00:00 2001 From: Thomas Berger Date: Tue, 14 Aug 2018 17:33:02 +0200 Subject: [PATCH 03/21] fix typos and add review --- install.js | 2 +- lib/installHelpers.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install.js b/install.js index 22bf5a2345..f05031dcce 100644 --- a/install.js +++ b/install.js @@ -27,7 +27,7 @@ var configResults; installHelpers.checkPrerequisites(function(error) { if(error) { - return handleError(error, 1, 'Not all required pre-requisites fulfilled. Please check install guides.'); + return handleError(error, 1, 'Not all pre-requisites fulfilled. Please check install guides.'); } installHelpers.getLatestFrameworkVersion(function(error, latestFrameworkTag) { diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 1c047e983b..c39e733f9b 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -581,7 +581,7 @@ function isSilent() { } /** -* Manually collect all misisng prerequisites +* Manually collect all missing prerequisites * Therefore we do not pass error to async-callbacks as this would exit the process */ function checkPrerequisites(callback) { @@ -633,7 +633,7 @@ function checkGithubConnection(result, githubCb) { method: 'GET' }, function(error, response) { if (error) { - result.errors.push(`Failed to´connect to ${url}`); + result.errors.push(`Failed to connect to ${url}`); } githubCb(); }); From 57bdc57e1da97995f0e74db4a7db2be4d9154a30 Mon Sep 17 00:00:00 2001 From: Thomas Berger Date: Tue, 21 Aug 2018 10:28:40 +0200 Subject: [PATCH 04/21] refactor: split into check for required optional dependencies add check for ffmpeg change error output format --- install.js | 452 +++++++++++++++++++++--------------------- lib/installHelpers.js | 59 ++++-- 2 files changed, 266 insertions(+), 245 deletions(-) diff --git a/install.js b/install.js index f05031dcce..aac7eb2a2b 100644 --- a/install.js +++ b/install.js @@ -25,251 +25,253 @@ var superUser = false; // from user input var configResults; -installHelpers.checkPrerequisites(function(error) { - if(error) { - return handleError(error, 1, 'Not all pre-requisites fulfilled. Please check install guides.'); - } +installHelpers.checkRequiredDependencies(function(error) { + if(error) return handleError(null, 1, error); - installHelpers.getLatestFrameworkVersion(function(error, latestFrameworkTag) { - if(error) { - return handleError(error, 1, 'Failed to get the latest framework version. Check package.json.'); - } - inputData = { - useConfigJSON: { - name: 'useJSON', - description: 'Use existing config values? y/N', - type: 'string', - before: installHelpers.inputHelpers.toBoolean, - default: 'N' - }, - startInstall: { - name: 'install', - description: 'Continue? Y/n', - type: 'string', - before: installHelpers.inputHelpers.toBoolean, - default: 'Y' - }, - server: [ - { - name: 'serverPort', - type: 'number', - description: 'Server port', - pattern: installHelpers.inputHelpers.numberValidator, - default: 5000 - }, - { - name: 'serverName', - type: 'string', - description: 'Server name', - default: 'localhost' - }, - { - name: 'dbHost', - type: 'string', - description: 'Database host', - default: 'localhost' - }, - { - name: 'dbName', - type: 'string', - description: 'Master database name', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'adapt-tenant-master' - }, - { - name: 'dbPort', - type: 'number', - description: 'Database server port', - pattern: installHelpers.inputHelpers.numberValidator, - default: 27017 - }, - { - name: 'dbUser', - type: 'string', - description: 'Database server user', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: '' - }, - { - name: 'dbPass', - type: 'string', - description: 'Database server password', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: '' - }, - { - name: 'dbAuthSource', - type: 'string', - description: 'Database server authentication database', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'admin' - }, - { - name: 'dataRoot', - type: 'string', - description: 'Data directory path', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'data' - }, - { - name: 'sessionSecret', - type: 'string', - description: 'Session secret (value used when saving session cookie data)', - pattern: /^.+$/, - default: 'your-session-secret' - }, - { - name: 'authoringToolRepository', - type: 'string', - description: "Git repository URL to be used for the authoring tool source code", - default: 'https://github.com/adaptlearning/adapt_authoring.git' - }, - { - name: 'frameworkRepository', + installHelpers.checkOptionalDependencies(function(warnings) { + if(warnings) console.log(warnings); + + installHelpers.getLatestFrameworkVersion(function(error, latestFrameworkTag) { + if(error) { + return handleError(error, 1, 'Failed to get the latest framework version. Check package.json.'); + } + inputData = { + useConfigJSON: { + name: 'useJSON', + description: 'Use existing config values? y/N', type: 'string', - description: "Git repository URL to be used for the framework source code", - default: 'https://github.com/adaptlearning/adapt_framework.git' + before: installHelpers.inputHelpers.toBoolean, + default: 'N' }, - { - name: 'frameworkRevision', + startInstall: { + name: 'install', + description: 'Continue? Y/n', type: 'string', - description: 'Specific git revision to be used for the framework. Accepts any valid revision type (e.g. branch/tag/commit)', - default: 'tags/' + latestFrameworkTag - } - ], - features: { - ffmpeg: { - name: 'useffmpeg', - type: 'string', - description: "Are you using ffmpeg? y/N", before: installHelpers.inputHelpers.toBoolean, - default: 'N' + default: 'Y' }, - smtp: { - confirm: { - name: 'useSmtp', + server: [ + { + name: 'serverPort', + type: 'number', + description: 'Server port', + pattern: installHelpers.inputHelpers.numberValidator, + default: 5000 + }, + { + name: 'serverName', type: 'string', - description: "Will you be using an SMTP server? (used for sending emails) y/N", - before: installHelpers.inputHelpers.toBoolean, - default: 'N' + description: 'Server name', + default: 'localhost' + }, + { + name: 'dbHost', + type: 'string', + description: 'Database host', + default: 'localhost' + }, + { + name: 'dbName', + type: 'string', + description: 'Master database name', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'adapt-tenant-master' + }, + { + name: 'dbPort', + type: 'number', + description: 'Database server port', + pattern: installHelpers.inputHelpers.numberValidator, + default: 27017 + }, + { + name: 'dbUser', + type: 'string', + description: 'Database server user', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: '' + }, + { + name: 'dbPass', + type: 'string', + description: 'Database server password', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: '' + }, + { + name: 'dbAuthSource', + type: 'string', + description: 'Database server authentication database', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'admin' }, - confirmConnectionUrl: { - name: 'useSmtpConnectionUrl', + { + name: 'dataRoot', type: 'string', - description: "Will you use a URL to connect to your smtp Server y/N", + description: 'Data directory path', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'data' + }, + { + name: 'sessionSecret', + type: 'string', + description: 'Session secret (value used when saving session cookie data)', + pattern: /^.+$/, + default: 'your-session-secret' + }, + { + name: 'authoringToolRepository', + type: 'string', + description: "Git repository URL to be used for the authoring tool source code", + default: 'https://github.com/adaptlearning/adapt_authoring.git' + }, + { + name: 'frameworkRepository', + type: 'string', + description: "Git repository URL to be used for the framework source code", + default: 'https://github.com/adaptlearning/adapt_framework.git' + }, + { + name: 'frameworkRevision', + type: 'string', + description: 'Specific git revision to be used for the framework. Accepts any valid revision type (e.g. branch/tag/commit)', + default: 'tags/' + latestFrameworkTag + } + ], + features: { + ffmpeg: { + name: 'useffmpeg', + type: 'string', + description: "Are you using ffmpeg? y/N", before: installHelpers.inputHelpers.toBoolean, default: 'N' }, - configure: [ - { - name: 'fromAddress', - type: 'string', - description: "Sender email address", - default: '', - }, - { - name: 'rootUrl', + smtp: { + confirm: { + name: 'useSmtp', type: 'string', - description: "The url this install will be accessible from", - default: '' // set using default server options - } - ], - configureService: [ - { - name: 'smtpService', - type: 'string', - description: "Which SMTP service (if any) will be used? (see https://github.com/andris9/nodemailer-wellknown#supported-services for a list of supported services.)", - default: 'none', + description: "Will you be using an SMTP server? (used for sending emails) y/N", + before: installHelpers.inputHelpers.toBoolean, + default: 'N' }, - { - name: 'smtpUsername', + confirmConnectionUrl: { + name: 'useSmtpConnectionUrl', type: 'string', - description: "SMTP username", - default: '', + description: "Will you use a URL to connect to your smtp Server y/N", + before: installHelpers.inputHelpers.toBoolean, + default: 'N' }, - { - name: 'smtpPassword', - type: 'string', - description: "SMTP password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - default: '', - before: installHelpers.inputHelpers.passwordBefore - } - ], - configureConnectionUrl: [ - { - name: 'smtpConnectionUrl', - type: 'string', - description: "Custom connection URL: smtps://user%40gmail.com:pass@smtp.gmail.com/?pool=true", - default: 'none', - } - ] - } - }, - tenant: [ - { - name: 'masterTenantName', - type: 'string', - description: "Set a unique name for your tenant", - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'master' - }, - { - name: 'masterTenantDisplayName', - type: 'string', - description: 'Set the display name for your tenant', - default: 'Master' - } - ], - tenantDelete: { - name: "confirm", - description: "Continue? (Y/n)", - before: installHelpers.inputHelpers.toBoolean, - default: "Y" - }, - superUser: [ - { - name: 'suEmail', - type: 'string', - description: "Email address", - required: true + configure: [ + { + name: 'fromAddress', + type: 'string', + description: "Sender email address", + default: '', + }, + { + name: 'rootUrl', + type: 'string', + description: "The url this install will be accessible from", + default: '' // set using default server options + } + ], + configureService: [ + { + name: 'smtpService', + type: 'string', + description: "Which SMTP service (if any) will be used? (see https://github.com/andris9/nodemailer-wellknown#supported-services for a list of supported services.)", + default: 'none', + }, + { + name: 'smtpUsername', + type: 'string', + description: "SMTP username", + default: '', + }, + { + name: 'smtpPassword', + type: 'string', + description: "SMTP password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + default: '', + before: installHelpers.inputHelpers.passwordBefore + } + ], + configureConnectionUrl: [ + { + name: 'smtpConnectionUrl', + type: 'string', + description: "Custom connection URL: smtps://user%40gmail.com:pass@smtp.gmail.com/?pool=true", + default: 'none', + } + ] + } }, - { - name: 'suPassword', - type: 'string', - description: "Password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - required: true, - before: installHelpers.inputHelpers.passwordBefore + tenant: [ + { + name: 'masterTenantName', + type: 'string', + description: "Set a unique name for your tenant", + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'master' + }, + { + name: 'masterTenantDisplayName', + type: 'string', + description: 'Set the display name for your tenant', + default: 'Master' + } + ], + tenantDelete: { + name: "confirm", + description: "Continue? (Y/n)", + before: installHelpers.inputHelpers.toBoolean, + default: "Y" }, - { - name: 'suRetypePassword', - type: 'string', - description: "Confirm Password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - required: true, - before: installHelpers.inputHelpers.passwordBefore - } - ] - }; - if(!IS_INTERACTIVE) { - return start(); - } - console.log(''); - if(!fs.existsSync('conf/config.json')) { - fs.ensureDirSync('conf'); - return start(); - } - console.log('Found an existing config.json file. Do you want to use the values in this file during install?'); - installHelpers.getInput(inputData.useConfigJSON, function(result) { + superUser: [ + { + name: 'suEmail', + type: 'string', + description: "Email address", + required: true + }, + { + name: 'suPassword', + type: 'string', + description: "Password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + required: true, + before: installHelpers.inputHelpers.passwordBefore + }, + { + name: 'suRetypePassword', + type: 'string', + description: "Confirm Password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + required: true, + before: installHelpers.inputHelpers.passwordBefore + } + ] + }; + if(!IS_INTERACTIVE) { + return start(); + } console.log(''); - USE_CONFIG = result.useJSON; - start(); + if(!fs.existsSync('conf/config.json')) { + fs.ensureDirSync('conf'); + return start(); + } + console.log('Found an existing config.json file. Do you want to use the values in this file during install?'); + installHelpers.getInput(inputData.useConfigJSON, function(result) { + console.log(''); + USE_CONFIG = result.useJSON; + start(); + }); }); - }); + }) }); // we need the framework version for the config items, so let's go diff --git a/lib/installHelpers.js b/lib/installHelpers.js index c39e733f9b..f9ca7c4ffc 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -63,7 +63,8 @@ var exports = module.exports = { updateFrameworkPlugins, updateAuthoring, buildAuthoring, - checkPrerequisites + checkRequiredDependencies, + checkOptionalDependencies }; function exit(code, msg, preCallback) { @@ -584,31 +585,40 @@ function isSilent() { * Manually collect all missing prerequisites * Therefore we do not pass error to async-callbacks as this would exit the process */ -function checkPrerequisites(callback) { - const result = { - errors: [], - warnings: [] - }; - - async.applyEach([ - checkGitInstalled, - checkGruntCliInstalled, - checkGithubConnection, - checkLocalMongoDbConnection - ], result, function(error) { +function checkDependencies(checks, message, callback) { + const result = []; + async.applyEach(checks, result, function(error) { if (error) return callback(error); - if (result.errors.length) { - return callback(new Error(result.errors.join(', '))); + if (result.length) { + result.unshift(message); + return callback(result.join('\n')); } - console.log(result.warnings.join('\n')); return callback(null); }); } +function checkRequiredDependencies(callback) { + checkDependencies([ + checkGitInstalled, + checkGruntCliInstalled, + checkGithubConnection + ], + 'Missing the following pre-requisites, please check install guides:', + callback); +} +function checkOptionalDependencies(callback) { + checkDependencies([ + checkLocalMongoDbConnection, + checkFfmpegInstalled + ], + 'Missing the following optional dependecies, please check install guides:', + callback); +} + function checkGitInstalled(result, gitCb) { execCommand('git --version', {}, function(error, stdOut) { if (error) { - result.errors.push('git must be installed'); + result.push('- git'); } gitCb(); }); @@ -617,7 +627,7 @@ function checkGitInstalled(result, gitCb) { function checkGruntCliInstalled(result, gruntCb) { execCommand('grunt --version', {}, function(error, stdOut) { if (error) { - result.errors.push('grunt-cli must be installed'); + result.push('- grunt-cli'); } gruntCb(); }); @@ -633,7 +643,7 @@ function checkGithubConnection(result, githubCb) { method: 'GET' }, function(error, response) { if (error) { - result.errors.push(`Failed to connect to ${url}`); + result.push(`- failed to connect to ${url}`); } githubCb(); }); @@ -642,7 +652,16 @@ function checkGithubConnection(result, githubCb) { function checkLocalMongoDbConnection(result, callback) { execCommand('mongod --version', {}, function(error, stdOut) { if (error) { - result.warnings.push('MongoDB was not found locally. Please install it locally or connect to a remote.'); + result.push('- local MongoDB'); + } + callback(); + }) +} + +function checkFfmpegInstalled(result, callback) { + execCommand('ffmpeg -version', {}, function(error, stdOut) { + if (error) { + result.push('- FFMPEG'); } callback(); }) From 2d9d3449b98cf7f30bb12ea789faa191398e19b1 Mon Sep 17 00:00:00 2001 From: Thomas Taylor Date: Fri, 31 Aug 2018 11:02:41 +0100 Subject: [PATCH 05/21] Add Node.js version checking --- install.js | 452 +++++++++++++++++++++--------------------- lib/application.js | 32 +-- lib/installHelpers.js | 10 + upgrade.js | 21 +- 4 files changed, 268 insertions(+), 247 deletions(-) diff --git a/install.js b/install.js index aac7eb2a2b..b5de63288d 100644 --- a/install.js +++ b/install.js @@ -25,253 +25,251 @@ var superUser = false; // from user input var configResults; -installHelpers.checkRequiredDependencies(function(error) { - if(error) return handleError(null, 1, error); - - installHelpers.checkOptionalDependencies(function(warnings) { - if(warnings) console.log(warnings); - - installHelpers.getLatestFrameworkVersion(function(error, latestFrameworkTag) { - if(error) { - return handleError(error, 1, 'Failed to get the latest framework version. Check package.json.'); - } - inputData = { - useConfigJSON: { - name: 'useJSON', - description: 'Use existing config values? y/N', +installHelpers.checkNodeVersion(function(error) { + if(error) { + return installHelpers.exit(1, error.message); + } + // we need the framework version for the config items, so let's go + installHelpers.getLatestFrameworkVersion(function(error, latestFrameworkTag) { + if(error) { + return handleError(error, 1, 'Failed to get the latest framework version. Check package.json.'); + } + inputData = { + useConfigJSON: { + name: 'useJSON', + description: 'Use existing config values? y/N', + type: 'string', + before: installHelpers.inputHelpers.toBoolean, + default: 'N' + }, + startInstall: { + name: 'install', + description: 'Continue? Y/n', + type: 'string', + before: installHelpers.inputHelpers.toBoolean, + default: 'Y' + }, + server: [ + { + name: 'serverPort', + type: 'number', + description: 'Server port', + pattern: installHelpers.inputHelpers.numberValidator, + default: 5000 + }, + { + name: 'serverName', type: 'string', - before: installHelpers.inputHelpers.toBoolean, - default: 'N' + description: 'Server name', + default: 'localhost' + }, + { + name: 'dbHost', + type: 'string', + description: 'Database host', + default: 'localhost' + }, + { + name: 'dbName', + type: 'string', + description: 'Master database name', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'adapt-tenant-master' + }, + { + name: 'dbPort', + type: 'number', + description: 'Database server port', + pattern: installHelpers.inputHelpers.numberValidator, + default: 27017 + }, + { + name: 'dbUser', + type: 'string', + description: 'Database server user', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: '' + }, + { + name: 'dbPass', + type: 'string', + description: 'Database server password', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: '' + }, + { + name: 'dbAuthSource', + type: 'string', + description: 'Database server authentication database', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'admin' + }, + { + name: 'dataRoot', + type: 'string', + description: 'Data directory path', + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'data' }, - startInstall: { - name: 'install', - description: 'Continue? Y/n', + { + name: 'sessionSecret', type: 'string', + description: 'Session secret (value used when saving session cookie data)', + pattern: /^.+$/, + default: 'your-session-secret' + }, + { + name: 'authoringToolRepository', + type: 'string', + description: "Git repository URL to be used for the authoring tool source code", + default: 'https://github.com/adaptlearning/adapt_authoring.git' + }, + { + name: 'frameworkRepository', + type: 'string', + description: "Git repository URL to be used for the framework source code", + default: 'https://github.com/adaptlearning/adapt_framework.git' + }, + { + name: 'frameworkRevision', + type: 'string', + description: 'Specific git revision to be used for the framework. Accepts any valid revision type (e.g. branch/tag/commit)', + default: 'tags/' + latestFrameworkTag + } + ], + features: { + ffmpeg: { + name: 'useffmpeg', + type: 'string', + description: "Are you using ffmpeg? y/N", before: installHelpers.inputHelpers.toBoolean, default: 'Y' }, - server: [ - { - name: 'serverPort', - type: 'number', - description: 'Server port', - pattern: installHelpers.inputHelpers.numberValidator, - default: 5000 - }, - { - name: 'serverName', + smtp: { + confirm: { + name: 'useSmtp', type: 'string', - description: 'Server name', - default: 'localhost' - }, - { - name: 'dbHost', - type: 'string', - description: 'Database host', - default: 'localhost' - }, - { - name: 'dbName', - type: 'string', - description: 'Master database name', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'adapt-tenant-master' - }, - { - name: 'dbPort', - type: 'number', - description: 'Database server port', - pattern: installHelpers.inputHelpers.numberValidator, - default: 27017 - }, - { - name: 'dbUser', - type: 'string', - description: 'Database server user', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: '' - }, - { - name: 'dbPass', - type: 'string', - description: 'Database server password', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: '' - }, - { - name: 'dbAuthSource', - type: 'string', - description: 'Database server authentication database', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'admin' - }, - { - name: 'dataRoot', - type: 'string', - description: 'Data directory path', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'data' - }, - { - name: 'sessionSecret', - type: 'string', - description: 'Session secret (value used when saving session cookie data)', - pattern: /^.+$/, - default: 'your-session-secret' - }, - { - name: 'authoringToolRepository', - type: 'string', - description: "Git repository URL to be used for the authoring tool source code", - default: 'https://github.com/adaptlearning/adapt_authoring.git' - }, - { - name: 'frameworkRepository', - type: 'string', - description: "Git repository URL to be used for the framework source code", - default: 'https://github.com/adaptlearning/adapt_framework.git' + description: "Will you be using an SMTP server? (used for sending emails) y/N", + before: installHelpers.inputHelpers.toBoolean, + default: 'N' }, - { - name: 'frameworkRevision', - type: 'string', - description: 'Specific git revision to be used for the framework. Accepts any valid revision type (e.g. branch/tag/commit)', - default: 'tags/' + latestFrameworkTag - } - ], - features: { - ffmpeg: { - name: 'useffmpeg', + confirmConnectionUrl: { + name: 'useSmtpConnectionUrl', type: 'string', - description: "Are you using ffmpeg? y/N", + description: "Will you use a URL to connect to your smtp Server y/N", before: installHelpers.inputHelpers.toBoolean, default: 'N' }, - smtp: { - confirm: { - name: 'useSmtp', + configure: [ + { + name: 'fromAddress', type: 'string', - description: "Will you be using an SMTP server? (used for sending emails) y/N", - before: installHelpers.inputHelpers.toBoolean, - default: 'N' + description: "Sender email address", + default: '', }, - confirmConnectionUrl: { - name: 'useSmtpConnectionUrl', + { + name: 'rootUrl', type: 'string', - description: "Will you use a URL to connect to your smtp Server y/N", - before: installHelpers.inputHelpers.toBoolean, - default: 'N' + description: "The url this install will be accessible from", + default: '' // set using default server options + } + ], + configureService: [ + { + name: 'smtpService', + type: 'string', + description: "Which SMTP service (if any) will be used? (see https://github.com/andris9/nodemailer-wellknown#supported-services for a list of supported services.)", + default: 'none', }, - configure: [ - { - name: 'fromAddress', - type: 'string', - description: "Sender email address", - default: '', - }, - { - name: 'rootUrl', - type: 'string', - description: "The url this install will be accessible from", - default: '' // set using default server options - } - ], - configureService: [ - { - name: 'smtpService', - type: 'string', - description: "Which SMTP service (if any) will be used? (see https://github.com/andris9/nodemailer-wellknown#supported-services for a list of supported services.)", - default: 'none', - }, - { - name: 'smtpUsername', - type: 'string', - description: "SMTP username", - default: '', - }, - { - name: 'smtpPassword', - type: 'string', - description: "SMTP password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - default: '', - before: installHelpers.inputHelpers.passwordBefore - } - ], - configureConnectionUrl: [ - { - name: 'smtpConnectionUrl', - type: 'string', - description: "Custom connection URL: smtps://user%40gmail.com:pass@smtp.gmail.com/?pool=true", - default: 'none', - } - ] - } + { + name: 'smtpUsername', + type: 'string', + description: "SMTP username", + default: '', + }, + { + name: 'smtpPassword', + type: 'string', + description: "SMTP password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + default: '', + before: installHelpers.inputHelpers.passwordBefore + } + ], + configureConnectionUrl: [ + { + name: 'smtpConnectionUrl', + type: 'string', + description: "Custom connection URL: smtps://user%40gmail.com:pass@smtp.gmail.com/?pool=true", + default: 'none', + } + ] + } + }, + tenant: [ + { + name: 'masterTenantName', + type: 'string', + description: "Set a unique name for your tenant", + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'master' }, - tenant: [ - { - name: 'masterTenantName', - type: 'string', - description: "Set a unique name for your tenant", - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'master' - }, - { - name: 'masterTenantDisplayName', - type: 'string', - description: 'Set the display name for your tenant', - default: 'Master' - } - ], - tenantDelete: { - name: "confirm", - description: "Continue? (Y/n)", - before: installHelpers.inputHelpers.toBoolean, - default: "Y" + { + name: 'masterTenantDisplayName', + type: 'string', + description: 'Set the display name for your tenant', + default: 'Master' + } + ], + tenantDelete: { + name: "confirm", + description: "Continue? (Y/n)", + before: installHelpers.inputHelpers.toBoolean, + default: "Y" + }, + superUser: [ + { + name: 'suEmail', + type: 'string', + description: "Email address", + required: true }, - superUser: [ - { - name: 'suEmail', - type: 'string', - description: "Email address", - required: true - }, - { - name: 'suPassword', - type: 'string', - description: "Password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - required: true, - before: installHelpers.inputHelpers.passwordBefore - }, - { - name: 'suRetypePassword', - type: 'string', - description: "Confirm Password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - required: true, - before: installHelpers.inputHelpers.passwordBefore - } - ] - }; - if(!IS_INTERACTIVE) { - return start(); - } + { + name: 'suPassword', + type: 'string', + description: "Password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + required: true, + before: installHelpers.inputHelpers.passwordBefore + }, + { + name: 'suRetypePassword', + type: 'string', + description: "Confirm Password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + required: true, + before: installHelpers.inputHelpers.passwordBefore + } + ] + }; + if(!IS_INTERACTIVE) { + return start(); + } + console.log(''); + if(!fs.existsSync('conf/config.json')) { + fs.ensureDirSync('conf'); + return start(); + } + console.log('Found an existing config.json file. Do you want to use the values in this file during install?'); + installHelpers.getInput(inputData.useConfigJSON, function(result) { console.log(''); - if(!fs.existsSync('conf/config.json')) { - fs.ensureDirSync('conf'); - return start(); - } - console.log('Found an existing config.json file. Do you want to use the values in this file during install?'); - installHelpers.getInput(inputData.useConfigJSON, function(result) { - console.log(''); - USE_CONFIG = result.useJSON; - start(); - }); + USE_CONFIG = result.useJSON; + start(); }); - }) + }); }); // we need the framework version for the config items, so let's go diff --git a/lib/application.js b/lib/application.js index ac8716cb2a..df7bee67e3 100644 --- a/lib/application.js +++ b/lib/application.js @@ -353,22 +353,30 @@ Origin.prototype.startServer = function (options) { if(typeof options === 'undefined') { options = { skipVersionCheck: false, skipStartLog: false }; } - var _checkForUpdates = function(callback) { - if(configuration.getConfig('isTestEnvironment') || options.skipVersionCheck) { - return callback(); - } - checkForUpdates(function(error) { - if(error) { - logger.log('error', `Check for updates failed, ${error}`); + var _checkPrerequisites = function(callback) { + async.series([ + function __checkNodeVersion(cb) { + installHelpers.checkNodeVersion(function(error) { + if(error) return cb(new Error(`Node version check failed, ${error}`)); + cb(); + }); + }, + function __checkForupdates(cb) { + if(configuration.getConfig('isTestEnvironment') || options.skipVersionCheck) { + return cb(); + } + checkForUpdates(function(error) { + if(error) cb(new Error(`Check for updates failed, ${error}`)); + cb(); + }); } - callback(); - }); + ], callback); }; - _checkForUpdates(function(err, result) { + _checkPrerequisites(function(err, result) { if(err) { - logger.log('error', `Check for updates failed, ${err}`); + logger.log('error', chalk.red(err.message)); + return process.exit(0); } - // configure server var serverOptions = { minimal: !app.configuration || !app.configuration.getConfig('dbName') diff --git a/lib/installHelpers.js b/lib/installHelpers.js index f9ca7c4ffc..36c1b261f0 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -49,6 +49,7 @@ var exports = module.exports = { hideSpinner, getInput, inputHelpers, + checkNodeVersion, getInstalledServerVersion, getLatestServerVersion, getInstalledFrameworkVersion, @@ -113,6 +114,15 @@ function getInput(items, callback) { }); } +function checkNodeVersion(callback) { + const requiredVersion = pkg.engines.node; + const installedVersion = process.versions.node; + if(!semver.satisfies(installedVersion, requiredVersion)) { + return callback(new Error(`The application requires Node.js v${requiredVersion} to run, found v${installedVersion}. Please make sure you have a compatible version.`)); + } + callback(); +} + function getInstalledServerVersion(callback) { try { var pkg = fs.readJSONSync('package.json'); diff --git a/upgrade.js b/upgrade.js index b089d4f584..095dcb11a0 100644 --- a/upgrade.js +++ b/upgrade.js @@ -25,16 +25,21 @@ var app = origin(); start(); function start() { - // don't show any logger messages in the console - logger.level('console','error'); + installHelpers.checkNodeVersion(function(error) { + if(error) { + return installHelpers.exit(1, error.message); + } + // don't show any logger messages in the console + logger.level('console','error'); - prompt.override = optimist.argv; + prompt.override = optimist.argv; - // start the server first - app.run({ skipVersionCheck: true, skipStartLog: true }); - app.on('serverStarted', function() { - ensureRepoValues(); - getUserInput(); + // start the server first + app.run({ skipVersionCheck: true, skipStartLog: true }); + app.on('serverStarted', function() { + ensureRepoValues(); + getUserInput(); + }); }); } From 2eed13cccad50cc0c7481f7bb7d8cb53c07df927 Mon Sep 17 00:00:00 2001 From: Thomas Taylor Date: Tue, 28 Aug 2018 09:47:33 +0100 Subject: [PATCH 06/21] Add warning for newer Node.js versions --- lib/installHelpers.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 36c1b261f0..2228bef911 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -117,6 +117,10 @@ function getInput(items, callback) { function checkNodeVersion(callback) { const requiredVersion = pkg.engines.node; const installedVersion = process.versions.node; + if(semver.gt(installedVersion, semver.coerce(requiredVersion))) { + warn(`You are using Node.js v${installedVersion} which is not yet supported by Adapt. If you encounter issues, please downgrade to v${requiredVersion}.`); + return callback(); + } if(!semver.satisfies(installedVersion, requiredVersion)) { return callback(new Error(`The application requires Node.js v${requiredVersion} to run, found v${installedVersion}. Please make sure you have a compatible version.`)); } From fcdcf6d8738f4cb3143d0e5b0776089c522525eb Mon Sep 17 00:00:00 2001 From: Thomas Taylor Date: Fri, 31 Aug 2018 11:03:52 +0100 Subject: [PATCH 07/21] Refactor dependency checks --- install.js | 107 ++++++++++++------------- lib/application.js | 8 +- lib/installHelpers.js | 178 +++++++++++++++++++++--------------------- upgrade.js | 20 ++--- 4 files changed, 150 insertions(+), 163 deletions(-) diff --git a/install.js b/install.js index b5de63288d..683d0e9a6b 100644 --- a/install.js +++ b/install.js @@ -25,14 +25,12 @@ var superUser = false; // from user input var configResults; -installHelpers.checkNodeVersion(function(error) { - if(error) { - return installHelpers.exit(1, error.message); - } - // we need the framework version for the config items, so let's go +installHelpers.checkPrimaryDependencies(function(error) { + if(error) return handleError(null, 1, error); + installHelpers.getLatestFrameworkVersion(function(error, latestFrameworkTag) { if(error) { - return handleError(error, 1, 'Failed to get the latest framework version. Check package.json.'); + return handleError(error, 1, 'Failed to get the latest framework version.'); } inputData = { useConfigJSON: { @@ -143,7 +141,7 @@ installHelpers.checkNodeVersion(function(error) { type: 'string', description: "Are you using ffmpeg? y/N", before: installHelpers.inputHelpers.toBoolean, - default: 'Y' + default: 'N' }, smtp: { confirm: { @@ -383,63 +381,56 @@ function configureMasterTenant(callback) { } else { console.log('Now we need to configure the master tenant. \nTip: just press ENTER to accept the default value in brackets.\n'); } - logger.clear(); - - installHelpers.showSpinner('Starting server'); + logger.level('console','warn'); // run the app app.run({ skipVersionCheck: true }); app.on('serverStarted', function() { - installHelpers.hideSpinner(); - database.checkConnection(function(error) { - if(error) { - return callback(error); - } - if(USE_CONFIG && prompt.override.masterTenantName) { - /** - * remove the masterTenantDisplayName, as we can use the existing value - * (which isn't in config.json so can't be used as an auto override) - */ - inputData.tenant = _.filter(inputData.tenant, function(item) { - return item.name !== 'masterTenantDisplayName'; - }); - } - installHelpers.getInput(inputData.tenant, function(result) { - console.log(''); - // add the input to our cached config - addConfig({ - masterTenant: { - name: result.masterTenantName, - displayName: result.masterTenantName - } - }); - // check if the tenant name already exists - app.tenantmanager.retrieveTenant({ name: result.masterTenantName }, function(error, tenant) { - if(error) { - return onError(error); - } - if(!tenant) { - return callback(); - } - if(!IS_INTERACTIVE) { - return exit(1, `Tenant '${tenant.name}' already exists, automatic install cannot continue.`); - } - if(!configResults.masterTenant.displayName) { - configResults.masterTenant.displayName = tenant.displayName; + + if(USE_CONFIG && prompt.override.masterTenantName) { + /** + * remove the masterTenantDisplayName, as we can use the existing value + * (which isn't in config.json so can't be used as an auto override) + */ + inputData.tenant = _.filter(inputData.tenant, function(item) { + return item.name !== 'masterTenantDisplayName'; + }); + } + installHelpers.getInput(inputData.tenant, function(result) { + console.log(''); + // add the input to our cached config + addConfig({ + masterTenant: { + name: result.masterTenantName, + displayName: result.masterTenantName + } + }); + // check if the tenant name already exists + app.tenantmanager.retrieveTenant({ name: result.masterTenantName }, function(error, tenant) { + if(error) { + return onError(error); + } + if(!tenant) { + return callback(); + } + if(!IS_INTERACTIVE) { + return exit(1, `Tenant '${tenant.name}' already exists, automatic install cannot continue.`); + } + if(!configResults.masterTenant.displayName) { + configResults.masterTenant.displayName = tenant.displayName; + } + console.log(chalk.yellow(`Tenant '${tenant.name}' already exists. ${chalk.underline('It must be deleted for install to continue.')}`)); + installHelpers.getInput(inputData.tenantDelete, function(result) { + console.log(''); + if(!result.confirm) { + return exit(1, 'Exiting install.'); } - console.log(chalk.yellow(`Tenant '${tenant.name}' already exists. ${chalk.underline('It must be deleted for install to continue.')}`)); - installHelpers.getInput(inputData.tenantDelete, function(result) { - console.log(''); - if(!result.confirm) { - return exit(1, 'Exiting install.'); - } - // delete tenant - async.eachSeries(app.db.getModelNames(), function(modelName, cb) { - app.db.destroy(modelName, null, cb); - }, callback); - }); + // delete tenant + async.eachSeries(app.db.getModelNames(), function(modelName, cb) { + app.db.destroy(modelName, null, cb); + }, callback); }); }); - }, configResults.dbName); + }); }); } diff --git a/lib/application.js b/lib/application.js index df7bee67e3..eba42da899 100644 --- a/lib/application.js +++ b/lib/application.js @@ -355,12 +355,8 @@ Origin.prototype.startServer = function (options) { } var _checkPrerequisites = function(callback) { async.series([ - function __checkNodeVersion(cb) { - installHelpers.checkNodeVersion(function(error) { - if(error) return cb(new Error(`Node version check failed, ${error}`)); - cb(); - }); - }, + installHelpers.checkPrimaryDependencies, + installHelpers.checkSecondaryDependencies, function __checkForupdates(cb) { if(configuration.getConfig('isTestEnvironment') || options.skipVersionCheck) { return cb(); diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 2228bef911..5c85057917 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -1,8 +1,10 @@ var _ = require('underscore'); var async = require('async'); var chalk = require('chalk'); +var database = require('./database'); var exec = require('child_process').exec; var fs = require('fs-extra'); +var logger = require('./logger'); var logUpdate = require('log-update'); var path = require('path'); var prompt = require('prompt'); @@ -50,6 +52,8 @@ var exports = module.exports = { getInput, inputHelpers, checkNodeVersion, + checkPrimaryDependencies, + checkSecondaryDependencies, getInstalledServerVersion, getLatestServerVersion, getInstalledFrameworkVersion, @@ -64,8 +68,6 @@ var exports = module.exports = { updateFrameworkPlugins, updateAuthoring, buildAuthoring, - checkRequiredDependencies, - checkOptionalDependencies }; function exit(code, msg, preCallback) { @@ -114,12 +116,51 @@ function getInput(items, callback) { }); } +/** +* Manually collect all missing prerequisites +* Therefore we do not pass error to async-callbacks as this would exit the process +*/ +function checkDependencies(checks, callback) { + let hasErrored = false; + async.each(checks, function(check, cb) { + check.call(this, function(error, warning) { + if(error) { + logger.log('error', error); + hasErrored = true; + } + if(warning) { + logger.log('warn', warning); + } + cb(); + }); + }, function(err) { + if(hasErrored) { + return callback(new Error('Some of the prerequisites could not be found, see above for details.')); + } + callback(); + }); +} + +function checkPrimaryDependencies(callback) { + checkDependencies([ + checkNodeVersion, + checkGitInstalled, + checkGruntCliInstalled, + checkGithubConnection + ], callback); +} +function checkSecondaryDependencies(callback) { + checkDependencies([ + checkDbConnection, + checkFfmpegInstalled + ], callback); +} + function checkNodeVersion(callback) { const requiredVersion = pkg.engines.node; const installedVersion = process.versions.node; if(semver.gt(installedVersion, semver.coerce(requiredVersion))) { - warn(`You are using Node.js v${installedVersion} which is not yet supported by Adapt. If you encounter issues, please downgrade to v${requiredVersion}.`); - return callback(); + return callback(null, `You are using Node.js v${installedVersion} which is not yet supported by Adapt. If you encounter issues, please downgrade to v${requiredVersion}.`); } if(!semver.satisfies(installedVersion, requiredVersion)) { return callback(new Error(`The application requires Node.js v${requiredVersion} to run, found v${installedVersion}. Please make sure you have a compatible version.`)); @@ -127,6 +168,49 @@ function checkNodeVersion(callback) { callback(); } +function checkGitInstalled(callback) { + execCommand('git --version', {}, function(error, stdOut) { + if (error) return callback('git could not be found, please check it is installed'); + callback(); + }); +} + +function checkGruntCliInstalled(callback) { + execCommand('grunt --version', {}, function(error, stdOut) { + if (error) return callback('grunt-cli could not be found, please check it is installed'); + callback(); + }); +} + +function checkGithubConnection(callback) { + const url = 'https://api.github.com/'; + request({ + headers: { 'User-Agent': DEFAULT_USER_AGENT }, + uri: url, + method: 'GET' + }, function(error, response) { + if (error) return callback(`Failed to connect to ${url}`); + callback(); + }); +} + +function checkDbConnection(callback) { + database.checkConnection(function(error) { + if (error) return callback(`Couldn't connect to the database, please check the connection details are valid`); + callback(); + }); +} + +function checkFfmpegInstalled(callback) { + if(!configuration.getConfig('useffmpeg')) { + return callback(); + } + execCommand('ffmpeg -version', {}, function(error, stdOut) { + if (error) return callback(null, 'Local FFmpeg could not be found, please check it is installed'); + callback(); + }); +} + function getInstalledServerVersion(callback) { try { var pkg = fs.readJSONSync('package.json'); @@ -594,89 +678,3 @@ function error(msg) { function isSilent() { return process.env.SILENT; } - -/** -* Manually collect all missing prerequisites -* Therefore we do not pass error to async-callbacks as this would exit the process -*/ -function checkDependencies(checks, message, callback) { - const result = []; - async.applyEach(checks, result, function(error) { - if (error) return callback(error); - if (result.length) { - result.unshift(message); - return callback(result.join('\n')); - } - return callback(null); - }); -} - -function checkRequiredDependencies(callback) { - checkDependencies([ - checkGitInstalled, - checkGruntCliInstalled, - checkGithubConnection - ], - 'Missing the following pre-requisites, please check install guides:', - callback); -} -function checkOptionalDependencies(callback) { - checkDependencies([ - checkLocalMongoDbConnection, - checkFfmpegInstalled - ], - 'Missing the following optional dependecies, please check install guides:', - callback); -} - -function checkGitInstalled(result, gitCb) { - execCommand('git --version', {}, function(error, stdOut) { - if (error) { - result.push('- git'); - } - gitCb(); - }); -} - -function checkGruntCliInstalled(result, gruntCb) { - execCommand('grunt --version', {}, function(error, stdOut) { - if (error) { - result.push('- grunt-cli'); - } - gruntCb(); - }); -} - -function checkGithubConnection(result, githubCb) { - const url = 'https://api.github.com/'; - request({ - headers: { - 'User-Agent': DEFAULT_USER_AGENT - }, - uri: url, - method: 'GET' - }, function(error, response) { - if (error) { - result.push(`- failed to connect to ${url}`); - } - githubCb(); - }); -} - -function checkLocalMongoDbConnection(result, callback) { - execCommand('mongod --version', {}, function(error, stdOut) { - if (error) { - result.push('- local MongoDB'); - } - callback(); - }) -} - -function checkFfmpegInstalled(result, callback) { - execCommand('ffmpeg -version', {}, function(error, stdOut) { - if (error) { - result.push('- FFMPEG'); - } - callback(); - }) -} diff --git a/upgrade.js b/upgrade.js index 095dcb11a0..20f09cc153 100644 --- a/upgrade.js +++ b/upgrade.js @@ -25,20 +25,22 @@ var app = origin(); start(); function start() { - installHelpers.checkNodeVersion(function(error) { + installHelpers.checkPrimaryDependencies(function(error) { if(error) { return installHelpers.exit(1, error.message); } - // don't show any logger messages in the console - logger.level('console','error'); + installHelpers.checkSecondaryDependencies(function(error) { + // don't show any logger messages in the console + logger.level('console','error'); - prompt.override = optimist.argv; + prompt.override = optimist.argv; - // start the server first - app.run({ skipVersionCheck: true, skipStartLog: true }); - app.on('serverStarted', function() { - ensureRepoValues(); - getUserInput(); + // start the server first + app.run({ skipVersionCheck: true, skipStartLog: true }); + app.on('serverStarted', function() { + ensureRepoValues(); + getUserInput(); + }); }); }); } From 9da67c367d2cde0331747285bbfdc4f9785c335c Mon Sep 17 00:00:00 2001 From: Thomas Taylor Date: Tue, 28 Aug 2018 14:31:32 +0100 Subject: [PATCH 08/21] Switch to gtr --- lib/installHelpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 5c85057917..9d6da10d82 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -159,7 +159,7 @@ function checkSecondaryDependencies(callback) { function checkNodeVersion(callback) { const requiredVersion = pkg.engines.node; const installedVersion = process.versions.node; - if(semver.gt(installedVersion, semver.coerce(requiredVersion))) { + if(semver.gtr(installedVersion, requiredVersion)) { return callback(null, `You are using Node.js v${installedVersion} which is not yet supported by Adapt. If you encounter issues, please downgrade to v${requiredVersion}.`); } if(!semver.satisfies(installedVersion, requiredVersion)) { From f810ed9e3eab863d51aa18471127f4f6b12fdd9a Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Thu, 13 Sep 2018 16:50:56 +0100 Subject: [PATCH 09/21] Update logger level --- install.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.js b/install.js index 380597218f..df958db928 100644 --- a/install.js +++ b/install.js @@ -377,7 +377,7 @@ function configureMasterTenant(callback) { } else { console.log('Now we need to configure the master tenant. \nTip: just press ENTER to accept the default value in brackets.\n'); } - logger.level('console','warn'); + logger.level('console','error'); // run the app app.run({ skipVersionCheck: true }); app.on('serverStarted', function() { From bc4020df76d10eb17fb0c5518a64d2096b14fa01 Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Fri, 14 Sep 2018 12:39:53 +0100 Subject: [PATCH 10/21] Consolidate checks --- lib/application.js | 22 ++++++++++------------ lib/installHelpers.js | 42 +++++++++++++++++++++++++++--------------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/lib/application.js b/lib/application.js index eba42da899..d6d5863e63 100644 --- a/lib/application.js +++ b/lib/application.js @@ -354,19 +354,17 @@ Origin.prototype.startServer = function (options) { options = { skipVersionCheck: false, skipStartLog: false }; } var _checkPrerequisites = function(callback) { - async.series([ - installHelpers.checkPrimaryDependencies, - installHelpers.checkSecondaryDependencies, - function __checkForupdates(cb) { - if(configuration.getConfig('isTestEnvironment') || options.skipVersionCheck) { - return cb(); - } - checkForUpdates(function(error) { - if(error) cb(new Error(`Check for updates failed, ${error}`)); - cb(); - }); + installHelpers.checkAllDependencies(error => { + if(error) { + return callback(error); } - ], callback); + if(configuration.getConfig('isTestEnvironment') || options.skipVersionCheck) { + return callback(); + } + checkForUpdates(function(error) { + callback(error ? new Error(`Check for updates failed, ${error}`) : null); + }); + }); }; _checkPrerequisites(function(err, result) { if(err) { diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 9d6da10d82..1e8f55e219 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -52,6 +52,7 @@ var exports = module.exports = { getInput, inputHelpers, checkNodeVersion, + checkAllDependencies, checkPrimaryDependencies, checkSecondaryDependencies, getInstalledServerVersion, @@ -116,6 +117,32 @@ function getInput(items, callback) { }); } +function checkAllDependencies(callback) { + async.parallel(async.reflectAll([ + checkPrimaryDependencies, + checkSecondaryDependencies + ]), (error, results) => { + const errors = results.map(result => result.error).filter(Boolean); + // all errors will be the same + callback(errors.length ? errors[0] : null); + }); +} + +function checkPrimaryDependencies(callback) { + checkDependencies([ + checkNodeVersion, + checkGitInstalled, + checkGruntCliInstalled, + checkGithubConnection + ], callback); +} +function checkSecondaryDependencies(callback) { + checkDependencies([ + checkDbConnection, + checkFfmpegInstalled + ], callback); +} + /** * Manually collect all missing prerequisites * Therefore we do not pass error to async-callbacks as this would exit the process @@ -141,21 +168,6 @@ function checkDependencies(checks, callback) { }); } -function checkPrimaryDependencies(callback) { - checkDependencies([ - checkNodeVersion, - checkGitInstalled, - checkGruntCliInstalled, - checkGithubConnection - ], callback); -} -function checkSecondaryDependencies(callback) { - checkDependencies([ - checkDbConnection, - checkFfmpegInstalled - ], callback); -} - function checkNodeVersion(callback) { const requiredVersion = pkg.engines.node; const installedVersion = process.versions.node; From 700647f75f02b4815447d942f2fbf2b6086293e1 Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Fri, 14 Sep 2018 12:40:50 +0100 Subject: [PATCH 11/21] Refactor --- lib/installHelpers.js | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 1e8f55e219..31db82c935 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -160,11 +160,8 @@ function checkDependencies(checks, callback) { } cb(); }); - }, function(err) { - if(hasErrored) { - return callback(new Error('Some of the prerequisites could not be found, see above for details.')); - } - callback(); + }, err => { + callback(hasErrored ? new Error('Some of the prerequisites could not be found, see above for details.') : null); }); } @@ -175,22 +172,20 @@ function checkNodeVersion(callback) { return callback(null, `You are using Node.js v${installedVersion} which is not yet supported by Adapt. If you encounter issues, please downgrade to v${requiredVersion}.`); } if(!semver.satisfies(installedVersion, requiredVersion)) { - return callback(new Error(`The application requires Node.js v${requiredVersion} to run, found v${installedVersion}. Please make sure you have a compatible version.`)); + return callback(`The application requires Node.js v${requiredVersion} to run, found v${installedVersion}. Please make sure you have a compatible version.`); } callback(); } function checkGitInstalled(callback) { - execCommand('git --version', {}, function(error, stdOut) { - if (error) return callback('git could not be found, please check it is installed'); - callback(); + execCommand('git --version', {}, error => { + callback(error ? 'git could not be found, please check it is installed' : null); }); } function checkGruntCliInstalled(callback) { - execCommand('grunt --version', {}, function(error, stdOut) { - if (error) return callback('grunt-cli could not be found, please check it is installed'); - callback(); + execCommand('grunt --version', {}, error => { + callback(error ? 'grunt-cli could not be found, please check it is installed' : null); }); } @@ -200,16 +195,14 @@ function checkGithubConnection(callback) { headers: { 'User-Agent': DEFAULT_USER_AGENT }, uri: url, method: 'GET' - }, function(error, response) { - if (error) return callback(`Failed to connect to ${url}`); - callback(); + }, error => { + callback(error ? `Failed to connect to ${url}` : null); }); } function checkDbConnection(callback) { - database.checkConnection(function(error) { - if (error) return callback(`Couldn't connect to the database, please check the connection details are valid`); - callback(); + database.checkConnection(error => { + callback(error ? `Couldn't connect to the database, please check the connection details are valid` : null); }); } @@ -217,9 +210,8 @@ function checkFfmpegInstalled(callback) { if(!configuration.getConfig('useffmpeg')) { return callback(); } - execCommand('ffmpeg -version', {}, function(error, stdOut) { - if (error) return callback(null, 'Local FFmpeg could not be found, please check it is installed'); - callback(); + execCommand('ffmpeg -version', {}, error => { + callback(error ? 'Local FFmpeg could not be found, please check it is installed' : null); }); } From f5279b64427d223da7c26eb78f85872ca7e8408c Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Fri, 14 Sep 2018 12:41:09 +0100 Subject: [PATCH 12/21] Make function async --- lib/installHelpers.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 31db82c935..1da069acec 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -216,12 +216,12 @@ function checkFfmpegInstalled(callback) { } function getInstalledServerVersion(callback) { - try { - var pkg = fs.readJSONSync('package.json'); + fs.readJSON('package.json', (error, pkg) => { + if(error) { + return callback(new Error(`Cannot determine authoring tool version\n${error}`)); + } callback(null, pkg.version); - } catch(e) { - callback(new Error(`Cannot determine authoring tool version\n${e}`)); - } + }); } function getLatestServerVersion(callback) { @@ -229,12 +229,12 @@ function getLatestServerVersion(callback) { } function getInstalledFrameworkVersion(callback) { - try { - var pkg = fs.readJSONSync(path.join(getFrameworkRoot(), 'package.json')); + fs.readJSON(path.join(getFrameworkRoot(), 'package.json'), (error, pkg) => { + if(error) { + return callback(new Error(`Cannot determine framework version\n${error}`)); + } callback(null, pkg.version); - } catch(e) { - return callback(new Error(`Cannot determine framework version\n${e}`)); - } + }); } function getLatestFrameworkVersion(callback) { From 4f55608d846705c1b77091e1a3ee493f139b20b5 Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Wed, 10 Oct 2018 08:45:01 +0100 Subject: [PATCH 13/21] Add SMTP check --- lib/installHelpers.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 1da069acec..5d822ced0c 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -6,6 +6,7 @@ var exec = require('child_process').exec; var fs = require('fs-extra'); var logger = require('./logger'); var logUpdate = require('log-update'); +var mailer = require('./mailer'); var path = require('path'); var prompt = require('prompt'); var readline = require('readline'); @@ -139,6 +140,7 @@ function checkPrimaryDependencies(callback) { function checkSecondaryDependencies(callback) { checkDependencies([ checkDbConnection, + checkSmtpConnection, checkFfmpegInstalled ], callback); } @@ -206,6 +208,13 @@ function checkDbConnection(callback) { }); } +function checkSmtpConnection(callback) { + if(!configuration.getConfig('useSmtp')) { + return callback(); + } + (new mailer()).testConnection(error => callback(error && error.message || null)); +} + function checkFfmpegInstalled(callback) { if(!configuration.getConfig('useffmpeg')) { return callback(); From f0c7174a07caa21170fbff2b4101a3d8328656a3 Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Wed, 10 Oct 2018 09:54:42 +0100 Subject: [PATCH 14/21] Make SMTP error handling more flexible --- lib/mailer.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/mailer.js b/lib/mailer.js index 3ea84228e4..a52c6d4f04 100644 --- a/lib/mailer.js +++ b/lib/mailer.js @@ -78,10 +78,11 @@ const configure = function(options, callback) { const generateFriendlyError = function(error) { let message, advice; - switch(error.errno) { + const code = error.errno || error.code; + switch(code) { case 'ENOTFOUND': message = `Couldn't connect to SMTP server`; - advice = `make sure you've specified the correct host`; + advice = `make sure you've specified a valid server`; break; case 'ECONNREFUSED': message = `Connection refused by server`; @@ -89,7 +90,7 @@ const generateFriendlyError = function(error) { break; case 'ETIMEDOUT': message = `Connection attempt timed out`; - advice = `check you've specified a valid port`; + advice = `check you've specified a valid server and port`; break; case 'EAUTH': message = `Authentication failed`; @@ -98,7 +99,7 @@ const generateFriendlyError = function(error) { default: message = `Unknown error: ${error.message}`; } - return new Error(`Failed to verify SMTP connection. ${message} (${error.errno}), ${advice}`); + return new Error(`Failed to verify SMTP connection. ${message} (${code}), ${advice}`); }; /** From 3c21a5c28ef2eafa799d68605a82f5dc0b4af778 Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Wed, 10 Oct 2018 10:57:53 +0100 Subject: [PATCH 15/21] Fix merge issue --- install.js | 317 +++++++++++++++++++---------------------------------- 1 file changed, 114 insertions(+), 203 deletions(-) diff --git a/install.js b/install.js index 66f5e1fab3..3ef98cfef9 100644 --- a/install.js +++ b/install.js @@ -78,8 +78,8 @@ installHelpers.checkPrimaryDependencies(function(error) { { name: 'frameworkRepository', type: 'string', - before: installHelpers.inputHelpers.toBoolean, - default: 'N' + description: "Git repository URL to be used for the framework source code", + default: 'https://github.com/adaptlearning/adapt_framework.git' }, { name: 'frameworkRevision', @@ -154,222 +154,133 @@ installHelpers.checkPrimaryDependencies(function(error) { ffmpeg: { name: 'useffmpeg', type: 'string', + description: "Are you using ffmpeg? y/N", before: installHelpers.inputHelpers.toBoolean, - default: 'Y' + default: 'N' }, - server: [ - { - name: 'serverPort', - type: 'number', - description: 'Server port', - pattern: installHelpers.inputHelpers.numberValidator, - default: 5000 - }, - { - name: 'serverName', - type: 'string', - description: 'Server name', - default: 'localhost' - }, - { - name: 'dbHost', - type: 'string', - description: 'Database host', - default: 'localhost' - }, - { - name: 'dbName', - type: 'string', - description: 'Master database name', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'adapt-tenant-master' - }, - { - name: 'dbPort', - type: 'number', - description: 'Database server port', - pattern: installHelpers.inputHelpers.numberValidator, - default: 27017 - }, - { - name: 'dbUser', + smtp: { + confirm: { + name: 'useSmtp', type: 'string', - description: 'Database server user', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: '' - }, - { - name: 'dbPass', - type: 'string', - description: 'Database server password', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: '' - }, - { - name: 'dbAuthSource', - type: 'string', - description: 'Database server authentication database', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'admin' - }, - { - name: 'dataRoot', - type: 'string', - description: 'Data directory path', - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'data' - }, - { - name: 'authoringToolRepository', - type: 'string', - description: "Git repository URL to be used for the authoring tool source code", - default: 'https://github.com/adaptlearning/adapt_authoring.git' - }, - { - name: 'frameworkRepository', - type: 'string', - description: "Git repository URL to be used for the framework source code", - default: 'https://github.com/adaptlearning/adapt_framework.git' + description: "Will you be using an SMTP server? (used for sending emails) y/N", + before: installHelpers.inputHelpers.toBoolean, + default: 'N' }, - { - name: 'frameworkRevision', - type: 'string', - description: 'Specific git revision to be used for the framework. Accepts any valid revision type (e.g. branch/tag/commit)', - default: 'tags/' + latestFrameworkTag - } - ], - features: { - ffmpeg: { - name: 'useffmpeg', + confirmConnectionUrl: { + name: 'useSmtpConnectionUrl', type: 'string', - description: "Are you using ffmpeg? y/N", + description: "Will you use a URL to connect to your smtp Server y/N", before: installHelpers.inputHelpers.toBoolean, default: 'N' }, - smtp: { - confirm: { - name: 'useSmtp', + configure: [ + { + name: 'fromAddress', type: 'string', - description: "Will you be using an SMTP server? (used for sending emails) y/N", - before: installHelpers.inputHelpers.toBoolean, - default: 'N' + description: "Sender email address", + default: '', }, - confirmConnectionUrl: { - name: 'useSmtpConnectionUrl', + { + name: 'rootUrl', + type: 'string', + description: "The url this install will be accessible from", + default: '' // set using default server options + } + ], + configureService: [ + { + name: 'smtpService', type: 'string', - description: "Will you use a URL to connect to your smtp Server y/N", - before: installHelpers.inputHelpers.toBoolean, - default: 'N' + description: "Which SMTP service (if any) will be used? (see https://github.com/andris9/nodemailer-wellknown#supported-services for a list of supported services.)", + default: 'none', }, - configure: [ - { - name: 'fromAddress', - type: 'string', - description: "Sender email address", - default: '', - }, - { - name: 'rootUrl', - type: 'string', - description: "The url this install will be accessible from", - default: '' // set using default server options - } - ], - configureService: [ - { - name: 'smtpService', - type: 'string', - description: "Which SMTP service (if any) will be used? (see https://github.com/andris9/nodemailer-wellknown#supported-services for a list of supported services.)", - default: 'none', - }, - { - name: 'smtpUsername', - type: 'string', - description: "SMTP username", - default: '', - }, - { - name: 'smtpPassword', - type: 'string', - description: "SMTP password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - default: '', - before: installHelpers.inputHelpers.passwordBefore - } - ], - configureConnectionUrl: [ - { - name: 'smtpConnectionUrl', - type: 'string', - description: "Custom connection URL: smtps://user%40gmail.com:pass@smtp.gmail.com/?pool=true", - default: 'none', - } - ] - } + { + name: 'smtpUsername', + type: 'string', + description: "SMTP username", + default: '', + }, + { + name: 'smtpPassword', + type: 'string', + description: "SMTP password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + default: '', + before: installHelpers.inputHelpers.passwordBefore + } + ], + configureConnectionUrl: [ + { + name: 'smtpConnectionUrl', + type: 'string', + description: "Custom connection URL: smtps://user%40gmail.com:pass@smtp.gmail.com/?pool=true", + default: 'none', + } + ] + } + }, + tenant: [ + { + name: 'masterTenantName', + type: 'string', + description: "Set a unique name for your tenant", + pattern: installHelpers.inputHelpers.alphanumValidator, + default: 'master' }, - tenant: [ - { - name: 'masterTenantName', - type: 'string', - description: "Set a unique name for your tenant", - pattern: installHelpers.inputHelpers.alphanumValidator, - default: 'master' - }, - { - name: 'masterTenantDisplayName', - type: 'string', - description: 'Set the display name for your tenant', - default: 'Master' - } - ], - tenantDelete: { - name: "confirm", - description: "Continue? (Y/n)", - before: installHelpers.inputHelpers.toBoolean, - default: "Y" + { + name: 'masterTenantDisplayName', + type: 'string', + description: 'Set the display name for your tenant', + default: 'Master' + } + ], + tenantDelete: { + name: "confirm", + description: "Continue? (Y/n)", + before: installHelpers.inputHelpers.toBoolean, + default: "Y" + }, + superUser: [ + { + name: 'suEmail', + type: 'string', + description: "Email address", + required: true }, - superUser: [ - { - name: 'suEmail', - type: 'string', - description: "Email address", - required: true - }, - { - name: 'suPassword', - type: 'string', - description: "Password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - required: true, - before: installHelpers.inputHelpers.passwordBefore - }, - { - name: 'suRetypePassword', - type: 'string', - description: "Confirm Password", - hidden: true, - replace: installHelpers.inputHelpers.passwordReplace, - required: true, - before: installHelpers.inputHelpers.passwordBefore - } - ] - }; - if(!IS_INTERACTIVE) { - return start(); - } + { + name: 'suPassword', + type: 'string', + description: "Password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + required: true, + before: installHelpers.inputHelpers.passwordBefore + }, + { + name: 'suRetypePassword', + type: 'string', + description: "Confirm Password", + hidden: true, + replace: installHelpers.inputHelpers.passwordReplace, + required: true, + before: installHelpers.inputHelpers.passwordBefore + } + ] + }; + if(!IS_INTERACTIVE) { + return start(); + } + console.log(''); + if(!fs.existsSync('conf/config.json')) { + fs.ensureDirSync('conf'); + return start(); + } + console.log('Found an existing config.json file. Do you want to use the values in this file during install?'); + installHelpers.getInput(inputData.useConfigJSON, function(result) { console.log(''); - if(!fs.existsSync('conf/config.json')) { - fs.ensureDirSync('conf'); - return start(); - } - console.log('Found an existing config.json file. Do you want to use the values in this file during install?'); - installHelpers.getInput(inputData.useConfigJSON, function(result) { - console.log(''); - USE_CONFIG = result.useJSON; - start(); - }); + USE_CONFIG = result.useJSON; + start(); }); }); }); From 802d7b2da85d219df68e4af73246fc169e412fc6 Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Wed, 10 Oct 2018 11:05:01 +0100 Subject: [PATCH 16/21] =?UTF-8?q?Remove=20=E2=80=98v=E2=80=99=20from=20err?= =?UTF-8?q?or=20messages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/installHelpers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 5d822ced0c..5a6b7c3338 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -171,10 +171,10 @@ function checkNodeVersion(callback) { const requiredVersion = pkg.engines.node; const installedVersion = process.versions.node; if(semver.gtr(installedVersion, requiredVersion)) { - return callback(null, `You are using Node.js v${installedVersion} which is not yet supported by Adapt. If you encounter issues, please downgrade to v${requiredVersion}.`); + return callback(null, `You are using Node.js ${installedVersion} which is not yet supported by Adapt. If you encounter issues, please downgrade to ${requiredVersion}.`); } if(!semver.satisfies(installedVersion, requiredVersion)) { - return callback(`The application requires Node.js v${requiredVersion} to run, found v${installedVersion}. Please make sure you have a compatible version.`); + return callback(`The application requires Node.js ${requiredVersion} to run, found ${installedVersion}. Please make sure you have a compatible version.`); } callback(); } From 2e4dac82e216f7dc6030cb3739865cf4a681bead Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Wed, 10 Oct 2018 11:05:09 +0100 Subject: [PATCH 17/21] Fix upgrade script --- upgrade.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/upgrade.js b/upgrade.js index 20f09cc153..b449205193 100644 --- a/upgrade.js +++ b/upgrade.js @@ -29,15 +29,15 @@ function start() { if(error) { return installHelpers.exit(1, error.message); } - installHelpers.checkSecondaryDependencies(function(error) { - // don't show any logger messages in the console - logger.level('console','error'); + // don't show any logger messages in the console + logger.level('console','error'); - prompt.override = optimist.argv; + prompt.override = optimist.argv; - // start the server first - app.run({ skipVersionCheck: true, skipStartLog: true }); - app.on('serverStarted', function() { + // start the server first + app.run({ skipVersionCheck: true, skipStartLog: true }); + app.on('serverStarted', function() { + installHelpers.checkSecondaryDependencies(function(error) { ensureRepoValues(); getUserInput(); }); From f671cdfe73456edb418e6b76da89874d21e0711d Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Wed, 10 Oct 2018 11:24:26 +0100 Subject: [PATCH 18/21] Add option to skip dependency check --- lib/application.js | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/lib/application.js b/lib/application.js index bb8bdd7078..b194f28201 100644 --- a/lib/application.js +++ b/lib/application.js @@ -351,22 +351,13 @@ Origin.prototype.startServer = function (options) { var app = this; // Ensure that the options object is set. if(typeof options === 'undefined') { - options = { skipVersionCheck: false, skipStartLog: false }; + options = { + skipDependencyCheck: false, + skipVersionCheck: false, + skipStartLog: false + }; } - var _checkPrerequisites = function(callback) { - installHelpers.checkAllDependencies(error => { - if(error) { - return callback(error); - } - if(configuration.getConfig('isTestEnvironment') || options.skipVersionCheck) { - return callback(); - } - checkForUpdates(function(error) { - callback(error ? new Error(`Check for updates failed, ${error}`) : null); - }); - }); - }; - _checkPrerequisites(function(err, result) { + checkPrerequisites(options, function(err, result) { if(err) { logger.log('error', chalk.red(err.message)); return process.exit(0); @@ -391,8 +382,9 @@ Origin.prototype.startServer = function (options) { app.router = router(app); // handle different server states app.emit(serverOptions.minimal ? "minimalServerStarted" : "serverStarted", app.server); - logger.log('info', `Server started listening on port ${port}`); - + if(!options.skipStartLog) { + logger.log('info', `Server started listening on port ${port}`); + } var writeRebuildFile = function(courseFolder, callback) { var OutputConstants = require('./outputmanager').Constants; var buildFolder = path.join(courseFolder, OutputConstants.Folders.Build); @@ -541,6 +533,23 @@ Origin.prototype.ModulePreloader.defOpts = { } }; +function checkPrerequisites(options, callback) { + async.series([ + function(cb) { + if(options.skipDependencyCheck) { + return cb(); + } + installHelpers.checkAllDependencies(cb); + }, + function(cb) { + if(configuration.getConfig('isTestEnvironment') || options.skipVersionCheck) { + return cb(); + } + checkForUpdates(error => cb(error ? new Error(`Check for updates failed, ${error}`) : null)); + } + ], callback); +} + function checkForUpdates(callback) { installHelpers.getInstalledVersions(function(error, installedData) { installHelpers.getUpdateData(function(error, updateData) { From 6e9cc207f189b9877a98ec657f6849e78443c69b Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Mon, 15 Oct 2018 13:20:33 +0100 Subject: [PATCH 19/21] Make ffmpeg and smtp errors non-fatal --- lib/installHelpers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 5a6b7c3338..3ad8e35d71 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -212,7 +212,7 @@ function checkSmtpConnection(callback) { if(!configuration.getConfig('useSmtp')) { return callback(); } - (new mailer()).testConnection(error => callback(error && error.message || null)); + (new mailer()).testConnection(error => callback(null, error && error.message || null)); } function checkFfmpegInstalled(callback) { @@ -220,7 +220,7 @@ function checkFfmpegInstalled(callback) { return callback(); } execCommand('ffmpeg -version', {}, error => { - callback(error ? 'Local FFmpeg could not be found, please check it is installed' : null); + callback(null, error && 'Local FFmpeg could not be found, please check it is installed' || null); }); } From 0d1eb37db4c06bb239c5ae4c472c94cf60e9a3e8 Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Mon, 15 Oct 2018 19:11:17 +0100 Subject: [PATCH 20/21] Convert strings to booleans on get --- lib/configuration.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/configuration.js b/lib/configuration.js index cf47501183..877be7f238 100644 --- a/lib/configuration.js +++ b/lib/configuration.js @@ -150,7 +150,13 @@ Configuration.prototype.setConfig = function (name, value) { */ Configuration.prototype.getConfig = function (name) { if (name && typeof name === 'string') { - return (this.conf[name] || ''); + switch(this.conf[name]) { + case 'y': case 'Y': + return true; + case 'n': case 'N': + return false; + } + return this.conf[name] || ''; } if (typeof name === 'undefined') { From aa78bd288b2e787a68c5a0e8f4552dbdad3d0f0f Mon Sep 17 00:00:00 2001 From: tomgreenfield Date: Wed, 17 Oct 2018 10:32:53 +0100 Subject: [PATCH 21/21] Remove trailing comma --- lib/installHelpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/installHelpers.js b/lib/installHelpers.js index 3ad8e35d71..f44d1d8f63 100644 --- a/lib/installHelpers.js +++ b/lib/installHelpers.js @@ -69,7 +69,7 @@ var exports = module.exports = { updateFramework, updateFrameworkPlugins, updateAuthoring, - buildAuthoring, + buildAuthoring }; function exit(code, msg, preCallback) {