Skip to content

Commit

Permalink
feat(twilio-run): restructure configuration (#198)
Browse files Browse the repository at this point in the history
This PR aims to restructure the way configuration is handled by dropping .twilio-functions files in
favor of a dedicated config file and a deploy info cache file.

BREAKING CHANGE: Drops support for .twilio-functions files and internally restructures activate
files to promote

fix #166
  • Loading branch information
dkundel authored Apr 16, 2021
1 parent 9c40a7f commit f88d490
Show file tree
Hide file tree
Showing 44 changed files with 1,525 additions and 648 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,6 @@ dist/

*.tsbuildinfo
.twilio-functions
*.twiliodeployinfo

packages/serverless-api/docs/
62 changes: 62 additions & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Configuration

## Examples

### Functions with Preprocessor like TypeScript or Babel

By default the Serverless Toolkit will be looking for Functions inside a `functions/` or `src/` directory and for assets for an `assets/` or `static/` directory.

If you are using a pre-processor such as TypeScript or Babel, your structure might look different. For example maybe you have a structure where `src/` contains all TypeScript files and `dist/` contains the output.

In which case you'd want a config that looks similar to this:

```json
{
"functionsFolderName": "dist"
}
```

### Using different `.env` files for different environments

If you are deploying to different environments you might want different environment variables for your application.

You can specify environment specific configurations inside the config file by using the domain suffix of your environment.

If you are using the `--production` flag you'll need to use the environment: `*`.

For example:

```json
{
"environments": {
"dev": {
"env": ".env"
},
"stage": {
"env": ".env.stage"
},
"*": {
"env": ".env.prod"
}
}
}
```

### Deploy to specific services on different accounts

There might be a scenario where you want to deploy the same project to different Twilio accounts or projects with different services.

Inside the config you can define which service the project should be deployed to depending on the Twilio Account SID.

```json
{
"projects": {
"AC11111111111111111111111111111111": {
"serviceSid": "ZSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"AC22222222222222222222222222222222": {
"serviceSid": "ZSbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}
}
}
```
41 changes: 41 additions & 0 deletions docs/MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Migration Guides

## Migrating from Serverless Toolkit V2 to V3

What changed? The main changes are the following:

### 1. No more `.twilio-functions` file.

The `.twilio-functions` file is being replaced by a `.twilioserverlessrc` file for any configuration you want to do and a `.twiliodeployinfo` file.

The `.twilioserverlessrc` file can be checked into your project and helps especially with more complex applications. Check out the [Configuration documentation](CONFIGURATION.md) for more information.

The `.twiliodeployinfo` file can be commited to your project but is primarily intended to make commands more convenient for you. This file gets updated as part of deployments.

To transition your `.twilio-functions` file we provide a convenience script that takes care of some of the work. You can run it by running:

```bash
npx -p twilio-run@3 twilio-upgrade-config
```

## FAQ

### How do I know which version I'm using?

There are two ways you can consume the Serverless Toolkit and the ways to determine your version are different.

**Scenario 1**: If you are using the Twilio CLI and `@twilio-labs/plugin-serverless` run the following command:

```bash
twilio plugins
```

Your output should contain something like: `@twilio-labs/plugin-serverless 1.9.0`. In this case your version of `@twilio-labs/plugin-serverless` is version 1.9.0 and to get your Serverless Toolkit version increment the first number by one. So in this case you have Serverless Toolkit V2.

**Scenario 2**: If you are using `twilio-run` directly.

Run the following command. The first number will be your Serverless Toolkit version:

```bash
npx twilio-run --version
```
10 changes: 5 additions & 5 deletions packages/plugin-serverless/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ USAGE
$ twilio serverless:deploy
OPTIONS
-c, --config=config [default: .twilio-functions] Location of the config file. Absolute path or
-c, --config=config Location of the config file. Absolute path or
relative to current working directory (cwd)
-l, --logLevel=logLevel [default: info] Level of logging messages.
Expand Down Expand Up @@ -156,7 +156,7 @@ ARGUMENTS
TYPES [default: services] Comma separated list of things to list (services,environments,functions,assets,variables)
OPTIONS
-c, --config=config [default: .twilio-functions] Location of the config file. Absolute path or relative
-c, --config=config Location of the config file. Absolute path or relative
to current working directory (cwd)
-l, --logLevel=logLevel [default: info] Level of logging messages.
Expand Down Expand Up @@ -207,7 +207,7 @@ USAGE
$ twilio serverless:logs
OPTIONS
-c, --config=config [default: .twilio-functions] Location of the config file. Absolute path or relative
-c, --config=config Location of the config file. Absolute path or relative
to current working directory (cwd)
-l, --logLevel=logLevel [default: info] Level of logging messages.
Expand Down Expand Up @@ -266,7 +266,7 @@ USAGE
$ twilio serverless:promote
OPTIONS
-c, --config=config [default: .twilio-functions] Location of the config file. Absolute path
-c, --config=config Location of the config file. Absolute path
or relative to current working directory (cwd)
-f, --source-environment=source-environment SID or suffix of an existing environment you want to deploy from.
Expand Down Expand Up @@ -319,7 +319,7 @@ ARGUMENTS
DIR Root directory to serve local Functions/Assets from
OPTIONS
-c, --config=config [default: .twilio-functions] Location of the config file. Absolute path or
-c, --config=config Location of the config file. Absolute path or
relative to current working directory (cwd)
-e, --env=env Loads .env file, overrides local env variables
Expand Down
4 changes: 3 additions & 1 deletion packages/serverless-runtime-types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
"url": "https://github.com/twilio-labs/serverless-toolkit/issues"
},
"dependencies": {
"twilio": "^3.33.0"
"@types/express": "^4.17.11",
"@types/qs": "^6.9.6",
"twilio": "^3.58.0"
},
"devDependencies": {
"@types/express": "^4.17.11",
Expand Down
48 changes: 48 additions & 0 deletions packages/twilio-run/__tests__/checks/legacy-config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { mocked } from 'ts-jest/utils';
import checkLegacyConfig, {
printConfigWarning,
} from '../../src/checks/legacy-config';
import { logger } from '../../src/utils/logger';

jest.mock('../../src/utils/fs', () => ({
fileExistsSync: jest.fn(() => {
return SHOULD_FILE_EXIST;
}),
}));

jest.mock('../../src/utils/logger', () => ({
logger: {
warn: jest.fn(),
},
}));

var SHOULD_FILE_EXIST = false;

describe('printLegacyConfig', () => {
it('should log a message with the correct title', () => {
printConfigWarning();
expect(logger.warn).toHaveBeenCalledTimes(1);
expect(
mocked(logger.warn).mock.calls[0][0].includes(
'We found a .twilio-functions file'
)
).toBeTruthy();
expect(mocked(logger.warn).mock.calls[0][1]).toEqual(
'Legacy Configuration Detected'
);
});
});

describe('checkLegacyConfig', () => {
it('should print a warning if the config file exists', () => {
SHOULD_FILE_EXIST = true;
checkLegacyConfig();
expect(logger.warn).toHaveBeenCalled();
});

it('should not print a warning if the file does not exist', () => {
SHOULD_FILE_EXIST = false;
checkLegacyConfig();
expect(logger.warn).not.toHaveBeenCalled();
});
});
131 changes: 131 additions & 0 deletions packages/twilio-run/__tests__/config/global.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
jest.mock('../../src/config/utils/configLoader');

import { readSpecializedConfig } from '../../src/config/global';
import { ConfigurationFile } from '../../src/types/config';
const {
__setTestConfig,
}: {
__setTestConfig: (config: Partial<ConfigurationFile>) => void;
} = require('../../src/config/utils/configLoader');

describe('readSpecializedConfig', () => {
test('returns the right base config', () => {
__setTestConfig({
serviceSid: 'ZS11112222111122221111222211112222',
env: '.env.example',
});

expect(
readSpecializedConfig('/tmp', '.twilioserverlessrc', 'deploy')
).toEqual({
serviceSid: 'ZS11112222111122221111222211112222',
env: '.env.example',
});
});

test('merges command-specific config', () => {
__setTestConfig({
serviceSid: 'ZS11112222111122221111222211112222',
commands: {
deploy: {
functionsFolder: '/tmp/functions',
},
},
});

expect(
readSpecializedConfig('/tmp', '.twilioserverlessrc', 'deploy')
).toEqual({
serviceSid: 'ZS11112222111122221111222211112222',
functionsFolder: '/tmp/functions',
});
});

test('ignores other command-specific config', () => {
__setTestConfig({
serviceSid: 'ZS11112222111122221111222211112222',
commands: {
deploy: {
functionsFolder: '/tmp/functions',
},
start: {
functionsFolder: '/tmp/src',
},
},
});

expect(
readSpecializedConfig('/tmp', '.twilioserverlessrc', 'deploy')
).toEqual({
serviceSid: 'ZS11112222111122221111222211112222',
functionsFolder: '/tmp/functions',
});
});

test('environments override other config', () => {
__setTestConfig({
serviceSid: 'ZS11112222111122221111222211112222',
env: '.env.example',
commands: {
deploy: {
functionsFolder: '/tmp/functions',
},
},
environments: {
stage: {
env: '.env.stage',
},
'*': {
env: '.env.prod',
},
},
});

expect(
readSpecializedConfig('/tmp', '.twilioserverlessrc', 'deploy', {
environmentSuffix: 'stage',
})
).toEqual({
serviceSid: 'ZS11112222111122221111222211112222',
functionsFolder: '/tmp/functions',
env: '.env.stage',
});
});

test('account config overrides every other config', () => {
__setTestConfig({
serviceSid: 'ZS11112222111122221111222211112222',
env: '.env.example',
commands: {
deploy: {
functionsFolder: '/tmp/functions',
},
},
environments: {
stage: {
serviceSid: 'ZS11112222111122221111222211112223',
env: '.env.stage',
},
'*': {
env: '.env.prod',
},
},
projects: {
AC11112222111122221111222211114444: {
serviceSid: 'ZS11112222111122221111222211114444',
},
},
});

expect(
readSpecializedConfig('/tmp', '.twilioserverlessrc', 'deploy', {
environmentSuffix: 'stage',
accountSid: 'AC11112222111122221111222211114444',
})
).toEqual({
serviceSid: 'ZS11112222111122221111222211114444',
functionsFolder: '/tmp/functions',
env: '.env.stage',
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import '../../../src/config/utils/mergeFlagsAndConfig';
import { mergeFlagsAndConfig } from '../../../src/config/utils/mergeFlagsAndConfig';

const baseFlags = {
config: '.twilio-functions',
config: '.twilioserverlessrc',
cwd: process.cwd(),
list: true,
};
Expand Down Expand Up @@ -58,7 +58,7 @@ describe('mergeFlagsAndConfig', () => {
expect(merged).toEqual({
template: 'bye',
list: false,
config: '.twilio-functions',
config: '.twilioserverlessrc',
cwd: process.cwd(),
});
});
Expand All @@ -75,7 +75,7 @@ describe('mergeFlagsAndConfig', () => {
expect(merged).toEqual({
template: 'hello',
list: false,
config: '.twilio-functions',
config: '.twilioserverlessrc',
cwd: process.cwd(),
});
});
Expand All @@ -93,7 +93,7 @@ describe('mergeFlagsAndConfig', () => {
expect(merged).toEqual({
template: 'hello',
list: false,
config: '.twilio-functions',
config: '.twilioserverlessrc',
cwd: '/some/path',
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { readPackageJsonContent } from '../../../src/config/utils/package-json';
import { getServiceNameFromFlags } from '../../../src/config/utils/service-name';

const baseFlags = {
config: '.twilio-functions',
config: '.twilioserverlessrc',
logLevel: 'info' as 'info',
};

Expand Down
Loading

0 comments on commit f88d490

Please sign in to comment.