Skip to content

Commit

Permalink
feat: upgrade command for installed binaries
Browse files Browse the repository at this point in the history
  • Loading branch information
medikoo committed Dec 18, 2019
1 parent f0f9698 commit c4efd66
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 2 deletions.
19 changes: 17 additions & 2 deletions lib/Serverless.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const path = require('path');
const BbPromise = require('bluebird');
const os = require('os');
const chalk = require('chalk');
const updateNotifier = require('update-notifier');
const minimist = require('minimist');
const pkg = require('../package.json');
Expand All @@ -17,6 +18,8 @@ const ServerlessError = require('./classes/Error').ServerlessError;
const Version = require('./../package.json').version;
const isStandaloneExecutable = require('./utils/isStandaloneExecutable');

const installationMaintananceCommands = new Set(['upgrade']);

class Serverless {
constructor(config) {
let configObject = config;
Expand Down Expand Up @@ -70,8 +73,20 @@ class Serverless {
this.pluginManager.setCliOptions(this.processedInput.options);
this.pluginManager.setCliCommands(this.processedInput.commands);

// Check if update is available
updateNotifier({ pkg }).notify();
if (!installationMaintananceCommands.has(this.processedInput.commands[0])) {
// Check if update is available
const notifier = updateNotifier({ pkg });
notifier.notify({
message:
isStandaloneExecutable && notifier.update
? `Update available ${chalk().dim(notifier.update.current)}${chalk().reset(
' → '
)}${chalk().green(notifier.update.latest)} \nRun ${chalk().cyan(
'serverless upgrade'
)} to update`
: null,
});
}

return this.service.load(this.processedInput.options);
})
Expand Down
98 changes: 98 additions & 0 deletions lib/plugins/executable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
'use strict';

const BbPromise = require('bluebird');
const fs = require('fs');
const os = require('os');
const streamPromise = require('stream-promise');
const fse = BbPromise.promisifyAll(require('fs-extra'));
const isStandaloneExecutable =
require('../../utils/isStandaloneExecutable') && process.platform !== 'win32';
const currentVersion = require('../../../package').version;
const fetch = require('node-fetch');

const BINARIES_DIR_PATH = `${os.homedir()}/.serverless/bin`;
const BINARY_TMP_PATH = `${BINARIES_DIR_PATH}/serverless-tmp`;
const BINARY_PATH = `${BINARIES_DIR_PATH}/serverless`;

module.exports = class Executable {
constructor(serverless) {
this.serverless = serverless;

this.commands = {
upgrade: {
isHidden: !isStandaloneExecutable,
usage: 'Upgrade Serverless',
lifecycleEvents: ['upgrade'],
},
};

this.hooks = {
'upgrade:upgrade': () => {
return isStandaloneExecutable ? this.upgrade() : this.rejectCommand('upgrade');
},
};
}

upgrade() {
return fetch('https://api.github.com/repos/serverless/serverless/releases/latest')
.then(response => {
if (!response.ok) {
throw new this.serverless.classes.Error(
'Sorry unable to `upgrade` at this point ' +
`(server rejected request with ${response.status})`
);
}
return response.json();
})
.then(({ tag_name: tagName }) => {
const latestVersion = tagName.slice(1);
if (latestVersion === currentVersion) {
this.serverless.cli.log('Already at latest version');
return null;
}
const platform = (() => {
switch (process.platform) {
case 'darwin':
return 'macos';
default:
return process.platform;
}
})();
const arch = (() => {
switch (process.arch) {
case 'x32':
return 'x86';
case 'arm':
case 'arm64':
return 'armv6';
default:
return process.arch;
}
})();
this.serverless.cli.log('Downloading new version...');
return fetch(
`https://github.com/serverless/serverless/releases/download/${tagName}/` +
`serverless-${platform}-${arch}`
)
.then(response => {
if (!response.ok) {
throw new this.serverless.classes.Error(
'Sorry unable to `upgrade` at this point ' +
`(server rejected request with ${response.status})`
);
}
return streamPromise(response.body.pipe(fs.createWriteStream(BINARY_TMP_PATH)))
.then(() => fse.renameAsync(BINARY_TMP_PATH, BINARY_PATH))
.then(() => fse.chmodAsync(BINARY_PATH, 0o755));
})
.then(() => this.serverless.cli.log(`Successfully upgraded to ${tagName}`));
});
}

rejectCommand(command) {
throw new this.serverless.classes.Error(
`\`${command}\` command is supported only in context of a standalone exacutable instance ` +
'in non Windows enviroment.'
);
}
};
1 change: 1 addition & 0 deletions lib/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ module.exports = [
require('./aws/deployFunction/index.js'),
require('./aws/deployList/index.js'),
require('./aws/invokeLocal/index.js'),
require('./executable'),
];
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
"replaceall": "^0.1.6",
"semver": "^5.7.1",
"semver-regex": "^1.0.0",
"stream-promise": "^3.2.0",
"tabtab": "^3.0.2",
"untildify": "^3.0.3",
"update-notifier": "^2.5.0",
Expand Down

0 comments on commit c4efd66

Please sign in to comment.