diff --git a/deploy/googleDeploy.js b/deploy/googleDeploy.js index 98360fa..f576bf1 100644 --- a/deploy/googleDeploy.js +++ b/deploy/googleDeploy.js @@ -1,6 +1,7 @@ 'use strict'; const BbPromise = require('bluebird'); +const path = require('path'); const validate = require('../shared/validate'); const utils = require('../shared/utils'); @@ -15,6 +16,11 @@ class GoogleDeploy { constructor(serverless, options) { this.serverless = serverless; this.options = options; + this.servicePath = this.serverless.config.servicePath || ''; + this.packagePath = + this.options.package || + this.serverless.service.package.path || + path.join(this.servicePath || '.', '.serverless'); this.provider = this.serverless.getProvider('google'); Object.assign( diff --git a/deploy/lib/uploadArtifacts.js b/deploy/lib/uploadArtifacts.js index c9773e4..aa69ed1 100644 --- a/deploy/lib/uploadArtifacts.js +++ b/deploy/lib/uploadArtifacts.js @@ -1,24 +1,62 @@ 'use strict'; const fs = require('fs'); +const _ = require('lodash'); +const BbPromise = require('bluebird'); +const path = require('path'); +const filesize = require('filesize'); module.exports = { uploadArtifacts() { this.serverless.cli.log('Uploading artifacts...'); - const params = { - bucket: this.serverless.service.provider.deploymentBucketName, - resource: { - name: this.serverless.service.package.artifactFilePath, - contentType: 'application/octet-stream', - }, - media: { - mimeType: 'application/octet-stream', - body: fs.createReadStream(this.serverless.service.package.artifact), - }, - }; - - return this.provider.request('storage', 'objects', 'insert', params).then(() => { + const functionNames = this.serverless.service.getAllFunctions(); + const artifactFilePaths = _.uniq( + _.map(functionNames, (name) => { + const functionArtifactFileName = `${name}.zip`; + const functionObject = this.serverless.service.getFunction(name); + functionObject.package = functionObject.package || {}; + const artifactFilePath = + functionObject.package.artifact || this.serverless.service.package.artifact; + + if ( + !artifactFilePath || + (this.serverless.service.artifact && !functionObject.package.artifact) + ) { + if (this.serverless.service.package.individually || functionObject.package.individually) { + const artifactFileName = functionArtifactFileName; + return path.join(this.packagePath, artifactFileName); + } + return path.join(this.packagePath, `${this.provider.serverless.service.service}.zip`); + } + + return artifactFilePath; + }) + ); + + return BbPromise.map(artifactFilePaths, (artifactFilePath) => { + const stats = fs.statSync(artifactFilePath); + const fileName = path.basename(artifactFilePath); + this.serverless.cli.log( + `Uploading service ${fileName} file to Google Cloud Storage (${filesize(stats.size)})...` + ); + + const params = { + bucket: this.serverless.service.provider.deploymentBucketName, + resource: { + name: `${this.serverless.service.package.artifactDirectoryName}/${path.basename( + artifactFilePath + )}`, + contentType: 'application/octet-stream', + }, + media: { + mimeType: 'application/octet-stream', + body: fs.createReadStream(artifactFilePath), + }, + }; + + return this.provider.request('storage', 'objects', 'insert', params); + }).then(() => { this.serverless.cli.log('Artifacts successfully uploaded...'); }); }, diff --git a/package.json b/package.json index cdbe374..d400c8e 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "async": "^2.6.3", "bluebird": "^3.7.2", "chalk": "^3.0.0", + "filesize": "^4.1.2", "fs-extra": "^8.1.0", "get-stdin": "^8.0.0", "googleapis": "^50.0.0", diff --git a/package/googlePackage.js b/package/googlePackage.js index 4ea2354..3836141 100644 --- a/package/googlePackage.js +++ b/package/googlePackage.js @@ -1,6 +1,7 @@ 'use strict'; const BbPromise = require('bluebird'); +const path = require('path'); const cleanupServerlessDir = require('./lib/cleanupServerlessDir'); const validate = require('../shared/validate'); @@ -17,6 +18,11 @@ class GooglePackage { constructor(serverless, options) { this.serverless = serverless; this.options = options; + this.servicePath = this.serverless.config.servicePath || ''; + this.packagePath = + this.options.package || + this.serverless.service.package.path || + path.join(this.servicePath || '.', '.serverless'); this.provider = this.serverless.getProvider('google'); this.serverless.configSchemaHandler.defineFunctionEvent('google', 'http', { type: 'string' }); this.serverless.configSchemaHandler.defineFunctionEvent('google', 'event', { diff --git a/package/lib/compileFunctions.js b/package/lib/compileFunctions.js index 535b55e..1c7f405 100644 --- a/package/lib/compileFunctions.js +++ b/package/lib/compileFunctions.js @@ -9,6 +9,81 @@ const BbPromise = require('bluebird'); const { validateEventsProperty } = require('../../shared/validate'); module.exports = { + compileFunction(functionName, projectName) { + const funcObject = this.serverless.service.getFunction(functionName); + + this.serverless.cli.log(`Compiling function "${functionName}"...`); + + validateHandlerProperty(funcObject, functionName); + validateEventsProperty(funcObject, functionName); + validateVpcConnectorProperty(funcObject, functionName); + + const funcTemplate = getFunctionTemplate( + funcObject, + projectName, + this.serverless.service.provider.region, + `gs://${this.serverless.service.provider.deploymentBucketName}/${this.serverless.service.package.artifactDirectoryName}/${functionName}.zip` + ); + + funcTemplate.properties.serviceAccountEmail = + _.get(funcObject, 'serviceAccountEmail') || + _.get(this, 'serverless.service.provider.serviceAccountEmail') || + null; + funcTemplate.properties.availableMemoryMb = + _.get(funcObject, 'memorySize') || + _.get(this, 'serverless.service.provider.memorySize') || + 256; + funcTemplate.properties.runtime = this.provider.getRuntime(funcObject); + funcTemplate.properties.timeout = + _.get(funcObject, 'timeout') || _.get(this, 'serverless.service.provider.timeout') || '60s'; + funcTemplate.properties.environmentVariables = + this.provider.getConfiguredEnvironment(funcObject); + + if (!funcTemplate.properties.serviceAccountEmail) { + delete funcTemplate.properties.serviceAccountEmail; + } + + if (funcObject.vpc) { + _.assign(funcTemplate.properties, { + vpcConnector: _.get(funcObject, 'vpc') || _.get(this, 'serverless.service.provider.vpc'), + }); + } + + if (funcObject.maxInstances) { + funcTemplate.properties.maxInstances = funcObject.maxInstances; + } + + if (!_.size(funcTemplate.properties.environmentVariables)) { + delete funcTemplate.properties.environmentVariables; + } + + funcTemplate.properties.labels = _.assign( + {}, + _.get(this, 'serverless.service.provider.labels') || {}, + _.get(funcObject, 'labels') || {} // eslint-disable-line comma-dangle + ); + + const eventType = Object.keys(funcObject.events[0])[0]; + + if (eventType === 'http') { + const url = funcObject.events[0].http; + + funcTemplate.properties.httpsTrigger = {}; + funcTemplate.properties.httpsTrigger.url = url; + } + if (eventType === 'event') { + const type = funcObject.events[0].event.eventType; + const path = funcObject.events[0].event.path; //eslint-disable-line + const resource = funcObject.events[0].event.resource; + + funcTemplate.properties.eventTrigger = {}; + funcTemplate.properties.eventTrigger.eventType = type; + if (path) funcTemplate.properties.eventTrigger.path = path; + funcTemplate.properties.eventTrigger.resource = resource; + } + + this.serverless.service.provider.compiledConfigurationTemplate.resources.push(funcTemplate); + }, compileFunctions() { const artifactFilePath = this.serverless.service.package.artifact; const fileName = artifactFilePath.split(path.sep).pop(); @@ -17,83 +92,10 @@ module.exports = { this.serverless.service.provider.region || 'us-central1'; this.serverless.service.package.artifactFilePath = `${this.serverless.service.package.artifactDirectoryName}/${fileName}`; - this.serverless.service.getAllFunctions().forEach((functionName) => { - const funcObject = this.serverless.service.getFunction(functionName); - - this.serverless.cli.log(`Compiling function "${functionName}"...`); - - validateHandlerProperty(funcObject, functionName); - validateEventsProperty(funcObject, functionName); - validateVpcConnectorProperty(funcObject, functionName); - - const funcTemplate = getFunctionTemplate( - funcObject, - projectName, - this.serverless.service.provider.region, - `gs://${this.serverless.service.provider.deploymentBucketName}/${this.serverless.service.package.artifactFilePath}` - ); - - funcTemplate.properties.serviceAccountEmail = - _.get(funcObject, 'serviceAccountEmail') || - _.get(this, 'serverless.service.provider.serviceAccountEmail') || - null; - funcTemplate.properties.availableMemoryMb = - _.get(funcObject, 'memorySize') || - _.get(this, 'serverless.service.provider.memorySize') || - 256; - funcTemplate.properties.runtime = this.provider.getRuntime(funcObject); - funcTemplate.properties.timeout = - _.get(funcObject, 'timeout') || _.get(this, 'serverless.service.provider.timeout') || '60s'; - funcTemplate.properties.environmentVariables = - this.provider.getConfiguredEnvironment(funcObject); - - if (!funcTemplate.properties.serviceAccountEmail) { - delete funcTemplate.properties.serviceAccountEmail; - } - - if (funcObject.vpc) { - _.assign(funcTemplate.properties, { - vpcConnector: _.get(funcObject, 'vpc') || _.get(this, 'serverless.service.provider.vpc'), - }); - } - - if (funcObject.maxInstances) { - funcTemplate.properties.maxInstances = funcObject.maxInstances; - } - - if (!_.size(funcTemplate.properties.environmentVariables)) { - delete funcTemplate.properties.environmentVariables; - } - - funcTemplate.properties.labels = _.assign( - {}, - _.get(this, 'serverless.service.provider.labels') || {}, - _.get(funcObject, 'labels') || {} // eslint-disable-line comma-dangle - ); - - const eventType = Object.keys(funcObject.events[0])[0]; - - if (eventType === 'http') { - const url = funcObject.events[0].http; - - funcTemplate.properties.httpsTrigger = {}; - funcTemplate.properties.httpsTrigger.url = url; - } - if (eventType === 'event') { - const type = funcObject.events[0].event.eventType; - const path = funcObject.events[0].event.path; //eslint-disable-line - const resource = funcObject.events[0].event.resource; - - funcTemplate.properties.eventTrigger = {}; - funcTemplate.properties.eventTrigger.eventType = type; - if (path) funcTemplate.properties.eventTrigger.path = path; - funcTemplate.properties.eventTrigger.resource = resource; - } - - this.serverless.service.provider.compiledConfigurationTemplate.resources.push(funcTemplate); - }); - - return BbPromise.resolve(); + const allFunctions = this.serverless.service.getAllFunctions(); + return BbPromise.each(allFunctions, (functionName) => + this.compileFunction(functionName, projectName) + ); }, };