From 6698ca094d75a3dea0496aedf5f150f80703a3b3 Mon Sep 17 00:00:00 2001 From: NGPixel Date: Sat, 25 Mar 2017 18:21:14 -0400 Subject: [PATCH] Setup Wizard - Git check --- agent.js | 1 - assets/js/configure.js | 2 +- client/js/configure.js | 4 +- configure.js | 83 +++++++++++++++++++++++++++++++-------- views/configure/index.pug | 8 ++-- 5 files changed, 74 insertions(+), 24 deletions(-) diff --git a/agent.js b/agent.js index aeb17ff3..f4add906 100644 --- a/agent.js +++ b/agent.js @@ -183,7 +183,6 @@ db.onReady.then(() => { timeZone: 'UTC', runOnInit: true }) - }) // ---------------------------------------- diff --git a/assets/js/configure.js b/assets/js/configure.js index 4750617f..943016d5 100644 --- a/assets/js/configure.js +++ b/assets/js/configure.js @@ -1 +1 @@ -"use strict";Vue.use(VeeValidate,{enableAutoClasses:!0,classNames:{touched:"is-touched",untouched:"is-untouched",valid:"is-valid",invalid:"is-invalid",pristine:"is-pristine",dirty:"is-dirty"}}),jQuery(document).ready(function(t){new Vue({el:"main",data:{loading:!1,state:"welcome",syscheck:{ok:!1,error:"",results:[]},dbcheck:{ok:!1,error:""},gitcheck:{ok:!1,error:""},final:{ok:!1,error:"",results:[]},conf:{title:"Wiki",host:"http://",port:80,lang:"en",db:"mongodb://localhost:27017/wiki",pathData:"./data",pathRepo:"./repo",gitUrl:"",gitBranch:"master",gitAuthType:"ssh",gitAuthSSHKey:"",gitAuthUser:"",gitAuthPass:"",gitAuthSSL:!0,gitSignatureName:"",gitSignatureEmail:"",adminEmail:"",adminPassword:"",adminPasswordConfirm:""},considerations:{https:!1,port:!1,localhost:!1}},computed:{currentProgress:function(){var t="0%";switch(this.state){case"welcome":t="0%";break;case"syscheck":t=this.syscheck.ok?"15%":"5%";break;case"general":t="20%";break;case"considerations":t="30%";break;case"db":t="35%";break;case"dbcheck":t=this.dbcheck.ok?"50%":"40%";break;case"paths":t="55%";break;case"git":t="60%";break;case"gitcheck":t=this.gitcheck.ok?"75%":"65%";break;case"admin":t="80%"}return t}},methods:{proceedToWelcome:function(t){this.state="welcome",this.loading=!1},proceedToSyscheck:function(t){var e=this;this.state="syscheck",this.loading=!0,e.syscheck={ok:!1,error:"",results:[]},_.delay(function(){axios.post("/syscheck").then(function(t){t.data.ok===!0?(e.syscheck.ok=!0,e.syscheck.results=t.data.results):(e.syscheck.ok=!1,e.syscheck.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToGeneral:function(t){var e=this;e.state="general",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("general")})},proceedToConsiderations:function(t){this.considerations={https:!_.startsWith(this.conf.host,"https"),port:!1,localhost:_.includes(this.conf.host,"localhost")},this.state="considerations",this.loading=!1},proceedToDb:function(t){var e=this;e.state="db",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("db")})},proceedToDbcheck:function(t){var e=this;this.state="dbcheck",this.loading=!0,e.dbcheck={ok:!1,error:""},_.delay(function(){axios.post("/dbcheck",{db:e.conf.db}).then(function(t){t.data.ok===!0?e.dbcheck.ok=!0:(e.dbcheck.ok=!1,e.dbcheck.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToPaths:function(t){var e=this;e.state="paths",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("paths")})},proceedToGit:function(t){var e=this;e.state="git",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("git")})},proceedToGitCheck:function(t){var e=this;this.state="gitcheck",this.loading=!0,e.dbcheck={ok:!1,error:""},_.delay(function(){axios.post("/gitcheck",e.conf).then(function(t){t.data.ok===!0?e.gitcheck.ok=!0:(e.gitcheck.ok=!1,e.gitcheck.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToAdmin:function(t){var e=this;e.state="admin",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("admin")})},proceedToFinal:function(t){var e=this;e.state="final",e.loading=!0,e.final={ok:!1,error:"",results:[]},_.delay(function(){axios.post("/finalize",e.conf).then(function(t){t.data.ok===!0?(e.final.ok=!0,e.final.results=t.data.results):(e.final.ok=!1,e.final.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},finish:function(t){}}})}); \ No newline at end of file +"use strict";Vue.use(VeeValidate,{enableAutoClasses:!0,classNames:{touched:"is-touched",untouched:"is-untouched",valid:"is-valid",invalid:"is-invalid",pristine:"is-pristine",dirty:"is-dirty"}}),jQuery(document).ready(function(t){new Vue({el:"main",data:{loading:!1,state:"welcome",syscheck:{ok:!1,error:"",results:[]},dbcheck:{ok:!1,error:""},gitcheck:{ok:!1,error:""},final:{ok:!1,error:"",results:[]},conf:{title:"Wiki",host:"http://",port:80,lang:"en",db:"mongodb://localhost:27017/wiki",pathData:"./data",pathRepo:"./repo",gitUrl:"",gitBranch:"master",gitAuthType:"ssh",gitAuthSSHKey:"",gitAuthUser:"",gitAuthPass:"",gitAuthSSL:!0,gitSignatureName:"",gitSignatureEmail:"",adminEmail:"",adminPassword:"",adminPasswordConfirm:""},considerations:{https:!1,port:!1,localhost:!1}},computed:{currentProgress:function(){var t="0%";switch(this.state){case"welcome":t="0%";break;case"syscheck":t=this.syscheck.ok?"15%":"5%";break;case"general":t="20%";break;case"considerations":t="30%";break;case"db":t="35%";break;case"dbcheck":t=this.dbcheck.ok?"50%":"40%";break;case"paths":t="55%";break;case"git":t="60%";break;case"gitcheck":t=this.gitcheck.ok?"75%":"65%";break;case"admin":t="80%"}return t}},methods:{proceedToWelcome:function(t){this.state="welcome",this.loading=!1},proceedToSyscheck:function(t){var e=this;this.state="syscheck",this.loading=!0,e.syscheck={ok:!1,error:"",results:[]},_.delay(function(){axios.post("/syscheck").then(function(t){t.data.ok===!0?(e.syscheck.ok=!0,e.syscheck.results=t.data.results):(e.syscheck.ok=!1,e.syscheck.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToGeneral:function(t){var e=this;e.state="general",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("general")})},proceedToConsiderations:function(t){this.considerations={https:!_.startsWith(this.conf.host,"https"),port:!1,localhost:_.includes(this.conf.host,"localhost")},this.state="considerations",this.loading=!1},proceedToDb:function(t){var e=this;e.state="db",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("db")})},proceedToDbcheck:function(t){var e=this;this.state="dbcheck",this.loading=!0,e.dbcheck={ok:!1,error:""},_.delay(function(){axios.post("/dbcheck",{db:e.conf.db}).then(function(t){t.data.ok===!0?e.dbcheck.ok=!0:(e.dbcheck.ok=!1,e.dbcheck.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToPaths:function(t){var e=this;e.state="paths",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("paths")})},proceedToGit:function(t){var e=this;e.state="git",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("git")})},proceedToGitCheck:function(t){var e=this;this.state="gitcheck",this.loading=!0,e.gitcheck={ok:!1,results:[],error:""},_.delay(function(){axios.post("/gitcheck",e.conf).then(function(t){t.data.ok===!0?(e.gitcheck.ok=!0,e.gitcheck.results=t.data.results):(e.gitcheck.ok=!1,e.gitcheck.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},proceedToAdmin:function(t){var e=this;e.state="admin",e.loading=!1,e.$nextTick(function(){e.$validator.validateAll("admin")})},proceedToFinal:function(t){var e=this;e.state="final",e.loading=!0,e.final={ok:!1,error:"",results:[]},_.delay(function(){axios.post("/finalize",e.conf).then(function(t){t.data.ok===!0?(e.final.ok=!0,e.final.results=t.data.results):(e.final.ok=!1,e.final.error=t.data.error),e.loading=!1,e.$nextTick()}).catch(function(t){window.alert(t.message)})},1e3)},finish:function(t){}}})}); \ No newline at end of file diff --git a/client/js/configure.js b/client/js/configure.js index ff88e362..3913a51a 100644 --- a/client/js/configure.js +++ b/client/js/configure.js @@ -205,8 +205,9 @@ jQuery(document).ready(function ($) { let self = this this.state = 'gitcheck' this.loading = true - self.dbcheck = { + self.gitcheck = { ok: false, + results: [], error: '' } @@ -214,6 +215,7 @@ jQuery(document).ready(function ($) { axios.post('/gitcheck', self.conf).then(resp => { if (resp.data.ok === true) { self.gitcheck.ok = true + self.gitcheck.results = resp.data.results } else { self.gitcheck.ok = false self.gitcheck.error = resp.data.error diff --git a/configure.js b/configure.js index 5db28f3c..bc85f3e6 100644 --- a/configure.js +++ b/configure.js @@ -15,11 +15,10 @@ module.exports = (port, spinner) => { const http = require('http') const path = require('path') const Promise = require('bluebird') - const fs = require('fs-extra') + const fs = Promise.promisifyAll(require('fs-extra')) const yaml = require('js-yaml') const _ = require('lodash') - // ---------------------------------------- // Define Express App // ---------------------------------------- @@ -160,26 +159,76 @@ module.exports = (port, spinner) => { */ app.post('/gitcheck', (req, res) => { const exec = require('execa') + const url = require('url') const dataDir = path.resolve(ROOTPATH, req.body.pathData) const gitDir = path.resolve(ROOTPATH, req.body.pathRepo) - let results = [] - fs.ensureDir(dataDir).then(() => { - results.push('Data directory path is valid.') - return fs.ensureDir(gitDir).then(() => { - results.push('Git directory path is valid.') - return true - }) - }).then(() => { - return exec.stdout('git', ['init'], { cwd: gitDir }).then(result => { - results.push('Git local repository initialized.') - return true - }) - }).then(() => { - return res.json({ ok: true, results }) + let urlObj = url.parse(req.body.gitUrl) + if (req.body.gitAuthType === 'basic') { + urlObj.auth = req.body.gitAuthUser + ':' + req.body.gitAuthPass + } + const gitRemoteUrl = url.format(urlObj) + + Promise.mapSeries([ + () => { + return fs.ensureDirAsync(dataDir).return('Data directory path is valid.') + }, + () => { + return fs.ensureDirAsync(gitDir).return('Git directory path is valid.') + }, + () => { + return exec.stdout('git', ['init'], { cwd: gitDir }).then(result => { + return 'Local git repository has been initialized.' + }) + }, + () => { + return exec.stdout('git', ['config', '--local', 'user.name', req.body.gitSignatureName], { cwd: gitDir }).then(result => { + return 'Git Signature Name has been set successfully.' + }) + }, + () => { + return exec.stdout('git', ['config', '--local', 'user.email', req.body.gitSignatureEmail], { cwd: gitDir }).then(result => { + return 'Git Signature Name has been set successfully.' + }) + }, + () => { + return exec.stdout('git', ['config', '--local', '--bool', 'http.sslVerify', req.body.gitAuthSSL], { cwd: gitDir }).then(result => { + return 'Git SSL Verify flag has been set successfully.' + }) + }, + () => { + if (req.body.gitAuthType === 'ssh') { + return exec.stdout('git', ['config', '--local', 'core.sshCommand', 'ssh -i "' + req.body.gitAuthSSHKey + '" -o StrictHostKeyChecking=no'], { cwd: gitDir }).then(result => { + return 'Git SSH Private Key path has been set successfully.' + }) + } else { + return false + } + }, + () => { + return exec.stdout('git', ['remote', 'remove', 'origin'], { cwd: gitDir }).catch(err => { + if (_.includes(err.message, 'No such remote')) { + return true + } else { + throw err + } + }).then(() => { + return exec.stdout('git', ['remote', 'add', 'origin', gitRemoteUrl], { cwd: gitDir }).then(result => { + return 'Git Remote was added successfully.' + }) + }) + }, + () => { + return exec.stdout('git', ['pull', 'origin', req.body.gitBranch], { cwd: gitDir }).then(result => { + return 'Git Pull operation successful.' + }) + } + ], step => { return step() }).then(results => { + return res.json({ ok: true, results: _.without(results, false) }) }).catch(err => { - res.json({ ok: false, error: err.message }) + let errMsg = (err.stderr) ? err.stderr.replace(/(error:|warning:|fatal:)/gi, '').replace(/ \s+/g, ' ') : err.message + res.json({ ok: false, error: errMsg }) }) }) diff --git a/views/configure/index.pug b/views/configure/index.pug index f2fcc454..b4bd57e0 100644 --- a/views/configure/index.pug +++ b/views/configure/index.pug @@ -252,17 +252,17 @@ html .column(v-show='conf.gitAuthType === "basic"') p.control.is-fullwidth label.label Username - input(type='text', v-model='conf.gitUrl') + input(type='text', v-model='conf.gitAuthUser') span.desc The username for the remote git connection. .column(v-show='conf.gitAuthType === "basic"') p.control.is-fullwidth label.label Password - input(type='password', v-model='conf.gitUrl') + input(type='password', v-model='conf.gitAuthPass') span.desc The password for the remote git connection. .column(v-show='conf.gitAuthType === "ssh"') p.control.is-fullwidth label.label Private Key location - input(type='text', placeholder='e.g. /etc/wiki/keys/git.pem') + input(type='text', placeholder='e.g. /etc/wiki/keys/git.pem', v-model='conf.gitAuthSSHKey') span.desc The full path to the private key on disk. section.columns .column @@ -277,7 +277,7 @@ html span.desc The email to use when pushing commits to the git repository. .panel-footer .progress-bar: div(v-bind:style='{width: currentProgress}') - button.button.is-indigo.is-outlined(v-on:click='proceedToDb', v-bind:disabled='loading') Back + button.button.is-indigo.is-outlined(v-on:click='proceedToPaths', v-bind:disabled='loading') Back button.button.is-indigo.is-outlined(v-on:click='proceedToAdmin', v-bind:disabled='loading') Skip this step button.button.is-indigo(v-on:click='proceedToGitCheck', v-bind:disabled='loading || errors.any("git")') Continue