generator-swiftserver
Version:
Generator for Kitura REST webservice servers
983 lines (903 loc) • 35.8 kB
JavaScript
/*
* Copyright IBM Corporation 2016-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
var debug = require('debug')('generator-swiftserver:app')
var Generator = require('yeoman-generator')
var chalk = require('chalk')
var path = require('path')
var Handlebars = require('../lib/handlebars.js')
var actions = require('../lib/actions')
var helpers = require('../lib/helpers')
var validateDirName = helpers.validateDirName
var validateAppName = helpers.validateAppName
var validateCredential = helpers.validateRequiredCredential
var validatePort = helpers.validatePort
var generateServiceName = helpers.generateServiceName
module.exports = Generator.extend({
constructor: function () {
Generator.apply(this, arguments)
// Allow the user to pass the application name into the generator directly
this.argument('name', {
desc: 'Name of the application to scaffold.',
required: false,
type: String
})
this.option('init', {
type: Boolean,
desc: 'Generate basic default scaffold without prompting user for input.',
defaults: false
})
this.option('skip-build', {
type: Boolean,
desc: 'Skip building the generated application',
defaults: false
})
this.option('single-shot', {
type: Boolean,
desc: 'Creates application without including generator metadata files',
defaults: false
})
this.option('type', {
type: String,
desc: 'Give a specific type of application to generate',
defaults: 'basic'
})
this.option('metrics', {
type: Boolean,
desc: 'Add health checking to project',
defaults: false
})
this.option('docker', {
type: Boolean,
desc: 'Generate a Dockerfile for the project',
defaults: false
})
this.option('healthcheck', {
type: Boolean,
desc: 'Add health checking to project',
defaults: true
})
this.option('openapi', {
type: Boolean,
desc: 'Add Kitura-OpenAPI to project',
defaults: false
})
},
initializing: {
ensureNotInProject: actions.ensureNotInProject,
checkWorkingDirectory: function () {
// check for %:;=<>”|\ since they break xcode if they are
// anywhere in the directory path.
if (validateDirName(process.cwd()) !== true) {
this.env.error(chalk.red(process.cwd(), 'directory path contains one or more of the following: %:;=<>”|\\ and will not compile in Xcode'))
}
},
initAppName: function () {
// save the initial directory for use by the fromSwagger processing.
this.initialWorkingDir = process.cwd()
this.appname = null // Discard yeoman default appname
this.skipPromptingAppName = false
if (this.options.name) {
// User passed a desired application name as an argument
var validation = validateAppName(this.options.name)
if (validation === true) {
// Desired application name is valid, skip prompting for it
// later
this.appname = this.options.name
this.skipPromptingAppName = true
} else {
// Log reason for validation failure, if provided
validation = validation || 'Application name not valid'
debug(this.options.name, ' is not valid because ', validation)
this.log(validation)
}
}
if (this.appname === null) {
// Fall back to name of current working directory
var sanitizedCWD = path.basename(process.cwd()).replace(/[åç/]+?/g, '-')
// if the name still contains characters %:;=<>”|\\ which
// will cause Xcode to crash, default to 'app'
if (validateAppName(sanitizedCWD) === true) {
this.appname = sanitizedCWD
} else {
// Fall back again to a known valid name
this.log('Failed to produce a valid application name from the current working directory')
debug(sanitizedCWD, ' is not a valid application name and defaulting to \'app\'')
this.appname = 'app'
}
}
},
_writeHandlebarsFile: function (templateFile, destinationFile, data) {
var template = this.fs.read(this.templatePath(templateFile))
var compiledTemplate = Handlebars.compile(template)
var output = compiledTemplate(data)
this.fs.write(this.destinationPath(destinationFile), output)
},
initSpec: function () {
function isTrue (value) {
return (value === true || value === 'true')
}
if (this.options.bluemix) {
this.skipPrompting = true
if (this.options.type) {
this.appType = this.options.type
}
if (typeof (this.options.bluemix) === 'string') {
this.options.bluemix = JSON.parse(this.options.bluemix)
}
if (typeof (this.options.starterOptions) === 'string') {
this.options.starterOptions = JSON.parse(this.options.starterOptions)
}
var appName = this.options.bluemix.name
var metrics = isTrue(this.options.metrics) || undefined
var docker = isTrue(this.options.docker) || undefined
var openapi = isTrue(this.options.openapi) || undefined
var usecase = isTrue(this.options.enableUsecase) || undefined
var starterOptions = this.options.starterOptions || undefined
var healthcheck = (typeof this.options.healthcheck === 'undefined') ? true : isTrue(this.options.healthcheck)
var web = (this.appType === 'web' || this.appType === 'bff' || undefined)
var hostSwagger = (this.appType === 'bff' || undefined)
var exampleEndpoints = (this.appType === 'bff' || undefined)
var swaggerUI = (this.appType === 'bff' || undefined)
this.spec = {
appName: appName,
appType: 'scaffold',
appDir: '.',
docker: docker,
web: web,
openapi: openapi,
hostSwagger: hostSwagger,
exampleEndpoints: exampleEndpoints,
swaggerUI: swaggerUI,
bluemix: this.options.bluemix,
metrics: metrics,
repoType: 'clone',
healthcheck: healthcheck,
usecase: usecase,
starterOptions: starterOptions,
deploymentOrg: this.options.deploymentOrg,
deploymentSpace: this.options.deploymentSpace,
deploymentRegion: this.options.deploymentRegion,
toolchainName: this.options.toolchainName
}
} else if (this.options.init) {
// User passed the --init flag, so no prompts, just generate basic default scaffold
this.destinationSet = true
if (this.appname !== path.basename(this.destinationRoot())) {
this.destinationRoot(path.resolve(this.appname))
}
this.skipPrompting = true
this.appPattern = 'Basic'
this.spec = {
appType: 'scaffold',
appName: this.appname,
docker: true,
metrics: true,
bluemix: {}
}
} else if (this.options.spec) {
try {
this.spec = JSON.parse(this.options.spec)
this.skipPrompting = true
} catch (err) {
this.env.error(chalk.red(err))
}
}
},
initForPrompting: function () {
if (this.skipPrompting) return
// initialize for prompting
this.bluemix = { server: {} }
}
},
_addService: function (serviceType, serviceName) {
this.services = this.services || {}
var service = {
serviceInfo: {
label: helpers.getBluemixServiceLabel(serviceType),
name: serviceName,
plan: helpers.getBluemixDefaultPlan(serviceType)
}
}
if (helpers.isThisServiceAnArray(serviceType)) service = [service]
this.services[serviceType] = service
},
prompting: {
promptAppName: function () {
if (this.skipPrompting) return
this.log(chalk.magenta('Initialization prompts'))
if (this.skipPromptingAppName) { return }
var prompts = [
{
name: 'name',
message: 'What\'s the name of your application?',
default: this.appname,
validate: validateAppName
}
]
return this.prompt(prompts).then((props) => {
this.appname = props.name
})
},
/*
* Configure the destination directory, asking the user if required.
* Set up the generator environment so that destinationRoot is set
* to point to the directory where we want to generate code.
*/
promptAppDir: function () {
if (this.skipPrompting) return
if (this.appname === path.basename(this.destinationRoot())) {
// When the project name is the same as the current directory,
// we are assuming the user has already created the project dir
this.destinationSet = true
return
}
var prompts = [
{
name: 'dir',
message: 'Enter the name of the directory to contain the project:',
default: this.appname,
validate: validateDirName
}
]
return this.prompt(prompts).then((answers) => {
if (answers.dir !== '.') {
this.destinationSet = true
this.destinationRoot(path.resolve(answers.dir))
}
})
},
ensureEmptyDirectory: function () {
if (this.skipPrompting) return
actions.ensureEmptyDirectory.call(this)
},
promptAppType: function () {
if (this.skipPrompting) return
var prompts = [{
name: 'appType',
type: 'list',
message: 'Select type of project:',
choices: [ 'Scaffold a starter', 'Generate a CRUD application' ],
default: 'Scaffold a starter'
}]
return this.prompt(prompts).then((answers) => {
switch (answers.appType) {
case 'Scaffold a starter': this.appType = 'scaffold'; break
case 'Generate a CRUD application': this.appType = 'crud'; break
default:
this.env.error(chalk.red(`Internal error: unknown application type ${answers.appType}`))
}
})
},
/*
* Determine the application pattern so that the capability
* defaults can be set appropriately.
*/
promptApplicationPattern: function () {
if (this.skipPrompting) return
if (this.appType !== 'scaffold') return
var prompts = [{
name: 'appPattern',
type: 'list',
message: 'Select capability presets for application pattern:',
choices: [ 'Basic', 'Web' ],
default: 'Basic'
}]
return this.prompt(prompts).then((answers) => {
switch (answers.appPattern) {
case 'Basic': this.appPattern = 'Basic'; break
case 'Web': this.appPattern = 'Web'; break
default:
this.env.error(chalk.red(`Internal error: unknown application pattern ${answers.appPattern}`))
}
})
},
promptCapabilities: function () {
if (this.skipPrompting) return
var self = this
function displayName (property) {
switch (property) {
case 'web': return 'Static web file serving'
case 'swaggerUI': return 'Swagger UI'
case 'metrics': return 'Embedded metrics dashboard'
case 'docker': return 'Docker files'
case 'openapi': return 'Kitura OpenAPI'
default:
self.env.error(chalk.red(`Internal error: unknown property ${property}`))
}
}
function defaultCapabilities (appPattern) {
switch (appPattern) {
case 'Basic': return [
'Docker files',
'Embedded metrics dashboard'
]
case 'Web': return [
'Static web file serving',
'Embedded metrics dashboard',
'Docker files'
]
default:
self.env.error(chalk.red(`Internal error: unknown application pattern ${appPattern}`))
}
}
var choices = ['metrics', 'docker', 'openapi']
var defaults = choices.map(displayName)
if (this.appType === 'scaffold') {
choices.unshift('swaggerUI')
choices.unshift('web')
defaults = defaultCapabilities(this.appPattern)
}
var prompts = [{
name: 'capabilities',
type: 'checkbox',
message: 'Select capabilities:',
choices: choices.map(displayName),
default: defaults
}]
return this.prompt(prompts).then((answers) => {
choices.forEach((choice) => {
this[choice] = (answers.capabilities.indexOf(displayName(choice)) !== -1)
})
})
},
promptServicesForScaffold: function () {
if (this.skipPrompting) return
if (this.appType !== 'scaffold') return
var choices = [
'Cloudant / CouchDB',
'Redis',
'MongoDB',
'PostgreSQL',
'ElephantSQL',
'AppID',
'Auto-scaling',
'Watson Assistant, formerly Conversation',
'Alert Notification',
'Push Notifications'
]
var prompts = [{
name: 'services',
type: 'checkbox',
message: 'Generate boilerplate for services:',
choices: choices,
default: []
}]
return this.prompt(prompts).then((answers) => {
if (answers.services.indexOf('Cloudant / CouchDB') !== -1) {
this._addService('cloudant', generateServiceName(this.appname, 'Cloudant'))
}
if (answers.services.indexOf('Redis') !== -1) {
this._addService('redis', generateServiceName(this.appname, 'Redis'))
}
if (answers.services.indexOf('MongoDB') !== -1) {
this._addService('mongodb', generateServiceName(this.appname, 'MongoDB'))
}
if (answers.services.indexOf('PostgreSQL') !== -1) {
this._addService('postgresql', generateServiceName(this.appname, 'PostgreSQL'))
}
if (answers.services.indexOf('ElephantSQL') !== -1) {
this._addService('elephantsql', generateServiceName(this.appname, 'ElephantSQL'))
}
if (answers.services.indexOf('AppID') !== -1) {
this._addService('appid', generateServiceName(this.appname, 'AppID'))
}
if (answers.services.indexOf('Watson Assistant, formerly Conversation') !== -1) {
this._addService('conversation', generateServiceName(this.appname, 'WatsonAssistant'))
}
if (answers.services.indexOf('Alert Notification') !== -1) {
this._addService('alertNotification', generateServiceName(this.appname, 'AlertNotification'))
}
if (answers.services.indexOf('Push Notifications') !== -1) {
this._addService('push', generateServiceName(this.appname, 'PushNotifications'))
}
if (answers.services.indexOf('Auto-scaling') !== -1) {
this._addService('autoscaling', generateServiceName(this.appname, 'AutoScaling'))
}
})
},
/*
* Configure the data store, asking the user what type of data store they
* are using and configuring the data store if needed. These answers will
* be the basis for the config.json.
*/
promptDataStoreForCRUD: function () {
if (this.skipPrompting) return
if (this.appType !== 'crud') return
var prompts = [
{
name: 'store',
message: 'Select data store:',
type: 'list',
choices: ['Memory (for development purposes)', 'Cloudant / CouchDB'],
filter: (store) => store.split(' ')[0]
}
]
return this.prompt(prompts).then((answer) => {
// NOTE(tunniclm): no need to do anything for memory it is the default
// if no crudservice is passed to the refresh generator
if (answer.store === 'Cloudant') {
this._addService('cloudant', 'crudDataStore')
this.crudservice = 'crudDataStore'
}
})
},
promptServicesForCRUD: function () {
if (this.skipPrompting) return
if (this.appType !== 'crud') return
var choices = ['Auto-scaling']
var prompts = [{
name: 'services',
type: 'checkbox',
message: 'Generate boilerplate for services:',
choices: choices,
default: []
}]
return this.prompt(prompts).then((answers) => {
if (answers.services.indexOf('Auto-scaling') !== -1) {
this._addService('autoscaling', generateServiceName(this.appname, 'AutoScaling'))
}
})
},
// NOTE(tunniclm): This part of the prompting assumes there can only
// be one of each type of service.
promptConfigureServices: function () {
if (this.skipPrompting) return
if (!this.services) return
if (Object.keys(this.services).length === 0) return
var self = this
function serviceDisplayType (serviceType) {
switch (serviceType) {
case 'cloudant': return 'Cloudant / CouchDB'
case 'redis': return 'Redis'
case 'mongodb': return 'MongoDB'
case 'postgresql': return 'PostgreSQL'
case 'elephantsql': return 'ElephantSQL'
case 'appid': return 'AppID'
case 'autoscaling': return 'Auto-scaling'
case 'conversation': return 'Watson Assistant'
case 'alertNotification': return 'Alert Notification'
case 'push': return 'Push Notifications'
default:
self.env.error(chalk.red(`Internal error: unknown service type ${serviceType}`))
}
}
var choices = Object.keys(this.services)
var prompts = [{
name: 'configure',
type: 'checkbox',
message: 'Configure service credentials (leave unchecked for defaults):',
choices: choices.map(serviceDisplayType),
default: []
}]
return this.prompt(prompts).then((answers) => {
this.servicesToConfigure = {}
choices.forEach((serviceType) => {
this.servicesToConfigure[serviceType] =
(answers.configure.indexOf(serviceDisplayType(serviceType)) !== -1)
})
})
},
promptConfigureCloudant: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.cloudant) return
this.log()
this.log('Configure Cloudant / CouchDB')
var prompts = [
{ name: 'cloudantName',
message: 'Enter name (blank for default):',
when: (answers) => this.appType !== 'crud'
},
{ name: 'cloudantHost', message: 'Enter host name (blank for localhost):' },
{
name: 'cloudantPort',
message: 'Enter port (blank for default):',
validate: (port) => validatePort(port),
filter: (port) => (port ? parseInt(port) : port)
},
{
name: 'cloudantSecured',
message: 'Secure (https)?',
type: 'confirm',
default: false
},
{ name: 'cloudantUsername', message: 'Enter username (blank for none):' },
{
name: 'cloudantPassword',
message: 'Enter password:',
type: 'password',
when: (answers) => answers.cloudantUsername,
validate: (password) => validateCredential(password)
}
]
return this.prompt(prompts).then((answers) => {
var cloudantService = this.services.cloudant[0]
this.services.cloudant[0] = {
host: answers.cloudantHost || undefined,
port: answers.cloudantPort || undefined,
secured: answers.cloudantSecured || undefined,
username: answers.cloudantUsername || undefined,
password: answers.cloudantPassword || undefined,
serviceInfo: {
label: cloudantService.serviceInfo.label,
name: answers.cloudantName || cloudantService.serviceInfo.name,
plan: cloudantService.serviceInfo.plan
}
}
})
},
promptConfigureRedis: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.redis) return
this.log()
this.log('Configure Redis')
var prompts = [
{ name: 'redisName',
message: 'Enter name (blank for default):'
},
{ name: 'redisHost', message: 'Enter host name:' },
{
name: 'redisPort',
message: 'Enter port:',
validate: (port) => validatePort(port),
filter: (port) => (port ? parseInt(port) : port)
},
{ name: 'redisPassword', message: 'Enter password:', type: 'password' }
]
return this.prompt(prompts).then((answers) => {
var redisService = this.services.redis
this.services.redis = {
host: answers.redisHost || undefined,
port: answers.redisPort || undefined,
password: answers.redisPassword || undefined,
serviceInfo: {
label: redisService.serviceInfo.label,
name: answers.redisName || redisService.serviceInfo.name,
plan: redisService.serviceInfo.plan
}
}
})
},
promptConfigureMongoDB: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.mongodb) return
this.log()
this.log('Configure MongoDB')
var prompts = [
{ name: 'mongodbName',
message: 'Enter name (blank for default):'
},
{ name: 'mongodbHost', message: 'Enter host name:' },
{
name: 'mongodbPort',
message: 'Enter port:',
validate: (port) => validatePort(port),
filter: (port) => (port ? parseInt(port) : port)
},
{ name: 'mongodbPassword', message: 'Enter password:', type: 'password' },
{ name: 'mongodbDatabase', message: 'Enter database name:' }
]
return this.prompt(prompts).then((answers) => {
var mongoService = this.services.mongodb
this.services.mongodb = {
host: answers.mongodbHost || undefined,
port: answers.mongodbPort || undefined,
password: answers.mongodbPassword || undefined,
database: answers.mongodbDatabase || undefined,
serviceInfo: {
label: mongoService.serviceInfo.label,
name: answers.mongodbName || mongoService.serviceInfo.name,
plan: mongoService.serviceInfo.plan
}
}
})
},
promptConfigurePostgreSQL: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.postgresql) return
this.log()
this.log('Configure PostgreSQL')
var prompts = [
{ name: 'postgresqlName',
message: 'Enter name (blank for default):'
},
{ name: 'postgresqlHost', message: 'Enter host name:' },
{
name: 'postgresqlPort',
message: 'Enter port:',
validate: (port) => validatePort(port),
filter: (port) => (port ? parseInt(port) : port)
},
{ name: 'postgresqlUsername', message: 'Enter username:' },
{ name: 'postgresqlPassword', message: 'Enter password:', type: 'password' },
{ name: 'postgresqlDatabase', message: 'Enter database name:' }
]
return this.prompt(prompts).then((answers) => {
var postgreService = this.services.postgresql
this.services.postgresql = {
host: answers.postgresqlHost || undefined,
port: answers.postgresqlPort || undefined,
username: answers.postgresqlUsername || undefined,
password: answers.postgresqlPassword || undefined,
database: answers.postgresqlDatabase || undefined,
serviceInfo: {
label: postgreService.serviceInfo.label,
name: answers.postgresqlName || postgreService.serviceInfo.name,
plan: postgreService.serviceInfo.plan
}
}
})
},
promptConfigureElephantSQL: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.elephantsql) return
this.log()
this.log('Configure ElephantSQL')
var prompts = [
{ name: 'elephantsqlName',
message: 'Enter name (blank for default):'
},
{ name: 'elephantsqlHost', message: 'Enter host name:' },
{
name: 'elephantsqlPort',
message: 'Enter port:',
validate: (port) => validatePort(port),
filter: (port) => (port ? parseInt(port) : port)
},
{ name: 'elephantsqlUsername', message: 'Enter username:' },
{ name: 'elephantsqlPassword', message: 'Enter password:', type: 'password' },
{ name: 'elephantsqlDatabase', message: 'Enter database name:' }
]
return this.prompt(prompts).then((answers) => {
var elephantsqlService = this.services.elephantsql
this.services.elephantsql = {
host: answers.elephantsqlHost || undefined,
port: answers.elephantsqlPort || undefined,
username: answers.elephantsqlUsername || undefined,
password: answers.elephantsqlPassword || undefined,
database: answers.elephantsqlDatabase || undefined,
serviceInfo: {
label: elephantsqlService.serviceInfo.label,
name: answers.elephantsqlName || elephantsqlService.serviceInfo.name,
plan: elephantsqlService.serviceInfo.plan
}
}
})
},
promptConfigureAutoscaling: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.autoscaling) return
this.log()
this.log('Configure Autoscaling')
var prompts = [
{ name: 'autoscalingName', message: 'Enter name (blank for default):' }
]
return this.prompt(prompts).then((answers) => {
this.services.autoscaling.serviceInfo.name = answers.autoscalingName || this.services.autoscaling.serviceInfo.name
})
},
promptConfigureWatsonAssistant: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.conversation) return
this.log()
this.log('Configure Watson Assistant')
var prompts = [
{ name: 'watsonAssistantName', message: 'Enter name (blank for default):' },
{ name: 'watsonAssistantAPIKey', message: 'Enter API key (blank for none):' },
{ name: 'watsonAssistantUrl', message: 'Enter url (blank for default):' }
]
return this.prompt(prompts).then((answers) => {
var watsonService = this.services.conversation
this.services.conversation = {
apikey: answers.watsonAssistantAPIKey || undefined,
url: answers.watsonAssistantUrl || undefined,
serviceInfo: {
label: watsonService.serviceInfo.label,
name: answers.watsonAssistantName || watsonService.serviceInfo.name,
plan: watsonService.serviceInfo.plan
}
}
})
},
promptConfigureAlertNotification: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.alertNotification) return
this.log()
this.log('Configure Alert Notification')
var prompts = [
{ name: 'alertNotificationName', message: 'Enter service name (blank for default):' },
{ name: 'alertNotificationUsername', message: 'Enter username (blank for none):' },
{ name: 'alertNotificationPassword', message: 'Enter password:', type: 'password' },
{ name: 'alertNotificationUrl', message: 'Enter url (blank for none):' }
]
return this.prompt(prompts).then((answers) => {
var alertNotificationService = this.services.alertNotification
this.services.alertNotification = {
name: answers.alertNotificationUsername || undefined,
password: answers.alertNotificationPassword || undefined,
url: answers.alertNotificationUrl || undefined,
serviceInfo: {
label: alertNotificationService.serviceInfo.label,
name: answers.alertNotificationName || alertNotificationService.serviceInfo.name,
plan: alertNotificationService.plan
}
}
})
},
promptConfigurePushNotifications: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.push) return
this.log()
this.log('Configure Push Notifications')
var prompts = [
{ name: 'pushNotificationsName', message: 'Enter service name (blank for default):' },
{ name: 'pushNotificationsAppGuid', message: 'Enter app GUID (blank for none):' },
{ name: 'pushNotificationsAPIKey', message: 'Enter API Key (blank for none):', type: 'password' },
{
name: 'pushNotificationsRegion',
type: 'list',
message: 'Enter Bluemix region:',
choices: [ 'US South', 'United Kingdom', 'Sydney' ],
default: 'US South'
}
]
return this.prompt(prompts).then((answers) => {
var pushService = this.services.push
this.services.push = {
appGuid: answers.pushNotificationsAppGuid || undefined,
apikey: answers.pushNotificationsAPIKey || undefined,
serviceInfo: {
label: pushService.serviceInfo.label,
name: answers.pushNotificationsName || pushService.serviceInfo.name,
plan: pushService.serviceInfo.plan
}
}
switch (answers.pushNotificationsRegion) {
case 'US South': this.services.push.url = 'https://imfpush.ng.bluemix.net'; break
case 'United Kingdom': this.services.push.url = 'https://imfpush.eu-gb.bluemix.net'; break
case 'Sydney': this.services.push.url = 'https://imfpush.au-syd.bluemix.net'; break
default:
this.env.error(chalk.red(`Internal error: unknown region ${answers.pushNotificationsRegion}`))
}
})
},
promptConfigureAppID: function () {
if (this.skipPrompting) return
if (!this.servicesToConfigure) return
if (!this.servicesToConfigure.appid) return
this.log()
this.log('Configure AppID')
var prompts = [
{ name: 'appidName', message: 'Enter name (blank for default):' },
{ name: 'appidTenantId', message: 'Enter tenant ID:' },
{ name: 'appidClientId', message: 'Enter client ID:' },
{ name: 'appidSecret', message: 'Enter secret:', type: 'password' }
]
return this.prompt(prompts).then((answers) => {
var appidService = this.services.appid
this.services.appid = {
tenantId: answers.appidTenantId || undefined,
clientId: answers.appidClientId || undefined,
secret: answers.appidSecret || undefined,
serviceInfo: {
label: appidService.serviceInfo.label,
name: answers.appidName || appidService.serviceInfo.name,
plan: appidService.serviceInfo.plan
}
}
})
}
},
createSpecFromAnswers: function () {
if (this.skipPrompting) return
// NOTE(tunniclm): This spec object may not exploit all possible functionality,
// some may only be available via non-prompting route.
if (this.services) {
this.bluemix.server.services = []
Object.keys(this.services).forEach(serviceType => {
var services = Array.isArray(this.services[serviceType]) ? this.services[serviceType] : [this.services[serviceType]]
services.forEach(service => {
this.bluemix.server.services.push(service.serviceInfo.name)
})
})
}
this.spec = {
appType: this.appType,
appName: this.appname,
docker: this.docker || undefined,
web: this.web || undefined,
openapi: this.openapi || undefined,
exampleEndpoints: this.exampleEndpoints || undefined,
fromSwagger: this.fromSwagger || undefined,
generateCodableRoutes: this.generateCodableRoutes || undefined,
serverSwaggerFiles: this.serverSwaggerFiles || undefined,
hostSwagger: this.hostSwagger || undefined,
swaggerUI: this.swaggerUI || undefined,
metrics: this.metrics || undefined,
crudservice: this.crudservice,
bluemix: Object.assign(this.bluemix, this.services) || {}
}
},
install: {
buildDefinitions: function () {
// this.composeWith() causes problems with testing using yeoman-test.
//
// When we composeWith() using the namespace:name format, then we
// have trouble with errors finding the composed generator when testing
// (it works usually when running while not testing.)
//
// So we resolve the generator to a real path to get around this, which
// works in both cases. However, this means the yeoman-test RunContext
// call withGenerators() no longer works to stub out dependent generators
// with dummies for unit testing.
//
// This problem is documented in https://github.com/yeoman/yeoman-test/issues/16
//
// To work around the problem, our unit tests will pass in an option 'testmode'
// and we will use the namespace:name form in that case.
var refreshGenerator = this.options.testmode ? 'swiftserver:refresh' : require.resolve('../refresh')
this.composeWith(refreshGenerator, {
// Pass in the option to refresh to decided whether or not we create the *-product.yml
apic: this.options.apic,
specObj: this.spec,
singleShot: this.options['single-shot'],
destinationSet: (this.destinationSet === true)
})
},
buildApp: function () {
if (this.skipBuild || this.options['skip-build']) return
var buildGenerator = this.options.testmode ? 'swiftserver:build' : require.resolve('../build')
this.composeWith(buildGenerator, {
// Pass in the option of doing single-shot so the appropriate checks are performed
singleShot: this.options['single-shot']
})
}
},
end: function () {
// Inform the user what they should do next
this.log('Next steps:')
this.log()
if (this.destinationRoot() && this.destinationRoot() !== '.') {
this.log(' Change directory to your app')
this.log(chalk.green(' $ cd ' + this.destinationRoot()))
this.log()
}
if (this.appType === 'crud') {
var createModelInstruction = ' $ yo swiftserver:model'
if (process.env.RUN_BY_COMMAND === 'swiftservergenerator') {
createModelInstruction = ' $ swiftservergenerator --model'
} else if (process.env.RUN_BY_COMMAND === 'apic') {
createModelInstruction = ' $ apic create --type model-swiftserver'
}
this.log(' Create a model in your app')
this.log(chalk.green(createModelInstruction))
this.log()
}
this.log(' Run your app')
this.log(chalk.green(' $ .build/debug/' + this.appname))
this.log()
}
})
module.exports._yeoman = Generator