feat: Heroku support - setup

This commit is contained in:
NGPixel 2017-05-14 20:17:08 -04:00
parent 6e0b7dc272
commit 451b2a646f
7 changed files with 215 additions and 20 deletions

View File

@ -1,6 +1,6 @@
'use strict' 'use strict'
/* global appconfig */ /* global appconfig, runmode */
import jQuery from 'jquery' import jQuery from 'jquery'
import _ from 'lodash' import _ from 'lodash'
@ -180,6 +180,9 @@ jQuery(document).ready(function ($) {
}, },
proceedToDb: function (ev) { proceedToDb: function (ev) {
let self = this let self = this
if (runmode.staticMongo) {
return self.proceedToDbcheck()
}
self.state = 'db' self.state = 'db'
self.loading = false self.loading = false
self.$nextTick(() => { self.$nextTick(() => {

View File

@ -0,0 +1,153 @@
#######################################################################
# Wiki.js - CONFIGURATION #
#######################################################################
# Full explanation + examples in the documentation:
# https://docs.requarks.io/wiki/install
# ---------------------------------------------------------------------
# Title of this site
# ---------------------------------------------------------------------
title: Wiki
# ---------------------------------------------------------------------
# Full public path to the site, without the trailing slash
# ---------------------------------------------------------------------
host: https://YOURAPP.herokuapp.com/
# ---------------------------------------------------------------------
# Port the main server should listen to (80 by default)
# ---------------------------------------------------------------------
port: $(PORT)
# ---------------------------------------------------------------------
# Data Directories
# ---------------------------------------------------------------------
paths:
repo: ./repo
data: ./data
# ---------------------------------------------------------------------
# Upload Limits
# ---------------------------------------------------------------------
# In megabytes (MB)
uploads:
maxImageFileSize: 3
maxOtherFileSize: 100
# ---------------------------------------------------------------------
# Site Language
# ---------------------------------------------------------------------
# Possible values: en, de, es, fr, ko, pt or ru
lang: en
# ---------------------------------------------------------------------
# Site Authentication
# ---------------------------------------------------------------------
public: false
auth:
defaultReadAccess: false
local:
enabled: true
google:
enabled: true
clientId: GOOGLE_CLIENT_ID
clientSecret: GOOGLE_CLIENT_SECRET
microsoft:
enabled: true
clientId: MS_APP_ID
clientSecret: MS_APP_SECRET
facebook:
enabled: false
clientId: FACEBOOK_APP_ID
clientSecret: FACEBOOK_APP_SECRET
github:
enabled: false
clientId: GITHUB_CLIENT_ID
clientSecret: GITHUB_CLIENT_SECRET
slack:
enabled: false
clientId: SLACK_CLIENT_ID
clientSecret: SLACK_CLIENT_SECRET
ldap:
enabled: false
url: ldap://serverhost:389
bindDn: cn='root'
bindCredentials: BIND_PASSWORD
searchBase: o=users,o=example.com
searchFilter: (uid={{username}})
tlsEnabled: false
tlsCertPath: C:\example\root_ca_cert.crt
azure:
enabled: false
clientID: APP_ID
clientSecret: APP_SECRET_KEY
resource: '00000002-0000-0000-c000-000000000000'
tenant: 'YOUR_TENANT.onmicrosoft.com'
# ---------------------------------------------------------------------
# Secret key to use when encrypting sessions
# ---------------------------------------------------------------------
# Use a long and unique random string (256-bit keys are perfect!)
sessionSecret: 1234567890abcdefghijklmnopqrstuvxyz
# ---------------------------------------------------------------------
# Database Connection String
# ---------------------------------------------------------------------
db: $(MONGO_URI)
# ---------------------------------------------------------------------
# Git Connection Info
# ---------------------------------------------------------------------
git:
url: https://github.com/Organization/Repo
branch: master
auth:
# Type: basic or ssh
type: ssh
# Only for Basic authentication:
username: marty
password: MartyMcFly88
# Only for SSH authentication:
privateKey: /etc/wiki/keys/git.pem
sslVerify: true
# Default email to use as commit author
serverEmail: marty@example.com
# Whether to use user email as author in commits
showUserEmail: true
# ---------------------------------------------------------------------
# Features
# ---------------------------------------------------------------------
# You can enable / disable specific features below
features:
mathjax: true
# ---------------------------------------------------------------------
# External Logging
# ---------------------------------------------------------------------
externalLogging:
bugsnag: false
loggly: false
papertrail: false
rollbar: false
sentry: false

View File

@ -136,11 +136,13 @@ const tasks = {
// Is New Install // Is New Install
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
ora.text = 'First-time install, creating a new config.yml...' ora.text = 'First-time install, creating a new config.yml...'
let sourceConfigFile = 'config.sample.yml' let sourceConfigFile = path.join(installDir, 'config.sample.yml')
if (process.env.WIKI_JS_DOCKER) { if (process.env.IS_HEROKU) {
sourceConfigFile = 'config.docker.yml' sourceConfigFile = path.join(__dirname, 'configs/config.heroku.yml')
} else if (process.env.WIKI_JS_DOCKER) {
sourceConfigFile = path.join(__dirname, 'configs/config.docker.yml')
} }
return fs.copyAsync(path.join(installDir, sourceConfigFile), path.join(installDir, 'config.yml')).then(() => { return fs.copyAsync(sourceConfigFile, path.join(installDir, 'config.yml')).then(() => {
ora.succeed('Installation succeeded.') ora.succeed('Installation succeeded.')
return true return true
}) })
@ -200,7 +202,11 @@ const tasks = {
}) })
}) })
} else { } else {
if (!process.env.IS_HEROKU && !process.env.WIKI_JS_DOCKER) {
console.info(colors.cyan('[WARNING] Non-interactive terminal detected. You must manually start the configuration wizard using the command: node wiki configure')) console.info(colors.cyan('[WARNING] Non-interactive terminal detected. You must manually start the configuration wizard using the command: node wiki configure'))
} else {
console.info('Container environment detected. Skipping setup wizard auto-start. OK.')
}
} }
} }
} }
@ -217,6 +223,8 @@ if (!process.env.IS_HEROKU && !process.env.WIKI_JS_DOCKER) {
' \\ /\\ /| | <| |_ | \\__ \\ \n' + ' \\ /\\ /| | <| |_ | \\__ \\ \n' +
' \\/ \\/ |_|_|\\_\\_(_)/ |___/ \n' + ' \\/ \\/ |_|_|\\_\\_(_)/ |___/ \n' +
' |__/\n')) ' |__/\n'))
} else {
console.info('=-=-= WIKI.JS =-=-=')
} }
let ora = require('ora')({ text: 'Initializing...', spinner: 'dots12' }).start() let ora = require('ora')({ text: 'Initializing...', spinner: 'dots12' }).start()

View File

@ -20,6 +20,7 @@ module.exports = (port, spinner) => {
const fs = Promise.promisifyAll(require('fs-extra')) const fs = Promise.promisifyAll(require('fs-extra'))
const yaml = require('js-yaml') const yaml = require('js-yaml')
const _ = require('lodash') const _ = require('lodash')
const cfgHelper = require('./helpers/config')
// ---------------------------------------- // ----------------------------------------
// Define Express App // Define Express App
@ -62,7 +63,14 @@ module.exports = (port, spinner) => {
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} }
res.render('configure/index', { langs, conf }) res.render('configure/index', {
langs,
conf,
runmode: {
staticPort: (process.env.IS_HEROKU || process.env.WIKI_JS_DOCKER) || true,
staticMongo: (!_.isNil(process.env.IS_HEROKU)) || true
}
})
}) })
/** /**
@ -127,7 +135,7 @@ module.exports = (port, spinner) => {
*/ */
app.post('/dbcheck', (req, res) => { app.post('/dbcheck', (req, res) => {
let mongo = require('mongodb').MongoClient let mongo = require('mongodb').MongoClient
let mongoURI = (_.startsWith(req.body.db, '$')) ? process.env[req.body.db.slice(1)] : req.body.db let mongoURI = cfgHelper.parseConfigValue(req.body.db)
mongo.connect(mongoURI, { mongo.connect(mongoURI, {
autoReconnect: false, autoReconnect: false,
reconnectTries: 2, reconnectTries: 2,
@ -166,13 +174,13 @@ module.exports = (port, spinner) => {
const exec = require('execa') const exec = require('execa')
const url = require('url') const url = require('url')
const dataDir = path.resolve(ROOTPATH, req.body.pathData) const dataDir = path.resolve(ROOTPATH, cfgHelper.parseConfigValue(req.body.pathData))
const gitDir = path.resolve(ROOTPATH, req.body.pathRepo) const gitDir = path.resolve(ROOTPATH, cfgHelper.parseConfigValue(req.body.pathRepo))
let gitRemoteUrl = '' let gitRemoteUrl = ''
if (req.body.gitUseRemote === true) { if (req.body.gitUseRemote === true) {
let urlObj = url.parse(req.body.gitUrl) let urlObj = url.parse(cfgHelper.parseConfigValue(req.body.gitUrl))
if (req.body.gitAuthType === 'basic') { if (req.body.gitAuthType === 'basic') {
urlObj.auth = req.body.gitAuthUser + ':' + req.body.gitAuthPass urlObj.auth = req.body.gitAuthUser + ':' + req.body.gitAuthPass
} }
@ -254,10 +262,11 @@ module.exports = (port, spinner) => {
const bcrypt = require('bcryptjs-then') const bcrypt = require('bcryptjs-then')
const crypto = Promise.promisifyAll(require('crypto')) const crypto = Promise.promisifyAll(require('crypto'))
let mongo = require('mongodb').MongoClient let mongo = require('mongodb').MongoClient
let parsedMongoConStr = cfgHelper.parseConfigValue(req.body.db)
Promise.join( Promise.join(
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
mongo.connect(req.body.db, { mongo.connect(parsedMongoConStr, {
autoReconnect: false, autoReconnect: false,
reconnectTries: 2, reconnectTries: 2,
reconnectInterval: 1000, reconnectInterval: 1000,

20
server/helpers/config.js Normal file
View File

@ -0,0 +1,20 @@
'use strict'
const _ = require('lodash')
module.exports = {
/**
* Parse configuration value for environment vars
*
* @param {any} cfg Configuration value
* @returns Parse configuration value
*/
parseConfigValue (cfg) {
return _.replace(
cfg,
(/\$\([A-Z0-9_]+\)/g,
(m) => { return process.env[m] })
)
}
}

View File

@ -12,6 +12,7 @@ html(data-logic='configure')
// JS / CSS // JS / CSS
script(type='text/javascript'). script(type='text/javascript').
var appconfig = !{JSON.stringify(conf)}; var appconfig = !{JSON.stringify(conf)};
var runmode = !{JSON.stringify(runmode)};
script(type='text/javascript', src='/js/configure.min.js') script(type='text/javascript', src='/js/configure.min.js')
body body
@ -89,13 +90,14 @@ html(data-logic='configure')
section section
p.control.is-fullwidth p.control.is-fullwidth
label.label Host label.label Host
input(type='text', placeholder='http://', v-model='conf.host', data-vv-scope='general', name='ipt-host', v-validate='{ required: true, url: true }') input(type='text', placeholder='http://', v-model='conf.host', data-vv-scope='general', name='ipt-host', v-validate='{ required: true, min: 4 }')
span.desc The full URL to your wiki, without the trailing slash. E.g.: http://wiki.domain.com. Note that sub-folders are not supported. span.desc The full URL to your wiki, without the trailing slash. E.g.: http://wiki.domain.com. Note that sub-folders are #[u not supported].
if !runmode.staticPort
section section
p.control p.control
label.label Port label.label Port
input(type='text', placeholder='e.g. 80', v-model.number='conf.port', data-vv-scope='general', name='ipt-port', v-validate='{ required: true, numeric: true, min_value: 0, max_value: 65535 }') input(type='text', placeholder='e.g. 80', v-model.number='conf.port', data-vv-scope='general', name='ipt-port', v-validate='{ required: true }')
span.desc The port on which Wiki.js will listen to. Usually port 80 if connecting directly, or a random port (e.g. 3000) if using a web server in front of it.<br>Set <strong>0</strong> to use $PORT system environment variable. span.desc The port on which Wiki.js will listen to. Usually port 80 if connecting directly, or a random port (e.g. 3000) if using a web server in front of it.<br>Set <strong>$(PORT)</strong> to use PORT environment variable.
section section
p.control p.control
label.label Site UI Language label.label Site UI Language
@ -160,7 +162,7 @@ html(data-logic='configure')
p.control.is-fullwidth p.control.is-fullwidth
label.label MongoDB Connection String label.label MongoDB Connection String
input(type='text', placeholder='e.g. mongodb://localhost:27017/wiki', v-model='conf.db', data-vv-scope='db', name='ipt-db', v-validate='{ required: true, min: 3 }') input(type='text', placeholder='e.g. mongodb://localhost:27017/wiki', v-model='conf.db', data-vv-scope='db', name='ipt-db', v-validate='{ required: true, min: 3 }')
span.desc The connection string to your MongoDB server. Leave the default localhost value if MongoDB is installed on the same server.<br />You can also specify an environment variable as the connection string (e.g. $MONGO_URI). span.desc The connection string to your MongoDB server. Leave the default localhost value if MongoDB is installed on the same server.<br />You can also specify an environment variable as the connection string, e.g. $(MONGO_URI).
.panel-footer .panel-footer
.progress-bar: div(v-bind:style='{width: currentProgress}') .progress-bar: div(v-bind:style='{width: currentProgress}')
button.button.is-light-blue.is-outlined(v-on:click='proceedToConsiderations', v-bind:disabled='loading') Back button.button.is-light-blue.is-outlined(v-on:click='proceedToConsiderations', v-bind:disabled='loading') Back