Skip to content

Commit 912903e

Browse files
committed
QA improvements
1 parent 591e07b commit 912903e

File tree

6 files changed

+114
-117
lines changed

6 files changed

+114
-117
lines changed

templates/cli/lib/commands/run.js.twig

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
11
const Tail = require('tail').Tail;
2-
const EventEmitter = require('node:events');
2+
const chalk = require('chalk');
33
const ignore = require("ignore");
44
const tar = require("tar");
55
const fs = require("fs");
6-
const ID = require("../id");
7-
const childProcess = require('child_process');
86
const chokidar = require('chokidar');
97
const inquirer = require("inquirer");
108
const path = require("path");
119
const { Command } = require("commander");
1210
const { localConfig, globalConfig } = require("../config");
1311
const { paginate } = require('../paginate');
1412
const { functionsListVariables } = require('./functions');
15-
const { usersGet, usersCreateJWT } = require('./users');
16-
const { projectsCreateJWT } = require('./projects');
1713
const { questionsRunFunctions } = require("../questions");
18-
const { actionRunner, success, log, error, commandDescriptions, drawTable } = require("../parser");
14+
const { actionRunner, success, log, warn, error, hint, commandDescriptions, drawTable } = require("../parser");
1915
const { systemHasCommand, isPortTaken, getAllFiles } = require('../utils');
20-
const { openRuntimesVersion, runtimeNames, systemTools, JwtManager, Queue } = require('../emulation/utils');
21-
const { dockerStop, dockerCleanup, dockerStart, dockerBuild, dockerPull, dockerStopActive } = require('../emulation/docker');
16+
const { runtimeNames, systemTools, JwtManager, Queue } = require('../emulation/utils');
17+
const { dockerStop, dockerCleanup, dockerStart, dockerBuild, dockerPull } = require('../emulation/docker');
2218

2319
const runFunction = async ({ port, functionId, noVariables, noReload, userId } = {}) => {
2420
// Selection
@@ -86,9 +82,9 @@ const runFunction = async ({ port, functionId, noVariables, noReload, userId } =
8682
commands: func.commands,
8783
};
8884

89-
log("Local function configuration:");
9085
drawTable([settings]);
9186
log('If you wish to change your local settings, update the appwrite.json file and rerun the `appwrite run` command.');
87+
hint("Permissions, events, CRON and timeouts dont apply when running locally.");
9288

9389
await dockerCleanup();
9490

@@ -116,22 +112,17 @@ const runFunction = async ({ port, functionId, noVariables, noReload, userId } =
116112

117113
const variables = {};
118114
if(!noVariables) {
119-
if (globalConfig.getEndpoint() === '' || globalConfig.getCookie() === '') {
120-
error("No user is signed in. To sign in, run: appwrite login. Function will run locally, but will not have your function's environment variables set.");
121-
} else {
122-
try {
123-
const { variables: remoteVariables } = await paginate(functionsListVariables, {
124-
functionId: func['$id'],
125-
parseOutput: false
126-
}, 100, 'variables');
127-
128-
remoteVariables.forEach((v) => {
129-
variables[v.key] = v.value;
130-
});
131-
} catch(err) {
132-
log("Could not fetch remote variables: " + err.message);
133-
log("Function will run locally, but will not have your function's environment variables set.");
134-
}
115+
try {
116+
const { variables: remoteVariables } = await paginate(functionsListVariables, {
117+
functionId: func['$id'],
118+
parseOutput: false
119+
}, 100, 'variables');
120+
121+
remoteVariables.forEach((v) => {
122+
variables[v.key] = v.value;
123+
});
124+
} catch(err) {
125+
warn("Remote variables could not be feched. Production environment variables will not be avaiable. Reason: " + err.message);
135126
}
136127
}
137128

@@ -143,7 +134,11 @@ const runFunction = async ({ port, functionId, noVariables, noReload, userId } =
143134
variables['APPWRITE_FUNCTION_RUNTIME_NAME'] = runtimeNames[runtimeName] ?? '';
144135
variables['APPWRITE_FUNCTION_RUNTIME_VERSION'] = func.runtime;
145136

146-
await JwtManager.setup(userId);
137+
try {
138+
await JwtManager.setup(userId);
139+
} catch(err) {
140+
warn("Dynamic API key could not be generated. Header x-appwrite-key will not be set. Reason: " + err.message);
141+
}
147142

148143
const headers = {};
149144
headers['x-appwrite-key'] = JwtManager.functionJwt ?? '';
@@ -155,13 +150,17 @@ const runFunction = async ({ port, functionId, noVariables, noReload, userId } =
155150

156151
await dockerPull(func);
157152
await dockerBuild(func, variables);
153+
154+
log('Starting function using Docker ...');
155+
hint('Function automatically restarts when you edit your code.');
156+
158157
await dockerStart(func, variables, port);
159158

160159
new Tail(logsPath).on("line", function(data) {
161-
console.log(data);
160+
process.stdout.write(chalk.white.dim(`${data}\n`));
162161
});
163162
new Tail(errorsPath).on("line", function(data) {
164-
console.log(data);
163+
process.stdout.write(chalk.white.dim(`${data}\n`));
165164
});
166165

167166
if(!noReload) {
@@ -177,23 +176,16 @@ const runFunction = async ({ port, functionId, noVariables, noReload, userId } =
177176
Queue.events.on('reload', async ({ files }) => {
178177
Queue.lock();
179178

180-
log('Live-reloading due to file changes: ');
181-
for(const file of files) {
182-
log(`- ${file}`);
183-
}
184-
185179
try {
186-
log('Stopping the function ...');
187-
188-
await dockerStopActive();
180+
await dockerStop(func.$id);
189181

190182
const dependencyFile = files.find((filePath) => tool.dependencyFiles.includes(filePath));
191183
if(tool.isCompiled || dependencyFile) {
192-
log(`Rebuilding the function due to cange in ${dependencyFile} ...`);
184+
log(`Rebuilding the function ...`);
193185
await dockerBuild(func, variables);
194186
await dockerStart(func, variables, port);
195187
} else {
196-
log('Hot-swapping function files ...');
188+
log('Hot-swapping function.. Files with change are ' + files.join(', '));
197189

198190
const functionPath = path.join(process.cwd(), func.path);
199191
const hotSwapPath = path.join(functionPath, '.appwrite/hot-swap');

templates/cli/lib/config.js.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ class Global extends Config {
520520
const current = this.getCurrentSession();
521521

522522
if (current) {
523-
const config = this.get(current);
523+
const config = this.get(current) ?? {};
524524

525525
return config[key] !== undefined;
526526
}
@@ -530,7 +530,7 @@ class Global extends Config {
530530
const current = this.getCurrentSession();
531531

532532
if (current) {
533-
const config = this.get(current);
533+
const config = this.get(current) ?? {};
534534

535535
return config[key];
536536
}

templates/cli/lib/emulation/docker.js.twig

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1+
const chalk = require('chalk');
12
const childProcess = require('child_process');
23
const { localConfig } = require("../config");
34
const path = require('path');
45
const fs = require('fs');
5-
const { log,success } = require("../parser");
6+
const { log, success, hint } = require("../parser");
67
const { openRuntimesVersion, systemTools } = require("./utils");
7-
const ID = require("../id");
8-
9-
const activeDockerIds = {};
108

119
async function dockerStop(id) {
12-
delete activeDockerIds[id];
1310
const stopProcess = childProcess.spawn('docker', ['rm', '--force', id], {
1411
stdio: 'pipe',
1512
});
@@ -18,20 +15,42 @@ async function dockerStop(id) {
1815
}
1916

2017
async function dockerPull(func) {
21-
log('Pulling Docker image of function runtime ...');
22-
2318
const runtimeChunks = func.runtime.split("-");
2419
const runtimeVersion = runtimeChunks.pop();
2520
const runtimeName = runtimeChunks.join("-");
2621
const imageName = `openruntimes/${runtimeName}:${openRuntimesVersion}-${runtimeVersion}`;
2722

28-
const pullProcess = childProcess.spawn('docker', ['pull', imageName], {
23+
const checkProcess = childProcess.spawn('docker', ['images', '--format', 'json', imageName], {
2924
stdio: 'pipe',
3025
pwd: path.join(process.cwd(), func.path)
3126
});
3227

33-
pullProcess.stderr.on('data', (data) => {
34-
process.stderr.write(`\n${data}$ `);
28+
let hasImage = false;
29+
30+
checkProcess.stdout.on('data', (data) => {
31+
if(data) {
32+
hasImage = false;
33+
}
34+
});
35+
36+
checkProcess.stderr.on('data', (data) => {
37+
if(data) {
38+
hasImage = false;
39+
}
40+
});
41+
42+
await new Promise((res) => { checkProcess.on('close', res) });
43+
44+
if(hasImage) {
45+
return;
46+
}
47+
48+
log('Pulling Docker image ...');
49+
hint('This may take a few minutes, but we only need to do this once.');
50+
51+
const pullProcess = childProcess.spawn('docker', ['pull', imageName], {
52+
stdio: 'pipe',
53+
pwd: path.join(process.cwd(), func.path)
3554
});
3655

3756
await new Promise((res) => { pullProcess.on('close', res) });
@@ -47,14 +66,15 @@ async function dockerBuild(func, variables) {
4766

4867
const functionDir = path.join(process.cwd(), func.path);
4968

50-
const id = ID.unique();
69+
const id = func.$id;
5170

5271
const params = [ 'run' ];
5372
params.push('--name', id);
5473
params.push('-v', `${functionDir}/:/mnt/code:rw`);
5574
params.push('-e', 'APPWRITE_ENV=development');
5675
params.push('-e', 'OPEN_RUNTIMES_ENV=development');
5776
params.push('-e', 'OPEN_RUNTIMES_SECRET=');
77+
params.push('-l', 'appwrite-env=dev');
5878
params.push('-e', `OPEN_RUNTIMES_ENTRYPOINT=${func.entrypoint}`);
5979

6080
for(const k of Object.keys(variables)) {
@@ -69,11 +89,11 @@ async function dockerBuild(func, variables) {
6989
});
7090

7191
buildProcess.stdout.on('data', (data) => {
72-
process.stdout.write(`\n${data}`);
92+
process.stdout.write(chalk.white.dim(`${data}\n`));
7393
});
7494

7595
buildProcess.stderr.on('data', (data) => {
76-
process.stderr.write(`\n${data}`);
96+
process.stderr.write(chalk.white.dim(`${data}\n`));
7797
});
7898

7999
await new Promise((res) => { buildProcess.on('close', res) });
@@ -91,14 +111,7 @@ async function dockerBuild(func, variables) {
91111

92112
await new Promise((res) => { copyProcess.on('close', res) });
93113

94-
const cleanupProcess = childProcess.spawn('docker', ['rm', '--force', id], {
95-
stdio: 'pipe',
96-
pwd: functionDir
97-
});
98-
99-
await new Promise((res) => { cleanupProcess.on('close', res) });
100-
101-
delete activeDockerIds[id];
114+
await dockerStop(id);
102115

103116
const tempPath = path.join(process.cwd(), func.path, 'code.tar.gz');
104117
if (fs.existsSync(tempPath)) {
@@ -107,15 +120,6 @@ async function dockerBuild(func, variables) {
107120
}
108121

109122
async function dockerStart(func, variables, port) {
110-
log('Starting function using Docker ...');
111-
112-
log("Permissions, events, CRON and timeouts dont apply when running locally.");
113-
114-
log('💡 Hint: Function automatically restarts when you edit your code.');
115-
116-
success(`Visit http://localhost:${port}/ to execute your function.`);
117-
118-
119123
const runtimeChunks = func.runtime.split("-");
120124
const runtimeVersion = runtimeChunks.pop();
121125
const runtimeName = runtimeChunks.join("-");
@@ -125,13 +129,14 @@ async function dockerStart(func, variables, port) {
125129

126130
const functionDir = path.join(process.cwd(), func.path);
127131

128-
const id = ID.unique();
132+
const id = func.$id;
129133

130134
const params = [ 'run' ];
131135
params.push('--rm');
132136
params.push('-d');
133137
params.push('--name', id);
134138
params.push('-p', `${port}:3000`);
139+
params.push('-l', 'appwrite-env=dev');
135140
params.push('-e', 'APPWRITE_ENV=development');
136141
params.push('-e', 'OPEN_RUNTIMES_ENV=development');
137142
params.push('-e', 'OPEN_RUNTIMES_SECRET=');
@@ -150,11 +155,11 @@ async function dockerStart(func, variables, port) {
150155
pwd: functionDir
151156
});
152157

153-
activeDockerIds[id] = true;
158+
success(`Visit http://localhost:${port}/ to execute your function.`);
154159
}
155160

156161
async function dockerCleanup() {
157-
await dockerStop();
162+
await dockerStopActive();
158163

159164
const functions = localConfig.getFunctions();
160165
for(const func of functions) {
@@ -171,17 +176,40 @@ async function dockerCleanup() {
171176
}
172177

173178
async function dockerStopActive() {
174-
const ids = Object.keys(activeDockerIds);
175-
for await (const id of ids) {
179+
const listProcess = childProcess.spawn('docker', ['ps', '-a', '-q', '--filter', 'label=appwrite-env=dev'], {
180+
stdio: 'pipe',
181+
});
182+
183+
const ids = [];
184+
function handleOutput(data) {
185+
const list = data.toString().split('\n');
186+
for(const id of list) {
187+
if(id && !id.includes(' ')) {
188+
ids.push(id);
189+
}
190+
}
191+
}
192+
193+
listProcess.stdout.on('data', (data) => {
194+
handleOutput(data);
195+
});
196+
197+
listProcess.stderr.on('data', (data) => {
198+
handleOutput(data);
199+
});
200+
201+
await new Promise((res) => { listProcess.on('close', res) });
202+
203+
for(const id of ids) {
176204
await dockerStop(id);
177205
}
178206
}
179207

180208
module.exports = {
181-
dockerStop,
182209
dockerPull,
183210
dockerBuild,
184211
dockerStart,
185212
dockerCleanup,
186213
dockerStopActive,
214+
dockerStop,
187215
}

templates/cli/lib/emulation/utils.js.twig

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ const EventEmitter = require('node:events');
22
const { projectsCreateJWT } = require('../commands/projects');
33
const { localConfig } = require("../config");
44

5-
6-
const openRuntimesVersion = 'v3';
5+
const openRuntimesVersion = 'v4';
76

87
const runtimeNames = {
98
'node': 'Node.js',
@@ -17,7 +16,8 @@ const runtimeNames = {
1716
'java': 'Java',
1817
'swift': 'Swift',
1918
'kotlin': 'Kotlin',
20-
'bun': 'Bun'
19+
'bun': 'Bun',
20+
'go': 'Go',
2121
};
2222

2323
const systemTools = {
@@ -81,6 +81,11 @@ const systemTools = {
8181
startCommand: "bun src/server.ts",
8282
dependencyFiles: [ "package.json", "package-lock.json", "bun.lockb" ]
8383
},
84+
'go': {
85+
isCompiled: true,
86+
startCommand: "src/function/server",
87+
dependencyFiles: [ ]
88+
},
8489
};
8590

8691
const JwtManager = {

0 commit comments

Comments
 (0)