Skip to content

Commit

Permalink
feat: add new env commands
Browse files Browse the repository at this point in the history
This change introduces a new set of commands around retrieving and modifying environment variables
from already deployed environments.

re #249
  • Loading branch information
dkundel committed Jun 25, 2021
1 parent 20d024d commit 44fbbbb
Show file tree
Hide file tree
Showing 25 changed files with 1,151 additions and 5 deletions.
3 changes: 3 additions & 0 deletions packages/plugin-serverless/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
},
"serverless:deploy": {
"description": "deploys your local serverless project"
},
"serverless:env": {
"description": "retrieve and modify the environment variables for your deployment"
}
}
},
Expand Down
41 changes: 41 additions & 0 deletions packages/plugin-serverless/src/commands/serverless/env/get.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { TwilioClientCommand } = require('@twilio/cli-core').baseCommands;

const {
handler,
cliInfo,
describe,
} = require('twilio-run/dist/commands/env/env-get');
const {
convertYargsOptionsToOclifFlags,
normalizeFlags,
createExternalCliOptions,
getRegionAndEdge,
} = require('../../../utils');

const { flags, aliasMap } = convertYargsOptionsToOclifFlags(cliInfo.options);

class EnvGet extends TwilioClientCommand {
async run() {
await super.run();

let { flags, args } = this.parse(EnvGet);
flags = normalizeFlags(flags, aliasMap, process.argv);

const externalOptions = createExternalCliOptions(flags, this.twilioClient);

const { edge, region } = getRegionAndEdge(flags, this);
flags.region = region;
flags.edge = edge;

const opts = Object.assign({}, flags, args);
return handler(opts, externalOptions);
}
}

EnvGet.description = describe;

EnvGet.flags = Object.assign(flags, {
profile: TwilioClientCommand.flags.profile,
});

module.exports = EnvGet;
41 changes: 41 additions & 0 deletions packages/plugin-serverless/src/commands/serverless/env/import.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { TwilioClientCommand } = require('@twilio/cli-core').baseCommands;

const {
handler,
cliInfo,
describe,
} = require('twilio-run/dist/commands/env/env-import');
const {
convertYargsOptionsToOclifFlags,
normalizeFlags,
createExternalCliOptions,
getRegionAndEdge,
} = require('../../../utils');

const { flags, aliasMap } = convertYargsOptionsToOclifFlags(cliInfo.options);

class EnvironmentImport extends TwilioClientCommand {
async run() {
await super.run();

let { flags, args } = this.parse(EnvironmentImport);
flags = normalizeFlags(flags, aliasMap, process.argv);

const externalOptions = createExternalCliOptions(flags, this.twilioClient);

const { edge, region } = getRegionAndEdge(flags, this);
flags.region = region;
flags.edge = edge;

const opts = Object.assign({}, flags, args);
return handler(opts, externalOptions);
}
}

EnvironmentImport.description = describe;

EnvironmentImport.flags = Object.assign(flags, {
profile: TwilioClientCommand.flags.profile,
});

module.exports = EnvironmentImport;
41 changes: 41 additions & 0 deletions packages/plugin-serverless/src/commands/serverless/env/list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { TwilioClientCommand } = require('@twilio/cli-core').baseCommands;

const {
handler,
cliInfo,
describe,
} = require('twilio-run/dist/commands/env/env-list');
const {
convertYargsOptionsToOclifFlags,
normalizeFlags,
createExternalCliOptions,
getRegionAndEdge,
} = require('../../../utils');

const { flags, aliasMap } = convertYargsOptionsToOclifFlags(cliInfo.options);

class EnvList extends TwilioClientCommand {
async run() {
await super.run();

let { flags, args } = this.parse(EnvList);
flags = normalizeFlags(flags, aliasMap, process.argv);

const externalOptions = createExternalCliOptions(flags, this.twilioClient);

const { edge, region } = getRegionAndEdge(flags, this);
flags.region = region;
flags.edge = edge;

const opts = Object.assign({}, flags, args);
return handler(opts, externalOptions);
}
}

EnvList.description = describe;

EnvList.flags = Object.assign(flags, {
profile: TwilioClientCommand.flags.profile,
});

module.exports = EnvList;
41 changes: 41 additions & 0 deletions packages/plugin-serverless/src/commands/serverless/env/unset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { TwilioClientCommand } = require('@twilio/cli-core').baseCommands;

const {
handler,
cliInfo,
describe,
} = require('twilio-run/dist/commands/env/env-unset');
const {
convertYargsOptionsToOclifFlags,
normalizeFlags,
createExternalCliOptions,
getRegionAndEdge,
} = require('../../../utils');

const { flags, aliasMap } = convertYargsOptionsToOclifFlags(cliInfo.options);

class EnvUnset extends TwilioClientCommand {
async run() {
await super.run();

let { flags, args } = this.parse(EnvUnset);
flags = normalizeFlags(flags, aliasMap, process.argv);

const externalOptions = createExternalCliOptions(flags, this.twilioClient);

const { edge, region } = getRegionAndEdge(flags, this);
flags.region = region;
flags.edge = edge;

const opts = Object.assign({}, flags, args);
return handler(opts, externalOptions);
}
}

EnvUnset.description = describe;

EnvUnset.flags = Object.assign(flags, {
profile: TwilioClientCommand.flags.profile,
});

module.exports = EnvUnset;
15 changes: 15 additions & 0 deletions packages/serverless-api/src/api/utils/type-checks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Sid } from '../../types';

const SidRegEx = /^[A-Z]{2}[a-f0-9]{32}$/;

export function isSid(value: unknown): value is Sid {
if (typeof value !== 'string') {
return false;
}

if (value.length !== 34) {
return false;
}

return SidRegEx.test(value);
}
58 changes: 56 additions & 2 deletions packages/serverless-api/src/api/variables.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
/** @module @twilio-labs/serverless-api/dist/api */

import debug from 'debug';
import { TwilioServerlessApiClient } from '../client';
import {
EnvironmentVariables,
Sid,
Variable,
VariableList,
VariableResource,
} from '../types';
import { TwilioServerlessApiClient } from '../client';
import { getPaginatedResource } from './utils/pagination';
import { ClientApiError } from '../utils/error';
import { getPaginatedResource } from './utils/pagination';
import { isSid } from './utils/type-checks';

const log = debug('twilio-serverless-api:variables');

Expand Down Expand Up @@ -182,3 +184,55 @@ export async function setEnvironmentVariables(

await Promise.all(variableResources);
}

export async function deleteEnvironmentVariable(
variableSid: string,
environmentSid: string,
serviceSid: string,
client: TwilioServerlessApiClient
): Promise<boolean> {
try {
const resp = await client.request(
'delete',
`Services/${serviceSid}/Environments/${environmentSid}/Variables/${variableSid}`
);
return true;
} catch (err) {
log('%O', new ClientApiError(err));
throw err;
}
}

export async function removeEnvironmentVariables(
keys: string[],
environmentSid: string,
serviceSid: string,
client: TwilioServerlessApiClient
): Promise<boolean> {
const existingVariables = await listVariablesForEnvironment(
environmentSid,
serviceSid,
client
);

const variableSidMap = new Map<string, Sid>();
existingVariables.forEach((variableResource) => {
variableSidMap.set(variableResource.key, variableResource.sid);
});

const requests: Promise<boolean>[] = keys.map((key) => {
const variableSid = variableSidMap.get(key);
if (isSid(variableSid)) {
return deleteEnvironmentVariable(
variableSid,
environmentSid,
serviceSid,
client
);
}
return Promise.resolve(true);
});

await Promise.all(requests);
return true;
}
Loading

0 comments on commit 44fbbbb

Please sign in to comment.