Skip to content
This repository was archived by the owner on Feb 3, 2022. It is now read-only.

Commit ffa1904

Browse files
committed
Adds template option to main CLI command
1 parent 1434a77 commit ffa1904

File tree

8 files changed

+167
-21
lines changed

8 files changed

+167
-21
lines changed

README.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,28 @@ create-twilio-function <name>
3838
3939
Creates a new Twilio Function project
4040
41+
Commands:
42+
create-twilio-function <name> Creates a new Twilio Function
43+
project [default]
44+
create-twilio-function list-templates List the available templates you can
45+
create a project with.
46+
4147
Positionals:
42-
name Name of your project. [string]
48+
name Name of your project. [string]
4349
4450
Options:
45-
--account-sid, -a The Account SID for your Twilio account [string]
46-
--auth-token, -t Your Twilio account Auth Token [string]
47-
--skip-credentials Don't ask for Twilio account credentials or import them
48-
from the environment [boolean] [default: false]
51+
--account-sid, -a The Account SID for your Twilio account [string]
52+
--auth-token, -t Your Twilio account Auth Token [string]
53+
--skip-credentials Don't ask for Twilio account credentials or import
54+
them from the environment [boolean] [default: false]
4955
--import-credentials Import credentials from the environment variables
5056
TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN
51-
[boolean] [default: false]
52-
-h, --help Show help [boolean]
53-
-v, --version Show version number [boolean]
54-
--path [default: (cwd)]
57+
[boolean] [default: false]
58+
--template Initialize your new project with a template from
59+
github.com/twilio-labs/function-templates [string]
60+
-h, --help Show help [boolean]
61+
-v, --version Show version number [boolean]
62+
--path [default: (cwd)]
5563
```
5664

5765
## Contributing

src/command.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ const cliInfo = {
2323
'Import credentials from the environment variables TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN',
2424
type: 'boolean',
2525
default: false
26+
},
27+
template: {
28+
describe:
29+
'Initialize your new project with a template from github.com/twilio-labs/function-templates',
30+
type: 'string'
2631
}
2732
}
2833
};

src/create-twilio-function.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const {
1414
const successMessage = require('./create-twilio-function/success-message');
1515
const ora = require('ora');
1616
const boxen = require('boxen');
17+
const { downloadTemplate } = require('twilio-run/dist/templating/actions');
1718

1819
async function createTwilioFunction(config) {
1920
const projectDir = `${config.path}/${config.name}`;
@@ -52,14 +53,19 @@ async function createTwilioFunction(config) {
5253
// Scaffold project
5354
const spinner = ora();
5455
spinner.start('Creating project directories and files');
55-
// await createDirectory(projectDir, 'functions');
56-
// await createDirectory(projectDir, 'assets');
56+
5757
await createEnvFile(projectDir, {
5858
accountSid: config.accountSid,
5959
authToken: config.authToken
6060
});
6161
await createNvmrcFile(projectDir);
62-
await createExampleFromTemplates(projectDir);
62+
if (config.template) {
63+
await createDirectory(projectDir, 'functions');
64+
await createDirectory(projectDir, 'assets');
65+
await downloadTemplate(config.template, '', projectDir);
66+
} else {
67+
await createExampleFromTemplates(projectDir);
68+
}
6369
await createPackageJSON(projectDir, config.name);
6470
spinner.succeed();
6571

tests/create-gitignore.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ const stat = promisify(fs.stat);
99

1010
beforeAll(async () => {
1111
await rimraf('./scratch');
12+
nock.disableNetConnect();
13+
});
14+
15+
afterAll(() => {
16+
nock.enableNetConnect();
1217
});
1318

1419
beforeEach(async () => {
@@ -20,6 +25,7 @@ beforeEach(async () => {
2025

2126
afterEach(async () => {
2227
await rimraf('./scratch');
28+
nock.cleanAll();
2329
});
2430

2531
describe('createGitignore', () => {

tests/create-twilio-function.test.js

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ const {
44
} = require('../src/create-twilio-function/install-dependencies');
55
const inquirer = require('inquirer');
66
const ora = require('ora');
7-
const boxen = require('boxen');
7+
const nock = require('nock');
88
const fs = require('fs');
99
const { promisify } = require('util');
1010
const rimraf = promisify(require('rimraf'));
1111
const mkdir = promisify(fs.mkdir);
1212
const stat = promisify(fs.stat);
13+
const readdir = promisify(fs.readdir);
1314

1415
jest.mock('inquirer');
1516
jest.mock('ora');
@@ -30,6 +31,11 @@ console.log = jest.fn();
3031

3132
beforeAll(async () => {
3233
await rimraf('./scratch');
34+
nock.disableNetConnect();
35+
});
36+
37+
afterAll(() => {
38+
nock.enableNetConnect();
3339
});
3440

3541
beforeEach(async () => {
@@ -38,10 +44,15 @@ beforeEach(async () => {
3844

3945
afterEach(async () => {
4046
await rimraf('./scratch');
47+
nock.cleanAll();
4148
});
4249

4350
describe('createTwilioFunction', () => {
44-
beforeEach(() => jest.clearAllMocks());
51+
beforeEach(() => {
52+
nock('https://raw.githubusercontent.com')
53+
.get('/github/gitignore/master/Node.gitignore')
54+
.reply(200, '*.log\n.env');
55+
});
4556

4657
test('it scaffolds a Twilio Function', async () => {
4758
inquirer.prompt = jest.fn(() =>
@@ -84,6 +95,96 @@ describe('createTwilioFunction', () => {
8495
expect(console.log).toHaveBeenCalledWith('success message');
8596
});
8697

98+
test('it scaffolds a Twilio Function with a template', async () => {
99+
inquirer.prompt = jest.fn(() =>
100+
Promise.resolve({
101+
accountSid: 'test-sid',
102+
authToken: 'test-auth-token'
103+
})
104+
);
105+
106+
const gitHubAPI = nock('https://api.github.com');
107+
gitHubAPI
108+
.get('/repos/twilio-labs/function-templates/contents/blank?ref=next')
109+
.reply(200, [
110+
{
111+
name: 'functions'
112+
},
113+
{
114+
name: '.env',
115+
download_url:
116+
'https://raw.githubusercontent.com/twilio-labs/function-templates/next/blank/.env'
117+
}
118+
]);
119+
gitHubAPI
120+
.get(
121+
'/repos/twilio-labs/function-templates/contents/blank/functions?ref=next'
122+
)
123+
.reply(200, [
124+
{
125+
name: 'blank.js',
126+
download_url:
127+
'https://raw.githubusercontent.com/twilio-labs/function-templates/next/blank/functions/blank.js'
128+
}
129+
]);
130+
const gitHubRaw = nock('https://raw.githubusercontent.com');
131+
gitHubRaw
132+
.get('/twilio-labs/function-templates/next/blank/functions/blank.js')
133+
.reply(
134+
200,
135+
`exports.handler = function(context, event, callback) {
136+
callback(null, {});
137+
};`
138+
);
139+
gitHubRaw
140+
.get('/github/gitignore/master/Node.gitignore')
141+
.reply(200, 'node_modules/');
142+
gitHubRaw
143+
.get('/twilio-labs/function-templates/next/blank/.env')
144+
.reply(200, '');
145+
146+
const name = 'test-function';
147+
await createTwilioFunction({
148+
name,
149+
path: './scratch',
150+
template: 'blank'
151+
});
152+
153+
const dir = await stat(`./scratch/${name}`);
154+
expect(dir.isDirectory());
155+
const env = await stat(`./scratch/${name}/.env`);
156+
expect(env.isFile());
157+
const nvmrc = await stat(`./scratch/${name}/.nvmrc`);
158+
expect(nvmrc.isFile());
159+
160+
const packageJSON = await stat(`./scratch/${name}/package.json`);
161+
expect(packageJSON.isFile());
162+
163+
const gitignore = await stat(`./scratch/${name}/.gitignore`);
164+
expect(gitignore.isFile());
165+
166+
const functions = await stat(`./scratch/${name}/functions`);
167+
expect(functions.isDirectory());
168+
169+
const assets = await stat(`./scratch/${name}/assets`);
170+
expect(assets.isDirectory());
171+
172+
const exampleFiles = await readdir(`./scratch/${name}/functions`);
173+
expect(exampleFiles).toEqual(
174+
expect.not.arrayContaining(['hello-world.js'])
175+
);
176+
177+
const templateFunction = await stat(`./scratch/${name}/functions/blank.js`);
178+
expect(templateFunction.isFile());
179+
180+
const exampleAssets = await readdir(`./scratch/${name}/assets`);
181+
expect(exampleAssets).toEqual(expect.not.arrayContaining(['index.html']));
182+
183+
expect(installDependencies).toHaveBeenCalledWith(`./scratch/${name}`);
184+
185+
expect(console.log).toHaveBeenCalledWith('success message');
186+
});
187+
87188
it("doesn't scaffold if the target folder name already exists", async () => {
88189
const name = 'test-function';
89190
await mkdir('./scratch/test-function');

tests/import-credentials.test.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ const importCredentials = require('../src/create-twilio-function/import-credenti
22
const inquirer = require('inquirer');
33

44
describe('importCredentials', () => {
5-
beforeEach(() => jest.clearAllMocks());
6-
75
describe('if credentials are present in the env', () => {
86
afterEach(() => {
97
delete process.env.TWILIO_ACCOUNT_SID;

tests/list-templates.test.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
1-
const templateActions = require('twilio-run/dist/templating/actions');
21
const listTemplates = require('../src/commands/list-templates');
2+
const ora = require('ora');
3+
const nock = require('nock');
34

4-
jest.mock('twilio-run/dist/templating/actions');
5+
jest.mock('ora');
6+
ora.mockImplementation(() => {
7+
const spinner = {
8+
start: () => spinner,
9+
stop: () => spinner
10+
};
11+
return spinner;
12+
});
13+
14+
beforeAll(() => {
15+
nock.disableNetConnect();
16+
});
17+
18+
afterAll(() => {
19+
nock.enableNetConnect();
20+
});
521

622
describe('listTemplates', () => {
23+
afterEach(() => {
24+
nock.cleanAll();
25+
});
26+
727
it('gets templates from twilio-run and displays them', async () => {
828
const consoleSpy = jest
929
.spyOn(global.console, 'log')
@@ -13,7 +33,11 @@ describe('listTemplates', () => {
1333
id: 'test-template',
1434
description: 'A template to test with'
1535
};
16-
templateActions.fetchListOfTemplates.mockResolvedValue([template]);
36+
nock('https://raw.githubusercontent.com')
37+
.get('/twilio-labs/function-templates/master/templates.json')
38+
.reply(200, {
39+
templates: [template]
40+
});
1741

1842
await listTemplates();
1943

tests/prompt.test.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ const {
44
const inquirer = require('inquirer');
55

66
describe('promptForAccountDetails', () => {
7-
beforeEach(() => jest.clearAllMocks());
8-
97
test(`should ask for an accountSid if not specified`, async () => {
108
inquirer.prompt = jest.fn(() =>
119
Promise.resolve({

0 commit comments

Comments
 (0)