Skip to content

Commit

Permalink
refactor(CLI Onboarding): Move dashboard-login step from plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrzesik committed Jul 20, 2021
1 parent b19d11f commit adef710
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 1 deletion.
76 changes: 76 additions & 0 deletions lib/cli/interactive-setup/dashboard-login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use strict';

const _ = require('lodash');
const { ServerlessSDK } = require('@serverless/platform-client');
const login = require('@serverless/dashboard-plugin/lib/login');
const configUtils = require('@serverless/utils/config');
const { StepHistory } = require('@serverless/utils/telemetry');

const loginOrRegisterQuestion = async (inquirer) =>
(
await inquirer.prompt({
message: 'Do you want to login/register to Serverless Dashboard?',
type: 'confirm',
name: 'shouldLoginOrRegister',
})
).shouldLoginOrRegister;

const steps = {
loginOrRegister: async (context) => {
const result = await loginOrRegisterQuestion(context.inquirer);
context.stepHistory.set('shouldLoginOrRegister', result);
if (result) {
await login({ isInteractive: true });
}
},
};

module.exports = {
async isApplicable(context) {
const { configuration, options, serviceDir } = context;

if (!serviceDir) {
context.inapplicabilityReasonCode = 'NOT_IN_SERVICE_DIRECTORY';
return false;
}

if (
_.get(configuration, 'provider') !== 'aws' &&
_.get(configuration, 'provider.name') !== 'aws'
) {
context.inapplicabilityReasonCode = 'NON_AWS_PROVIDER';
return false;
}

if (process.env.SERVERLESS_ACCESS_KEY) {
context.inapplicabilityReasonCode = 'SERVERLESS_ACCESS_KEY_PROVIDED';
return false;
}

const sdk = new ServerlessSDK();
const { supportedRegions, supportedRuntimes } = await sdk.metadata.get();
if (!supportedRuntimes.includes(_.get(configuration.provider, 'runtime') || 'nodejs12.x')) {
context.inapplicabilityReasonCode = 'UNSUPPORTED_RUNTIME';
return false;
}
if (
!supportedRegions.includes(options.region || configuration.provider.region || 'us-east-1')
) {
context.inapplicabilityReasonCode = 'UNSUPPORTED_REGION';
return false;
}
const isLoggedIn = Boolean(configUtils.getLoggedInUser());
if (isLoggedIn) {
context.inapplicabilityReasonCode = 'ALREADY_LOGGED_IN';
}
return !isLoggedIn;
},
async run(context) {
// TODO: Remove check for `StepHistory` after releasing new major version
if (!_.get(context.stepHistory, 'set')) context.stepHistory = new StepHistory();
process.stdout.write('You are not logged in or you do not have a Serverless account.\n\n');
return steps.loginOrRegister(context);
},
steps,
configuredQuestions: ['shouldLoginOrRegister'],
};
2 changes: 1 addition & 1 deletion lib/cli/interactive-setup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { resolveInitialContext } = require('./utils');

const steps = {
service: require('./service'),
dashboardLogin: require('@serverless/dashboard-plugin/lib/cli/interactive-setup/dashboard-login'),
dashboardLogin: require('./dashboard-login'),
dashboardSetOrg: require('@serverless/dashboard-plugin/lib/cli/interactive-setup/dashboard-set-org'),
awsCredentials: require('./aws-credentials'),
deploy: require('./deploy'),
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@serverless/cli": "^1.5.2",
"@serverless/components": "^3.13.4",
"@serverless/dashboard-plugin": "^5.4.3",
"@serverless/platform-client": "^4.2.5",
"@serverless/utils": "^5.3.0",
"ajv": "^6.12.6",
"ajv-keywords": "^3.5.2",
Expand Down
31 changes: 31 additions & 0 deletions test/fixtures/programmatic/aws-loggedin-service/.serverlessrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"frameworkId": "00000000-0000-0000-0000-000000000000",
"meta": {
"created_at": 1560000000,
"updated_at": 1560000000
},
"userId": "testinteractivecli",
"users": {
"testinteractivecli": {
"userId": "testinteractivecli",
"name": "Testing Interactive Cli",
"email": "test-interactive-cli@interactive.cli",
"username": "testinteractivecli",
"dashboard": {
"refreshToken": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"accessToken": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"idToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik56azVNREl5TVRnNFJqWTBORGswT0VJM1JrRXpORGN4UmtVMU1FWXdNemczT1VKQlFqRTBNZyJ9.eyJuaWNrbmFtZSI6InRlc3QtaW50ZXJhY3RpdmUtY2xpIiwibmFtZSI6IlRlc3RpbmcgSW50ZXJhY3RpdmUgQ2xpIiwicGljdHVyZSI6Imh0dHBzOi8vaW50ZXJhdGNpdmUuY2xpL3Rlc3RpbmcucG5nIiwidXBkYXRlZF9hdCI6IjIwMTktMDktMTZUMTU6MTg6NDMuOTk5WiIsImVtYWlsIjoidGVzdGluZ0BpbnRlcmFjdGl2ZS5jbGkiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6Ly9zZXJ2ZXJsZXNzaW5jLmF1dGgwLmNvbS8iLCJzdWIiOiJ0ZXN0LWludGVyYWN0aXZlLWNsaSIsImF1ZCI6IlhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYIiwiaWF0IjoxNTYwMDAwMDAwLCJleHAiOjMwMDAwMDAwMDB9.GcNQtWSxv9CHTABw-HIjYSvRxTEapDUDqIIWRGmz01XmShQxRGOHRuUg1NKU4w9MpOlB6txHKs8UWd2eZkzw_Z4QmIuLyAVhVklpWP2-xeysPLUyqVTgqAg8kgIUAwdKjmrdpQqHhGd-Q1BIX62-E-qKKx8prmADSw_hgmuvlMuSCa1ajCnfyUXycQxDmbFrvjd24lJER0FSpB2nWWW3KxZ_UBX-TuVmiEtRXg9GYeSv6oIU78PrIhYgJ0QjERRF1yAYamIXNRs-KZ7Z4YiFNC4uKzFH1524pZkS4Q0-pweIvBrrsjekz-vEYcbaVG1zAxDu_yNrYPk5phCy8MHTrQ",
"expiresAt": 3000000000000,
"username": "testinteractivecli",
"accessKeys": {
"testinteractivecli": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
},
"enterprise": {
"versionSDK": "2.1.1",
"timeLastLogin": 1560000000,
"timeLastLogout": 1560000000
}
}
}
}
Empty file.
10 changes: 10 additions & 0 deletions test/fixtures/programmatic/aws-loggedin-service/serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
service: 'some-aws-service'
provider: 'aws'

functions:
app:
handler: index.handler
foo: bar
org:
handler: index.handler
foo: bar
152 changes: 152 additions & 0 deletions test/unit/lib/cli/interactive-setup/dashboard-login.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
'use strict';

const chai = require('chai');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const overrideCwd = require('process-utils/override-cwd');
const configureInquirerStub = require('@serverless/test/configure-inquirer-stub');
const { StepHistory } = require('@serverless/utils/telemetry');
const inquirer = require('@serverless/utils/inquirer');

const { expect } = chai;

chai.use(require('chai-as-promised'));

const fixtures = require('../../../../fixtures/programmatic');

const ServerlessSDKMock = class ServerlessSDK {
constructor() {
this.metadata = {
get: async () => {
return {
awsAccountId: '377024778620',
supportedRuntimes: ['nodejs10.x', 'nodejs12.x', 'python2.7', 'python3.6', 'python3.7'],
supportedRegions: [
'us-east-1',
'us-east-2',
'us-west-2',
'eu-central-1',
'eu-west-1',
'eu-west-2',
'ap-northeast-1',
'ap-southeast-1',
'ap-southeast-2',
],
};
},
};
}
};

const step = proxyquire('../../../../../lib/cli/interactive-setup/dashboard-login', {
'@serverless/platform-client': {
ServerlessSDK: ServerlessSDKMock,
},
});

describe('test/unit/lib/cli/interactive-setup/dashboard-login.test.js', function () {
this.timeout(1000 * 60 * 3);

const loginStub = sinon.stub().resolves();

afterEach(() => {
loginStub.resetHistory();
});

it('Should be ineffective, when not at service path', async () => {
const context = {};
expect(await step.isApplicable(context)).to.be.false;
expect(context.inapplicabilityReasonCode).to.equal('NOT_IN_SERVICE_DIRECTORY');
});

it('Should be ineffective, when not at AWS service path', async () => {
const context = {
serviceDir: process.cwd(),
configuration: {},
configurationFilename: 'serverless.yml',
options: {},
inquirer,
};
expect(await step.isApplicable(context)).to.equal(false);
expect(context.inapplicabilityReasonCode).to.equal('NON_AWS_PROVIDER');
});

it('Should be ineffective, when not at supported runtime service path', async () => {
const context = {
serviceDir: process.cwd(),
configuration: { provider: { name: 'aws', runtime: 'java8' } },
configurationFilename: 'serverless.yml',
options: {},
inquirer,
};
expect(await step.isApplicable(context)).to.equal(false);
expect(context.inapplicabilityReasonCode).to.equal('UNSUPPORTED_RUNTIME');
});

it('Should be ineffective, when logged in', async () => {
const { servicePath: serviceDir, serviceConfig: configuration } = await fixtures.setup(
'aws-loggedin-service'
);
const context = {
serviceDir,
configuration,
configurationFilename: 'serverless.yml',
options: {},
inquirer,
};
expect(await overrideCwd(serviceDir, async () => await step.isApplicable(context))).to.equal(
false
);
expect(context.inapplicabilityReasonCode).to.equal('ALREADY_LOGGED_IN');
});

it('Should login when user decides to login/register', async () => {
configureInquirerStub(inquirer, {
confirm: { shouldLoginOrRegister: true },
});
const loginStep = proxyquire('../../../../../lib/cli/interactive-setup/dashboard-login', {
'@serverless/dashboard-plugin/lib/login': loginStub,
'@serverless/platform-client': {
ServerlessSDK: ServerlessSDKMock,
},
});
const context = {
serviceDir: process.cwd(),
configuration: { provider: { name: 'aws', runtime: 'nodejs12.x' } },
configurationFilename: 'serverless.yml',
options: {},
inquirer,
stepHistory: new StepHistory(),
};
await loginStep.run(context);
expect(loginStub.calledOnce).to.be.true;
expect(context.stepHistory.valuesMap()).to.deep.equal(
new Map([['shouldLoginOrRegister', true]])
);
});

it('Should not login when user decides not to login/register', async () => {
configureInquirerStub(inquirer, {
confirm: { shouldLoginOrRegister: false },
});
const loginStep = proxyquire('../../../../../lib/cli/interactive-setup/dashboard-login', {
'@serverless/dashboard-plugin/lib/login': loginStub,
'@serverless/platform-client': {
ServerlessSDK: ServerlessSDKMock,
},
});
const context = {
serviceDir: process.cwd(),
configuration: { provider: { name: 'aws', runtime: 'nodejs12.x' } },
configurationFilename: 'serverless.yml',
options: {},
inquirer,
stepHistory: new StepHistory(),
};
await loginStep.run(context);
expect(loginStub.called).to.be.false;
expect(context.stepHistory.valuesMap()).to.deep.equal(
new Map([['shouldLoginOrRegister', false]])
);
});
});

0 comments on commit adef710

Please sign in to comment.