diff --git a/docs/guides/deprecations.md b/docs/guides/deprecations.md
index 587b269b5..70cf8a59d 100644
--- a/docs/guides/deprecations.md
+++ b/docs/guides/deprecations.md
@@ -44,6 +44,24 @@ The standalone `sls upgrade` command no longer updates osls and is scheduled for
npm install -g osls@latest
```
+
+
+## Command `sls uninstall`
+
+Deprecation code: `STANDALONE_UNINSTALL_COMMAND_DEPRECATED`
+
+Removal target: osls v4.0.0
+
+The top-level standalone `sls uninstall` command is deprecated and scheduled for removal in osls v4.0.0. It only removes the legacy standalone binary directory and does not uninstall npm-installed osls.
+
+Use your package manager to uninstall npm-installed osls instead:
+
+```sh
+npm uninstall -g osls
+```
+
+This does not affect `serverless plugin uninstall`.
+
## Property `console`
diff --git a/lib/cli/commands-schema/no-service.js b/lib/cli/commands-schema/no-service.js
index 45b75999e..525a88783 100644
--- a/lib/cli/commands-schema/no-service.js
+++ b/lib/cli/commands-schema/no-service.js
@@ -155,7 +155,7 @@ commands.set('plugin search', {
lifecycleEvents: ['upgrade'],
});
commands.set('uninstall', {
- usage: 'Uninstall osls',
+ usage: 'Deprecated: uninstall standalone osls binary',
isHidden,
noSupportNotice,
lifecycleEvents: ['uninstall'],
diff --git a/lib/plugins/standalone.js b/lib/plugins/standalone.js
index bb9debd19..ca08eaff1 100644
--- a/lib/plugins/standalone.js
+++ b/lib/plugins/standalone.js
@@ -6,6 +6,7 @@ const ServerlessError = require('../serverless-error');
const standaloneUtils = require('../utils/standalone');
const { remove } = require('../utils/fs/remove');
const cliCommandsSchema = require('../cli/commands-schema');
+const logDeprecation = require('../utils/log-deprecation');
const BINARY_PATH = standaloneUtils.path;
const mainProgress = progress.get('main');
@@ -19,6 +20,11 @@ const upgradeCommandDeprecationMessage = [
'',
'More info: https://github.com/oss-serverless/osls/blob/main/docs/guides/deprecations.md#STANDALONE_UPGRADE_COMMAND_DEPRECATED',
].join('\n');
+const uninstallCommandDeprecationMessage = [
+ 'The top-level standalone `sls uninstall` command is deprecated and scheduled for removal in osls v4.0.0.',
+ 'It only removes the legacy standalone binary directory and does not uninstall npm-installed osls.',
+ 'Use your package manager to uninstall npm-installed osls. This does not affect `serverless plugin uninstall`.',
+].join('\n');
module.exports = class Standalone {
constructor(serverless, cliOptions) {
@@ -48,6 +54,7 @@ module.exports = class Standalone {
}
async uninstall() {
+ logDeprecation('STANDALONE_UNINSTALL_COMMAND_DEPRECATED', uninstallCommandDeprecationMessage);
mainProgress.notice('Uninstalling standalone binary', { isMainEvent: true });
await remove(path.dirname(BINARY_PATH));
log.notice();
diff --git a/test/unit/lib/plugins/standalone.test.js b/test/unit/lib/plugins/standalone.test.js
index 4c56d531e..1ff200d71 100644
--- a/test/unit/lib/plugins/standalone.test.js
+++ b/test/unit/lib/plugins/standalone.test.js
@@ -10,13 +10,14 @@ const { expect } = require('chai');
const { remove } = require('../../../../lib/utils/fs/remove');
-const loadStandalone = ({ binaryPath, removeStub } = {}) =>
+const loadStandalone = ({ binaryPath, logDeprecationStub, removeStub } = {}) =>
proxyquire('../../../../lib/plugins/standalone', {
'../utils/standalone': {
path: binaryPath,
resolveLatestTag: sinon.stub().throws(new Error('Unexpected latest tag lookup')),
resolveUrl: sinon.stub().throws(new Error('Unexpected download URL lookup')),
},
+ '../utils/log-deprecation': logDeprecationStub || sinon.stub(),
'../utils/fs/remove': { remove: removeStub || remove },
});
@@ -57,14 +58,20 @@ describe('test/unit/lib/plugins/standalone.test.js', () => {
it('recursively removes the standalone install directory on uninstall', async () => {
const binaryPath = path.join(tmpDir, 'install', 'bin', 'serverless');
+ const logDeprecationStub = sinon.stub();
await fsp.mkdir(path.dirname(binaryPath), { recursive: true });
await fsp.writeFile(binaryPath, 'binary');
await fsp.writeFile(path.join(tmpDir, 'install', 'config.json'), '{}');
- const Standalone = loadStandalone({ binaryPath });
+ const Standalone = loadStandalone({ binaryPath, logDeprecationStub });
const standalone = new Standalone({ pluginManager: { commandRunStartTime: Date.now() } }, {});
await standalone.uninstall();
+ expect(logDeprecationStub).to.have.been.calledOnce;
+ expect(logDeprecationStub.firstCall.args[0]).to.equal(
+ 'STANDALONE_UNINSTALL_COMMAND_DEPRECATED'
+ );
+ expect(logDeprecationStub.firstCall.args[1]).to.include('npm-installed osls');
expect(fs.existsSync(path.dirname(binaryPath))).to.equal(false);
});
});