diff --git a/packages/graphql/mixin.core.js b/packages/graphql/mixin.core.js index 92f0f43c8..b9a3adc6f 100644 --- a/packages/graphql/mixin.core.js +++ b/packages/graphql/mixin.core.js @@ -1,3 +1,4 @@ +const { existsSync } = require('fs'); const { Mixin } = require('hops-mixin'); const strip = require('strip-indent'); const { @@ -109,6 +110,17 @@ class GraphQLMixin extends Mixin { ); } } + + diagnose() { + if (!existsSync(this.config.fragmentsFile)) { + return [ + `Could not find a graphql introspection query result at "${ + this.config.fragmentsFile + }".`, + 'You might need to execute "hops graphql introspect"', + ]; + } + } } module.exports = GraphQLMixin; diff --git a/packages/graphql/mixin.server.js b/packages/graphql/mixin.server.js index 39d774681..eafe16205 100644 --- a/packages/graphql/mixin.server.js +++ b/packages/graphql/mixin.server.js @@ -18,7 +18,6 @@ const { const fetch = require('cross-fetch'); let introspectionResult = undefined; -let warned = false; class GraphQLMixin extends Mixin { constructor(config, element, { graphql: options = {} } = {}) { @@ -31,13 +30,6 @@ class GraphQLMixin extends Mixin { if (existsSync(config.fragmentsFile)) { const fileContent = readFileSync(config.fragmentsFile, 'utf-8'); introspectionResult = JSON.parse(fileContent); - } else if (!warned) { - warned = true; - console.warn( - 'Could not find a graphql introspection query result at %s.', - config.fragmentsFile, - 'You might need to execute `hops graphql introspect`' - ); } } catch (_) { introspectionResult = null; diff --git a/packages/lambda/lib/aws-config.js b/packages/lambda/lib/aws-config.js index 6ca071709..579c4889a 100644 --- a/packages/lambda/lib/aws-config.js +++ b/packages/lambda/lib/aws-config.js @@ -1,10 +1,7 @@ 'use strict'; -const semver = require('semver'); const { trimSlashes } = require('pathifist'); -const MAX_NODE_VERSION = '8.10'; - module.exports = function getAWSConfig(hopsConfig) { const awsConfig = hopsConfig._aws || hopsConfig.aws || {}; @@ -27,48 +24,5 @@ module.exports = function getAWSConfig(hopsConfig) { exclude: [...(awsConfig.exclude || [])], }; - const targetNodeVersion = - !hopsConfig.node || hopsConfig.node === 'current' - ? process.version - : hopsConfig.node; - - if ( - semver.gt(semver.coerce(targetNodeVersion), semver.coerce(MAX_NODE_VERSION)) - ) { - console.warn( - 'AWS Lambda only supports Node.js up to version:', - MAX_NODE_VERSION - ); - console.warn( - 'Please specify or use a Node.js version lower than or equal to this', - 'version in your Hops config (hops.node) to tell Babel for which version', - 'it should transpile for.' - ); - } - - if ( - !config.domainName && - config.basePath.indexOf(config.stageName) !== 0 && - trimSlashes(hopsConfig.assetPath).indexOf(config.stageName) !== 0 - ) { - console.warn( - 'When no custom domain is configured, the stageName (' + - config.stageName + - ') should be the first path segment in basePath (' + - config.basePath + - ') and assetPath (' + - hopsConfig.assetPath + - ').' - ); - } - - if (config.domainName && !config.certificateArn) { - console.error( - 'Setting a custom domain name also requires to specify the ACM', - 'certificate ARN.' - ); - process.exit(1); - } - return config; }; diff --git a/packages/lambda/lib/deploy.js b/packages/lambda/lib/deploy.js index 7b737a498..9d351d5de 100755 --- a/packages/lambda/lib/deploy.js +++ b/packages/lambda/lib/deploy.js @@ -3,7 +3,6 @@ var fs = require('fs'); var path = require('path'); var AWS = require('aws-sdk'); -var getAWSConfig = require('./aws-config'); var createLambdaBundle = require('./create-lambda-bundle'); var progressWriter = require('./progress-writer'); var fsUtils = require('./fs-utils'); @@ -140,14 +139,19 @@ function createOrUpdateStack(cloudformation, stackName, templateUrl, params) { }); } -module.exports = function deploy(config, options, parametersOverrides) { - var awsConfig = getAWSConfig(config); - - if (!fs.existsSync(config.buildDir)) { - console.error( - 'Could not find build directory. Please make sure that you ' + - 'have executed "hops build" before trying to deploy your application.' - ); +module.exports = function deploy( + { hopsConfig, awsConfig }, + options, + parametersOverrides, + logger +) { + if (!fs.existsSync(hopsConfig.buildDir)) { + if (logger) { + logger.error( + 'Could not find build directory. Please make sure that you ' + + 'have executed "hops build" before trying to deploy your application.' + ); + } return process.exit(1); } @@ -173,7 +177,7 @@ module.exports = function deploy(config, options, parametersOverrides) { return Promise.all([ createLambdaBundle( - config.rootDir, + hopsConfig.rootDir, zippedBundleLocation, awsConfig.include, awsConfig.exclude, diff --git a/packages/lambda/lib/destroy.js b/packages/lambda/lib/destroy.js index 67184dbc8..ce6a5861b 100644 --- a/packages/lambda/lib/destroy.js +++ b/packages/lambda/lib/destroy.js @@ -2,7 +2,6 @@ var AWS = require('aws-sdk'); var prompt = require('./prompt'); -var getAWSConfig = require('./aws-config'); function emptyBucket(s3, bucketName) { console.log('Deleting objects in S3 bucket'); @@ -57,9 +56,7 @@ function deleteStack(cloudFormation, stackName) { }); } -module.exports = function destroy(config, options) { - var awsConfig = getAWSConfig(config); - +module.exports = function destroy({ awsConfig }, options, logger) { AWS.config.update({ region: awsConfig.region }); AWS.config.apiVersions = { diff --git a/packages/lambda/mixin.core.js b/packages/lambda/mixin.core.js index cf0b73507..aad523cac 100644 --- a/packages/lambda/mixin.core.js +++ b/packages/lambda/mixin.core.js @@ -4,19 +4,35 @@ const { async: { callable: callableAsync }, }, } = require('hops-mixin'); +const { trimSlashes } = require('pathifist'); +const semver = require('semver'); const strip = require('strip-indent'); +const MAX_NODE_VERSION = '8.10'; +const getAWSConfig = require('./lib/aws-config'); + class LambdaMixin extends Mixin { + constructor(config, ...args) { + super(config, ...args); + + this.awsConfig = getAWSConfig(this.config); + } + deployLambda(parameterOverrides) { return require('./lib/deploy')( - this.config, + { hopsConfig: this.config, awsConfig: this.awsConfig }, this.options, - parameterOverrides + parameterOverrides, + typeof this.getLogger === 'function' ? this.getLogger() : null ); } destroyLambda() { - return require('./lib/destroy')(this.config, this.options); + return require('./lib/destroy')( + { hopsConfig: this.config, awsConfig: this.awsConfig }, + this.options, + typeof this.getLogger === 'function' ? this.getLogger() : null + ); } registerCommands(yargs) { @@ -69,6 +85,50 @@ class LambdaMixin extends Mixin { handleArguments(argv) { this.options = { ...this.options, ...argv }; } + + diagnose() { + const warnings = []; + const targetNodeVersion = + !this.config.node || this.config.node === 'current' + ? process.version + : this.config.node; + + if ( + semver.gt( + semver.coerce(targetNodeVersion), + semver.coerce(MAX_NODE_VERSION) + ) + ) { + warnings.push( + [ + `AWS Lambda only supports Node.js up to version: ${MAX_NODE_VERSION}.`, + 'Please specify or use a Node.js version lower than or equal to this', + 'version in your Hops config (hops.node) to tell Babel for which version', + 'it should transpile for.', + ].join('\n') + ); + } + + if ( + !this.awsConfig.domainName && + this.awsConfig.basePath.indexOf(this.awsConfig.stageName) !== 0 && + trimSlashes(this.config.assetPath).indexOf(this.awsConfig.stageName) !== 0 + ) { + warnings.push( + `When no custom domain is configured, the stageName (${ + this.awsConfig.stageName + }) should be the first path segment in basePath (${ + this.awsConfig.basePath + }) and assetPath (${this.config.assetPath}).` + ); + } + + if (this.awsConfig.domainName && !this.awsConfig.certificateArn) { + warnings.push( + 'Setting a custom domain name also requires to specify the ACM certificate ARN.' + ); + } + } } LambdaMixin.strategies = { diff --git a/packages/typescript/mixin.core.js b/packages/typescript/mixin.core.js index 0972a252b..8ddec3183 100644 --- a/packages/typescript/mixin.core.js +++ b/packages/typescript/mixin.core.js @@ -1,3 +1,5 @@ +const { existsSync } = require('fs'); +const { join } = require('path'); const { Mixin } = require('hops-mixin'); class TypescriptMixin extends Mixin { @@ -19,6 +21,20 @@ class TypescriptMixin extends Mixin { }); webpackConfig.resolve.extensions.push('.ts', '.tsx'); } + + diagnose() { + const tsConfigPath = join(this.config.rootDir, 'tsconfig.json'); + const exampleTsConfigPath = require.resolve( + 'hops-typescript/tsconfig.json' + ); + if (!existsSync(tsConfigPath)) { + return `No "tsconfig.json" file found in your project root directory ("${ + this.config.rootDir + }").\nAs a starting point you can copy our minimal example config file: "cp ${exampleTsConfigPath} ${ + this.config.rootDir + }/tsconfig.json"`; + } + } } module.exports = TypescriptMixin;