UNPKG

@serverless-rewrite/serverless

Version:

Serverless Framework - Build web, mobile and IoT applications with serverless architectures using AWS Lambda, Azure Functions, Google CloudFunctions & more

112 lines (102 loc) 3.97 kB
'use strict'; const fs = require('fs'); const fsp = require('fs').promises; const os = require('os'); const path = require('path'); const stream = require('stream'); const { promisify } = require('util'); const fse = require('fs-extra'); const fetch = require('node-fetch'); const { legacy, log, progress, style } = require('@serverless-rewrite/utils/log'); const currentVersion = require('../../package').version; const ServerlessError = require('../serverless-error'); const standaloneUtils = require('../utils/standalone'); const cliCommandsSchema = require('../cli/commands-schema'); const pipeline = promisify(stream.pipeline); const BINARY_TMP_PATH = path.resolve(os.tmpdir(), 'serverless-binary-tmp'); const BINARY_PATH = standaloneUtils.path; const mainProgress = progress.get('main'); module.exports = class Standalone { constructor(serverless, cliOptions) { this.serverless = serverless; this.cliOptions = cliOptions; this.commands = { upgrade: { ...cliCommandsSchema.get('upgrade'), }, uninstall: { ...cliCommandsSchema.get('uninstall'), }, }; this.hooks = { 'upgrade:upgrade': async () => this.upgrade(), 'uninstall:uninstall': async () => this.uninstall(), }; } async upgrade() { mainProgress.notice('Resolving latest standalone version', { isMainEvent: true }); const tagName = await standaloneUtils.resolveLatestTag(); const latestVersion = tagName.slice(1); if (latestVersion === currentVersion) { legacy.log('Already at latest version'); log.notice(); log.notice.skip( `Already at latest version ${style.aside( `(${Math.floor( (Date.now() - this.serverless.pluginManager.commandRunStartTime) / 1000 )}s)` )}` ); return; } const currentMajor = Number(currentVersion.split('.')[0]); const latestMajor = Number(latestVersion.split('.')[0]); if (latestMajor > currentMajor && !this.cliOptions.major) { throw new ServerlessError( [ 'Cannot upgrade to a new major release without introducing a breaking changes', '', 'If you\'ve confirmed it\'s safe and want to upgrade, run "sls upgrade --major"', '', 'Note: Service is safe to upgrade if no deprecations are logged during its deployment.', ` Check https://github.com/serverless/serverless/releases/tag/v${latestMajor}.0.0 ` + 'for list of all breaking changes', ].join('\n'), 'CANNOT_UPGRADE_MAJOR' ); } legacy.log('Downloading new version...'); mainProgress.notice('Downloading latest standalone version', { isMainEvent: true }); const executableUrl = standaloneUtils.resolveUrl(tagName); const standaloneResponse = await fetch(executableUrl); if (!standaloneResponse.ok) { throw new ServerlessError( 'Sorry unable to `upgrade` at this point ' + `(server rejected request with ${standaloneResponse.status})`, 'UPGRADE_ERROR' ); } await fse.remove(BINARY_TMP_PATH); await pipeline(standaloneResponse.body, fs.createWriteStream(BINARY_TMP_PATH)); await fsp.rename(BINARY_TMP_PATH, BINARY_PATH); await fsp.chmod(BINARY_PATH, 0o755); legacy.log(`Successfully upgraded to ${tagName}`); log.notice(); log.notice.success( `Successfully upgraded to ${tagName} ${style.aside( `(${Math.floor((Date.now() - this.serverless.pluginManager.commandRunStartTime) / 1000)}s)` )}` ); } async uninstall() { mainProgress.notice('Uninstalling standalone binary', { isMainEvent: true }); await fse.remove(path.dirname(BINARY_PATH)); legacy.log('Uninstalled'); log.notice(); log.notice.success( `Standalone binary uninstalled ${style.aside( `(${Math.floor((Date.now() - this.serverless.pluginManager.commandRunStartTime) / 1000)}s)` )}` ); } };