appwrite-cli 6.0.0-rc.3 → 6.0.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/docs/examples/account/delete-mfa-authenticator.md +1 -2
- package/install.ps1 +2 -2
- package/install.sh +1 -1
- package/lib/client.js +2 -2
- package/lib/commands/account.js +66 -71
- package/lib/commands/avatars.js +9 -9
- package/lib/commands/databases.js +140 -140
- package/lib/commands/functions.js +69 -69
- package/lib/commands/generic.js +4 -3
- package/lib/commands/health.js +22 -22
- package/lib/commands/init.js +4 -3
- package/lib/commands/locale.js +7 -7
- package/lib/commands/messaging.js +160 -160
- package/lib/commands/migrations.js +28 -28
- package/lib/commands/project.js +11 -11
- package/lib/commands/projects.js +122 -122
- package/lib/commands/proxy.js +10 -10
- package/lib/commands/pull.js +5 -4
- package/lib/commands/push.js +310 -98
- package/lib/commands/run.js +48 -8
- package/lib/commands/storage.js +44 -44
- package/lib/commands/teams.js +29 -29
- package/lib/commands/users.js +99 -99
- package/lib/commands/vcs.js +27 -27
- package/lib/config.js +22 -10
- package/lib/emulation/docker.js +78 -5
- package/lib/parser.js +3 -14
- package/lib/questions.js +16 -20
- package/lib/spinner.js +1 -0
- package/package.json +1 -1
- package/scoop/appwrite.json +3 -3
package/lib/commands/push.js
CHANGED
|
@@ -2,13 +2,13 @@ const chalk = require('chalk');
|
|
|
2
2
|
const inquirer = require("inquirer");
|
|
3
3
|
const JSONbig = require("json-bigint")({ storeAsString: false });
|
|
4
4
|
const { Command } = require("commander");
|
|
5
|
-
const { localConfig, globalConfig } = require("../config");
|
|
5
|
+
const { localConfig, globalConfig, KeysAttributes, KeysFunction, whitelistKeys, KeysTopics, KeysStorage, KeysTeams, } = require("../config");
|
|
6
6
|
const { Spinner, SPINNER_ARC, SPINNER_DOTS } = require('../spinner');
|
|
7
7
|
const { paginate } = require('../paginate');
|
|
8
|
-
const { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsGetEntrypoint, questionsPushCollections,
|
|
9
|
-
const { cliConfig, actionRunner, success, warn, log, error, commandDescriptions, drawTable } = require("../parser");
|
|
8
|
+
const { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsGetEntrypoint, questionsPushCollections, questionPushChanges, questionsPushMessagingTopics, questionsPushResources } = require("../questions");
|
|
9
|
+
const { cliConfig, actionRunner, success, warn, log, hint, error, commandDescriptions, drawTable } = require("../parser");
|
|
10
10
|
const { proxyListRules } = require('./proxy');
|
|
11
|
-
const { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment,
|
|
11
|
+
const { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment, functionsGetDeployment, functionsListVariables, functionsDeleteVariable, functionsCreateVariable } = require('./functions');
|
|
12
12
|
const {
|
|
13
13
|
databasesGet,
|
|
14
14
|
databasesCreate,
|
|
@@ -37,6 +37,7 @@ const {
|
|
|
37
37
|
databasesUpdateRelationshipAttribute,
|
|
38
38
|
databasesCreateRelationshipAttribute,
|
|
39
39
|
databasesDeleteAttribute,
|
|
40
|
+
databasesDeleteIndex,
|
|
40
41
|
databasesListAttributes,
|
|
41
42
|
databasesListIndexes,
|
|
42
43
|
databasesUpdateCollection
|
|
@@ -53,6 +54,7 @@ const {
|
|
|
53
54
|
teamsCreate
|
|
54
55
|
} = require("./teams");
|
|
55
56
|
const {
|
|
57
|
+
projectsGet,
|
|
56
58
|
projectsUpdate,
|
|
57
59
|
projectsUpdateServiceStatus,
|
|
58
60
|
projectsUpdateAuthStatus,
|
|
@@ -68,8 +70,9 @@ const { checkDeployConditions } = require('../utils');
|
|
|
68
70
|
const STEP_SIZE = 100; // Resources
|
|
69
71
|
const POLL_DEBOUNCE = 2000; // Milliseconds
|
|
70
72
|
const POLL_MAX_DEBOUNCE = 1800; // Times of POLL_DEBOUNCE (1 hour)
|
|
73
|
+
const POLL_DEFAULT_VALUE = 30;
|
|
71
74
|
|
|
72
|
-
let pollMaxDebounces =
|
|
75
|
+
let pollMaxDebounces = POLL_DEFAULT_VALUE;
|
|
73
76
|
|
|
74
77
|
const changeableKeys = ['status', 'required', 'xdefault', 'elements', 'min', 'max', 'default', 'error'];
|
|
75
78
|
|
|
@@ -90,11 +93,13 @@ const awaitPools = {
|
|
|
90
93
|
return true;
|
|
91
94
|
}
|
|
92
95
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
|
|
97
|
+
let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
|
|
98
|
+
if (steps > 1 && iteration === 1) {
|
|
99
|
+
pollMaxDebounces *= steps;
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
log('Found a large number of attributes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
102
|
+
}
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
@@ -121,11 +126,13 @@ const awaitPools = {
|
|
|
121
126
|
return true;
|
|
122
127
|
}
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
|
|
130
|
+
let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
|
|
131
|
+
if (steps > 1 && iteration === 1) {
|
|
132
|
+
pollMaxDebounces *= steps;
|
|
127
133
|
|
|
128
|
-
|
|
134
|
+
log('Found a large number of indexes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
135
|
+
}
|
|
129
136
|
}
|
|
130
137
|
|
|
131
138
|
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
@@ -151,11 +158,13 @@ const awaitPools = {
|
|
|
151
158
|
return true;
|
|
152
159
|
}
|
|
153
160
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
|
|
162
|
+
let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
|
|
163
|
+
if (steps > 1 && iteration === 1) {
|
|
164
|
+
pollMaxDebounces *= steps;
|
|
157
165
|
|
|
158
|
-
|
|
166
|
+
log('Found a large number of variables, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
167
|
+
}
|
|
159
168
|
}
|
|
160
169
|
|
|
161
170
|
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
@@ -170,11 +179,13 @@ const awaitPools = {
|
|
|
170
179
|
return false;
|
|
171
180
|
}
|
|
172
181
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
182
|
+
if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
|
|
183
|
+
let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE));
|
|
184
|
+
if (steps > 1 && iteration === 1) {
|
|
185
|
+
pollMaxDebounces *= steps;
|
|
176
186
|
|
|
177
|
-
|
|
187
|
+
log('Found a large number of attributes to be deleted. Increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
188
|
+
}
|
|
178
189
|
}
|
|
179
190
|
|
|
180
191
|
const { attributes } = await paginate(databasesListAttributes, {
|
|
@@ -203,11 +214,13 @@ const awaitPools = {
|
|
|
203
214
|
return false;
|
|
204
215
|
}
|
|
205
216
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
217
|
+
if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
|
|
218
|
+
let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE));
|
|
219
|
+
if (steps > 1 && iteration === 1) {
|
|
220
|
+
pollMaxDebounces *= steps;
|
|
209
221
|
|
|
210
|
-
|
|
222
|
+
log('Creating a large number of attributes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
223
|
+
}
|
|
211
224
|
}
|
|
212
225
|
|
|
213
226
|
const { attributes } = await paginate(databasesListAttributes, {
|
|
@@ -243,16 +256,53 @@ const awaitPools = {
|
|
|
243
256
|
iteration + 1
|
|
244
257
|
);
|
|
245
258
|
},
|
|
259
|
+
deleteIndexes: async (databaseId, collectionId, indexesKeys, iteration = 1) => {
|
|
260
|
+
if (iteration > pollMaxDebounces) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
|
|
265
|
+
let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE));
|
|
266
|
+
if (steps > 1 && iteration === 1) {
|
|
267
|
+
pollMaxDebounces *= steps;
|
|
268
|
+
|
|
269
|
+
log('Found a large number of indexes to be deleted. Increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const { indexes } = await paginate(databasesListIndexes, {
|
|
274
|
+
databaseId,
|
|
275
|
+
collectionId,
|
|
276
|
+
parseOutput: false
|
|
277
|
+
}, 100, 'indexes');
|
|
278
|
+
|
|
279
|
+
const ready = indexesKeys.filter(index => indexes.includes(index.key));
|
|
280
|
+
|
|
281
|
+
if (ready.length === 0) {
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
286
|
+
|
|
287
|
+
return await awaitPools.expectIndexes(
|
|
288
|
+
databaseId,
|
|
289
|
+
collectionId,
|
|
290
|
+
indexesKeys,
|
|
291
|
+
iteration + 1
|
|
292
|
+
);
|
|
293
|
+
},
|
|
246
294
|
expectIndexes: async (databaseId, collectionId, indexKeys, iteration = 1) => {
|
|
247
295
|
if (iteration > pollMaxDebounces) {
|
|
248
296
|
return false;
|
|
249
297
|
}
|
|
250
298
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
299
|
+
if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
|
|
300
|
+
let steps = Math.max(1, Math.ceil(indexKeys.length / STEP_SIZE));
|
|
301
|
+
if (steps > 1 && iteration === 1) {
|
|
302
|
+
pollMaxDebounces *= steps;
|
|
254
303
|
|
|
255
|
-
|
|
304
|
+
log('Creating a large number of indexes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
305
|
+
}
|
|
256
306
|
}
|
|
257
307
|
|
|
258
308
|
const { indexes } = await paginate(databasesListIndexes, {
|
|
@@ -290,6 +340,73 @@ const awaitPools = {
|
|
|
290
340
|
},
|
|
291
341
|
}
|
|
292
342
|
|
|
343
|
+
const approveChanges = async (resource, resourceGetFunction, keys, resourceName, resourcePlural) => {
|
|
344
|
+
log('Checking for changes');
|
|
345
|
+
const changes = [];
|
|
346
|
+
|
|
347
|
+
await Promise.all(resource.map(async (localResource) => {
|
|
348
|
+
try {
|
|
349
|
+
const remoteResource = await resourceGetFunction({
|
|
350
|
+
[resourceName]: localResource['$id'],
|
|
351
|
+
parseOutput: false,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
for (let [key, value] of Object.entries(whitelistKeys(remoteResource, keys))) {
|
|
355
|
+
if (Array.isArray(value) && Array.isArray(localResource[key])) {
|
|
356
|
+
if (JSON.stringify(value) !== JSON.stringify(localResource[key])) {
|
|
357
|
+
changes.push({
|
|
358
|
+
id: localResource['$id'],
|
|
359
|
+
key,
|
|
360
|
+
remote: chalk.red(value.join('\n')),
|
|
361
|
+
local: chalk.green(localResource[key].join('\n'))
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
} else if (value !== localResource[key]) {
|
|
365
|
+
changes.push({
|
|
366
|
+
id: localResource['$id'],
|
|
367
|
+
key,
|
|
368
|
+
remote: chalk.red(value),
|
|
369
|
+
local: chalk.green(localResource[key])
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
} catch (e) {
|
|
374
|
+
if (Number(e.code) !== 404) {
|
|
375
|
+
throw e;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}));
|
|
379
|
+
|
|
380
|
+
if (changes.length === 0) {
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
drawTable(changes);
|
|
385
|
+
if (!cliConfig.force) {
|
|
386
|
+
const answers = await inquirer.prompt(questionPushChanges);
|
|
387
|
+
if (answers.changes.toLowerCase() === 'yes') {
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
success(`Successfully pushed 0 ${resourcePlural}.`);
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const getObjectChanges = (remote, local, index, what) => {
|
|
397
|
+
const changes = [];
|
|
398
|
+
|
|
399
|
+
if (remote[index] && local[index]) {
|
|
400
|
+
for (let [service, status] of Object.entries(remote[index])) {
|
|
401
|
+
if (status !== local[index][service]) {
|
|
402
|
+
changes.push({ group: what,setting: service, remote: chalk.red(status), local: chalk.green(local[index][service]) })
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return changes;
|
|
408
|
+
}
|
|
409
|
+
|
|
293
410
|
const createAttribute = async (databaseId, collectionId, attribute) => {
|
|
294
411
|
switch (attribute.type) {
|
|
295
412
|
case 'string':
|
|
@@ -523,8 +640,18 @@ const updateAttribute = async (databaseId, collectionId, attribute) => {
|
|
|
523
640
|
})
|
|
524
641
|
}
|
|
525
642
|
}
|
|
526
|
-
const deleteAttribute = async (collection, attribute) => {
|
|
527
|
-
log(`Deleting attribute ${attribute.key} of ${collection.name} ( ${collection['$id']} )`);
|
|
643
|
+
const deleteAttribute = async (collection, attribute, isIndex = false) => {
|
|
644
|
+
log(`Deleting ${isIndex ? 'index' : 'attribute'} ${attribute.key} of ${collection.name} ( ${collection['$id']} )`);
|
|
645
|
+
|
|
646
|
+
if (isIndex) {
|
|
647
|
+
await databasesDeleteIndex({
|
|
648
|
+
databaseId: collection['databaseId'],
|
|
649
|
+
collectionId: collection['$id'],
|
|
650
|
+
key: attribute.key,
|
|
651
|
+
parseOutput: false
|
|
652
|
+
});
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
528
655
|
|
|
529
656
|
await databasesDeleteAttribute({
|
|
530
657
|
databaseId: collection['databaseId'],
|
|
@@ -555,6 +682,10 @@ const checkAttributeChanges = (remote, local, collection, recraeting = true) =>
|
|
|
555
682
|
let attribute = remote;
|
|
556
683
|
|
|
557
684
|
for (let key of Object.keys(remote)) {
|
|
685
|
+
if (!KeysAttributes.has(key)) {
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
|
|
558
689
|
if (changeableKeys.includes(key)) {
|
|
559
690
|
if (!recraeting) {
|
|
560
691
|
if (remote[key] !== local[key]) {
|
|
@@ -570,7 +701,12 @@ const checkAttributeChanges = (remote, local, collection, recraeting = true) =>
|
|
|
570
701
|
continue;
|
|
571
702
|
}
|
|
572
703
|
|
|
573
|
-
if (remote[key]
|
|
704
|
+
if (Array.isArray(remote[key]) && Array.isArray(local[key])) {
|
|
705
|
+
if (JSON.stringify(remote[key]) !== JSON.stringify(local[key])) {
|
|
706
|
+
const bol = reason === '' ? '' : '\n';
|
|
707
|
+
reason += `${bol}${key} changed from ${chalk.red(remote[key])} to ${chalk.green(local[key])}`;
|
|
708
|
+
}
|
|
709
|
+
} else if (remote[key] !== local[key]) {
|
|
574
710
|
const bol = reason === '' ? '' : '\n';
|
|
575
711
|
reason += `${bol}${key} changed from ${chalk.red(remote[key])} to ${chalk.green(local[key])}`;
|
|
576
712
|
}
|
|
@@ -590,7 +726,7 @@ const generateChangesObject = (attribute, collection, isAdding) => {
|
|
|
590
726
|
return {
|
|
591
727
|
key: `${chalk.yellow(attribute.key)} in ${collection.name} (${collection['$id']})`,
|
|
592
728
|
attribute: attribute,
|
|
593
|
-
reason: isAdding ? 'Field
|
|
729
|
+
reason: isAdding ? 'Field isn\'t present on the remote server' : 'Field isn\'t present on the appwrite.json file',
|
|
594
730
|
action: isAdding ? chalk.green('adding') : chalk.red('deleting')
|
|
595
731
|
};
|
|
596
732
|
|
|
@@ -599,12 +735,9 @@ const generateChangesObject = (attribute, collection, isAdding) => {
|
|
|
599
735
|
/**
|
|
600
736
|
* Filter deleted and recreated attributes,
|
|
601
737
|
* return list of attributes to create
|
|
602
|
-
* @param remoteAttributes
|
|
603
|
-
* @param localAttributes
|
|
604
|
-
* @param collection
|
|
605
738
|
* @returns {Promise<*|*[]>}
|
|
606
739
|
*/
|
|
607
|
-
const attributesToCreate = async (remoteAttributes, localAttributes, collection) => {
|
|
740
|
+
const attributesToCreate = async (remoteAttributes, localAttributes, collection, isIndex = false) => {
|
|
608
741
|
|
|
609
742
|
const deleting = remoteAttributes.filter((attribute) => !attributesContains(attribute, localAttributes)).map((attr) => generateChangesObject(attr, collection, false));
|
|
610
743
|
const adding = localAttributes.filter((attribute) => !attributesContains(attribute, remoteAttributes)).map((attr) => generateChangesObject(attr, collection, true));
|
|
@@ -626,14 +759,14 @@ const attributesToCreate = async (remoteAttributes, localAttributes, collection)
|
|
|
626
759
|
}));
|
|
627
760
|
|
|
628
761
|
if (!cliConfig.force) {
|
|
629
|
-
if (deleting.length > 0) {
|
|
762
|
+
if (deleting.length > 0 && !isIndex) {
|
|
630
763
|
log(`Attribute deletion will cause ${chalk.red('loss of data')}`);
|
|
631
764
|
}
|
|
632
|
-
if (conflicts.length > 0) {
|
|
765
|
+
if (conflicts.length > 0 && !isIndex) {
|
|
633
766
|
log(`Attribute recreation will cause ${chalk.red('loss of data')}`);
|
|
634
767
|
}
|
|
635
768
|
|
|
636
|
-
const answers = await inquirer.prompt(
|
|
769
|
+
const answers = await inquirer.prompt(questionPushChanges);
|
|
637
770
|
|
|
638
771
|
if (answers.changes.toLowerCase() !== 'yes') {
|
|
639
772
|
return changedAttributes;
|
|
@@ -642,17 +775,17 @@ const attributesToCreate = async (remoteAttributes, localAttributes, collection)
|
|
|
642
775
|
|
|
643
776
|
if (conflicts.length > 0) {
|
|
644
777
|
changedAttributes = conflicts.map((change) => change.attribute);
|
|
645
|
-
await Promise.all(changedAttributes.map((changed) => deleteAttribute(collection, changed)));
|
|
778
|
+
await Promise.all(changedAttributes.map((changed) => deleteAttribute(collection, changed, isIndex)));
|
|
646
779
|
remoteAttributes = remoteAttributes.filter((attribute) => !attributesContains(attribute, changedAttributes))
|
|
647
780
|
}
|
|
648
781
|
|
|
649
782
|
if (changes.length > 0) {
|
|
650
783
|
changedAttributes = changes.map((change) => change.attribute);
|
|
651
|
-
await Promise.all(changedAttributes.map((changed) => updateAttribute(collection['databaseId'],collection['$id'], changed)));
|
|
784
|
+
await Promise.all(changedAttributes.map((changed) => updateAttribute(collection['databaseId'], collection['$id'], changed)));
|
|
652
785
|
}
|
|
653
786
|
|
|
654
787
|
const deletingAttributes = deleting.map((change) => change.attribute);
|
|
655
|
-
await Promise.all(deletingAttributes.map((attribute) => deleteAttribute(collection, attribute)));
|
|
788
|
+
await Promise.all(deletingAttributes.map((attribute) => deleteAttribute(collection, attribute, isIndex)));
|
|
656
789
|
const attributeKeys = [...remoteAttributes.map(attribute => attribute.key), ...deletingAttributes.map(attribute => attribute.key)]
|
|
657
790
|
|
|
658
791
|
if (attributeKeys.length) {
|
|
@@ -737,6 +870,37 @@ const pushResources = async () => {
|
|
|
737
870
|
};
|
|
738
871
|
|
|
739
872
|
const pushSettings = async () => {
|
|
873
|
+
checkDeployConditions(localConfig);
|
|
874
|
+
|
|
875
|
+
try {
|
|
876
|
+
let response = await projectsGet({
|
|
877
|
+
parseOutput: false,
|
|
878
|
+
projectId: localConfig.getProject().projectId
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
const remoteSettings = localConfig.createSettingsObject(response ?? {});
|
|
882
|
+
const localSettings = localConfig.getProject().projectSettings ?? {};
|
|
883
|
+
|
|
884
|
+
log('Checking for changes');
|
|
885
|
+
const changes = [];
|
|
886
|
+
|
|
887
|
+
changes.push(...(getObjectChanges(remoteSettings, localSettings, 'services', 'Service')));
|
|
888
|
+
changes.push(...(getObjectChanges(remoteSettings['auth'] ?? {}, localSettings['auth'] ?? {}, 'methods', 'Auth method')));
|
|
889
|
+
changes.push(...(getObjectChanges(remoteSettings['auth'] ?? {}, localSettings['auth'] ?? {}, 'security', 'Auth security')));
|
|
890
|
+
|
|
891
|
+
if (changes.length > 0) {
|
|
892
|
+
drawTable(changes);
|
|
893
|
+
if (!cliConfig.force) {
|
|
894
|
+
const answers = await inquirer.prompt(questionPushChanges);
|
|
895
|
+
if (answers.changes.toLowerCase() !== 'yes') {
|
|
896
|
+
success(`Successfully pushed 0 project settings.`);
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
} catch (e) {
|
|
902
|
+
}
|
|
903
|
+
|
|
740
904
|
try {
|
|
741
905
|
log("Pushing project settings ...");
|
|
742
906
|
|
|
@@ -796,9 +960,7 @@ const pushSettings = async () => {
|
|
|
796
960
|
}
|
|
797
961
|
}
|
|
798
962
|
|
|
799
|
-
const pushFunction = async ({ functionId, async,
|
|
800
|
-
let response = {};
|
|
801
|
-
|
|
963
|
+
const pushFunction = async ({ functionId, async, code } = { returnOnZero: false }) => {
|
|
802
964
|
const functionIds = [];
|
|
803
965
|
|
|
804
966
|
if (functionId) {
|
|
@@ -806,11 +968,6 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
806
968
|
} else if (cliConfig.all) {
|
|
807
969
|
checkDeployConditions(localConfig);
|
|
808
970
|
const functions = localConfig.getFunctions();
|
|
809
|
-
if (functions.length === 0) {
|
|
810
|
-
log("No functions found.");
|
|
811
|
-
hint("Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one.");
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
814
971
|
functionIds.push(...functions.map((func) => {
|
|
815
972
|
return func.$id;
|
|
816
973
|
}));
|
|
@@ -818,7 +975,15 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
818
975
|
|
|
819
976
|
if (functionIds.length <= 0) {
|
|
820
977
|
const answers = await inquirer.prompt(questionsPushFunctions[0]);
|
|
821
|
-
|
|
978
|
+
if (answers.functions) {
|
|
979
|
+
functionIds.push(...answers.functions);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
if (functionIds.length === 0) {
|
|
984
|
+
log("No functions found.");
|
|
985
|
+
hint("Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one.");
|
|
986
|
+
return;
|
|
822
987
|
}
|
|
823
988
|
|
|
824
989
|
let functions = functionIds.map((id) => {
|
|
@@ -844,6 +1009,10 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
844
1009
|
}
|
|
845
1010
|
}
|
|
846
1011
|
|
|
1012
|
+
if (!(await approveChanges(functions, functionsGet, KeysFunction, 'functionId', 'functions'))) {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
847
1016
|
log('Pushing functions ...');
|
|
848
1017
|
|
|
849
1018
|
Spinner.start(false);
|
|
@@ -852,6 +1021,8 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
852
1021
|
const failedDeployments = [];
|
|
853
1022
|
|
|
854
1023
|
await Promise.all(functions.map(async (func) => {
|
|
1024
|
+
let response = {};
|
|
1025
|
+
|
|
855
1026
|
const ignore = func.ignore ? 'appwrite.json' : '.gitignore';
|
|
856
1027
|
let functionExists = false;
|
|
857
1028
|
let deploymentCreated = false;
|
|
@@ -859,7 +1030,6 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
859
1030
|
const updaterRow = new Spinner({ status: '', resource: func.name, id: func['$id'], end: `Ignoring using: ${ignore}` });
|
|
860
1031
|
|
|
861
1032
|
updaterRow.update({ status: 'Getting' }).startSpinner(SPINNER_DOTS);
|
|
862
|
-
|
|
863
1033
|
try {
|
|
864
1034
|
response = await functionsGet({
|
|
865
1035
|
functionId: func['$id'],
|
|
@@ -930,6 +1100,14 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
930
1100
|
}
|
|
931
1101
|
}
|
|
932
1102
|
|
|
1103
|
+
if (code === false) {
|
|
1104
|
+
successfullyPushed++;
|
|
1105
|
+
successfullyDeployed++;
|
|
1106
|
+
updaterRow.update({ status: 'Pushed' });
|
|
1107
|
+
updaterRow.stopSpinner();
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
933
1111
|
try {
|
|
934
1112
|
updaterRow.update({ status: 'Pushing' }).replaceSpinner(SPINNER_ARC);
|
|
935
1113
|
response = await functionsCreateDeployment({
|
|
@@ -961,11 +1139,6 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
961
1139
|
let pollChecks = 0;
|
|
962
1140
|
|
|
963
1141
|
while (true) {
|
|
964
|
-
if (pollChecks >= POLL_MAX_DEBOUNCE) {
|
|
965
|
-
updaterRow.update({ end: 'Deployment is taking too long. Please check the console for more details.' })
|
|
966
|
-
break;
|
|
967
|
-
}
|
|
968
|
-
|
|
969
1142
|
response = await functionsGetDeployment({
|
|
970
1143
|
functionId: func['$id'],
|
|
971
1144
|
deploymentId: deploymentId,
|
|
@@ -1004,7 +1177,7 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
1004
1177
|
}
|
|
1005
1178
|
|
|
1006
1179
|
pollChecks++;
|
|
1007
|
-
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
1180
|
+
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE * 1.5));
|
|
1008
1181
|
}
|
|
1009
1182
|
} catch (e) {
|
|
1010
1183
|
updaterRow.fail({ errorMessage: e.message ?? 'Unknown error occurred. Please try again' })
|
|
@@ -1018,15 +1191,15 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
1018
1191
|
|
|
1019
1192
|
failedDeployments.forEach((failed) => {
|
|
1020
1193
|
const { name, deployment, $id } = failed;
|
|
1021
|
-
const failUrl = `${globalConfig.getEndpoint().
|
|
1194
|
+
const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/functions/function-${$id}/deployment-${deployment}`;
|
|
1022
1195
|
|
|
1023
1196
|
error(`Deployment of ${name} has failed. Check at ${failUrl} for more details\n`);
|
|
1024
1197
|
});
|
|
1025
1198
|
|
|
1026
1199
|
if (!async) {
|
|
1027
|
-
if(successfullyPushed === 0) {
|
|
1200
|
+
if (successfullyPushed === 0) {
|
|
1028
1201
|
error('No functions were pushed.');
|
|
1029
|
-
} else if(successfullyDeployed
|
|
1202
|
+
} else if (successfullyDeployed !== successfullyPushed) {
|
|
1030
1203
|
warn(`Successfully pushed ${successfullyDeployed} of ${successfullyPushed} functions`)
|
|
1031
1204
|
} else {
|
|
1032
1205
|
success(`Successfully pushed ${successfullyPushed} functions.`);
|
|
@@ -1036,28 +1209,36 @@ const pushFunction = async ({ functionId, async, returnOnZero } = { returnOnZero
|
|
|
1036
1209
|
}
|
|
1037
1210
|
}
|
|
1038
1211
|
|
|
1039
|
-
const pushCollection = async ({ returnOnZero } = { returnOnZero: false }) => {
|
|
1212
|
+
const pushCollection = async ({ returnOnZero, attempts } = { returnOnZero: false }) => {
|
|
1040
1213
|
const collections = [];
|
|
1041
1214
|
|
|
1215
|
+
if (attempts) {
|
|
1216
|
+
pollMaxDebounces = attempts;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1042
1219
|
if (cliConfig.all) {
|
|
1043
1220
|
checkDeployConditions(localConfig);
|
|
1044
|
-
if (localConfig.getCollections().length === 0) {
|
|
1045
|
-
log("No collections found.");
|
|
1046
|
-
hint("Use 'appwrite pull collections' to synchronize existing one, or use 'appwrite init collection' to create a new one.");
|
|
1047
|
-
return;
|
|
1048
|
-
}
|
|
1049
1221
|
collections.push(...localConfig.getCollections());
|
|
1050
1222
|
} else {
|
|
1051
|
-
const answers = await inquirer.prompt(questionsPushCollections
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1223
|
+
const answers = await inquirer.prompt(questionsPushCollections)
|
|
1224
|
+
if (answers.collections) {
|
|
1225
|
+
const configCollections = new Map();
|
|
1226
|
+
localConfig.getCollections().forEach((c) => {
|
|
1227
|
+
configCollections.set(`${c['databaseId']}|${c['$id']}`, c);
|
|
1228
|
+
});
|
|
1229
|
+
answers.collections.forEach((a) => {
|
|
1230
|
+
const collection = configCollections.get(a);
|
|
1231
|
+
collections.push(collection);
|
|
1232
|
+
})
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
if (collections.length === 0) {
|
|
1237
|
+
log("No collections found.");
|
|
1238
|
+
hint("Use 'appwrite pull collections' to synchronize existing one, or use 'appwrite init collection' to create a new one.");
|
|
1239
|
+
return;
|
|
1060
1240
|
}
|
|
1241
|
+
|
|
1061
1242
|
const databases = Array.from(new Set(collections.map(collection => collection['databaseId'])));
|
|
1062
1243
|
|
|
1063
1244
|
log('Checking for changes ...');
|
|
@@ -1132,17 +1313,20 @@ const pushCollection = async ({ returnOnZero } = { returnOnZero: false }) => {
|
|
|
1132
1313
|
}
|
|
1133
1314
|
}
|
|
1134
1315
|
}))
|
|
1135
|
-
|
|
1316
|
+
let numberOfCollections = 0;
|
|
1136
1317
|
// Serialize attribute actions
|
|
1137
1318
|
for (let collection of collections) {
|
|
1138
1319
|
let attributes = collection.attributes;
|
|
1320
|
+
let indexes = collection.indexes;
|
|
1139
1321
|
|
|
1140
1322
|
if (collection.isExisted) {
|
|
1141
1323
|
attributes = await attributesToCreate(collection.remoteVersion.attributes, collection.attributes, collection);
|
|
1324
|
+
indexes = await attributesToCreate(collection.remoteVersion.indexes, collection.indexes, collection, true);
|
|
1142
1325
|
|
|
1143
|
-
if (Array.isArray(attributes) && attributes.length <= 0) {
|
|
1326
|
+
if ((Array.isArray(attributes) && attributes.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) {
|
|
1144
1327
|
continue;
|
|
1145
1328
|
}
|
|
1329
|
+
|
|
1146
1330
|
}
|
|
1147
1331
|
|
|
1148
1332
|
log(`Pushing collection ${collection.name} ( ${collection['databaseId']} - ${collection['$id']} ) attributes`)
|
|
@@ -1154,13 +1338,15 @@ const pushCollection = async ({ returnOnZero } = { returnOnZero: false }) => {
|
|
|
1154
1338
|
}
|
|
1155
1339
|
|
|
1156
1340
|
try {
|
|
1157
|
-
await createIndexes(
|
|
1341
|
+
await createIndexes(indexes, collection);
|
|
1158
1342
|
} catch (e) {
|
|
1159
1343
|
throw e;
|
|
1160
1344
|
}
|
|
1161
|
-
|
|
1345
|
+
numberOfCollections++;
|
|
1162
1346
|
success(`Pushed ${collection.name} ( ${collection['$id']} )`);
|
|
1163
1347
|
}
|
|
1348
|
+
|
|
1349
|
+
success(`Pushed ${numberOfCollections} collections`);
|
|
1164
1350
|
}
|
|
1165
1351
|
|
|
1166
1352
|
const pushBucket = async ({ returnOnZero } = { returnOnZero: false }) => {
|
|
@@ -1171,17 +1357,20 @@ const pushBucket = async ({ returnOnZero } = { returnOnZero: false }) => {
|
|
|
1171
1357
|
|
|
1172
1358
|
if (cliConfig.all) {
|
|
1173
1359
|
checkDeployConditions(localConfig);
|
|
1174
|
-
if (configBuckets.length === 0) {
|
|
1175
|
-
log("No buckets found.");
|
|
1176
|
-
hint("Use 'appwrite pull buckets' to synchronize existing one, or use 'appwrite init bucket' to create a new one.");
|
|
1177
|
-
return;
|
|
1178
|
-
}
|
|
1179
1360
|
bucketIds.push(...configBuckets.map((b) => b.$id));
|
|
1180
1361
|
}
|
|
1181
1362
|
|
|
1182
1363
|
if (bucketIds.length === 0) {
|
|
1183
1364
|
const answers = await inquirer.prompt(questionsPushBuckets[0])
|
|
1184
|
-
|
|
1365
|
+
if (answers.buckets) {
|
|
1366
|
+
bucketIds.push(...answers.buckets);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
if (bucketIds.length === 0) {
|
|
1371
|
+
log("No buckets found.");
|
|
1372
|
+
hint("Use 'appwrite pull buckets' to synchronize existing one, or use 'appwrite init bucket' to create a new one.");
|
|
1373
|
+
return;
|
|
1185
1374
|
}
|
|
1186
1375
|
|
|
1187
1376
|
let buckets = [];
|
|
@@ -1191,6 +1380,10 @@ const pushBucket = async ({ returnOnZero } = { returnOnZero: false }) => {
|
|
|
1191
1380
|
buckets.push(...idBuckets);
|
|
1192
1381
|
}
|
|
1193
1382
|
|
|
1383
|
+
if (!(await approveChanges(buckets, storageGetBucket, KeysStorage, 'bucketId', 'buckets'))) {
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1194
1387
|
log('Pushing buckets ...');
|
|
1195
1388
|
|
|
1196
1389
|
for (let bucket of buckets) {
|
|
@@ -1249,16 +1442,20 @@ const pushTeam = async ({ returnOnZero } = { returnOnZero: false }) => {
|
|
|
1249
1442
|
|
|
1250
1443
|
if (cliConfig.all) {
|
|
1251
1444
|
checkDeployConditions(localConfig);
|
|
1252
|
-
if (configTeams.length === 0) {
|
|
1253
|
-
log("No teams found.");
|
|
1254
|
-
hint("Use 'appwrite pull teams' to synchronize existing one, or use 'appwrite init team' to create a new one.");
|
|
1255
|
-
}
|
|
1256
1445
|
teamIds.push(...configTeams.map((t) => t.$id));
|
|
1257
1446
|
}
|
|
1258
1447
|
|
|
1259
1448
|
if (teamIds.length === 0) {
|
|
1260
1449
|
const answers = await inquirer.prompt(questionsPushTeams[0])
|
|
1261
|
-
|
|
1450
|
+
if (answers.teams) {
|
|
1451
|
+
teamIds.push(...answers.teams);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
if (teamIds.length === 0) {
|
|
1456
|
+
log("No teams found.");
|
|
1457
|
+
hint("Use 'appwrite pull teams' to synchronize existing one, or use 'appwrite init team' to create a new one.");
|
|
1458
|
+
return;
|
|
1262
1459
|
}
|
|
1263
1460
|
|
|
1264
1461
|
let teams = [];
|
|
@@ -1268,6 +1465,11 @@ const pushTeam = async ({ returnOnZero } = { returnOnZero: false }) => {
|
|
|
1268
1465
|
teams.push(...idTeams);
|
|
1269
1466
|
}
|
|
1270
1467
|
|
|
1468
|
+
if (!(await approveChanges(teams, teamsGet, KeysTeams, 'teamId', 'teams'))) {
|
|
1469
|
+
return;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
|
|
1271
1473
|
log('Pushing teams ...');
|
|
1272
1474
|
|
|
1273
1475
|
for (let team of teams) {
|
|
@@ -1311,16 +1513,20 @@ const pushMessagingTopic = async ({ returnOnZero } = { returnOnZero: false }) =>
|
|
|
1311
1513
|
|
|
1312
1514
|
if (cliConfig.all) {
|
|
1313
1515
|
checkDeployConditions(localConfig);
|
|
1314
|
-
if (configTopics.length === 0) {
|
|
1315
|
-
log("No topics found.");
|
|
1316
|
-
hint("Use 'appwrite pull topics' to synchronize existing one, or use 'appwrite init topic' to create a new one.");
|
|
1317
|
-
}
|
|
1318
1516
|
topicsIds.push(...configTopics.map((b) => b.$id));
|
|
1319
1517
|
}
|
|
1320
1518
|
|
|
1321
1519
|
if (topicsIds.length === 0) {
|
|
1322
1520
|
const answers = await inquirer.prompt(questionsPushMessagingTopics[0])
|
|
1323
|
-
|
|
1521
|
+
if (answers.topics) {
|
|
1522
|
+
topicsIds.push(...answers.topics);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
if (topicsIds.length === 0) {
|
|
1527
|
+
log("No topics found.");
|
|
1528
|
+
hint("Use 'appwrite pull topics' to synchronize existing one, or use 'appwrite init topic' to create a new one.");
|
|
1529
|
+
return;
|
|
1324
1530
|
}
|
|
1325
1531
|
|
|
1326
1532
|
let topics = [];
|
|
@@ -1337,6 +1543,10 @@ const pushMessagingTopic = async ({ returnOnZero } = { returnOnZero: false }) =>
|
|
|
1337
1543
|
}
|
|
1338
1544
|
}
|
|
1339
1545
|
|
|
1546
|
+
if (!(await approveChanges(topics, messagingGetTopic, KeysTopics, 'topicId', 'topics'))) {
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1340
1550
|
log('Pushing topics ...');
|
|
1341
1551
|
|
|
1342
1552
|
for (let topic of topics) {
|
|
@@ -1402,14 +1612,16 @@ push
|
|
|
1402
1612
|
.command("function")
|
|
1403
1613
|
.alias("functions")
|
|
1404
1614
|
.description("Push functions in the current directory.")
|
|
1405
|
-
.option(`-f, --
|
|
1615
|
+
.option(`-f, --function-id <function-id>`, `ID of function to run`)
|
|
1406
1616
|
.option(`-A, --async`, `Don't wait for functions deployments status`)
|
|
1617
|
+
.option("--no-code", "Don't push the function's code")
|
|
1407
1618
|
.action(actionRunner(pushFunction));
|
|
1408
1619
|
|
|
1409
1620
|
push
|
|
1410
1621
|
.command("collection")
|
|
1411
1622
|
.alias("collections")
|
|
1412
1623
|
.description("Push collections in the current project.")
|
|
1624
|
+
.option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`)
|
|
1413
1625
|
.action(actionRunner(pushCollection));
|
|
1414
1626
|
|
|
1415
1627
|
push
|