-
Notifications
You must be signed in to change notification settings - Fork 63
/
Copy pathcreate-twilio-function.js
190 lines (175 loc) · 5.34 KB
/
create-twilio-function.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
const { promisify } = require('util');
const path = require('path');
const ora = require('ora');
const boxen = require('boxen');
const rimraf = promisify(require('rimraf'));
const { downloadTemplate } = require('twilio-run/dist/templating/actions');
const {
promptForAccountDetails,
promptForProjectName,
} = require('./create-twilio-function/prompt');
const validateProjectName = require('./create-twilio-function/validate-project-name');
const {
createDirectory,
createEnvFile,
createExampleFromTemplates,
createPackageJSON,
createNvmrcFile,
createTsconfigFile,
createEmptyFileStructure,
createServerlessConfigFile,
} = require('./create-twilio-function/create-files');
const createGitignore = require('./create-twilio-function/create-gitignore');
const importCredentials = require('./create-twilio-function/import-credentials');
const {
installDependencies,
} = require('./create-twilio-function/install-dependencies');
const successMessage = require('./create-twilio-function/success-message');
async function cleanUpAndExit(projectDir, spinner, errorMessage) {
spinner.fail(errorMessage);
spinner.start('Cleaning up project directories and files');
try {
await rimraf(projectDir);
} catch (error) {
spinner.fail(
`There was an error cleaning up the project. Some files may still be present in ${projectDir}`
);
} finally {
spinner.stop().clear();
process.exitCode = 1;
}
}
async function performTaskWithSpinner(spinner, message, task) {
spinner.start(message);
await task();
spinner.succeed();
}
async function createTwilioFunction(config) {
const { valid, errors } = validateProjectName(config.name);
if (!valid) {
const { name } = await promptForProjectName(errors);
config.name = name;
}
const projectDir = path.join(config.path, config.name);
const projectType = config.typescript ? 'typescript' : 'javascript';
const spinner = ora();
// Check to see if the request is valid for a template or an empty project
if (config.empty && config.template) {
await cleanUpAndExit(
projectDir,
spinner,
'You cannot scaffold an empty Functions project with a template. Please choose empty or a template.'
);
return;
}
// Check to see if the project wants typescript and a template
if (config.template && projectType === 'typescript') {
await cleanUpAndExit(
projectDir,
spinner,
'There are no TypeScript templates available. You can generate an example project or an empty one with the --empty flag.'
);
return;
}
try {
await performTaskWithSpinner(
spinner,
'Creating project directory',
async () => {
await createDirectory(config.path, config.name);
}
);
} catch (e) {
if (e.code === 'EEXIST') {
spinner.fail(
`A directory called '${config.name}' already exists. Please create your function in a new directory.`
);
} else if (e.code === 'EACCES') {
spinner.fail(
`You do not have permission to create files or directories in the path '${config.path}'.`
);
} else {
spinner.fail(e.message);
}
process.exitCode = 1;
return;
}
// Get account sid and auth token
let accountDetails = await importCredentials(config);
if (Object.keys(accountDetails).length === 0) {
accountDetails = await promptForAccountDetails(config);
}
config = {
...accountDetails,
...config,
};
// Scaffold project
spinner.start('Creating project directories and files');
await createEnvFile(projectDir, {
accountSid: config.accountSid,
authToken: config.authToken,
});
await createNvmrcFile(projectDir);
await createPackageJSON(projectDir, config.name, projectType);
await createServerlessConfigFile(projectDir);
if (projectType === 'typescript') {
await createTsconfigFile(projectDir);
}
if (config.template) {
spinner.succeed();
spinner.start(`Downloading template: "${config.template}"`);
await createDirectory(projectDir, 'functions');
await createDirectory(projectDir, 'assets');
try {
await downloadTemplate(config.template, '', projectDir);
} catch (err) {
await cleanUpAndExit(
projectDir,
spinner,
`The template "${config.template}" doesn't exist`
);
return;
}
} else if (config.empty) {
await createEmptyFileStructure(projectDir, projectType);
} else {
await createExampleFromTemplates(projectDir, projectType);
}
spinner.succeed();
// Download .gitignore file from https://github.com/github/gitignore/
try {
await performTaskWithSpinner(
spinner,
'Downloading .gitignore file',
async () => {
await createGitignore(projectDir);
}
);
} catch (err) {
cleanUpAndExit(projectDir, spinner, 'Could not download .gitignore file');
return;
}
// Install dependencies with npm
try {
await performTaskWithSpinner(
spinner,
'Installing dependencies',
async () => {
await installDependencies(projectDir);
}
);
} catch (err) {
spinner.fail();
console.log(
`There was an error installing the dependencies, but your project is otherwise complete in ./${config.name}`
);
}
// Success message
console.log(
boxen(await successMessage(config), {
padding: 1,
borderStyle: 'round',
})
);
}
module.exports = createTwilioFunction;