Skip to content

Commit 3a47c66

Browse files
committed
feat(cli): Pulling function code and definition
1 parent c90817e commit 3a47c66

File tree

5 files changed

+117
-17
lines changed

5 files changed

+117
-17
lines changed

templates/cli/base/params.twig

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
if (!fs.lstatSync(folderPath).isDirectory()) {
1212
throw new Error('The path is not a directory.');
1313
}
14-
14+
1515
const ignorer = ignore();
1616

1717
const func = localConfig.getFunction(functionId);
@@ -23,7 +23,7 @@
2323
ignorer.add(fs.readFileSync(pathLib.join({{ parameter.name | caseCamel | escapeKeyword }}, '.gitignore')).toString());
2424
log('Ignoring files in .gitignore');
2525
}
26-
26+
2727
const files = getAllFiles({{ parameter.name | caseCamel | escapeKeyword }}).map((file) => pathLib.relative({{ parameter.name | caseCamel | escapeKeyword }}, file)).filter((file) => !ignorer.ignores(file));
2828

2929
await tar
@@ -77,8 +77,10 @@
7777
{% endif %}
7878
{% endfor %}
7979
{% if method.type == 'location' %}
80-
payload['project'] = localConfig.getProject().projectId
81-
payload['key'] = globalConfig.getKey();
82-
const queryParams = new URLSearchParams(payload);
83-
apiPath = `${globalConfig.getEndpoint()}${apiPath}?${queryParams.toString()}`;
84-
{% endif %}
80+
if (!overrideForCli) {
81+
payload['project'] = localConfig.getProject().projectId
82+
payload['key'] = globalConfig.getKey();
83+
const queryParams = new URLSearchParams(payload);
84+
apiPath = `${globalConfig.getEndpoint()}${apiPath}?${queryParams.toString()}`;
85+
}
86+
{% endif %}

templates/cli/base/requests/api.twig

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@
1010
}, payload{% if method.type == 'location' %}, 'arraybuffer'{% endif %});
1111

1212
{% if method.type == 'location' %}
13+
if (overrideForCli) {
14+
response = Buffer.from(response);
15+
}
16+
1317
fs.writeFileSync(destination, response);
1418

1519
{% endif %}
1620
if (parseOutput) {
1721
parse(response)
1822
success()
1923
}
20-
21-
return response;
24+
25+
return response;

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const {{ service.name | caseLower }} = new Command("{{ service.name | caseLower
4545
{% for parameter in method.parameters.all %}
4646
* @property {{ "{" }}{{ parameter | typeName }}{{ "}" }} {{ parameter.name | caseCamel | escapeKeyword }} {{ parameter.description | replace({'`':'\''}) | replace({'\n':' '}) | replace({'\n \n':' '}) }}
4747
{% endfor %}
48+
* @property {boolean} overrideForCli
4849
* @property {boolean} parseOutput
4950
* @property {libClient | undefined} sdk
5051
{% if 'multipart/form-data' in method.consumes %}
@@ -58,7 +59,7 @@ const {{ service.name | caseLower }} = new Command("{{ service.name | caseLower
5859
/**
5960
* @param {{ "{" }}{{ service.name | caseUcfirst }}{{ method.name | caseUcfirst }}RequestParams{{ "}" }} params
6061
*/
61-
const {{ service.name | caseLower }}{{ method.name | caseUcfirst }} = async ({ {% for parameter in method.parameters.all %}{{ parameter.name | caseCamel | escapeKeyword }}, {% endfor %}parseOutput = true, sdk = undefined{% if 'multipart/form-data' in method.consumes %}, onProgress = () => {}{% endif %}{% if method.type == 'location' %}, destination{% endif %}}) => {
62+
const {{ service.name | caseLower }}{{ method.name | caseUcfirst }} = async ({ {% for parameter in method.parameters.all %}{{ parameter.name | caseCamel | escapeKeyword }}, {% endfor %}parseOutput = true, overrideForCli = false, sdk = undefined{% if 'multipart/form-data' in method.consumes %}, onProgress = () => {}{% endif %}{% if method.type == 'location' %}, destination{% endif %}}) => {
6263
let client = !sdk ? await {% if service.name == "projects" %}sdkForConsole(){% else %}sdkForProject(){% endif %} : sdk;
6364
let apiPath = '{{ method.path }}'{% for parameter in method.parameters.path %}.replace('{{ '{' }}{{ parameter.name | caseCamel }}{{ '}' }}', {{ parameter.name | caseCamel | escapeKeyword }}){% endfor %};
6465
{{ include ('cli/base/params.twig') }}
@@ -90,4 +91,4 @@ module.exports = {
9091
{{ service.name | caseLower }}{{ method.name | caseUcfirst }}{% if not loop.last %},{% endif %}
9192

9293
{% endfor %}
93-
};
94+
};

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

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
const fs = require("fs");
2+
const tar = require("tar");
13
const { Command } = require("commander");
24
const inquirer = require("inquirer");
35
const { teamsCreate, teamsList } = require("./teams");
46
const { projectsCreate } = require("./projects");
7+
const { functionsList, functionsDownloadDeployment } = require("./functions");
58
const { databasesGet, databasesListCollections, databasesList } = require("./databases");
69
const { storageListBuckets } = require("./storage");
710
const { sdkForConsole } = require("../sdks");
811
const { localConfig } = require("../config");
912
const ID = require("../id");
1013
const { paginate } = require("../paginate");
11-
const { questionsPullProject, questionsPullCollection } = require("../questions");
14+
const { questionsPullProject, questionsPullCollection, questionsPullFunctions } = require("../questions");
1215
const { success, log, actionRunner, commandDescriptions } = require("../parser");
1316

1417
const pull = new Command("pull")
@@ -28,6 +31,64 @@ const pullProject = async () => {
2831
success();
2932
}
3033

34+
const pullFunctions = async ({ all, yes } = {}) => {
35+
let functions = [];
36+
let questions = questionsPullFunctions;
37+
38+
const localFunctions = localConfig.getFunctions();
39+
40+
if (all) {
41+
questions = yes ? [] : questionsPullFunctions[1];
42+
functions = (await paginate(functionsList, { parseOutput: false }, 100, 'functions')).functions;
43+
}
44+
45+
const answers = await inquirer.prompt(questions);
46+
47+
const overridingLocalChanges = yes ?? answers.override.toLowerCase() === "yes";
48+
const selectedFunctions = functions.length === 0 ? answers.functions : functions;
49+
50+
for (let func of selectedFunctions) {
51+
const functionExistLocally = localFunctions.find((localFunc) => localFunc['$id'] === func['$id']) !== undefined;
52+
53+
if (!overridingLocalChanges && functionExistLocally) {
54+
log(`Skipping locally found implementation of ${func['name']}`)
55+
continue;
56+
}
57+
if (functionExistLocally) {
58+
localConfig.updateFunction(func['$id'], func);
59+
} else {
60+
func['path'] = `functions/${func['$id']}`;
61+
localConfig.addFunction(func);
62+
}
63+
64+
const localFunction = localFunctions.find((localFunc) => localFunc['$id'] === func['$id']);
65+
66+
if (localFunction['deployment'] === '') {
67+
continue
68+
}
69+
70+
const compressedFileName = `${+new Date()}.tar.gz`
71+
72+
await functionsDownloadDeployment({
73+
functionId: func['$id'],
74+
deploymentId: func['deployment'],
75+
destination: compressedFileName,
76+
overrideForCli: true,
77+
parseOutput: false
78+
})
79+
80+
tar.extract({
81+
sync: true,
82+
cwd: localFunction['path'],
83+
file: compressedFileName,
84+
strict: false,
85+
});
86+
87+
fs.rmSync(compressedFileName);
88+
success(`Pulled ${func['name']} code and definition`)
89+
}
90+
}
91+
3192
const pullCollection = async ({ all, databaseId } = {}) => {
3293
const databaseIds = [];
3394

@@ -104,14 +165,21 @@ const pullTeam = async () => {
104165

105166
pull
106167
.command("project")
107-
.description("Pulling your {{ spec.title|caseUcfirst }} project")
168+
.description("Pulling your Appwrite project")
108169
.action(actionRunner(pullProject));
109170

171+
pull
172+
.command("function")
173+
.description(`Pulling your Appwrite functions`)
174+
.option(`--yes`, `Flag to confirm all warnings`)
175+
.option(`--all`, `Flag to pull all functions`)
176+
.action(actionRunner(pullFunctions));
177+
110178
pull
111179
.command("collection")
112-
.description("Pulling your {{ spec.title|caseUcfirst }} collections")
180+
.description("Pulling your Appwrite collections")
113181
.option(`--databaseId <databaseId>`, `Database ID`)
114-
.option(`--all`, `Flag to pullialize all databases`)
182+
.option(`--all`, `Flag to pull all databases`)
115183
.action(actionRunner(pullCollection))
116184

117185
pull

templates/cli/lib/questions.js.twig

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
const { localConfig } = require('./config');
22
const { projectsList } = require('./commands/projects');
33
const { teamsList } = require('./commands/teams');
4-
const { functionsListRuntimes } = require('./commands/functions');
4+
const { functionsListRuntimes, functionsList } = require('./commands/functions');
55
const { accountListMfaFactors } = require("./commands/account");
66
const { sdkForConsole } = require("./sdks");
77
const { validateRequired } = require("./validations");
88
const { paginate } = require('./paginate');
9-
9+
const chalk = require('chalk');
1010
const { databasesList } = require('./commands/databases');
1111
const JSONbig = require("json-bigint")({ storeAsString: false });
1212

@@ -311,6 +311,30 @@ const questionsPullProject = [
311311
}
312312
];
313313

314+
315+
const questionsPullFunctions = [
316+
{
317+
type: "checkbox",
318+
name: "functions",
319+
message: "Which functions would you like to pull?",
320+
choices: async () => {
321+
const { functions } = await paginate(functionsList, { parseOutput: false }, 100, 'functions');
322+
323+
return functions.map(func => {
324+
return {
325+
name: `${func.name} (${func.$id})`,
326+
value: func
327+
}
328+
});
329+
}
330+
},
331+
{
332+
type: "input",
333+
name: "override",
334+
message: `Do you want to override local functions code and definition? ${chalk.red('all local changes will lost!')} Type "YES" to confirm.`
335+
}
336+
];
337+
314338
const questionsPullCollection = [
315339
{
316340
type: "checkbox",
@@ -539,6 +563,7 @@ module.exports = {
539563
questionsCreateCollection,
540564
questionsCreateMessagingTopic,
541565
questionsPullProject,
566+
questionsPullFunctions,
542567
questionsLogin,
543568
questionsPullCollection,
544569
questionsPushFunctions,

0 commit comments

Comments
 (0)