appwrite-cli 13.0.0-rc.1 → 13.0.0-rc.3
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/.github/workflows/publish.yml +68 -0
- package/CHANGELOG.md +10 -1
- package/LICENSE.md +1 -1
- package/README.md +3 -3
- package/cli.ts +152 -0
- package/dist/bundle.cjs +95813 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +145 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -142
- package/dist/index.js.map +1 -1
- package/dist/lib/client.d.ts +2 -3
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +57 -45
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/commands/config.d.ts +562 -0
- package/dist/lib/commands/config.d.ts.map +1 -0
- package/dist/lib/commands/config.js +416 -0
- package/dist/lib/commands/config.js.map +1 -0
- package/dist/lib/commands/db.d.ts +34 -0
- package/dist/lib/commands/db.d.ts.map +1 -0
- package/dist/lib/commands/db.js +247 -0
- package/dist/lib/commands/db.js.map +1 -0
- package/dist/lib/commands/errors.d.ts +68 -0
- package/dist/lib/commands/errors.d.ts.map +1 -0
- package/dist/lib/commands/errors.js +72 -0
- package/dist/lib/commands/errors.js.map +1 -0
- package/dist/lib/commands/generic.d.ts +2 -2
- package/dist/lib/commands/generic.d.ts.map +1 -1
- package/dist/lib/commands/generic.js +170 -157
- package/dist/lib/commands/generic.js.map +1 -1
- package/dist/lib/commands/init.d.ts +1 -1
- package/dist/lib/commands/init.d.ts.map +1 -1
- package/dist/lib/commands/init.js +201 -192
- package/dist/lib/commands/init.js.map +1 -1
- package/dist/lib/commands/pull.d.ts +105 -3
- package/dist/lib/commands/pull.d.ts.map +1 -1
- package/dist/lib/commands/pull.js +530 -370
- package/dist/lib/commands/pull.js.map +1 -1
- package/dist/lib/commands/push.d.ts +106 -0
- package/dist/lib/commands/push.d.ts.map +1 -1
- package/dist/lib/commands/push.js +1432 -1830
- package/dist/lib/commands/push.js.map +1 -1
- package/dist/lib/commands/run.d.ts +1 -1
- package/dist/lib/commands/run.d.ts.map +1 -1
- package/dist/lib/commands/run.js +129 -127
- package/dist/lib/commands/run.js.map +1 -1
- package/dist/lib/commands/schema.d.ts +59 -0
- package/dist/lib/commands/schema.d.ts.map +1 -0
- package/dist/lib/commands/schema.js +86 -0
- package/dist/lib/commands/schema.js.map +1 -0
- package/dist/lib/commands/services/account.d.ts +3 -0
- package/dist/lib/commands/services/account.d.ts.map +1 -0
- package/dist/lib/commands/services/account.js +328 -0
- package/dist/lib/commands/services/account.js.map +1 -0
- package/dist/lib/commands/services/console.d.ts +3 -0
- package/dist/lib/commands/services/console.d.ts.map +1 -0
- package/dist/lib/commands/services/console.js +28 -0
- package/dist/lib/commands/services/console.js.map +1 -0
- package/dist/lib/commands/services/databases.d.ts +3 -0
- package/dist/lib/commands/services/databases.d.ts.map +1 -0
- package/dist/lib/commands/services/databases.js +620 -0
- package/dist/lib/commands/services/databases.js.map +1 -0
- package/dist/lib/commands/services/functions.d.ts +3 -0
- package/dist/lib/commands/services/functions.d.ts.map +1 -0
- package/dist/lib/commands/services/functions.js +266 -0
- package/dist/lib/commands/services/functions.js.map +1 -0
- package/dist/lib/commands/services/graphql.d.ts +3 -0
- package/dist/lib/commands/services/graphql.d.ts.map +1 -0
- package/dist/lib/commands/services/graphql.js +28 -0
- package/dist/lib/commands/services/graphql.js.map +1 -0
- package/dist/lib/commands/services/health.d.ts +3 -0
- package/dist/lib/commands/services/health.d.ts.map +1 -0
- package/dist/lib/commands/services/health.js +123 -0
- package/dist/lib/commands/services/health.js.map +1 -0
- package/dist/lib/commands/services/locale.d.ts +3 -0
- package/dist/lib/commands/services/locale.d.ts.map +1 -0
- package/dist/lib/commands/services/locale.js +52 -0
- package/dist/lib/commands/services/locale.js.map +1 -0
- package/dist/lib/commands/services/messaging.d.ts +3 -0
- package/dist/lib/commands/services/messaging.d.ts.map +1 -0
- package/dist/lib/commands/services/messaging.js +505 -0
- package/dist/lib/commands/services/messaging.js.map +1 -0
- package/dist/lib/commands/services/migrations.d.ts +3 -0
- package/dist/lib/commands/services/migrations.d.ts.map +1 -0
- package/dist/lib/commands/services/migrations.js +135 -0
- package/dist/lib/commands/services/migrations.js.map +1 -0
- package/dist/lib/commands/services/project.d.ts +3 -0
- package/dist/lib/commands/services/project.d.ts.map +1 -0
- package/dist/lib/commands/services/project.js +54 -0
- package/dist/lib/commands/services/project.js.map +1 -0
- package/dist/lib/commands/services/projects.d.ts +3 -0
- package/dist/lib/commands/services/projects.d.ts.map +1 -0
- package/dist/lib/commands/services/projects.js +415 -0
- package/dist/lib/commands/services/projects.js.map +1 -0
- package/dist/lib/commands/services/proxy.d.ts +3 -0
- package/dist/lib/commands/services/proxy.d.ts.map +1 -0
- package/dist/lib/commands/services/proxy.js +68 -0
- package/dist/lib/commands/services/proxy.js.map +1 -0
- package/dist/lib/commands/services/sites.d.ts +3 -0
- package/dist/lib/commands/services/sites.d.ts.map +1 -0
- package/dist/lib/commands/services/sites.js +250 -0
- package/dist/lib/commands/services/sites.js.map +1 -0
- package/dist/lib/commands/services/storage.d.ts +3 -0
- package/dist/lib/commands/services/storage.d.ts.map +1 -0
- package/dist/lib/commands/services/storage.js +175 -0
- package/dist/lib/commands/services/storage.js.map +1 -0
- package/dist/lib/commands/services/tables-db.d.ts +3 -0
- package/dist/lib/commands/services/tables-db.d.ts.map +1 -0
- package/dist/lib/commands/services/tables-db.js +613 -0
- package/dist/lib/commands/services/tables-db.js.map +1 -0
- package/dist/lib/commands/services/teams.d.ts +3 -0
- package/dist/lib/commands/services/teams.d.ts.map +1 -0
- package/dist/lib/commands/services/teams.js +123 -0
- package/dist/lib/commands/services/teams.js.map +1 -0
- package/dist/lib/commands/services/tokens.d.ts +3 -0
- package/dist/lib/commands/services/tokens.d.ts.map +1 -0
- package/dist/lib/commands/services/tokens.js +49 -0
- package/dist/lib/commands/services/tokens.js.map +1 -0
- package/dist/lib/commands/services/users.d.ts +3 -0
- package/dist/lib/commands/services/users.d.ts.map +1 -0
- package/dist/lib/commands/services/users.js +312 -0
- package/dist/lib/commands/services/users.js.map +1 -0
- package/dist/lib/commands/services/vcs.d.ts +3 -0
- package/dist/lib/commands/services/vcs.d.ts.map +1 -0
- package/dist/lib/commands/services/vcs.js +87 -0
- package/dist/lib/commands/services/vcs.js.map +1 -0
- package/dist/lib/commands/types.d.ts +1 -1
- package/dist/lib/commands/types.d.ts.map +1 -1
- package/dist/lib/commands/types.js +53 -57
- package/dist/lib/commands/types.js.map +1 -1
- package/dist/lib/commands/update.d.ts +1 -1
- package/dist/lib/commands/update.d.ts.map +1 -1
- package/dist/lib/commands/update.js +69 -69
- package/dist/lib/commands/update.js.map +1 -1
- package/dist/lib/commands/utils/attributes.d.ts +47 -0
- package/dist/lib/commands/utils/attributes.d.ts.map +1 -0
- package/dist/lib/commands/utils/attributes.js +514 -0
- package/dist/lib/commands/utils/attributes.js.map +1 -0
- package/dist/lib/commands/utils/change-approval.d.ts +25 -0
- package/dist/lib/commands/utils/change-approval.d.ts.map +1 -0
- package/dist/lib/commands/utils/change-approval.js +129 -0
- package/dist/lib/commands/utils/change-approval.js.map +1 -0
- package/dist/lib/commands/utils/database-sync.d.ts +10 -0
- package/dist/lib/commands/utils/database-sync.d.ts.map +1 -0
- package/dist/lib/commands/utils/database-sync.js +136 -0
- package/dist/lib/commands/utils/database-sync.js.map +1 -0
- package/dist/lib/commands/utils/deployment.d.ts +34 -0
- package/dist/lib/commands/utils/deployment.d.ts.map +1 -0
- package/dist/lib/commands/utils/deployment.js +109 -0
- package/dist/lib/commands/utils/deployment.js.map +1 -0
- package/dist/lib/commands/utils/error-formatter.d.ts +19 -0
- package/dist/lib/commands/utils/error-formatter.d.ts.map +1 -0
- package/dist/lib/commands/utils/error-formatter.js +333 -0
- package/dist/lib/commands/utils/error-formatter.js.map +1 -0
- package/dist/lib/commands/utils/pools.d.ts +16 -0
- package/dist/lib/commands/utils/pools.d.ts.map +1 -0
- package/dist/lib/commands/utils/pools.js +198 -0
- package/dist/lib/commands/utils/pools.js.map +1 -0
- package/dist/lib/config.d.ts +41 -40
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +264 -239
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/constants.d.ts +14 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +19 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/emulation/docker.d.ts +4 -12
- package/dist/lib/emulation/docker.d.ts.map +1 -1
- package/dist/lib/emulation/docker.js +159 -142
- package/dist/lib/emulation/docker.js.map +1 -1
- package/dist/lib/emulation/utils.d.ts +1 -1
- package/dist/lib/emulation/utils.d.ts.map +1 -1
- package/dist/lib/emulation/utils.js +55 -58
- package/dist/lib/emulation/utils.js.map +1 -1
- package/dist/lib/id.d.ts +1 -1
- package/dist/lib/id.d.ts.map +1 -1
- package/dist/lib/id.js +13 -18
- package/dist/lib/id.js.map +1 -1
- package/dist/lib/paginate.d.ts +3 -4
- package/dist/lib/paginate.d.ts.map +1 -1
- package/dist/lib/paginate.js +7 -10
- package/dist/lib/paginate.js.map +1 -1
- package/dist/lib/parser.d.ts +1 -1
- package/dist/lib/parser.d.ts.map +1 -1
- package/dist/lib/parser.js +92 -103
- package/dist/lib/parser.js.map +1 -1
- package/dist/lib/questions.d.ts +1 -1
- package/dist/lib/questions.d.ts.map +1 -1
- package/dist/lib/questions.js +381 -385
- package/dist/lib/questions.js.map +1 -1
- package/dist/lib/sdks.d.ts +1 -1
- package/dist/lib/sdks.d.ts.map +1 -1
- package/dist/lib/sdks.js +39 -30
- package/dist/lib/sdks.js.map +1 -1
- package/dist/lib/services.d.ts +13 -0
- package/dist/lib/services.d.ts.map +1 -0
- package/dist/lib/services.js +47 -0
- package/dist/lib/services.js.map +1 -0
- package/dist/lib/spinner.d.ts +1 -1
- package/dist/lib/spinner.d.ts.map +1 -1
- package/dist/lib/spinner.js +25 -27
- package/dist/lib/spinner.js.map +1 -1
- package/dist/lib/type-generation/attribute.d.ts +1 -1
- package/dist/lib/type-generation/attribute.d.ts.map +1 -1
- package/dist/lib/type-generation/attribute.js +14 -17
- package/dist/lib/type-generation/attribute.js.map +1 -1
- package/dist/lib/type-generation/languages/csharp.d.ts +1 -1
- package/dist/lib/type-generation/languages/csharp.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/csharp.js +34 -34
- package/dist/lib/type-generation/languages/csharp.js.map +1 -1
- package/dist/lib/type-generation/languages/dart.d.ts +1 -1
- package/dist/lib/type-generation/languages/dart.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/dart.js +57 -57
- package/dist/lib/type-generation/languages/dart.js.map +1 -1
- package/dist/lib/type-generation/languages/java.d.ts +1 -1
- package/dist/lib/type-generation/languages/java.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/java.js +35 -35
- package/dist/lib/type-generation/languages/java.js.map +1 -1
- package/dist/lib/type-generation/languages/javascript.d.ts +1 -1
- package/dist/lib/type-generation/languages/javascript.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/javascript.js +45 -44
- package/dist/lib/type-generation/languages/javascript.js.map +1 -1
- package/dist/lib/type-generation/languages/kotlin.d.ts +1 -1
- package/dist/lib/type-generation/languages/kotlin.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/kotlin.js +35 -35
- package/dist/lib/type-generation/languages/kotlin.js.map +1 -1
- package/dist/lib/type-generation/languages/language.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/language.js +32 -37
- package/dist/lib/type-generation/languages/language.js.map +1 -1
- package/dist/lib/type-generation/languages/php.d.ts +1 -1
- package/dist/lib/type-generation/languages/php.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/php.js +34 -34
- package/dist/lib/type-generation/languages/php.js.map +1 -1
- package/dist/lib/type-generation/languages/swift.d.ts +1 -1
- package/dist/lib/type-generation/languages/swift.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/swift.js +35 -35
- package/dist/lib/type-generation/languages/swift.js.map +1 -1
- package/dist/lib/type-generation/languages/typescript.d.ts +1 -1
- package/dist/lib/type-generation/languages/typescript.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/typescript.js +49 -46
- package/dist/lib/type-generation/languages/typescript.js.map +1 -1
- package/dist/lib/types.d.ts +38 -108
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +1 -2
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +142 -98
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/validations.d.ts.map +1 -1
- package/dist/lib/validations.js +2 -6
- package/dist/lib/validations.js.map +1 -1
- package/dist/package.json +68 -0
- package/index.ts +25 -149
- package/install.ps1 +2 -2
- package/install.sh +1 -1
- package/lib/client.ts +261 -220
- package/lib/commands/config.ts +494 -0
- package/lib/commands/db.ts +324 -0
- package/lib/commands/errors.ts +93 -0
- package/lib/commands/generic.ts +371 -269
- package/lib/commands/init.ts +631 -519
- package/lib/commands/pull.ts +827 -453
- package/lib/commands/push.ts +2191 -2349
- package/lib/commands/run.ts +382 -302
- package/lib/commands/schema.ts +122 -0
- package/lib/commands/services/account.ts +647 -0
- package/lib/commands/services/console.ts +52 -0
- package/lib/commands/services/databases.ts +1163 -0
- package/lib/commands/services/functions.ts +536 -0
- package/lib/commands/services/graphql.ts +50 -0
- package/lib/commands/services/health.ts +260 -0
- package/lib/commands/services/locale.ts +102 -0
- package/lib/commands/services/messaging.ts +1052 -0
- package/lib/commands/services/migrations.ts +249 -0
- package/lib/commands/services/project.ts +112 -0
- package/lib/commands/services/projects.ts +785 -0
- package/lib/commands/services/proxy.ts +135 -0
- package/lib/commands/services/sites.ts +505 -0
- package/lib/commands/services/storage.ts +338 -0
- package/lib/commands/services/tables-db.ts +1150 -0
- package/lib/commands/services/teams.ts +232 -0
- package/lib/commands/services/tokens.ts +94 -0
- package/lib/commands/services/users.ts +616 -0
- package/lib/commands/services/vcs.ts +165 -0
- package/lib/commands/types.ts +145 -118
- package/lib/commands/update.ts +189 -159
- package/lib/commands/utils/attributes.ts +719 -0
- package/lib/commands/utils/change-approval.ts +186 -0
- package/lib/commands/utils/database-sync.ts +180 -0
- package/lib/commands/utils/deployment.ts +184 -0
- package/lib/commands/utils/error-formatter.ts +417 -0
- package/lib/commands/utils/pools.ts +355 -0
- package/lib/config.ts +766 -687
- package/lib/constants.ts +22 -0
- package/lib/emulation/docker.ts +277 -216
- package/lib/emulation/utils.ts +188 -174
- package/lib/id.ts +23 -23
- package/lib/paginate.ts +69 -55
- package/lib/parser.ts +220 -189
- package/lib/questions.ts +1024 -948
- package/lib/sdks.ts +84 -51
- package/lib/services.ts +72 -0
- package/lib/spinner.ts +112 -99
- package/lib/type-generation/attribute.ts +15 -14
- package/lib/type-generation/languages/csharp.ts +71 -60
- package/lib/type-generation/languages/dart.ts +106 -93
- package/lib/type-generation/languages/java.ts +69 -58
- package/lib/type-generation/languages/javascript.ts +84 -73
- package/lib/type-generation/languages/kotlin.ts +71 -60
- package/lib/type-generation/languages/language.ts +103 -95
- package/lib/type-generation/languages/php.ts +67 -56
- package/lib/type-generation/languages/swift.ts +71 -60
- package/lib/type-generation/languages/typescript.ts +93 -76
- package/lib/types.ts +50 -125
- package/lib/utils.ts +304 -233
- package/lib/validations.ts +17 -14
- package/package.json +31 -22
- package/scoop/appwrite.config.json +3 -3
- package/tsconfig.json +7 -13
- package/.github/workflows/autoclose.yml +0 -11
- package/.github/workflows/npm-publish.yml +0 -49
- package/dist/lib/commands/account.d.ts +0 -379
- package/dist/lib/commands/account.d.ts.map +0 -1
- package/dist/lib/commands/account.js +0 -1228
- package/dist/lib/commands/account.js.map +0 -1
- package/dist/lib/commands/console.d.ts +0 -20
- package/dist/lib/commands/console.d.ts.map +0 -1
- package/dist/lib/commands/console.js +0 -78
- package/dist/lib/commands/console.js.map +0 -1
- package/dist/lib/commands/databases.d.ts +0 -732
- package/dist/lib/commands/databases.d.ts.map +0 -1
- package/dist/lib/commands/databases.js +0 -2196
- package/dist/lib/commands/databases.js.map +0 -1
- package/dist/lib/commands/functions.d.ts +0 -310
- package/dist/lib/commands/functions.d.ts.map +0 -1
- package/dist/lib/commands/functions.js +0 -1100
- package/dist/lib/commands/functions.js.map +0 -1
- package/dist/lib/commands/graphql.d.ts +0 -19
- package/dist/lib/commands/graphql.d.ts.map +0 -1
- package/dist/lib/commands/graphql.js +0 -77
- package/dist/lib/commands/graphql.js.map +0 -1
- package/dist/lib/commands/health.d.ts +0 -153
- package/dist/lib/commands/health.d.ts.map +0 -1
- package/dist/lib/commands/health.js +0 -464
- package/dist/lib/commands/health.js.map +0 -1
- package/dist/lib/commands/locale.d.ts +0 -53
- package/dist/lib/commands/locale.d.ts.map +0 -1
- package/dist/lib/commands/locale.js +0 -165
- package/dist/lib/commands/locale.js.map +0 -1
- package/dist/lib/commands/messaging.d.ts +0 -588
- package/dist/lib/commands/messaging.d.ts.map +0 -1
- package/dist/lib/commands/messaging.js +0 -2042
- package/dist/lib/commands/messaging.js.map +0 -1
- package/dist/lib/commands/migrations.d.ts +0 -150
- package/dist/lib/commands/migrations.d.ts.map +0 -1
- package/dist/lib/commands/migrations.js +0 -524
- package/dist/lib/commands/migrations.js.map +0 -1
- package/dist/lib/commands/organizations.d.ts +0 -11
- package/dist/lib/commands/organizations.d.ts.map +0 -1
- package/dist/lib/commands/organizations.js +0 -31
- package/dist/lib/commands/organizations.js.map +0 -1
- package/dist/lib/commands/project.d.ts +0 -53
- package/dist/lib/commands/project.d.ts.map +0 -1
- package/dist/lib/commands/project.js +0 -176
- package/dist/lib/commands/project.js.map +0 -1
- package/dist/lib/commands/projects.d.ts +0 -516
- package/dist/lib/commands/projects.d.ts.map +0 -1
- package/dist/lib/commands/projects.js +0 -1590
- package/dist/lib/commands/projects.js.map +0 -1
- package/dist/lib/commands/proxy.d.ts +0 -71
- package/dist/lib/commands/proxy.d.ts.map +0 -1
- package/dist/lib/commands/proxy.js +0 -240
- package/dist/lib/commands/proxy.js.map +0 -1
- package/dist/lib/commands/sites.d.ts +0 -296
- package/dist/lib/commands/sites.d.ts.map +0 -1
- package/dist/lib/commands/sites.js +0 -1046
- package/dist/lib/commands/sites.js.map +0 -1
- package/dist/lib/commands/storage.d.ts +0 -170
- package/dist/lib/commands/storage.d.ts.map +0 -1
- package/dist/lib/commands/storage.js +0 -651
- package/dist/lib/commands/storage.js.map +0 -1
- package/dist/lib/commands/tables-db.d.ts +0 -728
- package/dist/lib/commands/tables-db.d.ts.map +0 -1
- package/dist/lib/commands/tables-db.js +0 -2198
- package/dist/lib/commands/tables-db.js.map +0 -1
- package/dist/lib/commands/teams.d.ts +0 -129
- package/dist/lib/commands/teams.d.ts.map +0 -1
- package/dist/lib/commands/teams.js +0 -403
- package/dist/lib/commands/teams.js.map +0 -1
- package/dist/lib/commands/tokens.d.ts +0 -48
- package/dist/lib/commands/tokens.d.ts.map +0 -1
- package/dist/lib/commands/tokens.js +0 -156
- package/dist/lib/commands/tokens.js.map +0 -1
- package/dist/lib/commands/users.d.ts +0 -382
- package/dist/lib/commands/users.d.ts.map +0 -1
- package/dist/lib/commands/users.js +0 -1195
- package/dist/lib/commands/users.js.map +0 -1
- package/dist/lib/commands/vcs.d.ts +0 -92
- package/dist/lib/commands/vcs.d.ts.map +0 -1
- package/dist/lib/commands/vcs.js +0 -276
- package/dist/lib/commands/vcs.js.map +0 -1
- package/dist/lib/exception.d.ts +0 -8
- package/dist/lib/exception.d.ts.map +0 -1
- package/dist/lib/exception.js +0 -16
- package/dist/lib/exception.js.map +0 -1
- package/lib/commands/account.ts +0 -1867
- package/lib/commands/console.ts +0 -112
- package/lib/commands/databases.ts +0 -3272
- package/lib/commands/functions.ts +0 -1587
- package/lib/commands/graphql.ts +0 -110
- package/lib/commands/health.ts +0 -753
- package/lib/commands/locale.ts +0 -270
- package/lib/commands/messaging.ts +0 -2878
- package/lib/commands/migrations.ts +0 -754
- package/lib/commands/organizations.ts +0 -46
- package/lib/commands/project.ts +0 -266
- package/lib/commands/projects.ts +0 -2370
- package/lib/commands/proxy.ts +0 -357
- package/lib/commands/sites.ts +0 -1514
- package/lib/commands/storage.ts +0 -919
- package/lib/commands/tables-db.ts +0 -3260
- package/lib/commands/teams.ts +0 -609
- package/lib/commands/tokens.ts +0 -232
- package/lib/commands/users.ts +0 -1804
- package/lib/commands/vcs.ts +0 -428
- package/lib/exception.ts +0 -20
package/lib/commands/push.ts
CHANGED
|
@@ -1,1202 +1,623 @@
|
|
|
1
|
-
import fs
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import chalk from 'chalk';
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { parse as parseDotenv } from "dotenv";
|
|
3
|
+
import chalk from "chalk";
|
|
5
4
|
import inquirer from "inquirer";
|
|
6
|
-
import JSONbig from "json-bigint";
|
|
7
5
|
import { Command } from "commander";
|
|
8
|
-
import ID from "../id";
|
|
9
|
-
import {
|
|
10
|
-
import { Spinner, SPINNER_ARC, SPINNER_DOTS } from '../spinner';
|
|
11
|
-
import { paginate } from '../paginate';
|
|
12
|
-
import { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsPushSites, questionsGetEntrypoint, questionsPushCollections, questionsPushTables, questionPushChanges, questionPushChangesConfirmation, questionsPushMessagingTopics, questionsPushResources } from "../questions";
|
|
13
|
-
import { cliConfig, actionRunner, success, warn, log, hint, error, commandDescriptions, drawTable } from "../parser";
|
|
14
|
-
import { proxyCreateFunctionRule, proxyCreateSiteRule, proxyListRules } from './proxy';
|
|
15
|
-
import { consoleVariables } from './console';
|
|
16
|
-
import { sdkForConsole } from '../sdks';
|
|
17
|
-
import { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment, functionsGetDeployment, functionsListVariables, functionsDeleteVariable, functionsCreateVariable } from './functions';
|
|
18
|
-
import { sitesGet, sitesCreate, sitesUpdate, sitesCreateDeployment, sitesGetDeployment, sitesCreateVariable, sitesListVariables, sitesDeleteVariable } from './sites';
|
|
6
|
+
import ID from "../id.js";
|
|
7
|
+
import { EXECUTABLE_NAME } from "../constants.js";
|
|
19
8
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
databasesUpdateBooleanAttribute,
|
|
36
|
-
databasesUpdateStringAttribute,
|
|
37
|
-
databasesUpdateIntegerAttribute,
|
|
38
|
-
databasesUpdateFloatAttribute,
|
|
39
|
-
databasesUpdateEmailAttribute,
|
|
40
|
-
databasesUpdateDatetimeAttribute,
|
|
41
|
-
databasesUpdateUrlAttribute,
|
|
42
|
-
databasesUpdateIpAttribute,
|
|
43
|
-
databasesUpdateEnumAttribute,
|
|
44
|
-
databasesUpdateRelationshipAttribute,
|
|
45
|
-
databasesCreateRelationshipAttribute,
|
|
46
|
-
databasesCreatePointAttribute,
|
|
47
|
-
databasesUpdatePointAttribute,
|
|
48
|
-
databasesCreateLineAttribute,
|
|
49
|
-
databasesUpdateLineAttribute,
|
|
50
|
-
databasesCreatePolygonAttribute,
|
|
51
|
-
databasesUpdatePolygonAttribute,
|
|
52
|
-
databasesDeleteAttribute,
|
|
53
|
-
databasesDeleteIndex,
|
|
54
|
-
databasesListAttributes,
|
|
55
|
-
databasesListIndexes,
|
|
56
|
-
databasesUpdateCollection
|
|
57
|
-
} from "./databases";
|
|
9
|
+
localConfig,
|
|
10
|
+
globalConfig,
|
|
11
|
+
KeysFunction,
|
|
12
|
+
KeysSite,
|
|
13
|
+
KeysTopics,
|
|
14
|
+
KeysStorage,
|
|
15
|
+
KeysTeams,
|
|
16
|
+
KeysCollection,
|
|
17
|
+
KeysTable,
|
|
18
|
+
} from "../config.js";
|
|
19
|
+
import type { SettingsType, ConfigType } from "./config.js";
|
|
20
|
+
import { createSettingsObject } from "../utils.js";
|
|
21
|
+
import { Spinner, SPINNER_DOTS } from "../spinner.js";
|
|
22
|
+
import { paginate } from "../paginate.js";
|
|
23
|
+
import { pushDeployment } from "./utils/deployment.js";
|
|
58
24
|
import {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
} from "./tables-db";
|
|
25
|
+
questionsPushBuckets,
|
|
26
|
+
questionsPushTeams,
|
|
27
|
+
questionsPushFunctions,
|
|
28
|
+
questionsPushSites,
|
|
29
|
+
questionsGetEntrypoint,
|
|
30
|
+
questionsPushCollections,
|
|
31
|
+
questionsPushTables,
|
|
32
|
+
questionsPushMessagingTopics,
|
|
33
|
+
questionsPushResources,
|
|
34
|
+
} from "../questions.js";
|
|
70
35
|
import {
|
|
71
|
-
|
|
72
|
-
|
|
36
|
+
cliConfig,
|
|
37
|
+
actionRunner,
|
|
38
|
+
success,
|
|
39
|
+
warn,
|
|
40
|
+
log,
|
|
41
|
+
hint,
|
|
42
|
+
error,
|
|
43
|
+
commandDescriptions,
|
|
44
|
+
drawTable,
|
|
45
|
+
} from "../parser.js";
|
|
73
46
|
import {
|
|
74
|
-
|
|
75
|
-
|
|
47
|
+
getProxyService,
|
|
48
|
+
getConsoleService,
|
|
49
|
+
getFunctionsService,
|
|
50
|
+
getSitesService,
|
|
51
|
+
getDatabasesService,
|
|
52
|
+
getTablesDBService,
|
|
53
|
+
getStorageService,
|
|
54
|
+
getMessagingService,
|
|
55
|
+
getTeamsService,
|
|
56
|
+
getProjectsService,
|
|
57
|
+
} from "../services.js";
|
|
58
|
+
import { sdkForProject, sdkForConsole } from "../sdks.js";
|
|
76
59
|
import {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
60
|
+
ApiService,
|
|
61
|
+
AuthMethod,
|
|
62
|
+
AppwriteException,
|
|
63
|
+
Client,
|
|
64
|
+
Query,
|
|
65
|
+
} from "@appwrite.io/console";
|
|
66
|
+
import { checkDeployConditions } from "../utils.js";
|
|
67
|
+
import { Pools } from "./utils/pools.js";
|
|
68
|
+
import { Attributes, Collection } from "./utils/attributes.js";
|
|
81
69
|
import {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
projectsUpdateAuthSessionsLimit,
|
|
89
|
-
projectsUpdateAuthPasswordDictionary,
|
|
90
|
-
projectsUpdateAuthPasswordHistory,
|
|
91
|
-
projectsUpdatePersonalDataCheck,
|
|
92
|
-
projectsUpdateSessionAlerts,
|
|
93
|
-
projectsUpdateMockNumbers,
|
|
94
|
-
} from "./projects";
|
|
95
|
-
import { checkDeployConditions } from '../utils';
|
|
96
|
-
|
|
97
|
-
const JSONbigNative = JSONbig({ storeAsString: false });
|
|
98
|
-
|
|
99
|
-
const STEP_SIZE = 100; // Resources
|
|
70
|
+
getConfirmation,
|
|
71
|
+
approveChanges,
|
|
72
|
+
getObjectChanges,
|
|
73
|
+
} from "./utils/change-approval.js";
|
|
74
|
+
import { checkAndApplyTablesDBChanges } from "./utils/database-sync.js";
|
|
75
|
+
|
|
100
76
|
const POLL_DEBOUNCE = 2000; // Milliseconds
|
|
101
|
-
const POLL_MAX_DEBOUNCE = 1800; // Times of POLL_DEBOUNCE (1 hour)
|
|
102
77
|
const POLL_DEFAULT_VALUE = 30;
|
|
78
|
+
const DEPLOYMENT_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
|
|
79
|
+
|
|
80
|
+
export interface PushOptions {
|
|
81
|
+
all?: boolean;
|
|
82
|
+
settings?: boolean;
|
|
83
|
+
functions?: boolean;
|
|
84
|
+
sites?: boolean;
|
|
85
|
+
collections?: boolean;
|
|
86
|
+
tables?: boolean;
|
|
87
|
+
buckets?: boolean;
|
|
88
|
+
teams?: boolean;
|
|
89
|
+
topics?: boolean;
|
|
90
|
+
skipDeprecated?: boolean;
|
|
91
|
+
skipConfirmation?: boolean;
|
|
92
|
+
functionOptions?: {
|
|
93
|
+
async?: boolean;
|
|
94
|
+
code?: boolean;
|
|
95
|
+
withVariables?: boolean;
|
|
96
|
+
};
|
|
97
|
+
siteOptions?: {
|
|
98
|
+
async?: boolean;
|
|
99
|
+
code?: boolean;
|
|
100
|
+
withVariables?: boolean;
|
|
101
|
+
};
|
|
102
|
+
tableOptions?: {
|
|
103
|
+
attempts?: number;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
interface PushSiteOptions {
|
|
108
|
+
siteId?: string;
|
|
109
|
+
async?: boolean;
|
|
110
|
+
code?: boolean;
|
|
111
|
+
withVariables?: boolean;
|
|
112
|
+
}
|
|
107
113
|
|
|
108
|
-
interface
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
deleteIndexes: (databaseId: string, collectionId: string, indexesKeys: any[], iteration?: number) => Promise<boolean>;
|
|
114
|
-
expectIndexes: (databaseId: string, collectionId: string, indexKeys: string[], iteration?: number) => Promise<boolean>;
|
|
114
|
+
interface PushFunctionOptions {
|
|
115
|
+
functionId?: string;
|
|
116
|
+
async?: boolean;
|
|
117
|
+
code?: boolean;
|
|
118
|
+
withVariables?: boolean;
|
|
115
119
|
}
|
|
116
120
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
121
|
+
interface PushTableOptions {
|
|
122
|
+
attempts?: number;
|
|
123
|
+
skipConfirmation?: boolean;
|
|
124
|
+
}
|
|
122
125
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
export class Push {
|
|
127
|
+
private projectClient: Client;
|
|
128
|
+
private consoleClient: Client;
|
|
129
|
+
private silent: boolean;
|
|
130
|
+
|
|
131
|
+
constructor(projectClient: Client, consoleClient: Client, silent = false) {
|
|
132
|
+
this.projectClient = projectClient;
|
|
133
|
+
this.consoleClient = consoleClient;
|
|
134
|
+
this.silent = silent;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Log a message (respects silent mode)
|
|
139
|
+
*/
|
|
140
|
+
private log(message: string): void {
|
|
141
|
+
if (!this.silent) {
|
|
142
|
+
log(message);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Log a success message (respects silent mode)
|
|
148
|
+
*/
|
|
149
|
+
private success(message: string): void {
|
|
150
|
+
if (!this.silent) {
|
|
151
|
+
success(message);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Log a warning message (respects silent mode)
|
|
157
|
+
*/
|
|
158
|
+
private warn(message: string): void {
|
|
159
|
+
if (!this.silent) {
|
|
160
|
+
warn(message);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Log an error message (respects silent mode)
|
|
166
|
+
*/
|
|
167
|
+
private error(message: string): void {
|
|
168
|
+
if (!this.silent) {
|
|
169
|
+
error(message);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public async pushResources(
|
|
174
|
+
config: ConfigType,
|
|
175
|
+
options: PushOptions = { all: true, skipDeprecated: true },
|
|
176
|
+
): Promise<{
|
|
177
|
+
results: Record<string, any>;
|
|
178
|
+
errors: any[];
|
|
179
|
+
}> {
|
|
180
|
+
const { skipDeprecated = true } = options;
|
|
181
|
+
const results: Record<string, any> = {};
|
|
182
|
+
const allErrors: any[] = [];
|
|
183
|
+
const shouldPushAll = options.all === true;
|
|
184
|
+
|
|
185
|
+
// Push settings
|
|
186
|
+
if (
|
|
187
|
+
(shouldPushAll || options.settings) &&
|
|
188
|
+
(config.projectName || config.settings)
|
|
189
|
+
) {
|
|
190
|
+
try {
|
|
191
|
+
this.log("Pushing settings ...");
|
|
192
|
+
await this.pushSettings({
|
|
193
|
+
projectId: config.projectId,
|
|
194
|
+
projectName: config.projectName,
|
|
195
|
+
settings: config.settings,
|
|
128
196
|
});
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
|
|
135
|
-
let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
|
|
136
|
-
if (steps > 1 && iteration === 1) {
|
|
137
|
-
pollMaxDebounces *= steps;
|
|
138
|
-
|
|
139
|
-
log('Found a large number of attributes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
144
|
-
|
|
145
|
-
return await awaitPools.wipeAttributes(
|
|
146
|
-
databaseId,
|
|
147
|
-
collectionId,
|
|
148
|
-
iteration + 1
|
|
197
|
+
this.success(
|
|
198
|
+
`Successfully pushed ${chalk.bold("all")} project settings.`,
|
|
149
199
|
);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
|
|
169
|
-
if (steps > 1 && iteration === 1) {
|
|
170
|
-
pollMaxDebounces *= steps;
|
|
171
|
-
|
|
172
|
-
log('Found a large number of indexes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
177
|
-
|
|
178
|
-
return await awaitPools.wipeIndexes(
|
|
179
|
-
databaseId,
|
|
180
|
-
collectionId,
|
|
181
|
-
iteration + 1
|
|
200
|
+
results.settings = { success: true };
|
|
201
|
+
} catch (e: any) {
|
|
202
|
+
allErrors.push(e);
|
|
203
|
+
results.settings = { success: false, error: e.message };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Push buckets
|
|
208
|
+
if (
|
|
209
|
+
(shouldPushAll || options.buckets) &&
|
|
210
|
+
config.buckets &&
|
|
211
|
+
config.buckets.length > 0
|
|
212
|
+
) {
|
|
213
|
+
try {
|
|
214
|
+
this.log("Pushing buckets ...");
|
|
215
|
+
const result = await this.pushBuckets(config.buckets);
|
|
216
|
+
this.success(
|
|
217
|
+
`Successfully pushed ${chalk.bold(result.successfullyPushed)} buckets.`,
|
|
182
218
|
);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}, 100, 'attributes');
|
|
203
|
-
|
|
204
|
-
const ready = attributeKeys.filter((attribute: any) => attributes.includes(attribute.key));
|
|
205
|
-
|
|
206
|
-
if (ready.length === 0) {
|
|
207
|
-
return true;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
211
|
-
|
|
212
|
-
return await awaitPools.expectAttributes(
|
|
213
|
-
databaseId,
|
|
214
|
-
collectionId,
|
|
215
|
-
attributeKeys,
|
|
216
|
-
iteration + 1
|
|
219
|
+
results.buckets = result;
|
|
220
|
+
allErrors.push(...result.errors);
|
|
221
|
+
} catch (e: any) {
|
|
222
|
+
allErrors.push(e);
|
|
223
|
+
results.buckets = { successfullyPushed: 0, errors: [e] };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Push teams
|
|
228
|
+
if (
|
|
229
|
+
(shouldPushAll || options.teams) &&
|
|
230
|
+
config.teams &&
|
|
231
|
+
config.teams.length > 0
|
|
232
|
+
) {
|
|
233
|
+
try {
|
|
234
|
+
this.log("Pushing teams ...");
|
|
235
|
+
const result = await this.pushTeams(config.teams);
|
|
236
|
+
this.success(
|
|
237
|
+
`Successfully pushed ${chalk.bold(result.successfullyPushed)} teams.`,
|
|
217
238
|
);
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}, 100, 'attributes');
|
|
238
|
-
|
|
239
|
-
const ready = attributes
|
|
240
|
-
.filter((attribute: any) => {
|
|
241
|
-
if (attributeKeys.includes(attribute.key)) {
|
|
242
|
-
if (['stuck', 'failed'].includes(attribute.status)) {
|
|
243
|
-
throw new Error(`Attribute '${attribute.key}' failed!`);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return attribute.status === 'available';
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return false;
|
|
250
|
-
})
|
|
251
|
-
.map((attribute: any) => attribute.key);
|
|
252
|
-
|
|
253
|
-
if (ready.length === attributeKeys.length) {
|
|
254
|
-
return true;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
258
|
-
|
|
259
|
-
return await awaitPools.expectAttributes(
|
|
260
|
-
databaseId,
|
|
261
|
-
collectionId,
|
|
262
|
-
attributeKeys,
|
|
263
|
-
iteration + 1
|
|
239
|
+
results.teams = result;
|
|
240
|
+
allErrors.push(...result.errors);
|
|
241
|
+
} catch (e: any) {
|
|
242
|
+
allErrors.push(e);
|
|
243
|
+
results.teams = { successfullyPushed: 0, errors: [e] };
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Push messaging topics
|
|
248
|
+
if (
|
|
249
|
+
(shouldPushAll || options.topics) &&
|
|
250
|
+
config.topics &&
|
|
251
|
+
config.topics.length > 0
|
|
252
|
+
) {
|
|
253
|
+
try {
|
|
254
|
+
this.log("Pushing topics ...");
|
|
255
|
+
const result = await this.pushMessagingTopics(config.topics);
|
|
256
|
+
this.success(
|
|
257
|
+
`Successfully pushed ${chalk.bold(result.successfullyPushed)} topics.`,
|
|
264
258
|
);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}, 100, 'indexes');
|
|
285
|
-
|
|
286
|
-
const ready = indexesKeys.filter((index: any) => indexes.includes(index.key));
|
|
287
|
-
|
|
288
|
-
if (ready.length === 0) {
|
|
289
|
-
return true;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
293
|
-
|
|
294
|
-
return await awaitPools.expectIndexes(
|
|
295
|
-
databaseId,
|
|
296
|
-
collectionId,
|
|
297
|
-
indexesKeys,
|
|
298
|
-
iteration + 1
|
|
259
|
+
results.topics = result;
|
|
260
|
+
allErrors.push(...result.errors);
|
|
261
|
+
} catch (e: any) {
|
|
262
|
+
allErrors.push(e);
|
|
263
|
+
results.topics = { successfullyPushed: 0, errors: [e] };
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Push functions
|
|
268
|
+
if (
|
|
269
|
+
(shouldPushAll || options.functions) &&
|
|
270
|
+
config.functions &&
|
|
271
|
+
config.functions.length > 0
|
|
272
|
+
) {
|
|
273
|
+
try {
|
|
274
|
+
this.log("Pushing functions ...");
|
|
275
|
+
const result = await this.pushFunctions(
|
|
276
|
+
config.functions,
|
|
277
|
+
options.functionOptions,
|
|
299
278
|
);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (iteration > pollMaxDebounces) {
|
|
303
|
-
return false;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
|
|
307
|
-
let steps = Math.max(1, Math.ceil(indexKeys.length / STEP_SIZE));
|
|
308
|
-
if (steps > 1 && iteration === 1) {
|
|
309
|
-
pollMaxDebounces *= steps;
|
|
310
|
-
|
|
311
|
-
log('Creating a large number of indexes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const { indexes } = await paginate(databasesListIndexes, {
|
|
316
|
-
databaseId,
|
|
317
|
-
collectionId,
|
|
318
|
-
parseOutput: false
|
|
319
|
-
}, 100, 'indexes');
|
|
320
|
-
|
|
321
|
-
const ready = indexes
|
|
322
|
-
.filter((index: any) => {
|
|
323
|
-
if (indexKeys.includes(index.key)) {
|
|
324
|
-
if (['stuck', 'failed'].includes(index.status)) {
|
|
325
|
-
throw new Error(`Index '${index.key}' failed!`);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return index.status === 'available';
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
return false;
|
|
332
|
-
})
|
|
333
|
-
.map((index: any) => index.key);
|
|
334
|
-
|
|
335
|
-
if (ready.length >= indexKeys.length) {
|
|
336
|
-
return true;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
|
|
340
|
-
|
|
341
|
-
return await awaitPools.expectIndexes(
|
|
342
|
-
databaseId,
|
|
343
|
-
collectionId,
|
|
344
|
-
indexKeys,
|
|
345
|
-
iteration + 1
|
|
279
|
+
this.success(
|
|
280
|
+
`Successfully pushed ${chalk.bold(result.successfullyPushed)} functions.`,
|
|
346
281
|
);
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
282
|
+
results.functions = result;
|
|
283
|
+
allErrors.push(...result.errors);
|
|
284
|
+
} catch (e: any) {
|
|
285
|
+
allErrors.push(e);
|
|
286
|
+
results.functions = {
|
|
287
|
+
successfullyPushed: 0,
|
|
288
|
+
successfullyDeployed: 0,
|
|
289
|
+
failedDeployments: [],
|
|
290
|
+
errors: [e],
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Push sites
|
|
296
|
+
if (
|
|
297
|
+
(shouldPushAll || options.sites) &&
|
|
298
|
+
config.sites &&
|
|
299
|
+
config.sites.length > 0
|
|
300
|
+
) {
|
|
301
|
+
try {
|
|
302
|
+
this.log("Pushing sites ...");
|
|
303
|
+
const result = await this.pushSites(config.sites, options.siteOptions);
|
|
304
|
+
this.success(
|
|
305
|
+
`Successfully pushed ${chalk.bold(result.successfullyPushed)} sites.`,
|
|
306
|
+
);
|
|
307
|
+
results.sites = result;
|
|
308
|
+
allErrors.push(...result.errors);
|
|
309
|
+
} catch (e: any) {
|
|
310
|
+
allErrors.push(e);
|
|
311
|
+
results.sites = {
|
|
312
|
+
successfullyPushed: 0,
|
|
313
|
+
successfullyDeployed: 0,
|
|
314
|
+
failedDeployments: [],
|
|
315
|
+
errors: [e],
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Push tables
|
|
321
|
+
if (
|
|
322
|
+
(shouldPushAll || options.tables) &&
|
|
323
|
+
config.tables &&
|
|
324
|
+
config.tables.length > 0
|
|
325
|
+
) {
|
|
326
|
+
try {
|
|
327
|
+
this.log("Pushing tables ...");
|
|
328
|
+
const result = await this.pushTables(config.tables, {
|
|
329
|
+
attempts: options.tableOptions?.attempts,
|
|
330
|
+
skipConfirmation: options.skipConfirmation,
|
|
331
|
+
});
|
|
332
|
+
this.success(
|
|
333
|
+
`Successfully pushed ${chalk.bold(result.successfullyPushed)} tables.`,
|
|
334
|
+
);
|
|
335
|
+
results.tables = result;
|
|
336
|
+
allErrors.push(...result.errors);
|
|
337
|
+
} catch (e: any) {
|
|
338
|
+
allErrors.push(e);
|
|
339
|
+
results.tables = { successfullyPushed: 0, errors: [e] };
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Push collections (skipDeprecated only applies when pushing all, explicit collections option takes precedence)
|
|
344
|
+
if (
|
|
345
|
+
(options.collections || (shouldPushAll && !skipDeprecated)) &&
|
|
346
|
+
config.collections &&
|
|
347
|
+
config.collections.length > 0
|
|
348
|
+
) {
|
|
349
|
+
try {
|
|
350
|
+
this.log("Pushing collections ...");
|
|
351
|
+
// Add database names to collections
|
|
352
|
+
const collectionsWithDbNames = config.collections.map(
|
|
353
|
+
(collection: any) => {
|
|
354
|
+
const database = config.databases?.find(
|
|
355
|
+
(db: any) => db.$id === collection.databaseId,
|
|
356
|
+
);
|
|
357
|
+
return {
|
|
358
|
+
...collection,
|
|
359
|
+
databaseName: database?.name ?? collection.databaseId,
|
|
389
360
|
};
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const remoteResource = await resourceGetFunction(options);
|
|
396
|
-
|
|
397
|
-
for (let [key, value] of Object.entries(whitelistKeys(remoteResource, keys))) {
|
|
398
|
-
if (skipKeys.includes(key)) {
|
|
399
|
-
continue;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (isEmpty(value) && isEmpty(localResource[key])) {
|
|
403
|
-
continue;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
if (Array.isArray(value) && Array.isArray(localResource[key])) {
|
|
407
|
-
if (JSON.stringify(value) !== JSON.stringify(localResource[key])) {
|
|
408
|
-
changes.push({
|
|
409
|
-
id: localResource['$id'],
|
|
410
|
-
key,
|
|
411
|
-
remote: chalk.red((value as string[]).join('\n')),
|
|
412
|
-
local: chalk.green(localResource[key].join('\n'))
|
|
413
|
-
})
|
|
414
|
-
}
|
|
415
|
-
} else if (value !== localResource[key]) {
|
|
416
|
-
changes.push({
|
|
417
|
-
id: localResource['$id'],
|
|
418
|
-
key,
|
|
419
|
-
remote: chalk.red(value),
|
|
420
|
-
local: chalk.green(localResource[key])
|
|
421
|
-
})
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
} catch (e: any) {
|
|
425
|
-
if (Number(e.code) !== 404) {
|
|
426
|
-
throw e;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}));
|
|
430
|
-
|
|
431
|
-
if (changes.length === 0) {
|
|
432
|
-
return true;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
drawTable(changes);
|
|
436
|
-
if ((await getConfirmation()) === true) {
|
|
437
|
-
return true;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
success(`Successfully pushed 0 ${resourcePlural}.`);
|
|
441
|
-
return false;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
const getObjectChanges = (remote: any, local: any, index: string, what: string): any[] => {
|
|
445
|
-
const changes: any[] = [];
|
|
446
|
-
|
|
447
|
-
if (remote[index] && local[index]) {
|
|
448
|
-
for (let [service, status] of Object.entries(remote[index])) {
|
|
449
|
-
const localValue = local[index][service];
|
|
450
|
-
let valuesEqual = false;
|
|
451
|
-
|
|
452
|
-
if (Array.isArray(status) && Array.isArray(localValue)) {
|
|
453
|
-
valuesEqual = JSON.stringify(status) === JSON.stringify(localValue);
|
|
454
|
-
} else {
|
|
455
|
-
valuesEqual = status === localValue;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
if (!valuesEqual) {
|
|
459
|
-
changes.push({ group: what, setting: service, remote: chalk.red(status), local: chalk.green(localValue) })
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
return changes;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
const createAttribute = (databaseId: string, collectionId: string, attribute: any): Promise<any> => {
|
|
468
|
-
switch (attribute.type) {
|
|
469
|
-
case 'string':
|
|
470
|
-
switch (attribute.format) {
|
|
471
|
-
case 'email':
|
|
472
|
-
return databasesCreateEmailAttribute({
|
|
473
|
-
databaseId,
|
|
474
|
-
collectionId,
|
|
475
|
-
key: attribute.key,
|
|
476
|
-
required: attribute.required,
|
|
477
|
-
xdefault: attribute.default,
|
|
478
|
-
array: attribute.array,
|
|
479
|
-
parseOutput: false
|
|
480
|
-
})
|
|
481
|
-
case 'url':
|
|
482
|
-
return databasesCreateUrlAttribute({
|
|
483
|
-
databaseId,
|
|
484
|
-
collectionId,
|
|
485
|
-
key: attribute.key,
|
|
486
|
-
required: attribute.required,
|
|
487
|
-
xdefault: attribute.default,
|
|
488
|
-
array: attribute.array,
|
|
489
|
-
parseOutput: false
|
|
490
|
-
})
|
|
491
|
-
case 'ip':
|
|
492
|
-
return databasesCreateIpAttribute({
|
|
493
|
-
databaseId,
|
|
494
|
-
collectionId,
|
|
495
|
-
key: attribute.key,
|
|
496
|
-
required: attribute.required,
|
|
497
|
-
xdefault: attribute.default,
|
|
498
|
-
array: attribute.array,
|
|
499
|
-
parseOutput: false
|
|
500
|
-
})
|
|
501
|
-
case 'enum':
|
|
502
|
-
return databasesCreateEnumAttribute({
|
|
503
|
-
databaseId,
|
|
504
|
-
collectionId,
|
|
505
|
-
key: attribute.key,
|
|
506
|
-
elements: attribute.elements,
|
|
507
|
-
required: attribute.required,
|
|
508
|
-
xdefault: attribute.default,
|
|
509
|
-
array: attribute.array,
|
|
510
|
-
parseOutput: false
|
|
511
|
-
})
|
|
512
|
-
default:
|
|
513
|
-
return databasesCreateStringAttribute({
|
|
514
|
-
databaseId,
|
|
515
|
-
collectionId,
|
|
516
|
-
key: attribute.key,
|
|
517
|
-
size: attribute.size,
|
|
518
|
-
required: attribute.required,
|
|
519
|
-
xdefault: attribute.default,
|
|
520
|
-
array: attribute.array,
|
|
521
|
-
encrypt: attribute.encrypt,
|
|
522
|
-
parseOutput: false
|
|
523
|
-
})
|
|
524
|
-
|
|
525
|
-
}
|
|
526
|
-
case 'integer':
|
|
527
|
-
return databasesCreateIntegerAttribute({
|
|
528
|
-
databaseId,
|
|
529
|
-
collectionId,
|
|
530
|
-
key: attribute.key,
|
|
531
|
-
required: attribute.required,
|
|
532
|
-
min: attribute.min,
|
|
533
|
-
max: attribute.max,
|
|
534
|
-
xdefault: attribute.default,
|
|
535
|
-
array: attribute.array,
|
|
536
|
-
parseOutput: false
|
|
537
|
-
})
|
|
538
|
-
case 'double':
|
|
539
|
-
return databasesCreateFloatAttribute({
|
|
540
|
-
databaseId,
|
|
541
|
-
collectionId,
|
|
542
|
-
key: attribute.key,
|
|
543
|
-
required: attribute.required,
|
|
544
|
-
min: attribute.min,
|
|
545
|
-
max: attribute.max,
|
|
546
|
-
xdefault: attribute.default,
|
|
547
|
-
array: attribute.array,
|
|
548
|
-
parseOutput: false
|
|
549
|
-
})
|
|
550
|
-
case 'boolean':
|
|
551
|
-
return databasesCreateBooleanAttribute({
|
|
552
|
-
databaseId,
|
|
553
|
-
collectionId,
|
|
554
|
-
key: attribute.key,
|
|
555
|
-
required: attribute.required,
|
|
556
|
-
xdefault: attribute.default,
|
|
557
|
-
array: attribute.array,
|
|
558
|
-
parseOutput: false
|
|
559
|
-
})
|
|
560
|
-
case 'datetime':
|
|
561
|
-
return databasesCreateDatetimeAttribute({
|
|
562
|
-
databaseId,
|
|
563
|
-
collectionId,
|
|
564
|
-
key: attribute.key,
|
|
565
|
-
required: attribute.required,
|
|
566
|
-
xdefault: attribute.default,
|
|
567
|
-
array: attribute.array,
|
|
568
|
-
parseOutput: false
|
|
569
|
-
})
|
|
570
|
-
case 'relationship':
|
|
571
|
-
return databasesCreateRelationshipAttribute({
|
|
572
|
-
databaseId,
|
|
573
|
-
collectionId,
|
|
574
|
-
relatedCollectionId: attribute.relatedTable ?? attribute.relatedCollection,
|
|
575
|
-
type: attribute.relationType,
|
|
576
|
-
twoWay: attribute.twoWay,
|
|
577
|
-
key: attribute.key,
|
|
578
|
-
twoWayKey: attribute.twoWayKey,
|
|
579
|
-
onDelete: attribute.onDelete,
|
|
580
|
-
parseOutput: false
|
|
581
|
-
})
|
|
582
|
-
case 'point':
|
|
583
|
-
return databasesCreatePointAttribute({
|
|
584
|
-
databaseId,
|
|
585
|
-
collectionId,
|
|
586
|
-
key:attribute.key,
|
|
587
|
-
required:attribute.required,
|
|
588
|
-
xdefault:attribute.default,
|
|
589
|
-
parseOutput:false
|
|
590
|
-
})
|
|
591
|
-
case 'linestring':
|
|
592
|
-
return databasesCreateLineAttribute({
|
|
593
|
-
databaseId,
|
|
594
|
-
collectionId,
|
|
595
|
-
key:attribute.key,
|
|
596
|
-
required:attribute.required,
|
|
597
|
-
xdefault:attribute.default,
|
|
598
|
-
parseOutput:false
|
|
599
|
-
})
|
|
600
|
-
case 'polygon':
|
|
601
|
-
return databasesCreatePolygonAttribute({
|
|
602
|
-
databaseId,
|
|
603
|
-
collectionId,
|
|
604
|
-
key:attribute.key,
|
|
605
|
-
required:attribute.required,
|
|
606
|
-
xdefault:attribute.default,
|
|
607
|
-
parseOutput:false
|
|
608
|
-
})
|
|
609
|
-
default:
|
|
610
|
-
throw new Error(`Unsupported attribute type: ${attribute.type}`);
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
const updateAttribute = (databaseId: string, collectionId: string, attribute: any): Promise<any> => {
|
|
615
|
-
switch (attribute.type) {
|
|
616
|
-
case 'string':
|
|
617
|
-
switch (attribute.format) {
|
|
618
|
-
case 'email':
|
|
619
|
-
return databasesUpdateEmailAttribute({
|
|
620
|
-
databaseId,
|
|
621
|
-
collectionId,
|
|
622
|
-
key: attribute.key,
|
|
623
|
-
required: attribute.required,
|
|
624
|
-
xdefault: attribute.default,
|
|
625
|
-
array: attribute.array,
|
|
626
|
-
parseOutput: false
|
|
627
|
-
})
|
|
628
|
-
case 'url':
|
|
629
|
-
return databasesUpdateUrlAttribute({
|
|
630
|
-
databaseId,
|
|
631
|
-
collectionId,
|
|
632
|
-
key: attribute.key,
|
|
633
|
-
required: attribute.required,
|
|
634
|
-
xdefault: attribute.default,
|
|
635
|
-
array: attribute.array,
|
|
636
|
-
parseOutput: false
|
|
637
|
-
})
|
|
638
|
-
case 'ip':
|
|
639
|
-
return databasesUpdateIpAttribute({
|
|
640
|
-
databaseId,
|
|
641
|
-
collectionId,
|
|
642
|
-
key: attribute.key,
|
|
643
|
-
required: attribute.required,
|
|
644
|
-
xdefault: attribute.default,
|
|
645
|
-
array: attribute.array,
|
|
646
|
-
parseOutput: false
|
|
647
|
-
})
|
|
648
|
-
case 'enum':
|
|
649
|
-
return databasesUpdateEnumAttribute({
|
|
650
|
-
databaseId,
|
|
651
|
-
collectionId,
|
|
652
|
-
key: attribute.key,
|
|
653
|
-
elements: attribute.elements,
|
|
654
|
-
required: attribute.required,
|
|
655
|
-
xdefault: attribute.default,
|
|
656
|
-
array: attribute.array,
|
|
657
|
-
parseOutput: false
|
|
658
|
-
})
|
|
659
|
-
default:
|
|
660
|
-
return databasesUpdateStringAttribute({
|
|
661
|
-
databaseId,
|
|
662
|
-
collectionId,
|
|
663
|
-
key: attribute.key,
|
|
664
|
-
size: attribute.size,
|
|
665
|
-
required: attribute.required,
|
|
666
|
-
xdefault: attribute.default,
|
|
667
|
-
array: attribute.array,
|
|
668
|
-
parseOutput: false
|
|
669
|
-
})
|
|
670
|
-
|
|
671
|
-
}
|
|
672
|
-
case 'integer':
|
|
673
|
-
return databasesUpdateIntegerAttribute({
|
|
674
|
-
databaseId,
|
|
675
|
-
collectionId,
|
|
676
|
-
key: attribute.key,
|
|
677
|
-
required: attribute.required,
|
|
678
|
-
min: attribute.min,
|
|
679
|
-
max: attribute.max,
|
|
680
|
-
xdefault: attribute.default,
|
|
681
|
-
array: attribute.array,
|
|
682
|
-
parseOutput: false
|
|
683
|
-
})
|
|
684
|
-
case 'double':
|
|
685
|
-
return databasesUpdateFloatAttribute({
|
|
686
|
-
databaseId,
|
|
687
|
-
collectionId,
|
|
688
|
-
key: attribute.key,
|
|
689
|
-
required: attribute.required,
|
|
690
|
-
min: attribute.min,
|
|
691
|
-
max: attribute.max,
|
|
692
|
-
xdefault: attribute.default,
|
|
693
|
-
array: attribute.array,
|
|
694
|
-
parseOutput: false
|
|
695
|
-
})
|
|
696
|
-
case 'boolean':
|
|
697
|
-
return databasesUpdateBooleanAttribute({
|
|
698
|
-
databaseId,
|
|
699
|
-
collectionId,
|
|
700
|
-
key: attribute.key,
|
|
701
|
-
required: attribute.required,
|
|
702
|
-
xdefault: attribute.default,
|
|
703
|
-
array: attribute.array,
|
|
704
|
-
parseOutput: false
|
|
705
|
-
})
|
|
706
|
-
case 'datetime':
|
|
707
|
-
return databasesUpdateDatetimeAttribute({
|
|
708
|
-
databaseId,
|
|
709
|
-
collectionId,
|
|
710
|
-
key: attribute.key,
|
|
711
|
-
required: attribute.required,
|
|
712
|
-
xdefault: attribute.default,
|
|
713
|
-
array: attribute.array,
|
|
714
|
-
parseOutput: false
|
|
715
|
-
})
|
|
716
|
-
case 'relationship':
|
|
717
|
-
return databasesUpdateRelationshipAttribute({
|
|
718
|
-
databaseId,
|
|
719
|
-
collectionId,
|
|
720
|
-
relatedCollectionId: attribute.relatedTable ?? attribute.relatedCollection,
|
|
721
|
-
type: attribute.relationType,
|
|
722
|
-
twoWay: attribute.twoWay,
|
|
723
|
-
key: attribute.key,
|
|
724
|
-
twoWayKey: attribute.twoWayKey,
|
|
725
|
-
onDelete: attribute.onDelete,
|
|
726
|
-
parseOutput: false
|
|
727
|
-
})
|
|
728
|
-
case 'point':
|
|
729
|
-
return databasesUpdatePointAttribute({
|
|
730
|
-
databaseId,
|
|
731
|
-
collectionId,
|
|
732
|
-
key:attribute.key,
|
|
733
|
-
required:attribute.required,
|
|
734
|
-
xdefault:attribute.default,
|
|
735
|
-
parseOutput:false
|
|
736
|
-
})
|
|
737
|
-
case 'linestring':
|
|
738
|
-
return databasesUpdateLineAttribute({
|
|
739
|
-
databaseId,
|
|
740
|
-
collectionId,
|
|
741
|
-
key:attribute.key,
|
|
742
|
-
required:attribute.required,
|
|
743
|
-
xdefault:attribute.default,
|
|
744
|
-
parseOutput:false
|
|
745
|
-
})
|
|
746
|
-
case 'polygon':
|
|
747
|
-
return databasesUpdatePolygonAttribute({
|
|
748
|
-
databaseId,
|
|
749
|
-
collectionId,
|
|
750
|
-
key:attribute.key,
|
|
751
|
-
required:attribute.required,
|
|
752
|
-
xdefault:attribute.default,
|
|
753
|
-
parseOutput:false
|
|
754
|
-
})
|
|
755
|
-
default:
|
|
756
|
-
throw new Error(`Unsupported attribute type: ${attribute.type}`);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
const deleteAttribute = async (collection: any, attribute: any, isIndex: boolean = false): Promise<void> => {
|
|
760
|
-
log(`Deleting ${isIndex ? 'index' : 'attribute'} ${attribute.key} of ${collection.name} ( ${collection['$id']} )`);
|
|
761
|
-
|
|
762
|
-
if (isIndex) {
|
|
763
|
-
await databasesDeleteIndex({
|
|
764
|
-
databaseId: collection['databaseId'],
|
|
765
|
-
collectionId: collection['$id'],
|
|
766
|
-
key: attribute.key,
|
|
767
|
-
parseOutput: false
|
|
361
|
+
},
|
|
362
|
+
);
|
|
363
|
+
const result = await this.pushCollections(collectionsWithDbNames, {
|
|
364
|
+
skipConfirmation: options.skipConfirmation,
|
|
768
365
|
});
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
const isEqual = (a: any, b: any): boolean => {
|
|
781
|
-
if (a === b) return true;
|
|
782
|
-
|
|
783
|
-
if (a && b && typeof a === 'object' && typeof b === 'object') {
|
|
784
|
-
if (a.constructor && a.constructor.name === 'BigNumber' &&
|
|
785
|
-
b.constructor && b.constructor.name === 'BigNumber') {
|
|
786
|
-
return a.eq(b);
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
if (typeof a.equals === 'function') {
|
|
790
|
-
return a.equals(b);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
if (typeof a.eq === 'function') {
|
|
794
|
-
return a.eq(b);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
if (typeof a === 'number' && typeof b === 'number') {
|
|
799
|
-
if (isNaN(a) && isNaN(b)) return true;
|
|
800
|
-
if (!isFinite(a) && !isFinite(b)) return a === b;
|
|
801
|
-
return Math.abs(a - b) < Number.EPSILON;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
return false;
|
|
805
|
-
};
|
|
806
|
-
|
|
807
|
-
const compareAttribute = (remote: any, local: any, reason: string, key: string): string => {
|
|
808
|
-
if (isEmpty(remote) && isEmpty(local)) {
|
|
809
|
-
return reason;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
if (Array.isArray(remote) && Array.isArray(local)) {
|
|
813
|
-
if (JSON.stringify(remote) !== JSON.stringify(local)) {
|
|
814
|
-
const bol = reason === '' ? '' : '\n';
|
|
815
|
-
reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`;
|
|
816
|
-
}
|
|
817
|
-
} else if (!isEqual(remote, local)) {
|
|
818
|
-
const bol = reason === '' ? '' : '\n';
|
|
819
|
-
reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
return reason
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
interface AttributeChange {
|
|
826
|
-
key: string;
|
|
827
|
-
attribute: any;
|
|
828
|
-
reason: string;
|
|
829
|
-
action: string;
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
/**
|
|
833
|
-
* Check if attribute non-changeable fields has been changed
|
|
834
|
-
* If so return the differences as an object.
|
|
835
|
-
*/
|
|
836
|
-
const checkAttributeChanges = (remote: any, local: any, collection: any, recreating: boolean = true): AttributeChange | undefined => {
|
|
837
|
-
if (local === undefined) {
|
|
838
|
-
return undefined;
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
const keyName = `${chalk.yellow(local.key)} in ${collection.name} (${collection['$id']})`;
|
|
842
|
-
const action = chalk.cyan(recreating ? 'recreating' : 'changing');
|
|
843
|
-
let reason = '';
|
|
844
|
-
let attribute = recreating ? remote : local;
|
|
845
|
-
|
|
846
|
-
for (let key of Object.keys(remote)) {
|
|
847
|
-
if (!KeysAttributes.has(key)) {
|
|
848
|
-
continue;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
if (changeableKeys.includes(key)) {
|
|
852
|
-
if (!recreating) {
|
|
853
|
-
reason = compareAttribute(remote[key], local[key], reason, key)
|
|
854
|
-
}
|
|
855
|
-
continue;
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
if (!recreating) {
|
|
859
|
-
continue;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
reason = compareAttribute(remote[key], local[key], reason, key)
|
|
366
|
+
this.success(
|
|
367
|
+
`Successfully pushed ${chalk.bold(result.successfullyPushed)} collections.`,
|
|
368
|
+
);
|
|
369
|
+
results.collections = result;
|
|
370
|
+
allErrors.push(...result.errors);
|
|
371
|
+
} catch (e: any) {
|
|
372
|
+
allErrors.push(e);
|
|
373
|
+
results.collections = { successfullyPushed: 0, errors: [e] };
|
|
374
|
+
}
|
|
863
375
|
}
|
|
864
376
|
|
|
865
|
-
return reason === '' ? undefined : { key: keyName, attribute, reason, action };
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
/**
|
|
869
|
-
* Check if attributes contain the given attribute
|
|
870
|
-
*/
|
|
871
|
-
const attributesContains = (attribute: any, attributes: any[]): any => attributes.find((attr) => attr.key === attribute.key);
|
|
872
|
-
|
|
873
|
-
const generateChangesObject = (attribute: any, collection: any, isAdding: boolean): AttributeChange => {
|
|
874
377
|
return {
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
reason: isAdding ? 'Field isn\'t present on the remote server' : 'Field isn\'t present on the appwrite.config.json file',
|
|
878
|
-
action: isAdding ? chalk.green('adding') : chalk.red('deleting')
|
|
378
|
+
results,
|
|
379
|
+
errors: allErrors,
|
|
879
380
|
};
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
const
|
|
889
|
-
const
|
|
890
|
-
const
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
if (!cliConfig.force) {
|
|
908
|
-
if (deleting.length > 0 && !isIndex) {
|
|
909
|
-
console.log(`${chalk.red('------------------------------------------------------')}`);
|
|
910
|
-
console.log(`${chalk.red('| WARNING: Attribute deletion may cause loss of data |')}`);
|
|
911
|
-
console.log(`${chalk.red('------------------------------------------------------')}`);
|
|
912
|
-
console.log();
|
|
913
|
-
}
|
|
914
|
-
if (conflicts.length > 0 && !isIndex) {
|
|
915
|
-
console.log(`${chalk.red('--------------------------------------------------------')}`);
|
|
916
|
-
console.log(`${chalk.red('| WARNING: Attribute recreation may cause loss of data |')}`);
|
|
917
|
-
console.log(`${chalk.red('--------------------------------------------------------')}`);
|
|
918
|
-
console.log();
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
if ((await getConfirmation()) !== true) {
|
|
922
|
-
return changedAttributes;
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
if (conflicts.length > 0) {
|
|
927
|
-
changedAttributes = conflicts.map((change) => change.attribute);
|
|
928
|
-
await Promise.all(changedAttributes.map((changed) => deleteAttribute(collection, changed, isIndex)));
|
|
929
|
-
remoteAttributes = remoteAttributes.filter((attribute) => !attributesContains(attribute, changedAttributes))
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
if (changes.length > 0) {
|
|
933
|
-
changedAttributes = changes.map((change) => change.attribute);
|
|
934
|
-
await Promise.all(changedAttributes.map((changed) => updateAttribute(collection['databaseId'], collection['$id'], changed)));
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
const deletingAttributes = deleting.map((change) => change.attribute);
|
|
938
|
-
await Promise.all(deletingAttributes.map((attribute) => deleteAttribute(collection, attribute, isIndex)));
|
|
939
|
-
const attributeKeys = [...remoteAttributes.map((attribute: any) => attribute.key), ...deletingAttributes.map((attribute: any) => attribute.key)]
|
|
940
|
-
|
|
941
|
-
if (attributeKeys.length) {
|
|
942
|
-
const deleteAttributesPoolStatus = await awaitPools.deleteAttributes(collection['databaseId'], collection['$id'], attributeKeys);
|
|
943
|
-
|
|
944
|
-
if (!deleteAttributesPoolStatus) {
|
|
945
|
-
throw new Error("Attribute deletion timed out.");
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
return localAttributes.filter((attribute) => !attributesContains(attribute, remoteAttributes));
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
const createIndexes = async (indexes: any[], collection: any): Promise<void> => {
|
|
953
|
-
log(`Creating indexes ...`)
|
|
954
|
-
|
|
955
|
-
for (let index of indexes) {
|
|
956
|
-
await databasesCreateIndex({
|
|
957
|
-
databaseId: collection['databaseId'],
|
|
958
|
-
collectionId: collection['$id'],
|
|
959
|
-
key: index.key,
|
|
960
|
-
type: index.type,
|
|
961
|
-
attributes: index.columns ?? index.attributes,
|
|
962
|
-
orders: index.orders,
|
|
963
|
-
parseOutput: false
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
public async pushSettings(config: {
|
|
384
|
+
projectId: string;
|
|
385
|
+
projectName?: string;
|
|
386
|
+
settings?: SettingsType;
|
|
387
|
+
}): Promise<void> {
|
|
388
|
+
const projectsService = await getProjectsService(this.consoleClient);
|
|
389
|
+
const projectId = config.projectId;
|
|
390
|
+
const projectName = config.projectName;
|
|
391
|
+
const settings = config.settings ?? {};
|
|
392
|
+
|
|
393
|
+
if (projectName) {
|
|
394
|
+
this.log("Applying project name ...");
|
|
395
|
+
await projectsService.update({
|
|
396
|
+
projectId: projectId,
|
|
397
|
+
name: projectName,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (settings.services) {
|
|
402
|
+
this.log("Applying service statuses ...");
|
|
403
|
+
for (let [service, status] of Object.entries(settings.services)) {
|
|
404
|
+
await projectsService.updateServiceStatus({
|
|
405
|
+
projectId: projectId,
|
|
406
|
+
service: service as ApiService,
|
|
407
|
+
status: status,
|
|
964
408
|
});
|
|
409
|
+
}
|
|
965
410
|
}
|
|
966
411
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
if (!result) {
|
|
974
|
-
throw new Error('Index creation timed out.');
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
success(`Created ${indexes.length} indexes`);
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
const createAttributes = async (attributes: any[], collection: any): Promise<void> => {
|
|
981
|
-
for (let attribute of attributes) {
|
|
982
|
-
if (attribute.side !== 'child') {
|
|
983
|
-
await createAttribute(collection['databaseId'], collection['$id'], attribute);
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
const result = await awaitPools.expectAttributes(
|
|
988
|
-
collection['databaseId'],
|
|
989
|
-
collection['$id'],
|
|
990
|
-
collection.attributes.filter((attribute: any) => attribute.side !== 'child').map((attribute: any) => attribute.key)
|
|
991
|
-
);
|
|
992
|
-
|
|
993
|
-
if (!result) {
|
|
994
|
-
throw new Error(`Attribute creation timed out.`);
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
success(`Created ${attributes.length} attributes`);
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
const createColumns = async (columns: any[], table: any): Promise<void> => {
|
|
1001
|
-
for (let column of columns) {
|
|
1002
|
-
if (column.side !== 'child') {
|
|
1003
|
-
await createAttribute(table['databaseId'], table['$id'], column);
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
const result = await awaitPools.expectAttributes(
|
|
1008
|
-
table['databaseId'],
|
|
1009
|
-
table['$id'],
|
|
1010
|
-
table.columns.filter((column: any) => column.side !== 'child').map((column: any) => column.key)
|
|
1011
|
-
);
|
|
1012
|
-
|
|
1013
|
-
if (!result) {
|
|
1014
|
-
throw new Error(`Column creation timed out.`);
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
success(`Created ${columns.length} columns`);
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
const pushResources = async (): Promise<void> => {
|
|
1021
|
-
const actions: Record<string, (options?: any) => Promise<void>> = {
|
|
1022
|
-
settings: pushSettings,
|
|
1023
|
-
functions: pushFunction,
|
|
1024
|
-
sites: pushSite,
|
|
1025
|
-
collections: pushCollection,
|
|
1026
|
-
tables: pushTable,
|
|
1027
|
-
buckets: pushBucket,
|
|
1028
|
-
teams: pushTeam,
|
|
1029
|
-
messages: pushMessagingTopic
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
if (cliConfig.all) {
|
|
1033
|
-
for (let action of Object.values(actions)) {
|
|
1034
|
-
await action({ returnOnZero: true });
|
|
1035
|
-
}
|
|
1036
|
-
} else {
|
|
1037
|
-
const answers = await inquirer.prompt(questionsPushResources[0]);
|
|
1038
|
-
|
|
1039
|
-
const action = actions[answers.resource];
|
|
1040
|
-
if (action !== undefined) {
|
|
1041
|
-
await action({ returnOnZero: true });
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
};
|
|
1045
|
-
|
|
1046
|
-
const pushSettings = async (): Promise<void> => {
|
|
1047
|
-
checkDeployConditions(localConfig);
|
|
1048
|
-
|
|
1049
|
-
try {
|
|
1050
|
-
let response = await projectsGet({
|
|
1051
|
-
parseOutput: false,
|
|
1052
|
-
projectId: localConfig.getProject().projectId
|
|
412
|
+
if (settings.auth) {
|
|
413
|
+
if (settings.auth.security) {
|
|
414
|
+
this.log("Applying auth security settings ...");
|
|
415
|
+
await projectsService.updateAuthDuration({
|
|
416
|
+
projectId,
|
|
417
|
+
duration: settings.auth.security.duration,
|
|
1053
418
|
});
|
|
419
|
+
await projectsService.updateAuthLimit({
|
|
420
|
+
projectId,
|
|
421
|
+
limit: settings.auth.security.limit,
|
|
422
|
+
});
|
|
423
|
+
await projectsService.updateAuthSessionsLimit({
|
|
424
|
+
projectId,
|
|
425
|
+
limit: settings.auth.security.sessionsLimit,
|
|
426
|
+
});
|
|
427
|
+
await projectsService.updateAuthPasswordDictionary({
|
|
428
|
+
projectId,
|
|
429
|
+
enabled: settings.auth.security.passwordDictionary,
|
|
430
|
+
});
|
|
431
|
+
await projectsService.updateAuthPasswordHistory({
|
|
432
|
+
projectId,
|
|
433
|
+
limit: settings.auth.security.passwordHistory,
|
|
434
|
+
});
|
|
435
|
+
await projectsService.updatePersonalDataCheck({
|
|
436
|
+
projectId,
|
|
437
|
+
enabled: settings.auth.security.personalDataCheck,
|
|
438
|
+
});
|
|
439
|
+
await projectsService.updateSessionAlerts({
|
|
440
|
+
projectId,
|
|
441
|
+
alerts: settings.auth.security.sessionAlerts,
|
|
442
|
+
});
|
|
443
|
+
await projectsService.updateMockNumbers({
|
|
444
|
+
projectId,
|
|
445
|
+
numbers: settings.auth.security.mockNumbers,
|
|
446
|
+
});
|
|
447
|
+
}
|
|
1054
448
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
changes.push(...(getObjectChanges(remoteSettings['auth'] ?? {}, localSettings['auth'] ?? {}, 'security', 'Auth security')));
|
|
1064
|
-
|
|
1065
|
-
if (changes.length > 0) {
|
|
1066
|
-
drawTable(changes);
|
|
1067
|
-
if ((await getConfirmation()) !== true) {
|
|
1068
|
-
success(`Successfully pushed 0 project settings.`);
|
|
1069
|
-
return;
|
|
1070
|
-
}
|
|
449
|
+
if (settings.auth.methods) {
|
|
450
|
+
this.log("Applying auth methods statuses ...");
|
|
451
|
+
for (let [method, status] of Object.entries(settings.auth.methods)) {
|
|
452
|
+
await projectsService.updateAuthStatus({
|
|
453
|
+
projectId,
|
|
454
|
+
method: method as AuthMethod,
|
|
455
|
+
status: status,
|
|
456
|
+
});
|
|
1071
457
|
}
|
|
1072
|
-
|
|
458
|
+
}
|
|
1073
459
|
}
|
|
460
|
+
}
|
|
1074
461
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
if (projectName) {
|
|
1083
|
-
log("Applying project name ...");
|
|
1084
|
-
await projectsUpdate({
|
|
1085
|
-
projectId,
|
|
1086
|
-
name: projectName,
|
|
1087
|
-
parseOutput: false
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
if (settings.services) {
|
|
1092
|
-
log("Applying service statuses ...");
|
|
1093
|
-
for (let [service, status] of Object.entries(settings.services)) {
|
|
1094
|
-
await projectsUpdateServiceStatus({
|
|
1095
|
-
projectId,
|
|
1096
|
-
service,
|
|
1097
|
-
status,
|
|
1098
|
-
parseOutput: false
|
|
1099
|
-
});
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
if (settings.auth) {
|
|
1104
|
-
if (settings.auth.security) {
|
|
1105
|
-
log("Applying auth security settings ...");
|
|
1106
|
-
await projectsUpdateAuthDuration({ projectId, duration: settings.auth.security.duration, parseOutput: false });
|
|
1107
|
-
await projectsUpdateAuthLimit({ projectId, limit: settings.auth.security.limit, parseOutput: false });
|
|
1108
|
-
await projectsUpdateAuthSessionsLimit({ projectId, limit: settings.auth.security.sessionsLimit, parseOutput: false });
|
|
1109
|
-
await projectsUpdateAuthPasswordDictionary({ projectId, enabled: settings.auth.security.passwordDictionary, parseOutput: false });
|
|
1110
|
-
await projectsUpdateAuthPasswordHistory({ projectId, limit: settings.auth.security.passwordHistory, parseOutput: false });
|
|
1111
|
-
await projectsUpdatePersonalDataCheck({ projectId, enabled: settings.auth.security.personalDataCheck, parseOutput: false });
|
|
1112
|
-
await projectsUpdateSessionAlerts({ projectId, alerts: settings.auth.security.sessionAlerts, parseOutput: false });
|
|
1113
|
-
await projectsUpdateMockNumbers({ projectId, numbers: settings.auth.security.mockNumbers, parseOutput: false });
|
|
1114
|
-
}
|
|
462
|
+
public async pushBuckets(buckets: any[]): Promise<{
|
|
463
|
+
successfullyPushed: number;
|
|
464
|
+
errors: any[];
|
|
465
|
+
}> {
|
|
466
|
+
let successfullyPushed = 0;
|
|
467
|
+
const errors: any[] = [];
|
|
1115
468
|
|
|
1116
|
-
|
|
1117
|
-
|
|
469
|
+
for (const bucket of buckets) {
|
|
470
|
+
try {
|
|
471
|
+
this.log(`Pushing bucket ${chalk.bold(bucket["name"])} ...`);
|
|
472
|
+
const storageService = await getStorageService(this.projectClient);
|
|
1118
473
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
474
|
+
try {
|
|
475
|
+
await storageService.getBucket(bucket["$id"]);
|
|
476
|
+
await storageService.updateBucket({
|
|
477
|
+
bucketId: bucket["$id"],
|
|
478
|
+
name: bucket.name,
|
|
479
|
+
permissions: bucket["$permissions"],
|
|
480
|
+
fileSecurity: bucket.fileSecurity,
|
|
481
|
+
enabled: bucket.enabled,
|
|
482
|
+
maximumFileSize: bucket.maximumFileSize,
|
|
483
|
+
allowedFileExtensions: bucket.allowedFileExtensions,
|
|
484
|
+
encryption: bucket.encryption,
|
|
485
|
+
antivirus: bucket.antivirus,
|
|
486
|
+
compression: bucket.compression,
|
|
487
|
+
});
|
|
488
|
+
} catch (e: unknown) {
|
|
489
|
+
if (e instanceof AppwriteException && Number(e.code) === 404) {
|
|
490
|
+
await storageService.createBucket({
|
|
491
|
+
bucketId: bucket["$id"],
|
|
492
|
+
name: bucket.name,
|
|
493
|
+
permissions: bucket["$permissions"],
|
|
494
|
+
fileSecurity: bucket.fileSecurity,
|
|
495
|
+
enabled: bucket.enabled,
|
|
496
|
+
maximumFileSize: bucket.maximumFileSize,
|
|
497
|
+
allowedFileExtensions: bucket.allowedFileExtensions,
|
|
498
|
+
compression: bucket.compression,
|
|
499
|
+
encryption: bucket.encryption,
|
|
500
|
+
antivirus: bucket.antivirus,
|
|
501
|
+
});
|
|
502
|
+
} else {
|
|
503
|
+
throw e;
|
|
504
|
+
}
|
|
1128
505
|
}
|
|
1129
506
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
507
|
+
successfullyPushed++;
|
|
508
|
+
} catch (e: any) {
|
|
509
|
+
errors.push(e);
|
|
510
|
+
this.error(`Failed to push bucket ${bucket["name"]}: ${e.message}`);
|
|
511
|
+
}
|
|
1133
512
|
}
|
|
1134
|
-
}
|
|
1135
513
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
returnOnZero?: boolean;
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
const pushSite = async({ siteId, async: asyncDeploy, code, withVariables }: PushSiteOptions = { returnOnZero: false }): Promise<void> => {
|
|
1145
|
-
process.chdir(localConfig.configDirectoryPath)
|
|
514
|
+
return {
|
|
515
|
+
successfullyPushed,
|
|
516
|
+
errors,
|
|
517
|
+
};
|
|
518
|
+
}
|
|
1146
519
|
|
|
1147
|
-
|
|
520
|
+
public async pushTeams(teams: any[]): Promise<{
|
|
521
|
+
successfullyPushed: number;
|
|
522
|
+
errors: any[];
|
|
523
|
+
}> {
|
|
524
|
+
let successfullyPushed = 0;
|
|
525
|
+
const errors: any[] = [];
|
|
1148
526
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
const sites = localConfig.getSites();
|
|
1154
|
-
siteIds.push(...sites.map((site: any) => {
|
|
1155
|
-
return site.$id;
|
|
1156
|
-
}));
|
|
1157
|
-
}
|
|
527
|
+
for (const team of teams) {
|
|
528
|
+
try {
|
|
529
|
+
this.log(`Pushing team ${chalk.bold(team["name"])} ...`);
|
|
530
|
+
const teamsService = await getTeamsService(this.projectClient);
|
|
1158
531
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
532
|
+
try {
|
|
533
|
+
await teamsService.get(team["$id"]);
|
|
534
|
+
await teamsService.updateName({
|
|
535
|
+
teamId: team["$id"],
|
|
536
|
+
name: team.name,
|
|
537
|
+
});
|
|
538
|
+
} catch (e: unknown) {
|
|
539
|
+
if (e instanceof AppwriteException && Number(e.code) === 404) {
|
|
540
|
+
await teamsService.create({
|
|
541
|
+
teamId: team["$id"],
|
|
542
|
+
name: team.name,
|
|
543
|
+
});
|
|
544
|
+
} else {
|
|
545
|
+
throw e;
|
|
546
|
+
}
|
|
1163
547
|
}
|
|
1164
|
-
}
|
|
1165
548
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
549
|
+
successfullyPushed++;
|
|
550
|
+
} catch (e: any) {
|
|
551
|
+
errors.push(e);
|
|
552
|
+
this.error(`Failed to push team ${team["name"]}: ${e.message}`);
|
|
553
|
+
}
|
|
1170
554
|
}
|
|
1171
555
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
throw new Error("Site '" + id + "' not found.")
|
|
1178
|
-
}
|
|
556
|
+
return {
|
|
557
|
+
successfullyPushed,
|
|
558
|
+
errors,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
1179
561
|
|
|
1180
|
-
|
|
1181
|
-
|
|
562
|
+
public async pushMessagingTopics(topics: any[]): Promise<{
|
|
563
|
+
successfullyPushed: number;
|
|
564
|
+
errors: any[];
|
|
565
|
+
}> {
|
|
566
|
+
let successfullyPushed = 0;
|
|
567
|
+
const errors: any[] = [];
|
|
1182
568
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
569
|
+
for (const topic of topics) {
|
|
570
|
+
try {
|
|
571
|
+
this.log(`Pushing topic ${chalk.bold(topic["name"])} ...`);
|
|
572
|
+
const messagingService = await getMessagingService(this.projectClient);
|
|
1186
573
|
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
574
|
+
try {
|
|
575
|
+
await messagingService.getTopic(topic["$id"]);
|
|
576
|
+
await messagingService.updateTopic({
|
|
577
|
+
topicId: topic["$id"],
|
|
578
|
+
name: topic.name,
|
|
579
|
+
subscribe: topic.subscribe,
|
|
580
|
+
});
|
|
581
|
+
} catch (e: unknown) {
|
|
582
|
+
if (e instanceof AppwriteException && Number(e.code) === 404) {
|
|
583
|
+
await messagingService.createTopic({
|
|
584
|
+
topicId: topic["$id"],
|
|
585
|
+
name: topic.name,
|
|
586
|
+
subscribe: topic.subscribe,
|
|
587
|
+
});
|
|
588
|
+
} else {
|
|
589
|
+
throw e;
|
|
590
|
+
}
|
|
1192
591
|
}
|
|
1193
|
-
}
|
|
1194
592
|
|
|
1195
|
-
|
|
1196
|
-
|
|
593
|
+
this.success(`Pushed ${topic.name} ( ${topic["$id"]} )`);
|
|
594
|
+
successfullyPushed++;
|
|
595
|
+
} catch (e: any) {
|
|
596
|
+
errors.push(e);
|
|
597
|
+
this.error(`Failed to push topic ${topic["name"]}: ${e.message}`);
|
|
598
|
+
}
|
|
1197
599
|
}
|
|
1198
600
|
|
|
1199
|
-
|
|
601
|
+
return {
|
|
602
|
+
successfullyPushed,
|
|
603
|
+
errors,
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
public async pushFunctions(
|
|
608
|
+
functions: any[],
|
|
609
|
+
options: {
|
|
610
|
+
async?: boolean;
|
|
611
|
+
code?: boolean;
|
|
612
|
+
withVariables?: boolean;
|
|
613
|
+
} = {},
|
|
614
|
+
): Promise<{
|
|
615
|
+
successfullyPushed: number;
|
|
616
|
+
successfullyDeployed: number;
|
|
617
|
+
failedDeployments: any[];
|
|
618
|
+
errors: any[];
|
|
619
|
+
}> {
|
|
620
|
+
const { async: asyncDeploy, code, withVariables } = options;
|
|
1200
621
|
|
|
1201
622
|
Spinner.start(false);
|
|
1202
623
|
let successfullyPushed = 0;
|
|
@@ -1204,1411 +625,1832 @@ const pushSite = async({ siteId, async: asyncDeploy, code, withVariables }: Push
|
|
|
1204
625
|
const failedDeployments: any[] = [];
|
|
1205
626
|
const errors: any[] = [];
|
|
1206
627
|
|
|
1207
|
-
await Promise.all(
|
|
628
|
+
await Promise.all(
|
|
629
|
+
functions.map(async (func: any) => {
|
|
1208
630
|
let response: any = {};
|
|
1209
631
|
|
|
1210
|
-
const ignore =
|
|
1211
|
-
let
|
|
632
|
+
const ignore = func.ignore ? "appwrite.config.json" : ".gitignore";
|
|
633
|
+
let functionExists = false;
|
|
1212
634
|
let deploymentCreated = false;
|
|
1213
635
|
|
|
1214
|
-
const updaterRow = new Spinner({
|
|
1215
|
-
|
|
1216
|
-
|
|
636
|
+
const updaterRow = new Spinner({
|
|
637
|
+
status: "",
|
|
638
|
+
resource: func.name,
|
|
639
|
+
id: func["$id"],
|
|
640
|
+
end: `Ignoring using: ${ignore}`,
|
|
641
|
+
});
|
|
1217
642
|
|
|
643
|
+
updaterRow.update({ status: "Getting" }).startSpinner(SPINNER_DOTS);
|
|
644
|
+
const functionsService = await getFunctionsService(this.projectClient);
|
|
1218
645
|
try {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
if (response.framework !== site.framework) {
|
|
1225
|
-
updaterRow.fail({ errorMessage: `Framework mismatch! (local=${site.framework},remote=${response.framework}) Please delete remote site or update your appwrite.config.json` })
|
|
1226
|
-
return;
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
updaterRow.update({ status: 'Updating' }).replaceSpinner(SPINNER_ARC);
|
|
1230
|
-
|
|
1231
|
-
response = await sitesUpdate({
|
|
1232
|
-
siteId: site['$id'],
|
|
1233
|
-
name: site.name,
|
|
1234
|
-
framework: site.framework,
|
|
1235
|
-
buildRuntime: site.buildRuntime,
|
|
1236
|
-
specification: site.specification,
|
|
1237
|
-
timeout: site.timeout,
|
|
1238
|
-
enabled: site.enabled,
|
|
1239
|
-
logging: site.logging,
|
|
1240
|
-
adapter: site.adapter,
|
|
1241
|
-
buildCommand: site.buildCommand,
|
|
1242
|
-
installCommand: site.installCommand,
|
|
1243
|
-
outputDirectory: site.outputDirectory,
|
|
1244
|
-
fallbackFile: site.fallbackFile,
|
|
1245
|
-
vars: JSON.stringify(response.vars),
|
|
1246
|
-
parseOutput: false
|
|
646
|
+
response = await functionsService.get({ functionId: func["$id"] });
|
|
647
|
+
functionExists = true;
|
|
648
|
+
if (response.runtime !== func.runtime) {
|
|
649
|
+
updaterRow.fail({
|
|
650
|
+
errorMessage: `Runtime mismatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.config.json`,
|
|
1247
651
|
});
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
updaterRow
|
|
656
|
+
.update({ status: "Updating" })
|
|
657
|
+
.replaceSpinner(SPINNER_DOTS);
|
|
658
|
+
|
|
659
|
+
response = await functionsService.update({
|
|
660
|
+
functionId: func["$id"],
|
|
661
|
+
name: func.name,
|
|
662
|
+
runtime: func.runtime,
|
|
663
|
+
execute: func.execute,
|
|
664
|
+
events: func.events,
|
|
665
|
+
schedule: func.schedule,
|
|
666
|
+
timeout: func.timeout,
|
|
667
|
+
enabled: func.enabled,
|
|
668
|
+
logging: func.logging,
|
|
669
|
+
entrypoint: func.entrypoint,
|
|
670
|
+
commands: func.commands,
|
|
671
|
+
scopes: func.scopes,
|
|
672
|
+
specification: func.specification,
|
|
673
|
+
});
|
|
1248
674
|
} catch (e: any) {
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
}
|
|
675
|
+
if (Number(e.code) === 404) {
|
|
676
|
+
functionExists = false;
|
|
677
|
+
} else {
|
|
678
|
+
errors.push(e);
|
|
679
|
+
updaterRow.fail({
|
|
680
|
+
errorMessage:
|
|
681
|
+
e.message ?? "General error occurs please try again",
|
|
682
|
+
});
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
1257
685
|
}
|
|
1258
686
|
|
|
1259
|
-
if (!
|
|
1260
|
-
|
|
687
|
+
if (!functionExists) {
|
|
688
|
+
updaterRow
|
|
689
|
+
.update({ status: "Creating" })
|
|
690
|
+
.replaceSpinner(SPINNER_DOTS);
|
|
691
|
+
|
|
692
|
+
try {
|
|
693
|
+
response = await functionsService.create({
|
|
694
|
+
functionId: func.$id,
|
|
695
|
+
name: func.name,
|
|
696
|
+
runtime: func.runtime,
|
|
697
|
+
execute: func.execute,
|
|
698
|
+
events: func.events,
|
|
699
|
+
schedule: func.schedule,
|
|
700
|
+
timeout: func.timeout,
|
|
701
|
+
enabled: func.enabled,
|
|
702
|
+
logging: func.logging,
|
|
703
|
+
entrypoint: func.entrypoint,
|
|
704
|
+
commands: func.commands,
|
|
705
|
+
scopes: func.scopes,
|
|
706
|
+
specification: func.specification,
|
|
707
|
+
});
|
|
1261
708
|
|
|
709
|
+
let domain = "";
|
|
1262
710
|
try {
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
fallbackFile: site.fallbackFile,
|
|
1273
|
-
adapter: site.adapter,
|
|
1274
|
-
timeout: site.timeout,
|
|
1275
|
-
enabled: site.enabled,
|
|
1276
|
-
logging: site.logging,
|
|
1277
|
-
parseOutput: false
|
|
1278
|
-
});
|
|
1279
|
-
|
|
1280
|
-
let domain = '';
|
|
1281
|
-
try {
|
|
1282
|
-
const variables = await consoleVariables({ parseOutput: false, sdk: await sdkForConsole() });
|
|
1283
|
-
domain = ID.unique() + '.' + variables['_APP_DOMAIN_SITES'];
|
|
1284
|
-
} catch (error) {
|
|
1285
|
-
console.error('Error fetching console variables.');
|
|
1286
|
-
throw error;
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
try {
|
|
1290
|
-
const rule = await proxyCreateSiteRule(
|
|
1291
|
-
{
|
|
1292
|
-
domain: domain,
|
|
1293
|
-
siteId: site.$id
|
|
1294
|
-
}
|
|
1295
|
-
);
|
|
1296
|
-
} catch (error) {
|
|
1297
|
-
console.error('Error creating site rule.');
|
|
1298
|
-
throw error;
|
|
1299
|
-
}
|
|
711
|
+
const consoleService = await getConsoleService(
|
|
712
|
+
this.consoleClient,
|
|
713
|
+
);
|
|
714
|
+
const variables = await consoleService.variables();
|
|
715
|
+
domain = ID.unique() + "." + variables["_APP_DOMAIN_FUNCTIONS"];
|
|
716
|
+
} catch (err) {
|
|
717
|
+
this.error("Error fetching console variables.");
|
|
718
|
+
throw err;
|
|
719
|
+
}
|
|
1300
720
|
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
721
|
+
try {
|
|
722
|
+
const proxyService = await getProxyService(this.projectClient);
|
|
723
|
+
await proxyService.createFunctionRule(domain, func.$id);
|
|
724
|
+
} catch (err) {
|
|
725
|
+
this.error("Error creating function rule.");
|
|
726
|
+
throw err;
|
|
1306
727
|
}
|
|
728
|
+
|
|
729
|
+
updaterRow.update({ status: "Created" });
|
|
730
|
+
} catch (e: any) {
|
|
731
|
+
errors.push(e);
|
|
732
|
+
updaterRow.fail({
|
|
733
|
+
errorMessage:
|
|
734
|
+
e.message ?? "General error occurs please try again",
|
|
735
|
+
});
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
1307
738
|
}
|
|
1308
739
|
|
|
1309
740
|
if (withVariables) {
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
741
|
+
updaterRow
|
|
742
|
+
.update({ status: "Updating variables" })
|
|
743
|
+
.replaceSpinner(SPINNER_DOTS);
|
|
744
|
+
|
|
745
|
+
const functionsServiceForVars = await getFunctionsService(
|
|
746
|
+
this.projectClient,
|
|
747
|
+
);
|
|
748
|
+
const { variables } = await paginate(
|
|
749
|
+
async (args: any) => {
|
|
750
|
+
return await functionsServiceForVars.listVariables({
|
|
751
|
+
functionId: args.functionId,
|
|
752
|
+
});
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
functionId: func["$id"],
|
|
756
|
+
},
|
|
757
|
+
100,
|
|
758
|
+
"variables",
|
|
759
|
+
);
|
|
760
|
+
|
|
761
|
+
await Promise.all(
|
|
762
|
+
variables.map(async (variable: any) => {
|
|
763
|
+
const functionsServiceDel = await getFunctionsService(
|
|
764
|
+
this.projectClient,
|
|
765
|
+
);
|
|
766
|
+
await functionsServiceDel.deleteVariable({
|
|
767
|
+
functionId: func["$id"],
|
|
768
|
+
variableId: variable["$id"],
|
|
769
|
+
});
|
|
770
|
+
}),
|
|
771
|
+
);
|
|
772
|
+
|
|
773
|
+
const envFileLocation = `${func["path"]}/.env`;
|
|
774
|
+
let envVariables: Array<{ key: string; value: string }> = [];
|
|
775
|
+
try {
|
|
776
|
+
if (fs.existsSync(envFileLocation)) {
|
|
777
|
+
const envObject = parseDotenv(
|
|
778
|
+
fs.readFileSync(envFileLocation, "utf8"),
|
|
779
|
+
);
|
|
780
|
+
envVariables = Object.entries(envObject || {}).map(
|
|
781
|
+
([key, value]) => ({ key, value }),
|
|
782
|
+
);
|
|
1335
783
|
}
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
784
|
+
} catch (error) {
|
|
785
|
+
envVariables = [];
|
|
786
|
+
}
|
|
787
|
+
await Promise.all(
|
|
788
|
+
envVariables.map(async (variable) => {
|
|
789
|
+
const functionsServiceCreate = await getFunctionsService(
|
|
790
|
+
this.projectClient,
|
|
791
|
+
);
|
|
792
|
+
await functionsServiceCreate.createVariable({
|
|
793
|
+
functionId: func["$id"],
|
|
794
|
+
key: variable.key,
|
|
795
|
+
value: variable.value,
|
|
796
|
+
secret: false,
|
|
797
|
+
});
|
|
798
|
+
}),
|
|
799
|
+
);
|
|
1345
800
|
}
|
|
1346
801
|
|
|
1347
802
|
if (code === false) {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
803
|
+
successfullyPushed++;
|
|
804
|
+
successfullyDeployed++;
|
|
805
|
+
updaterRow.update({ status: "Pushed" });
|
|
806
|
+
updaterRow.stopSpinner();
|
|
807
|
+
return;
|
|
1353
808
|
}
|
|
1354
809
|
|
|
1355
810
|
try {
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
811
|
+
updaterRow.update({ status: "Pushing" }).replaceSpinner(SPINNER_DOTS);
|
|
812
|
+
const functionsServiceDeploy = await getFunctionsService(
|
|
813
|
+
this.projectClient,
|
|
814
|
+
);
|
|
815
|
+
|
|
816
|
+
const result = await pushDeployment({
|
|
817
|
+
resourcePath: func.path,
|
|
818
|
+
createDeployment: async (codeFile) => {
|
|
819
|
+
return await functionsServiceDeploy.createDeployment({
|
|
820
|
+
functionId: func["$id"],
|
|
821
|
+
entrypoint: func.entrypoint,
|
|
822
|
+
commands: func.commands,
|
|
823
|
+
code: codeFile,
|
|
1364
824
|
activate: true,
|
|
1365
|
-
|
|
1366
|
-
}
|
|
825
|
+
});
|
|
826
|
+
},
|
|
827
|
+
pollForStatus: false,
|
|
828
|
+
});
|
|
1367
829
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
successfullyPushed++;
|
|
1371
|
-
} catch (e: any) {
|
|
1372
|
-
errors.push(e);
|
|
830
|
+
response = result.deployment;
|
|
831
|
+
updaterRow.update({ status: "Pushed" });
|
|
1373
832
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
833
|
+
deploymentCreated = true;
|
|
834
|
+
successfullyPushed++;
|
|
835
|
+
} catch (e: any) {
|
|
836
|
+
errors.push(e);
|
|
837
|
+
|
|
838
|
+
switch (e.code) {
|
|
839
|
+
case "ENOENT":
|
|
840
|
+
updaterRow.fail({
|
|
841
|
+
errorMessage: "Not found in the current directory. Skipping...",
|
|
842
|
+
});
|
|
843
|
+
break;
|
|
844
|
+
default:
|
|
845
|
+
updaterRow.fail({
|
|
846
|
+
errorMessage:
|
|
847
|
+
e.message ?? "An unknown error occurred. Please try again.",
|
|
848
|
+
});
|
|
849
|
+
}
|
|
1381
850
|
}
|
|
1382
851
|
|
|
1383
852
|
if (deploymentCreated && !asyncDeploy) {
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
while (true) {
|
|
1390
|
-
response = await sitesGetDeployment({
|
|
1391
|
-
siteId: site['$id'],
|
|
1392
|
-
deploymentId: deploymentId,
|
|
1393
|
-
parseOutput: false
|
|
1394
|
-
});
|
|
1395
|
-
|
|
1396
|
-
const status = response['status'];
|
|
1397
|
-
if (status === 'ready') {
|
|
1398
|
-
successfullyDeployed++;
|
|
1399
|
-
|
|
1400
|
-
let url = '';
|
|
1401
|
-
const res = await proxyListRules({
|
|
1402
|
-
parseOutput: false,
|
|
1403
|
-
queries: [
|
|
1404
|
-
JSON.stringify({ method: 'limit', values: [1] }),
|
|
1405
|
-
JSON.stringify({ method: 'equal', "attribute": "deploymentResourceType", "values": ["site"] }),
|
|
1406
|
-
JSON.stringify({ method: 'equal', "attribute": "deploymentResourceId", "values": [site['$id']] }),
|
|
1407
|
-
JSON.stringify({ method: 'equal', "attribute": "trigger", "values": ["manual"] }),
|
|
1408
|
-
],
|
|
1409
|
-
});
|
|
1410
|
-
|
|
1411
|
-
if (Number(res.total) === 1) {
|
|
1412
|
-
url = res.rules[0].domain;
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
updaterRow.update({ status: 'Deployed', end: url });
|
|
1416
|
-
|
|
1417
|
-
break;
|
|
1418
|
-
} else if (status === 'failed') {
|
|
1419
|
-
failedDeployments.push({ name: site['name'], $id: site['$id'], deployment: response['$id'] });
|
|
1420
|
-
updaterRow.fail({ errorMessage: `Failed to deploy` });
|
|
1421
|
-
|
|
1422
|
-
break;
|
|
1423
|
-
} else {
|
|
1424
|
-
updaterRow.update({ status: 'Deploying', end: `Current status: ${status}` })
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
pollChecks++;
|
|
1428
|
-
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE * 1.5));
|
|
1429
|
-
}
|
|
1430
|
-
} catch (e: any) {
|
|
1431
|
-
errors.push(e);
|
|
1432
|
-
updaterRow.fail({ errorMessage: e.message ?? 'Unknown error occurred. Please try again' })
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
updaterRow.stopSpinner();
|
|
1437
|
-
}));
|
|
1438
|
-
|
|
1439
|
-
Spinner.stop();
|
|
1440
|
-
|
|
1441
|
-
failedDeployments.forEach((failed) => {
|
|
1442
|
-
const { name, deployment, $id } = failed;
|
|
1443
|
-
const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/sites/site-${$id}/deployments/deployment-${deployment}`;
|
|
1444
|
-
|
|
1445
|
-
error(`Deployment of ${name} has failed. Check at ${failUrl} for more details\n`);
|
|
1446
|
-
});
|
|
1447
|
-
|
|
1448
|
-
if (!asyncDeploy) {
|
|
1449
|
-
if (successfullyPushed === 0) {
|
|
1450
|
-
error('No sites were pushed.');
|
|
1451
|
-
} else if (successfullyDeployed !== successfullyPushed) {
|
|
1452
|
-
warn(`Successfully pushed ${successfullyDeployed} of ${successfullyPushed} sites`)
|
|
1453
|
-
} else {
|
|
1454
|
-
success(`Successfully pushed ${successfullyPushed} sites.`);
|
|
1455
|
-
}
|
|
1456
|
-
} else {
|
|
1457
|
-
success(`Successfully pushed ${successfullyPushed} sites.`);
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
if (cliConfig.verbose) {
|
|
1461
|
-
errors.forEach(e => {
|
|
1462
|
-
console.error(e);
|
|
1463
|
-
})
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
interface PushFunctionOptions {
|
|
1468
|
-
functionId?: string;
|
|
1469
|
-
async?: boolean;
|
|
1470
|
-
code?: boolean;
|
|
1471
|
-
withVariables?: boolean;
|
|
1472
|
-
returnOnZero?: boolean;
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
const pushFunction = async ({ functionId, async: asyncDeploy, code, withVariables }: PushFunctionOptions = { returnOnZero: false }): Promise<void> => {
|
|
1476
|
-
process.chdir(localConfig.configDirectoryPath)
|
|
1477
|
-
|
|
1478
|
-
const functionIds: string[] = [];
|
|
1479
|
-
|
|
1480
|
-
if (functionId) {
|
|
1481
|
-
functionIds.push(functionId);
|
|
1482
|
-
} else if (cliConfig.all) {
|
|
1483
|
-
checkDeployConditions(localConfig);
|
|
1484
|
-
const functions = localConfig.getFunctions();
|
|
1485
|
-
functionIds.push(...functions.map((func: any) => {
|
|
1486
|
-
return func.$id;
|
|
1487
|
-
}));
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
if (functionIds.length <= 0) {
|
|
1491
|
-
const answers = await inquirer.prompt(questionsPushFunctions[0]);
|
|
1492
|
-
if (answers.functions) {
|
|
1493
|
-
functionIds.push(...answers.functions);
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
if (functionIds.length === 0) {
|
|
1498
|
-
log("No functions found.");
|
|
1499
|
-
hint("Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one.");
|
|
1500
|
-
return;
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
let functions = functionIds.map((id: string) => {
|
|
1504
|
-
const functions = localConfig.getFunctions();
|
|
1505
|
-
const func = functions.find((f: any) => f.$id === id);
|
|
1506
|
-
|
|
1507
|
-
if (!func) {
|
|
1508
|
-
throw new Error("Function '" + id + "' not found.")
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
return func;
|
|
1512
|
-
});
|
|
1513
|
-
|
|
1514
|
-
log('Validating functions ...');
|
|
1515
|
-
// Validation is done BEFORE pushing so the deployment process can be run in async with progress update
|
|
1516
|
-
for (let func of functions) {
|
|
1517
|
-
|
|
1518
|
-
if (!func.entrypoint) {
|
|
1519
|
-
log(`Function ${func.name} is missing an entrypoint.`);
|
|
1520
|
-
const answers = await inquirer.prompt(questionsGetEntrypoint)
|
|
1521
|
-
func.entrypoint = answers.entrypoint;
|
|
1522
|
-
localConfig.addFunction(func);
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
if (!(await approveChanges(functions, functionsGet, KeysFunction, 'functionId', 'functions', ['vars']))) {
|
|
1527
|
-
return;
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
log('Pushing functions ...');
|
|
1531
|
-
|
|
1532
|
-
Spinner.start(false);
|
|
1533
|
-
let successfullyPushed = 0;
|
|
1534
|
-
let successfullyDeployed = 0;
|
|
1535
|
-
const failedDeployments: any[] = [];
|
|
1536
|
-
const errors: any[] = [];
|
|
1537
|
-
|
|
1538
|
-
await Promise.all(functions.map(async (func: any) => {
|
|
1539
|
-
let response: any = {};
|
|
1540
|
-
|
|
1541
|
-
const ignore = func.ignore ? 'appwrite.config.json' : '.gitignore';
|
|
1542
|
-
let functionExists = false;
|
|
1543
|
-
let deploymentCreated = false;
|
|
1544
|
-
|
|
1545
|
-
const updaterRow = new Spinner({ status: '', resource: func.name, id: func['$id'], end: `Ignoring using: ${ignore}` });
|
|
1546
|
-
|
|
1547
|
-
updaterRow.update({ status: 'Getting' }).startSpinner(SPINNER_DOTS);
|
|
1548
|
-
try {
|
|
1549
|
-
response = await functionsGet({
|
|
1550
|
-
functionId: func['$id'],
|
|
1551
|
-
parseOutput: false,
|
|
853
|
+
try {
|
|
854
|
+
const deploymentId = response["$id"];
|
|
855
|
+
updaterRow.update({
|
|
856
|
+
status: "Deploying",
|
|
857
|
+
end: "Checking deployment status...",
|
|
1552
858
|
});
|
|
1553
|
-
functionExists = true;
|
|
1554
|
-
if (response.runtime !== func.runtime) {
|
|
1555
|
-
updaterRow.fail({ errorMessage: `Runtime mismatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.config.json` })
|
|
1556
|
-
return;
|
|
1557
|
-
}
|
|
1558
859
|
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
response = await functionsUpdate({
|
|
1562
|
-
functionId: func['$id'],
|
|
1563
|
-
name: func.name,
|
|
1564
|
-
specification: func.specification,
|
|
1565
|
-
execute: func.execute,
|
|
1566
|
-
events: func.events,
|
|
1567
|
-
schedule: func.schedule,
|
|
1568
|
-
timeout: func.timeout,
|
|
1569
|
-
enabled: func.enabled,
|
|
1570
|
-
logging: func.logging,
|
|
1571
|
-
entrypoint: func.entrypoint,
|
|
1572
|
-
commands: func.commands,
|
|
1573
|
-
scopes: func.scopes,
|
|
1574
|
-
vars: JSON.stringify(response.vars),
|
|
1575
|
-
parseOutput: false
|
|
1576
|
-
});
|
|
1577
|
-
} catch (e: any) {
|
|
1578
|
-
|
|
1579
|
-
if (Number(e.code) === 404) {
|
|
1580
|
-
functionExists = false;
|
|
1581
|
-
} else {
|
|
1582
|
-
errors.push(e);
|
|
1583
|
-
updaterRow.fail({ errorMessage: e.message ?? 'General error occurs please try again' });
|
|
1584
|
-
return;
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
|
|
1588
|
-
if (!functionExists) {
|
|
1589
|
-
updaterRow.update({ status: 'Creating' }).replaceSpinner(SPINNER_DOTS);
|
|
860
|
+
const timeoutDeadline = Date.now() + DEPLOYMENT_TIMEOUT_MS;
|
|
1590
861
|
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
862
|
+
while (true) {
|
|
863
|
+
if (Date.now() > timeoutDeadline) {
|
|
864
|
+
failedDeployments.push({
|
|
865
|
+
name: func["name"],
|
|
866
|
+
$id: func["$id"],
|
|
867
|
+
deployment: deploymentId,
|
|
868
|
+
});
|
|
869
|
+
updaterRow.fail({
|
|
870
|
+
errorMessage: "Deployment timed out after 10 minutes",
|
|
871
|
+
});
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
const functionsServicePoll = await getFunctionsService(
|
|
876
|
+
this.projectClient,
|
|
877
|
+
);
|
|
878
|
+
response = await functionsServicePoll.getDeployment({
|
|
879
|
+
functionId: func["$id"],
|
|
880
|
+
deploymentId: deploymentId,
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
const status = response["status"];
|
|
884
|
+
if (status === "ready") {
|
|
885
|
+
successfullyDeployed++;
|
|
886
|
+
|
|
887
|
+
let url = "";
|
|
888
|
+
const proxyServiceUrl = await getProxyService(
|
|
889
|
+
this.projectClient,
|
|
890
|
+
);
|
|
891
|
+
const res = await proxyServiceUrl.listRules({
|
|
892
|
+
queries: [
|
|
893
|
+
Query.limit(1),
|
|
894
|
+
Query.equal("deploymentResourceType", "function"),
|
|
895
|
+
Query.equal("deploymentResourceId", func["$id"]),
|
|
896
|
+
Query.equal("trigger", "manual"),
|
|
897
|
+
],
|
|
1607
898
|
});
|
|
1608
899
|
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
const variables = await consoleVariables({ parseOutput: false, sdk: await sdkForConsole() });
|
|
1612
|
-
domain = ID.unique() + '.' + variables['_APP_DOMAIN_FUNCTIONS'];
|
|
1613
|
-
} catch (error) {
|
|
1614
|
-
console.error('Error fetching console variables.');
|
|
1615
|
-
throw error;
|
|
900
|
+
if (Number(res.total) === 1) {
|
|
901
|
+
url = `https://${res.rules[0].domain}`;
|
|
1616
902
|
}
|
|
1617
903
|
|
|
1618
|
-
|
|
1619
|
-
const rule = await proxyCreateFunctionRule(
|
|
1620
|
-
{
|
|
1621
|
-
domain: domain,
|
|
1622
|
-
functionId: func.$id
|
|
1623
|
-
}
|
|
1624
|
-
);
|
|
1625
|
-
} catch (error) {
|
|
1626
|
-
console.error('Error creating function rule.');
|
|
1627
|
-
throw error;
|
|
1628
|
-
}
|
|
904
|
+
updaterRow.update({ status: "Deployed", end: url });
|
|
1629
905
|
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
if (withVariables) {
|
|
1639
|
-
updaterRow.update({ status: 'Updating variables' }).replaceSpinner(SPINNER_ARC);
|
|
1640
|
-
|
|
1641
|
-
const { variables } = await paginate(functionsListVariables, {
|
|
1642
|
-
functionId: func['$id'],
|
|
1643
|
-
parseOutput: false
|
|
1644
|
-
}, 100, 'variables');
|
|
1645
|
-
|
|
1646
|
-
await Promise.all(variables.map(async (variable: any) => {
|
|
1647
|
-
await functionsDeleteVariable({
|
|
1648
|
-
functionId: func['$id'],
|
|
1649
|
-
variableId: variable['$id'],
|
|
1650
|
-
parseOutput: false
|
|
906
|
+
break;
|
|
907
|
+
} else if (status === "failed") {
|
|
908
|
+
failedDeployments.push({
|
|
909
|
+
name: func["name"],
|
|
910
|
+
$id: func["$id"],
|
|
911
|
+
deployment: response["$id"],
|
|
1651
912
|
});
|
|
1652
|
-
|
|
913
|
+
updaterRow.fail({ errorMessage: `Failed to deploy` });
|
|
1653
914
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value }));
|
|
1660
|
-
}
|
|
1661
|
-
} catch (error) {
|
|
1662
|
-
// Handle parsing errors gracefully
|
|
1663
|
-
envVariables = [];
|
|
1664
|
-
}
|
|
1665
|
-
await Promise.all(envVariables.map(async (variable) => {
|
|
1666
|
-
await functionsCreateVariable({
|
|
1667
|
-
functionId: func['$id'],
|
|
1668
|
-
variableId: ID.unique(),
|
|
1669
|
-
key: variable.key,
|
|
1670
|
-
value: variable.value,
|
|
1671
|
-
parseOutput: false,
|
|
1672
|
-
secret: false
|
|
915
|
+
break;
|
|
916
|
+
} else {
|
|
917
|
+
updaterRow.update({
|
|
918
|
+
status: "Deploying",
|
|
919
|
+
end: `Current status: ${status}`,
|
|
1673
920
|
});
|
|
1674
|
-
|
|
1675
|
-
}
|
|
1676
|
-
|
|
1677
|
-
if (code === false) {
|
|
1678
|
-
successfullyPushed++;
|
|
1679
|
-
successfullyDeployed++;
|
|
1680
|
-
updaterRow.update({ status: 'Pushed' });
|
|
1681
|
-
updaterRow.stopSpinner();
|
|
1682
|
-
return;
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
try {
|
|
1686
|
-
updaterRow.update({ status: 'Pushing' }).replaceSpinner(SPINNER_ARC);
|
|
1687
|
-
response = await functionsCreateDeployment({
|
|
1688
|
-
functionId: func['$id'],
|
|
1689
|
-
entrypoint: func.entrypoint,
|
|
1690
|
-
commands: func.commands,
|
|
1691
|
-
code: func.path,
|
|
1692
|
-
activate: true,
|
|
1693
|
-
parseOutput: false
|
|
1694
|
-
})
|
|
1695
|
-
|
|
1696
|
-
updaterRow.update({ status: 'Pushed' });
|
|
1697
|
-
deploymentCreated = true;
|
|
1698
|
-
successfullyPushed++;
|
|
1699
|
-
} catch (e: any) {
|
|
1700
|
-
errors.push(e);
|
|
921
|
+
}
|
|
1701
922
|
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
break;
|
|
1706
|
-
default:
|
|
1707
|
-
updaterRow.fail({ errorMessage: e.message ?? 'An unknown error occurred. Please try again.' })
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
if (deploymentCreated && !asyncDeploy) {
|
|
1712
|
-
try {
|
|
1713
|
-
const deploymentId = response['$id'];
|
|
1714
|
-
updaterRow.update({ status: 'Deploying', end: 'Checking deployment status...' })
|
|
1715
|
-
let pollChecks = 0;
|
|
1716
|
-
|
|
1717
|
-
while (true) {
|
|
1718
|
-
response = await functionsGetDeployment({
|
|
1719
|
-
functionId: func['$id'],
|
|
1720
|
-
deploymentId: deploymentId,
|
|
1721
|
-
parseOutput: false
|
|
1722
|
-
});
|
|
1723
|
-
|
|
1724
|
-
const status = response['status'];
|
|
1725
|
-
if (status === 'ready') {
|
|
1726
|
-
successfullyDeployed++;
|
|
1727
|
-
|
|
1728
|
-
let url = '';
|
|
1729
|
-
const res = await proxyListRules({
|
|
1730
|
-
parseOutput: false,
|
|
1731
|
-
queries: [
|
|
1732
|
-
JSON.stringify({ method: 'limit', values: [1] }),
|
|
1733
|
-
JSON.stringify({ method: 'equal', "attribute": "deploymentResourceType", "values": ["function"] }),
|
|
1734
|
-
JSON.stringify({ method: 'equal', "attribute": "deploymentResourceId", "values": [func['$id']] }),
|
|
1735
|
-
JSON.stringify({ method: 'equal', "attribute": "trigger", "values": ["manual"] }),
|
|
1736
|
-
],
|
|
1737
|
-
});
|
|
1738
|
-
|
|
1739
|
-
if (Number(res.total) === 1) {
|
|
1740
|
-
url = res.rules[0].domain;
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
updaterRow.update({ status: 'Deployed', end: url });
|
|
1744
|
-
|
|
1745
|
-
break;
|
|
1746
|
-
} else if (status === 'failed') {
|
|
1747
|
-
failedDeployments.push({ name: func['name'], $id: func['$id'], deployment: response['$id'] });
|
|
1748
|
-
updaterRow.fail({ errorMessage: `Failed to deploy` });
|
|
1749
|
-
|
|
1750
|
-
break;
|
|
1751
|
-
} else {
|
|
1752
|
-
updaterRow.update({ status: 'Deploying', end: `Current status: ${status}` })
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
pollChecks++;
|
|
1756
|
-
await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE * 1.5));
|
|
1757
|
-
}
|
|
1758
|
-
} catch (e: any) {
|
|
1759
|
-
errors.push(e);
|
|
1760
|
-
updaterRow.fail({ errorMessage: e.message ?? 'Unknown error occurred. Please try again' })
|
|
923
|
+
await new Promise((resolve) =>
|
|
924
|
+
setTimeout(resolve, POLL_DEBOUNCE),
|
|
925
|
+
);
|
|
1761
926
|
}
|
|
927
|
+
} catch (e: any) {
|
|
928
|
+
errors.push(e);
|
|
929
|
+
updaterRow.fail({
|
|
930
|
+
errorMessage:
|
|
931
|
+
e.message ?? "Unknown error occurred. Please try again",
|
|
932
|
+
});
|
|
933
|
+
}
|
|
1762
934
|
}
|
|
1763
935
|
|
|
1764
936
|
updaterRow.stopSpinner();
|
|
1765
|
-
|
|
937
|
+
}),
|
|
938
|
+
);
|
|
1766
939
|
|
|
1767
940
|
Spinner.stop();
|
|
1768
941
|
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
}
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
})
|
|
1792
|
-
}
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
interface TablesDBChangesResult {
|
|
1796
|
-
applied: boolean;
|
|
1797
|
-
resyncNeeded: boolean;
|
|
1798
|
-
}
|
|
1799
|
-
|
|
1800
|
-
const checkAndApplyTablesDBChanges = async (): Promise<TablesDBChangesResult> => {
|
|
1801
|
-
log('Checking for tablesDB changes ...');
|
|
1802
|
-
|
|
1803
|
-
const localTablesDBs = localConfig.getTablesDBs();
|
|
1804
|
-
const { databases: remoteTablesDBs } = await paginate(tablesDBList, { parseOutput: false }, 100, 'databases');
|
|
1805
|
-
|
|
1806
|
-
if (localTablesDBs.length === 0 && remoteTablesDBs.length === 0) {
|
|
1807
|
-
return { applied: false, resyncNeeded: false };
|
|
1808
|
-
}
|
|
1809
|
-
|
|
1810
|
-
const changes: any[] = [];
|
|
1811
|
-
const toCreate: any[] = [];
|
|
1812
|
-
const toUpdate: any[] = [];
|
|
1813
|
-
const toDelete: any[] = [];
|
|
1814
|
-
|
|
1815
|
-
// Check for deletions - remote DBs that aren't in local config
|
|
1816
|
-
for (const remoteDB of remoteTablesDBs) {
|
|
1817
|
-
const localDB = localTablesDBs.find((db: any) => db.$id === remoteDB.$id);
|
|
1818
|
-
if (!localDB) {
|
|
1819
|
-
toDelete.push(remoteDB);
|
|
1820
|
-
changes.push({
|
|
1821
|
-
id: remoteDB.$id,
|
|
1822
|
-
action: chalk.red('deleting'),
|
|
1823
|
-
key: 'Database',
|
|
1824
|
-
remote: remoteDB.name,
|
|
1825
|
-
local: '(deleted locally)'
|
|
1826
|
-
});
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
942
|
+
return {
|
|
943
|
+
successfullyPushed,
|
|
944
|
+
successfullyDeployed,
|
|
945
|
+
failedDeployments,
|
|
946
|
+
errors,
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
public async pushSites(
|
|
951
|
+
sites: any[],
|
|
952
|
+
options: {
|
|
953
|
+
async?: boolean;
|
|
954
|
+
code?: boolean;
|
|
955
|
+
withVariables?: boolean;
|
|
956
|
+
} = {},
|
|
957
|
+
): Promise<{
|
|
958
|
+
successfullyPushed: number;
|
|
959
|
+
successfullyDeployed: number;
|
|
960
|
+
failedDeployments: any[];
|
|
961
|
+
errors: any[];
|
|
962
|
+
}> {
|
|
963
|
+
const { async: asyncDeploy, code, withVariables } = options;
|
|
1829
964
|
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
toCreate.push(localDB);
|
|
1836
|
-
changes.push({
|
|
1837
|
-
id: localDB.$id,
|
|
1838
|
-
action: chalk.green('creating'),
|
|
1839
|
-
key: 'Database',
|
|
1840
|
-
remote: '(does not exist)',
|
|
1841
|
-
local: localDB.name
|
|
1842
|
-
});
|
|
1843
|
-
} else {
|
|
1844
|
-
let hasChanges = false;
|
|
1845
|
-
|
|
1846
|
-
if (remoteDB.name !== localDB.name) {
|
|
1847
|
-
hasChanges = true;
|
|
1848
|
-
changes.push({
|
|
1849
|
-
id: localDB.$id,
|
|
1850
|
-
action: chalk.yellow('updating'),
|
|
1851
|
-
key: 'Name',
|
|
1852
|
-
remote: remoteDB.name,
|
|
1853
|
-
local: localDB.name
|
|
1854
|
-
});
|
|
1855
|
-
}
|
|
1856
|
-
|
|
1857
|
-
if (remoteDB.enabled !== localDB.enabled) {
|
|
1858
|
-
hasChanges = true;
|
|
1859
|
-
changes.push({
|
|
1860
|
-
id: localDB.$id,
|
|
1861
|
-
action: chalk.yellow('updating'),
|
|
1862
|
-
key: 'Enabled',
|
|
1863
|
-
remote: remoteDB.enabled,
|
|
1864
|
-
local: localDB.enabled
|
|
1865
|
-
});
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
|
-
if (hasChanges) {
|
|
1869
|
-
toUpdate.push(localDB);
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
965
|
+
Spinner.start(false);
|
|
966
|
+
let successfullyPushed = 0;
|
|
967
|
+
let successfullyDeployed = 0;
|
|
968
|
+
const failedDeployments: any[] = [];
|
|
969
|
+
const errors: any[] = [];
|
|
1873
970
|
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
return { applied: false, resyncNeeded: false };
|
|
1878
|
-
}
|
|
971
|
+
await Promise.all(
|
|
972
|
+
sites.map(async (site: any) => {
|
|
973
|
+
let response: any = {};
|
|
1879
974
|
|
|
1880
|
-
|
|
1881
|
-
|
|
975
|
+
const ignore = site.ignore ? "appwrite.config.json" : ".gitignore";
|
|
976
|
+
let siteExists = false;
|
|
977
|
+
let deploymentCreated = false;
|
|
1882
978
|
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
979
|
+
const updaterRow = new Spinner({
|
|
980
|
+
status: "",
|
|
981
|
+
resource: site.name,
|
|
982
|
+
id: site["$id"],
|
|
983
|
+
end: `Ignoring using: ${ignore}`,
|
|
984
|
+
});
|
|
1889
985
|
|
|
1890
|
-
|
|
1891
|
-
return { applied: false, resyncNeeded: false };
|
|
1892
|
-
}
|
|
986
|
+
updaterRow.update({ status: "Getting" }).startSpinner(SPINNER_DOTS);
|
|
1893
987
|
|
|
1894
|
-
|
|
1895
|
-
let needsResync = false;
|
|
1896
|
-
for (const db of toDelete) {
|
|
988
|
+
const sitesService = await getSitesService(this.projectClient);
|
|
1897
989
|
try {
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
990
|
+
response = await sitesService.get({ siteId: site["$id"] });
|
|
991
|
+
siteExists = true;
|
|
992
|
+
if (response.framework !== site.framework) {
|
|
993
|
+
updaterRow.fail({
|
|
994
|
+
errorMessage: `Framework mismatch! (local=${site.framework},remote=${response.framework}) Please delete remote site or update your appwrite.config.json`,
|
|
1902
995
|
});
|
|
1903
|
-
|
|
1904
|
-
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
updaterRow
|
|
1000
|
+
.update({ status: "Updating" })
|
|
1001
|
+
.replaceSpinner(SPINNER_DOTS);
|
|
1002
|
+
|
|
1003
|
+
response = await sitesService.update({
|
|
1004
|
+
siteId: site["$id"],
|
|
1005
|
+
name: site.name,
|
|
1006
|
+
framework: site.framework,
|
|
1007
|
+
enabled: site.enabled,
|
|
1008
|
+
logging: site.logging,
|
|
1009
|
+
timeout: site.timeout,
|
|
1010
|
+
installCommand: site.installCommand,
|
|
1011
|
+
buildCommand: site.buildCommand,
|
|
1012
|
+
outputDirectory: site.outputDirectory,
|
|
1013
|
+
buildRuntime: site.buildRuntime,
|
|
1014
|
+
adapter: site.adapter,
|
|
1015
|
+
specification: site.specification,
|
|
1016
|
+
});
|
|
1905
1017
|
} catch (e: any) {
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
try {
|
|
1914
|
-
log(`Creating database ${db.name} ( ${db.$id} ) ...`);
|
|
1915
|
-
await tablesDBCreate({
|
|
1916
|
-
databaseId: db.$id,
|
|
1917
|
-
name: db.name,
|
|
1918
|
-
enabled: db.enabled,
|
|
1919
|
-
parseOutput: false
|
|
1018
|
+
if (Number(e.code) === 404) {
|
|
1019
|
+
siteExists = false;
|
|
1020
|
+
} else {
|
|
1021
|
+
errors.push(e);
|
|
1022
|
+
updaterRow.fail({
|
|
1023
|
+
errorMessage:
|
|
1024
|
+
e.message ?? "General error occurs please try again",
|
|
1920
1025
|
});
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
error(`Failed to create database ${db.name} ( ${db.$id} ): ${e.message}`);
|
|
1924
|
-
throw new Error(`Database sync failed during creation of ${db.$id}. Some changes may have been applied.`);
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1925
1028
|
}
|
|
1926
|
-
}
|
|
1927
1029
|
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1030
|
+
if (!siteExists) {
|
|
1031
|
+
updaterRow
|
|
1032
|
+
.update({ status: "Creating" })
|
|
1033
|
+
.replaceSpinner(SPINNER_DOTS);
|
|
1034
|
+
|
|
1035
|
+
try {
|
|
1036
|
+
response = await sitesService.create({
|
|
1037
|
+
siteId: site.$id,
|
|
1038
|
+
name: site.name,
|
|
1039
|
+
framework: site.framework,
|
|
1040
|
+
enabled: site.enabled,
|
|
1041
|
+
logging: site.logging,
|
|
1042
|
+
timeout: site.timeout,
|
|
1043
|
+
installCommand: site.installCommand,
|
|
1044
|
+
buildCommand: site.buildCommand,
|
|
1045
|
+
outputDirectory: site.outputDirectory,
|
|
1046
|
+
buildRuntime: site.buildRuntime,
|
|
1047
|
+
adapter: site.adapter,
|
|
1048
|
+
specification: site.specification,
|
|
1937
1049
|
});
|
|
1938
|
-
success(`Updated ${db.name} ( ${db.$id} )`);
|
|
1939
|
-
} catch (e: any) {
|
|
1940
|
-
error(`Failed to update database ${db.name} ( ${db.$id} ): ${e.message}`);
|
|
1941
|
-
throw new Error(`Database sync failed during update of ${db.$id}. Some changes may have been applied.`);
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
1050
|
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1051
|
+
let domain = "";
|
|
1052
|
+
try {
|
|
1053
|
+
const consoleService = await getConsoleService(
|
|
1054
|
+
this.consoleClient,
|
|
1055
|
+
);
|
|
1056
|
+
const variables = await consoleService.variables();
|
|
1057
|
+
domain = ID.unique() + "." + variables["_APP_DOMAIN_SITES"];
|
|
1058
|
+
} catch (err) {
|
|
1059
|
+
this.error("Error fetching console variables.");
|
|
1060
|
+
throw err;
|
|
1061
|
+
}
|
|
1948
1062
|
|
|
1949
|
-
|
|
1950
|
-
|
|
1063
|
+
try {
|
|
1064
|
+
const proxyService = await getProxyService(this.projectClient);
|
|
1065
|
+
await proxyService.createSiteRule(domain, site.$id);
|
|
1066
|
+
} catch (err) {
|
|
1067
|
+
this.error("Error creating site rule.");
|
|
1068
|
+
throw err;
|
|
1069
|
+
}
|
|
1951
1070
|
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1071
|
+
updaterRow.update({ status: "Created" });
|
|
1072
|
+
} catch (e: any) {
|
|
1073
|
+
errors.push(e);
|
|
1074
|
+
updaterRow.fail({
|
|
1075
|
+
errorMessage:
|
|
1076
|
+
e.message ?? "General error occurs please try again",
|
|
1077
|
+
});
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1956
1081
|
|
|
1957
|
-
|
|
1958
|
-
|
|
1082
|
+
if (withVariables) {
|
|
1083
|
+
updaterRow
|
|
1084
|
+
.update({ status: "Creating variables" })
|
|
1085
|
+
.replaceSpinner(SPINNER_DOTS);
|
|
1086
|
+
|
|
1087
|
+
const sitesServiceForVars = await getSitesService(this.projectClient);
|
|
1088
|
+
const { variables } = await paginate(
|
|
1089
|
+
async (args: any) => {
|
|
1090
|
+
return await sitesServiceForVars.listVariables({
|
|
1091
|
+
siteId: args.siteId,
|
|
1092
|
+
});
|
|
1093
|
+
},
|
|
1094
|
+
{
|
|
1095
|
+
siteId: site["$id"],
|
|
1096
|
+
},
|
|
1097
|
+
100,
|
|
1098
|
+
"variables",
|
|
1099
|
+
);
|
|
1100
|
+
|
|
1101
|
+
await Promise.all(
|
|
1102
|
+
variables.map(async (variable: any) => {
|
|
1103
|
+
const sitesServiceDel = await getSitesService(this.projectClient);
|
|
1104
|
+
await sitesServiceDel.deleteVariable({
|
|
1105
|
+
siteId: site["$id"],
|
|
1106
|
+
variableId: variable["$id"],
|
|
1107
|
+
});
|
|
1108
|
+
}),
|
|
1109
|
+
);
|
|
1110
|
+
|
|
1111
|
+
const envFileLocation = `${site["path"]}/.env`;
|
|
1112
|
+
let envVariables: Array<{ key: string; value: string }> = [];
|
|
1113
|
+
try {
|
|
1114
|
+
if (fs.existsSync(envFileLocation)) {
|
|
1115
|
+
const envObject = parseDotenv(
|
|
1116
|
+
fs.readFileSync(envFileLocation, "utf8"),
|
|
1117
|
+
);
|
|
1118
|
+
envVariables = Object.entries(envObject || {}).map(
|
|
1119
|
+
([key, value]) => ({ key, value }),
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
} catch (error) {
|
|
1123
|
+
envVariables = [];
|
|
1124
|
+
}
|
|
1125
|
+
await Promise.all(
|
|
1126
|
+
envVariables.map(async (variable) => {
|
|
1127
|
+
const sitesServiceCreate = await getSitesService(
|
|
1128
|
+
this.projectClient,
|
|
1129
|
+
);
|
|
1130
|
+
await sitesServiceCreate.createVariable({
|
|
1131
|
+
siteId: site["$id"],
|
|
1132
|
+
key: variable.key,
|
|
1133
|
+
value: variable.value,
|
|
1134
|
+
secret: false,
|
|
1135
|
+
});
|
|
1136
|
+
}),
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1959
1139
|
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1140
|
+
if (code === false) {
|
|
1141
|
+
successfullyPushed++;
|
|
1142
|
+
successfullyDeployed++;
|
|
1143
|
+
updaterRow.update({ status: "Pushed" });
|
|
1144
|
+
updaterRow.stopSpinner();
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1963
1147
|
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1148
|
+
try {
|
|
1149
|
+
updaterRow.update({ status: "Pushing" }).replaceSpinner(SPINNER_DOTS);
|
|
1150
|
+
const sitesServiceDeploy = await getSitesService(this.projectClient);
|
|
1151
|
+
|
|
1152
|
+
const result = await pushDeployment({
|
|
1153
|
+
resourcePath: site.path,
|
|
1154
|
+
createDeployment: async (codeFile) => {
|
|
1155
|
+
return await sitesServiceDeploy.createDeployment({
|
|
1156
|
+
siteId: site["$id"],
|
|
1157
|
+
installCommand: site.installCommand,
|
|
1158
|
+
buildCommand: site.buildCommand,
|
|
1159
|
+
outputDirectory: site.outputDirectory,
|
|
1160
|
+
code: codeFile,
|
|
1161
|
+
activate: true,
|
|
1162
|
+
});
|
|
1163
|
+
},
|
|
1164
|
+
pollForStatus: false,
|
|
1165
|
+
});
|
|
1166
|
+
|
|
1167
|
+
response = result.deployment;
|
|
1168
|
+
updaterRow.update({ status: "Pushed" });
|
|
1169
|
+
deploymentCreated = true;
|
|
1170
|
+
successfullyPushed++;
|
|
1171
|
+
} catch (e: any) {
|
|
1172
|
+
errors.push(e);
|
|
1173
|
+
|
|
1174
|
+
switch (e.code) {
|
|
1175
|
+
case "ENOENT":
|
|
1176
|
+
updaterRow.fail({
|
|
1177
|
+
errorMessage: "Not found in the current directory. Skipping...",
|
|
1178
|
+
});
|
|
1179
|
+
break;
|
|
1180
|
+
default:
|
|
1181
|
+
updaterRow.fail({
|
|
1182
|
+
errorMessage:
|
|
1183
|
+
e.message ?? "An unknown error occurred. Please try again.",
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1967
1187
|
|
|
1968
|
-
|
|
1969
|
-
|
|
1188
|
+
if (deploymentCreated && !asyncDeploy) {
|
|
1189
|
+
try {
|
|
1190
|
+
const deploymentId = response["$id"];
|
|
1191
|
+
updaterRow.update({
|
|
1192
|
+
status: "Deploying",
|
|
1193
|
+
end: "Checking deployment status...",
|
|
1194
|
+
});
|
|
1970
1195
|
|
|
1971
|
-
|
|
1972
|
-
const localTables = localConfig.getTables();
|
|
1973
|
-
const validTables = localTables.filter((table: any) => remoteDatabaseIds.has(table.databaseId));
|
|
1196
|
+
const timeoutDeadline = Date.now() + DEPLOYMENT_TIMEOUT_MS;
|
|
1974
1197
|
|
|
1975
|
-
|
|
1198
|
+
while (true) {
|
|
1199
|
+
if (Date.now() > timeoutDeadline) {
|
|
1200
|
+
failedDeployments.push({
|
|
1201
|
+
name: site["name"],
|
|
1202
|
+
$id: site["$id"],
|
|
1203
|
+
deployment: deploymentId,
|
|
1204
|
+
});
|
|
1205
|
+
updaterRow.fail({
|
|
1206
|
+
errorMessage: "Deployment timed out after 10 minutes",
|
|
1207
|
+
});
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
const sitesServicePoll = await getSitesService(
|
|
1212
|
+
this.projectClient,
|
|
1213
|
+
);
|
|
1214
|
+
response = await sitesServicePoll.getDeployment({
|
|
1215
|
+
siteId: site["$id"],
|
|
1216
|
+
deploymentId: deploymentId,
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
const status = response["status"];
|
|
1220
|
+
if (status === "ready") {
|
|
1221
|
+
successfullyDeployed++;
|
|
1222
|
+
|
|
1223
|
+
let url = "";
|
|
1224
|
+
const proxyServiceUrl = await getProxyService(
|
|
1225
|
+
this.projectClient,
|
|
1226
|
+
);
|
|
1227
|
+
const res = await proxyServiceUrl.listRules({
|
|
1228
|
+
queries: [
|
|
1229
|
+
Query.limit(1),
|
|
1230
|
+
Query.equal("deploymentResourceType", "site"),
|
|
1231
|
+
Query.equal("deploymentResourceId", site["$id"]),
|
|
1232
|
+
Query.equal("trigger", "manual"),
|
|
1233
|
+
],
|
|
1234
|
+
});
|
|
1976
1235
|
|
|
1977
|
-
|
|
1978
|
-
|
|
1236
|
+
if (Number(res.total) === 1) {
|
|
1237
|
+
url = `https://${res.rules[0].domain}`;
|
|
1238
|
+
}
|
|
1979
1239
|
|
|
1980
|
-
|
|
1981
|
-
console.log();
|
|
1982
|
-
}
|
|
1240
|
+
updaterRow.update({ status: "Deployed", end: url });
|
|
1983
1241
|
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1242
|
+
break;
|
|
1243
|
+
} else if (status === "failed") {
|
|
1244
|
+
failedDeployments.push({
|
|
1245
|
+
name: site["name"],
|
|
1246
|
+
$id: site["$id"],
|
|
1247
|
+
deployment: response["$id"],
|
|
1248
|
+
});
|
|
1249
|
+
updaterRow.fail({ errorMessage: `Failed to deploy` });
|
|
1988
1250
|
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
for (const remoteTable of remoteTables) {
|
|
1997
|
-
const localTable = localTables.find((t: any) => t.$id === remoteTable.$id && t.databaseId === db.$id);
|
|
1998
|
-
if (!localTable) {
|
|
1999
|
-
tablesToDelete.push({
|
|
2000
|
-
...remoteTable,
|
|
2001
|
-
databaseId: db.$id,
|
|
2002
|
-
databaseName: db.name
|
|
2003
|
-
});
|
|
2004
|
-
}
|
|
2005
|
-
}
|
|
2006
|
-
} catch (e) {
|
|
2007
|
-
// Skip if database doesn't exist or other errors
|
|
2008
|
-
}
|
|
2009
|
-
}
|
|
1251
|
+
break;
|
|
1252
|
+
} else {
|
|
1253
|
+
updaterRow.update({
|
|
1254
|
+
status: "Deploying",
|
|
1255
|
+
end: `Current status: ${status}`,
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
2010
1258
|
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
id: table.$id,
|
|
2015
|
-
action: chalk.red('deleting'),
|
|
2016
|
-
key: 'Table',
|
|
2017
|
-
database: table.databaseName,
|
|
2018
|
-
remote: table.name,
|
|
2019
|
-
local: '(deleted locally)'
|
|
2020
|
-
}));
|
|
2021
|
-
drawTable(deletionChanges);
|
|
2022
|
-
|
|
2023
|
-
if ((await getConfirmation()) === true) {
|
|
2024
|
-
for (const table of tablesToDelete) {
|
|
2025
|
-
try {
|
|
2026
|
-
log(`Deleting table ${table.name} ( ${table.$id} ) from database ${table.databaseName} ...`);
|
|
2027
|
-
await tablesDBDeleteTable({
|
|
2028
|
-
databaseId: table.databaseId,
|
|
2029
|
-
tableId: table.$id,
|
|
2030
|
-
parseOutput: false
|
|
2031
|
-
});
|
|
2032
|
-
success(`Deleted ${table.name} ( ${table.$id} )`);
|
|
2033
|
-
} catch (e: any) {
|
|
2034
|
-
error(`Failed to delete table ${table.name} ( ${table.$id} ): ${e.message}`);
|
|
2035
|
-
}
|
|
1259
|
+
await new Promise((resolve) =>
|
|
1260
|
+
setTimeout(resolve, POLL_DEBOUNCE),
|
|
1261
|
+
);
|
|
2036
1262
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
if (cliConfig.all) {
|
|
2044
|
-
checkDeployConditions(localConfig);
|
|
2045
|
-
tables.push(...localConfig.getTables());
|
|
2046
|
-
} else {
|
|
2047
|
-
const answers = await inquirer.prompt(questionsPushTables)
|
|
2048
|
-
if (answers.tables) {
|
|
2049
|
-
const configTables = new Map();
|
|
2050
|
-
localConfig.getTables().forEach((c: any) => {
|
|
2051
|
-
configTables.set(`${c['databaseId']}|${c['$id']}`, c);
|
|
1263
|
+
} catch (e: any) {
|
|
1264
|
+
errors.push(e);
|
|
1265
|
+
updaterRow.fail({
|
|
1266
|
+
errorMessage:
|
|
1267
|
+
e.message ?? "Unknown error occurred. Please try again",
|
|
2052
1268
|
});
|
|
2053
|
-
|
|
2054
|
-
const table = configTables.get(a);
|
|
2055
|
-
tables.push(table);
|
|
2056
|
-
})
|
|
1269
|
+
}
|
|
2057
1270
|
}
|
|
2058
|
-
}
|
|
2059
1271
|
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
1272
|
+
updaterRow.stopSpinner();
|
|
1273
|
+
}),
|
|
1274
|
+
);
|
|
1275
|
+
|
|
1276
|
+
Spinner.stop();
|
|
1277
|
+
|
|
1278
|
+
return {
|
|
1279
|
+
successfullyPushed,
|
|
1280
|
+
successfullyDeployed,
|
|
1281
|
+
failedDeployments,
|
|
1282
|
+
errors,
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
public async pushTables(
|
|
1287
|
+
tables: any[],
|
|
1288
|
+
options: PushTableOptions = {},
|
|
1289
|
+
): Promise<{
|
|
1290
|
+
successfullyPushed: number;
|
|
1291
|
+
errors: any[];
|
|
1292
|
+
}> {
|
|
1293
|
+
const { attempts, skipConfirmation = false } = options;
|
|
1294
|
+
const pollMaxDebounces = attempts ?? POLL_DEFAULT_VALUE;
|
|
1295
|
+
const pools = new Pools(pollMaxDebounces);
|
|
1296
|
+
const attributes = new Attributes(pools, skipConfirmation);
|
|
2065
1297
|
|
|
2066
|
-
if (!(await approveChanges(tables, tablesDBGetTable, KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId'))) {
|
|
2067
|
-
return;
|
|
2068
|
-
}
|
|
2069
1298
|
let tablesChanged = new Set();
|
|
1299
|
+
const errors: any[] = [];
|
|
2070
1300
|
|
|
2071
1301
|
// Parallel tables actions
|
|
2072
|
-
await Promise.all(
|
|
1302
|
+
await Promise.all(
|
|
1303
|
+
tables.map(async (table: any) => {
|
|
2073
1304
|
try {
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
1305
|
+
const tablesService = await getTablesDBService(this.projectClient);
|
|
1306
|
+
const remoteTable = await tablesService.getTable({
|
|
1307
|
+
databaseId: table["databaseId"],
|
|
1308
|
+
tableId: table["$id"],
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
const changes: string[] = [];
|
|
1312
|
+
if (remoteTable.name !== table.name) changes.push("name");
|
|
1313
|
+
if (remoteTable.rowSecurity !== table.rowSecurity)
|
|
1314
|
+
changes.push("rowSecurity");
|
|
1315
|
+
if (remoteTable.enabled !== table.enabled) changes.push("enabled");
|
|
1316
|
+
if (
|
|
1317
|
+
JSON.stringify(remoteTable["$permissions"]) !==
|
|
1318
|
+
JSON.stringify(table["$permissions"])
|
|
1319
|
+
)
|
|
1320
|
+
changes.push("permissions");
|
|
1321
|
+
|
|
1322
|
+
if (changes.length > 0) {
|
|
1323
|
+
await tablesService.updateTable({
|
|
1324
|
+
databaseId: table["databaseId"],
|
|
1325
|
+
tableId: table["$id"],
|
|
1326
|
+
name: table.name,
|
|
1327
|
+
rowSecurity: table.rowSecurity,
|
|
1328
|
+
permissions: table["$permissions"],
|
|
2078
1329
|
});
|
|
2079
1330
|
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
if (changes.length > 0) {
|
|
2087
|
-
await tablesDBUpdateTable({
|
|
2088
|
-
databaseId: table['databaseId'],
|
|
2089
|
-
tableId: table['$id'],
|
|
2090
|
-
name: table.name,
|
|
2091
|
-
parseOutput: false,
|
|
2092
|
-
rowSecurity: table.rowSecurity,
|
|
2093
|
-
permissions: table['$permissions']
|
|
2094
|
-
})
|
|
2095
|
-
|
|
2096
|
-
success(`Updated ${table.name} ( ${table['$id']} ) - ${changes.join(', ')}`);
|
|
2097
|
-
tablesChanged.add(table['$id']);
|
|
2098
|
-
}
|
|
2099
|
-
table.remoteVersion = remoteTable;
|
|
1331
|
+
this.success(
|
|
1332
|
+
`Updated ${table.name} ( ${table["$id"]} ) - ${changes.join(", ")}`,
|
|
1333
|
+
);
|
|
1334
|
+
tablesChanged.add(table["$id"]);
|
|
1335
|
+
}
|
|
1336
|
+
table.remoteVersion = remoteTable;
|
|
2100
1337
|
|
|
2101
|
-
|
|
1338
|
+
table.isExisted = true;
|
|
2102
1339
|
} catch (e: any) {
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
}
|
|
2117
|
-
|
|
2118
|
-
}
|
|
1340
|
+
if (Number(e.code) === 404) {
|
|
1341
|
+
this.log(
|
|
1342
|
+
`Table ${table.name} does not exist in the project. Creating ... `,
|
|
1343
|
+
);
|
|
1344
|
+
const tablesService = await getTablesDBService(this.projectClient);
|
|
1345
|
+
await tablesService.createTable({
|
|
1346
|
+
databaseId: table["databaseId"],
|
|
1347
|
+
tableId: table["$id"],
|
|
1348
|
+
name: table.name,
|
|
1349
|
+
rowSecurity: table.rowSecurity,
|
|
1350
|
+
permissions: table["$permissions"]
|
|
1351
|
+
? [...table["$permissions"]]
|
|
1352
|
+
: undefined,
|
|
1353
|
+
});
|
|
1354
|
+
|
|
1355
|
+
this.success(`Created ${table.name} ( ${table["$id"]} )`);
|
|
1356
|
+
tablesChanged.add(table["$id"]);
|
|
1357
|
+
} else {
|
|
1358
|
+
errors.push(e);
|
|
1359
|
+
throw e;
|
|
1360
|
+
}
|
|
2119
1361
|
}
|
|
2120
|
-
|
|
1362
|
+
}),
|
|
1363
|
+
);
|
|
2121
1364
|
|
|
2122
1365
|
// Serialize attribute actions
|
|
2123
1366
|
for (let table of tables) {
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
await createColumns(columns, table)
|
|
2140
|
-
} catch (e) {
|
|
2141
|
-
throw e;
|
|
2142
|
-
}
|
|
1367
|
+
let columns = table.columns;
|
|
1368
|
+
let indexes = table.indexes;
|
|
1369
|
+
|
|
1370
|
+
if (table.isExisted) {
|
|
1371
|
+
columns = await attributes.attributesToCreate(
|
|
1372
|
+
table.remoteVersion.columns,
|
|
1373
|
+
table.columns,
|
|
1374
|
+
table as Collection,
|
|
1375
|
+
);
|
|
1376
|
+
indexes = await attributes.attributesToCreate(
|
|
1377
|
+
table.remoteVersion.indexes,
|
|
1378
|
+
table.indexes,
|
|
1379
|
+
table as Collection,
|
|
1380
|
+
true,
|
|
1381
|
+
);
|
|
2143
1382
|
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
1383
|
+
if (
|
|
1384
|
+
Array.isArray(columns) &&
|
|
1385
|
+
columns.length <= 0 &&
|
|
1386
|
+
Array.isArray(indexes) &&
|
|
1387
|
+
indexes.length <= 0
|
|
1388
|
+
) {
|
|
1389
|
+
continue;
|
|
2148
1390
|
}
|
|
2149
|
-
|
|
2150
|
-
success(`Successfully pushed ${table.name} ( ${table['$id']} )`);
|
|
2151
|
-
}
|
|
2152
|
-
|
|
2153
|
-
success(`Successfully pushed ${tablesChanged.size} tables`);
|
|
2154
|
-
}
|
|
1391
|
+
}
|
|
2155
1392
|
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
}
|
|
1393
|
+
this.log(
|
|
1394
|
+
`Pushing table ${table.name} ( ${table["databaseId"]} - ${table["$id"]} ) attributes`,
|
|
1395
|
+
);
|
|
2160
1396
|
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
1397
|
+
try {
|
|
1398
|
+
await attributes.createColumns(columns, table as Collection);
|
|
1399
|
+
} catch (e) {
|
|
1400
|
+
errors.push(e);
|
|
1401
|
+
throw e;
|
|
1402
|
+
}
|
|
2164
1403
|
|
|
2165
|
-
|
|
2166
|
-
|
|
1404
|
+
try {
|
|
1405
|
+
await attributes.createIndexes(indexes, table as Collection);
|
|
1406
|
+
} catch (e) {
|
|
1407
|
+
errors.push(e);
|
|
1408
|
+
throw e;
|
|
1409
|
+
}
|
|
1410
|
+
tablesChanged.add(table["$id"]);
|
|
1411
|
+
this.success(`Successfully pushed ${table.name} ( ${table["$id"]} )`);
|
|
2167
1412
|
}
|
|
2168
1413
|
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
1414
|
+
return {
|
|
1415
|
+
successfullyPushed: tablesChanged.size,
|
|
1416
|
+
errors,
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
public async pushCollections(
|
|
1421
|
+
collections: any[],
|
|
1422
|
+
options: { skipConfirmation?: boolean } = {},
|
|
1423
|
+
): Promise<{
|
|
1424
|
+
successfullyPushed: number;
|
|
1425
|
+
errors: any[];
|
|
1426
|
+
}> {
|
|
1427
|
+
const { skipConfirmation = false } = options;
|
|
1428
|
+
const pools = new Pools(POLL_DEFAULT_VALUE);
|
|
1429
|
+
const attributes = new Attributes(pools, skipConfirmation);
|
|
2185
1430
|
|
|
2186
|
-
|
|
2187
|
-
log("No collections found.");
|
|
2188
|
-
hint("Use 'appwrite pull collections' to synchronize existing one, or use 'appwrite init collection' to create a new one.");
|
|
2189
|
-
return;
|
|
2190
|
-
}
|
|
1431
|
+
const errors: any[] = [];
|
|
2191
1432
|
|
|
2192
|
-
const databases = Array.from(
|
|
1433
|
+
const databases = Array.from(
|
|
1434
|
+
new Set(collections.map((collection: any) => collection["databaseId"])),
|
|
1435
|
+
);
|
|
2193
1436
|
|
|
2194
1437
|
// Parallel db actions
|
|
2195
|
-
await Promise.all(
|
|
2196
|
-
|
|
2197
|
-
|
|
1438
|
+
await Promise.all(
|
|
1439
|
+
databases.map(async (databaseId: any) => {
|
|
1440
|
+
const databasesService = await getDatabasesService(this.projectClient);
|
|
2198
1441
|
try {
|
|
2199
|
-
|
|
2200
|
-
databaseId: databaseId,
|
|
2201
|
-
parseOutput: false,
|
|
2202
|
-
});
|
|
1442
|
+
const database = await databasesService.get(databaseId);
|
|
2203
1443
|
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
})
|
|
1444
|
+
// Note: We can't get the local database name here since we don't have access to localConfig
|
|
1445
|
+
// This will need to be handled by the caller if needed
|
|
1446
|
+
const localDatabaseName =
|
|
1447
|
+
collections.find((c: any) => c.databaseId === databaseId)
|
|
1448
|
+
?.databaseName ?? databaseId;
|
|
2210
1449
|
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
} catch (err) {
|
|
2214
|
-
log(`Database ${databaseId} not found. Creating it now ...`);
|
|
1450
|
+
if (database.name !== localDatabaseName) {
|
|
1451
|
+
await databasesService.update(databaseId, localDatabaseName);
|
|
2215
1452
|
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
});
|
|
1453
|
+
this.success(`Updated ${localDatabaseName} ( ${databaseId} ) name`);
|
|
1454
|
+
}
|
|
1455
|
+
} catch (err: any) {
|
|
1456
|
+
if (Number(err.code) === 404) {
|
|
1457
|
+
this.log(`Database ${databaseId} not found. Creating it now ...`);
|
|
1458
|
+
|
|
1459
|
+
const localDatabaseName =
|
|
1460
|
+
collections.find((c: any) => c.databaseId === databaseId)
|
|
1461
|
+
?.databaseName ?? databaseId;
|
|
1462
|
+
|
|
1463
|
+
await databasesService.create(databaseId, localDatabaseName);
|
|
1464
|
+
} else {
|
|
1465
|
+
throw err;
|
|
1466
|
+
}
|
|
2221
1467
|
}
|
|
2222
|
-
|
|
1468
|
+
}),
|
|
1469
|
+
);
|
|
2223
1470
|
|
|
2224
|
-
if (!(await approveChanges(collections, databasesGetCollection, KeysCollection, 'collectionId', 'collections', ['attributes', 'indexes'], 'databaseId', 'databaseId',))) {
|
|
2225
|
-
return;
|
|
2226
|
-
}
|
|
2227
1471
|
// Parallel collection actions
|
|
2228
|
-
await Promise.all(
|
|
1472
|
+
await Promise.all(
|
|
1473
|
+
collections.map(async (collection: any) => {
|
|
2229
1474
|
try {
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
1475
|
+
const databasesService = await getDatabasesService(
|
|
1476
|
+
this.projectClient,
|
|
1477
|
+
);
|
|
1478
|
+
const remoteCollection = await databasesService.getCollection(
|
|
1479
|
+
collection["databaseId"],
|
|
1480
|
+
collection["$id"],
|
|
1481
|
+
);
|
|
1482
|
+
|
|
1483
|
+
if (remoteCollection.name !== collection.name) {
|
|
1484
|
+
await databasesService.updateCollection(
|
|
1485
|
+
collection["databaseId"],
|
|
1486
|
+
collection["$id"],
|
|
1487
|
+
collection.name,
|
|
1488
|
+
);
|
|
1489
|
+
|
|
1490
|
+
this.success(
|
|
1491
|
+
`Updated ${collection.name} ( ${collection["$id"]} ) name`,
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1494
|
+
collection.remoteVersion = remoteCollection;
|
|
1495
|
+
|
|
1496
|
+
collection.isExisted = true;
|
|
2249
1497
|
} catch (e: any) {
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
1498
|
+
if (Number(e.code) === 404) {
|
|
1499
|
+
this.log(
|
|
1500
|
+
`Collection ${collection.name} does not exist in the project. Creating ... `,
|
|
1501
|
+
);
|
|
1502
|
+
const databasesService = await getDatabasesService(
|
|
1503
|
+
this.projectClient,
|
|
1504
|
+
);
|
|
1505
|
+
await databasesService.createCollection({
|
|
1506
|
+
databaseId: collection["databaseId"],
|
|
1507
|
+
collectionId: collection["$id"],
|
|
1508
|
+
name: collection.name,
|
|
1509
|
+
documentSecurity: collection.documentSecurity,
|
|
1510
|
+
permissions: collection["$permissions"],
|
|
1511
|
+
});
|
|
1512
|
+
} else {
|
|
1513
|
+
errors.push(e);
|
|
1514
|
+
throw e;
|
|
1515
|
+
}
|
|
2263
1516
|
}
|
|
2264
|
-
|
|
1517
|
+
}),
|
|
1518
|
+
);
|
|
1519
|
+
|
|
2265
1520
|
let numberOfCollections = 0;
|
|
2266
1521
|
// Serialize attribute actions
|
|
2267
1522
|
for (let collection of collections) {
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
1523
|
+
let collectionAttributes = collection.attributes;
|
|
1524
|
+
let indexes = collection.indexes;
|
|
1525
|
+
|
|
1526
|
+
if (collection.isExisted) {
|
|
1527
|
+
collectionAttributes = await attributes.attributesToCreate(
|
|
1528
|
+
collection.remoteVersion.attributes,
|
|
1529
|
+
collection.attributes,
|
|
1530
|
+
collection as Collection,
|
|
1531
|
+
);
|
|
1532
|
+
indexes = await attributes.attributesToCreate(
|
|
1533
|
+
collection.remoteVersion.indexes,
|
|
1534
|
+
collection.indexes,
|
|
1535
|
+
collection as Collection,
|
|
1536
|
+
true,
|
|
1537
|
+
);
|
|
2278
1538
|
|
|
1539
|
+
if (
|
|
1540
|
+
Array.isArray(collectionAttributes) &&
|
|
1541
|
+
collectionAttributes.length <= 0 &&
|
|
1542
|
+
Array.isArray(indexes) &&
|
|
1543
|
+
indexes.length <= 0
|
|
1544
|
+
) {
|
|
1545
|
+
continue;
|
|
2279
1546
|
}
|
|
1547
|
+
}
|
|
2280
1548
|
|
|
2281
|
-
|
|
1549
|
+
this.log(
|
|
1550
|
+
`Pushing collection ${collection.name} ( ${collection["databaseId"]} - ${collection["$id"]} ) attributes`,
|
|
1551
|
+
);
|
|
2282
1552
|
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
1553
|
+
try {
|
|
1554
|
+
await attributes.createAttributes(
|
|
1555
|
+
collectionAttributes,
|
|
1556
|
+
collection as Collection,
|
|
1557
|
+
);
|
|
1558
|
+
} catch (e) {
|
|
1559
|
+
errors.push(e);
|
|
1560
|
+
throw e;
|
|
1561
|
+
}
|
|
2288
1562
|
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
1563
|
+
try {
|
|
1564
|
+
await attributes.createIndexes(indexes, collection as Collection);
|
|
1565
|
+
} catch (e) {
|
|
1566
|
+
errors.push(e);
|
|
1567
|
+
throw e;
|
|
1568
|
+
}
|
|
1569
|
+
numberOfCollections++;
|
|
1570
|
+
this.success(
|
|
1571
|
+
`Successfully pushed ${collection.name} ( ${collection["$id"]} )`,
|
|
1572
|
+
);
|
|
2296
1573
|
}
|
|
2297
1574
|
|
|
2298
|
-
|
|
1575
|
+
return {
|
|
1576
|
+
successfullyPushed: numberOfCollections,
|
|
1577
|
+
errors,
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
2299
1580
|
}
|
|
2300
1581
|
|
|
2301
|
-
|
|
2302
|
-
|
|
1582
|
+
async function createPushInstance(silent = false): Promise<Push> {
|
|
1583
|
+
const projectClient = await sdkForProject();
|
|
1584
|
+
const consoleClient = await sdkForConsole();
|
|
1585
|
+
return new Push(projectClient, consoleClient, silent);
|
|
2303
1586
|
}
|
|
2304
1587
|
|
|
2305
|
-
const
|
|
2306
|
-
|
|
1588
|
+
const pushResources = async ({
|
|
1589
|
+
skipDeprecated = false,
|
|
1590
|
+
}: {
|
|
1591
|
+
skipDeprecated?: boolean;
|
|
1592
|
+
} = {}): Promise<void> => {
|
|
1593
|
+
if (cliConfig.all) {
|
|
1594
|
+
checkDeployConditions(localConfig);
|
|
2307
1595
|
|
|
2308
|
-
|
|
2309
|
-
const
|
|
1596
|
+
const pushInstance = await createPushInstance();
|
|
1597
|
+
const config = localConfig.getProject() as ConfigType;
|
|
2310
1598
|
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
1599
|
+
await pushInstance.pushResources(config, {
|
|
1600
|
+
skipDeprecated,
|
|
1601
|
+
functionOptions: { code: true, withVariables: false },
|
|
1602
|
+
siteOptions: { code: true, withVariables: false },
|
|
1603
|
+
});
|
|
1604
|
+
} else {
|
|
1605
|
+
const actions: Record<string, (options?: any) => Promise<void>> = {
|
|
1606
|
+
settings: pushSettings,
|
|
1607
|
+
functions: pushFunction,
|
|
1608
|
+
sites: pushSite,
|
|
1609
|
+
collections: pushCollection,
|
|
1610
|
+
tables: pushTable,
|
|
1611
|
+
buckets: pushBucket,
|
|
1612
|
+
teams: pushTeam,
|
|
1613
|
+
messages: pushMessagingTopic,
|
|
1614
|
+
};
|
|
2315
1615
|
|
|
2316
|
-
if (
|
|
2317
|
-
|
|
2318
|
-
if (answers.buckets) {
|
|
2319
|
-
bucketIds.push(...answers.buckets);
|
|
2320
|
-
}
|
|
1616
|
+
if (skipDeprecated) {
|
|
1617
|
+
delete actions.collections;
|
|
2321
1618
|
}
|
|
2322
1619
|
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
1620
|
+
const answers = await inquirer.prompt(questionsPushResources);
|
|
1621
|
+
|
|
1622
|
+
const action = actions[answers.resource];
|
|
1623
|
+
if (action !== undefined) {
|
|
1624
|
+
await action();
|
|
2327
1625
|
}
|
|
1626
|
+
}
|
|
1627
|
+
};
|
|
2328
1628
|
|
|
2329
|
-
|
|
1629
|
+
const pushSettings = async (): Promise<void> => {
|
|
1630
|
+
checkDeployConditions(localConfig);
|
|
2330
1631
|
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
1632
|
+
try {
|
|
1633
|
+
const projectsService = await getProjectsService();
|
|
1634
|
+
let response = await projectsService.get(
|
|
1635
|
+
localConfig.getProject().projectId,
|
|
1636
|
+
);
|
|
1637
|
+
|
|
1638
|
+
const remoteSettings = createSettingsObject(response);
|
|
1639
|
+
const localSettings = localConfig.getProject().projectSettings ?? {};
|
|
2335
1640
|
|
|
2336
|
-
|
|
1641
|
+
log("Checking for changes ...");
|
|
1642
|
+
const changes: any[] = [];
|
|
1643
|
+
|
|
1644
|
+
changes.push(
|
|
1645
|
+
...getObjectChanges(remoteSettings, localSettings, "services", "Service"),
|
|
1646
|
+
);
|
|
1647
|
+
changes.push(
|
|
1648
|
+
...getObjectChanges(
|
|
1649
|
+
remoteSettings["auth"] ?? {},
|
|
1650
|
+
localSettings["auth"] ?? {},
|
|
1651
|
+
"methods",
|
|
1652
|
+
"Auth method",
|
|
1653
|
+
),
|
|
1654
|
+
);
|
|
1655
|
+
changes.push(
|
|
1656
|
+
...getObjectChanges(
|
|
1657
|
+
remoteSettings["auth"] ?? {},
|
|
1658
|
+
localSettings["auth"] ?? {},
|
|
1659
|
+
"security",
|
|
1660
|
+
"Auth security",
|
|
1661
|
+
),
|
|
1662
|
+
);
|
|
1663
|
+
|
|
1664
|
+
if (changes.length > 0) {
|
|
1665
|
+
drawTable(changes);
|
|
1666
|
+
if ((await getConfirmation()) !== true) {
|
|
1667
|
+
success(`Successfully pushed 0 project settings.`);
|
|
2337
1668
|
return;
|
|
1669
|
+
}
|
|
2338
1670
|
}
|
|
1671
|
+
} catch (e) {}
|
|
2339
1672
|
|
|
2340
|
-
|
|
1673
|
+
try {
|
|
1674
|
+
log("Pushing project settings ...");
|
|
2341
1675
|
|
|
2342
|
-
|
|
2343
|
-
|
|
1676
|
+
const pushInstance = await createPushInstance();
|
|
1677
|
+
const config = localConfig.getProject();
|
|
2344
1678
|
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
await storageUpdateBucket({
|
|
2352
|
-
bucketId: bucket['$id'],
|
|
2353
|
-
name: bucket.name,
|
|
2354
|
-
permissions: bucket['$permissions'],
|
|
2355
|
-
fileSecurity: bucket.fileSecurity,
|
|
2356
|
-
enabled: bucket.enabled,
|
|
2357
|
-
maximumFileSize: bucket.maximumFileSize,
|
|
2358
|
-
allowedFileExtensions: bucket.allowedFileExtensions,
|
|
2359
|
-
encryption: bucket.encryption,
|
|
2360
|
-
antivirus: bucket.antivirus,
|
|
2361
|
-
compression: bucket.compression,
|
|
2362
|
-
parseOutput: false
|
|
2363
|
-
});
|
|
2364
|
-
} catch (e: any) {
|
|
2365
|
-
if (Number(e.code) === 404) {
|
|
2366
|
-
log(`Bucket ${bucket.name} does not exist in the project. Creating ... `);
|
|
2367
|
-
|
|
2368
|
-
response = await storageCreateBucket({
|
|
2369
|
-
bucketId: bucket['$id'],
|
|
2370
|
-
name: bucket.name,
|
|
2371
|
-
permissions: bucket['$permissions'],
|
|
2372
|
-
fileSecurity: bucket.fileSecurity,
|
|
2373
|
-
enabled: bucket.enabled,
|
|
2374
|
-
maximumFileSize: bucket.maximumFileSize,
|
|
2375
|
-
allowedFileExtensions: bucket.allowedFileExtensions,
|
|
2376
|
-
compression: bucket.compression,
|
|
2377
|
-
encryption: bucket.encryption,
|
|
2378
|
-
antivirus: bucket.antivirus,
|
|
2379
|
-
parseOutput: false
|
|
2380
|
-
})
|
|
2381
|
-
} else {
|
|
2382
|
-
throw e;
|
|
2383
|
-
}
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
1679
|
+
await pushInstance.pushSettings({
|
|
1680
|
+
projectId: config.projectId,
|
|
1681
|
+
projectName: config.projectName,
|
|
1682
|
+
settings: config.projectSettings,
|
|
1683
|
+
});
|
|
2386
1684
|
|
|
2387
|
-
success(`Successfully pushed ${
|
|
2388
|
-
}
|
|
1685
|
+
success(`Successfully pushed ${chalk.bold("all")} project settings.`);
|
|
1686
|
+
} catch (e) {
|
|
1687
|
+
throw e;
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
2389
1690
|
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
1691
|
+
const pushSite = async ({
|
|
1692
|
+
siteId,
|
|
1693
|
+
async: asyncDeploy,
|
|
1694
|
+
code,
|
|
1695
|
+
withVariables,
|
|
1696
|
+
}: PushSiteOptions = {}): Promise<void> => {
|
|
1697
|
+
process.chdir(localConfig.configDirectoryPath);
|
|
2393
1698
|
|
|
2394
|
-
const
|
|
2395
|
-
let response: any = {};
|
|
1699
|
+
const siteIds: string[] = [];
|
|
2396
1700
|
|
|
2397
|
-
|
|
2398
|
-
|
|
1701
|
+
if (siteId) {
|
|
1702
|
+
siteIds.push(siteId);
|
|
1703
|
+
} else if (cliConfig.all) {
|
|
1704
|
+
checkDeployConditions(localConfig);
|
|
1705
|
+
const sites = localConfig.getSites();
|
|
1706
|
+
siteIds.push(
|
|
1707
|
+
...sites.map((site: any) => {
|
|
1708
|
+
return site.$id;
|
|
1709
|
+
}),
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
2399
1712
|
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
1713
|
+
if (siteIds.length <= 0) {
|
|
1714
|
+
const answers = await inquirer.prompt(questionsPushSites);
|
|
1715
|
+
if (answers.sites) {
|
|
1716
|
+
siteIds.push(...answers.sites);
|
|
2403
1717
|
}
|
|
1718
|
+
}
|
|
2404
1719
|
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
1720
|
+
if (siteIds.length === 0) {
|
|
1721
|
+
log("No sites found.");
|
|
1722
|
+
hint(
|
|
1723
|
+
`Use '${EXECUTABLE_NAME} pull sites' to synchronize existing one, or use '${EXECUTABLE_NAME} init site' to create a new one.`,
|
|
1724
|
+
);
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
let sites = siteIds.map((id: string) => {
|
|
1729
|
+
const sites = localConfig.getSites();
|
|
1730
|
+
const site = sites.find((s: any) => s.$id === id);
|
|
1731
|
+
|
|
1732
|
+
if (!site) {
|
|
1733
|
+
throw new Error("Site '" + id + "' not found.");
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
return site;
|
|
1737
|
+
});
|
|
1738
|
+
|
|
1739
|
+
log("Validating sites ...");
|
|
1740
|
+
// Validation is done BEFORE pushing so the deployment process can be run in async with progress update
|
|
1741
|
+
for (let site of sites) {
|
|
1742
|
+
if (!site.buildCommand) {
|
|
1743
|
+
log(`Site ${site.name} is missing build command.`);
|
|
1744
|
+
const answers = await inquirer.prompt(questionsGetEntrypoint);
|
|
1745
|
+
site.buildCommand = answers.entrypoint;
|
|
1746
|
+
localConfig.addSite(site);
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
if (
|
|
1751
|
+
!(await approveChanges(
|
|
1752
|
+
sites,
|
|
1753
|
+
async (args: any) => {
|
|
1754
|
+
const sitesService = await getSitesService();
|
|
1755
|
+
return await sitesService.get({ siteId: args.siteId });
|
|
1756
|
+
},
|
|
1757
|
+
KeysSite,
|
|
1758
|
+
"siteId",
|
|
1759
|
+
"sites",
|
|
1760
|
+
["vars"],
|
|
1761
|
+
))
|
|
1762
|
+
) {
|
|
1763
|
+
return;
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
log("Pushing sites ...");
|
|
1767
|
+
|
|
1768
|
+
const pushInstance = await createPushInstance();
|
|
1769
|
+
const result = await pushInstance.pushSites(sites, {
|
|
1770
|
+
async: asyncDeploy,
|
|
1771
|
+
code,
|
|
1772
|
+
withVariables,
|
|
1773
|
+
});
|
|
1774
|
+
|
|
1775
|
+
const {
|
|
1776
|
+
successfullyPushed,
|
|
1777
|
+
successfullyDeployed,
|
|
1778
|
+
failedDeployments,
|
|
1779
|
+
errors,
|
|
1780
|
+
} = result;
|
|
1781
|
+
|
|
1782
|
+
failedDeployments.forEach((failed) => {
|
|
1783
|
+
const { name, deployment, $id } = failed;
|
|
1784
|
+
const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/sites/site-${$id}/deployments/deployment-${deployment}`;
|
|
1785
|
+
|
|
1786
|
+
error(
|
|
1787
|
+
`Deployment of ${name} has failed. Check at ${failUrl} for more details\n`,
|
|
1788
|
+
);
|
|
1789
|
+
});
|
|
1790
|
+
|
|
1791
|
+
if (!asyncDeploy) {
|
|
1792
|
+
if (successfullyPushed === 0) {
|
|
1793
|
+
error("No sites were pushed.");
|
|
1794
|
+
} else if (successfullyDeployed !== successfullyPushed) {
|
|
1795
|
+
warn(
|
|
1796
|
+
`Successfully pushed ${successfullyDeployed} of ${successfullyPushed} sites`,
|
|
1797
|
+
);
|
|
1798
|
+
} else {
|
|
1799
|
+
success(`Successfully pushed ${successfullyPushed} sites.`);
|
|
2410
1800
|
}
|
|
1801
|
+
} else {
|
|
1802
|
+
success(`Successfully pushed ${successfullyPushed} sites.`);
|
|
1803
|
+
}
|
|
2411
1804
|
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
1805
|
+
if (cliConfig.verbose) {
|
|
1806
|
+
errors.forEach((e) => {
|
|
1807
|
+
console.error(e);
|
|
1808
|
+
});
|
|
1809
|
+
}
|
|
1810
|
+
};
|
|
1811
|
+
|
|
1812
|
+
const pushFunction = async ({
|
|
1813
|
+
functionId,
|
|
1814
|
+
async: asyncDeploy,
|
|
1815
|
+
code,
|
|
1816
|
+
withVariables,
|
|
1817
|
+
}: PushFunctionOptions = {}): Promise<void> => {
|
|
1818
|
+
process.chdir(localConfig.configDirectoryPath);
|
|
2417
1819
|
|
|
2418
|
-
|
|
1820
|
+
const functionIds: string[] = [];
|
|
2419
1821
|
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
1822
|
+
if (functionId) {
|
|
1823
|
+
functionIds.push(functionId);
|
|
1824
|
+
} else if (cliConfig.all) {
|
|
1825
|
+
checkDeployConditions(localConfig);
|
|
1826
|
+
const functions = localConfig.getFunctions();
|
|
1827
|
+
functionIds.push(
|
|
1828
|
+
...functions.map((func: any) => {
|
|
1829
|
+
return func.$id;
|
|
1830
|
+
}),
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
if (functionIds.length <= 0) {
|
|
1835
|
+
const answers = await inquirer.prompt(questionsPushFunctions);
|
|
1836
|
+
if (answers.functions) {
|
|
1837
|
+
functionIds.push(...answers.functions);
|
|
2423
1838
|
}
|
|
1839
|
+
}
|
|
2424
1840
|
|
|
2425
|
-
|
|
2426
|
-
|
|
1841
|
+
if (functionIds.length === 0) {
|
|
1842
|
+
log("No functions found.");
|
|
1843
|
+
hint(
|
|
1844
|
+
`Use '${EXECUTABLE_NAME} pull functions' to synchronize existing one, or use '${EXECUTABLE_NAME} init function' to create a new one.`,
|
|
1845
|
+
);
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
let functions = functionIds.map((id: string) => {
|
|
1850
|
+
const functions = localConfig.getFunctions();
|
|
1851
|
+
const func = functions.find((f: any) => f.$id === id);
|
|
1852
|
+
|
|
1853
|
+
if (!func) {
|
|
1854
|
+
throw new Error("Function '" + id + "' not found.");
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
return func;
|
|
1858
|
+
});
|
|
1859
|
+
|
|
1860
|
+
log("Validating functions ...");
|
|
1861
|
+
for (let func of functions) {
|
|
1862
|
+
if (!func.entrypoint) {
|
|
1863
|
+
log(`Function ${func.name} is missing an entrypoint.`);
|
|
1864
|
+
const answers = await inquirer.prompt(questionsGetEntrypoint);
|
|
1865
|
+
func.entrypoint = answers.entrypoint;
|
|
1866
|
+
localConfig.addFunction(func);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
if (
|
|
1871
|
+
!(await approveChanges(
|
|
1872
|
+
functions,
|
|
1873
|
+
async (args: any) => {
|
|
1874
|
+
const functionsService = await getFunctionsService();
|
|
1875
|
+
return await functionsService.get({ functionId: args.functionId });
|
|
1876
|
+
},
|
|
1877
|
+
KeysFunction,
|
|
1878
|
+
"functionId",
|
|
1879
|
+
"functions",
|
|
1880
|
+
["vars"],
|
|
1881
|
+
))
|
|
1882
|
+
) {
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
log("Pushing functions ...");
|
|
1887
|
+
|
|
1888
|
+
const pushInstance = await createPushInstance();
|
|
1889
|
+
const result = await pushInstance.pushFunctions(functions, {
|
|
1890
|
+
async: asyncDeploy,
|
|
1891
|
+
code,
|
|
1892
|
+
withVariables,
|
|
1893
|
+
});
|
|
1894
|
+
|
|
1895
|
+
const {
|
|
1896
|
+
successfullyPushed,
|
|
1897
|
+
successfullyDeployed,
|
|
1898
|
+
failedDeployments,
|
|
1899
|
+
errors,
|
|
1900
|
+
} = result;
|
|
1901
|
+
|
|
1902
|
+
failedDeployments.forEach((failed) => {
|
|
1903
|
+
const { name, deployment, $id } = failed;
|
|
1904
|
+
const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/functions/function-${$id}/deployment-${deployment}`;
|
|
1905
|
+
|
|
1906
|
+
error(
|
|
1907
|
+
`Deployment of ${name} has failed. Check at ${failUrl} for more details\n`,
|
|
1908
|
+
);
|
|
1909
|
+
});
|
|
1910
|
+
|
|
1911
|
+
if (!asyncDeploy) {
|
|
1912
|
+
if (successfullyPushed === 0) {
|
|
1913
|
+
error("No functions were pushed.");
|
|
1914
|
+
} else if (successfullyDeployed !== successfullyPushed) {
|
|
1915
|
+
warn(
|
|
1916
|
+
`Successfully pushed ${successfullyDeployed} of ${successfullyPushed} functions`,
|
|
1917
|
+
);
|
|
1918
|
+
} else {
|
|
1919
|
+
success(`Successfully pushed ${successfullyPushed} functions.`);
|
|
2427
1920
|
}
|
|
1921
|
+
} else {
|
|
1922
|
+
success(`Successfully pushed ${successfullyPushed} functions.`);
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
if (cliConfig.verbose) {
|
|
1926
|
+
errors.forEach((e) => {
|
|
1927
|
+
console.error(e);
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
|
|
1932
|
+
const pushTable = async ({
|
|
1933
|
+
attempts,
|
|
1934
|
+
}: PushTableOptions = {}): Promise<void> => {
|
|
1935
|
+
const tables: any[] = [];
|
|
1936
|
+
|
|
1937
|
+
const { resyncNeeded } = await checkAndApplyTablesDBChanges();
|
|
1938
|
+
if (resyncNeeded) {
|
|
1939
|
+
log("Resyncing configuration due to tables deletions ...");
|
|
1940
|
+
|
|
1941
|
+
const remoteTablesDBs = (
|
|
1942
|
+
await paginate(
|
|
1943
|
+
async (args: any) => {
|
|
1944
|
+
const tablesService = await getTablesDBService();
|
|
1945
|
+
return await tablesService.list(args.queries || []);
|
|
1946
|
+
},
|
|
1947
|
+
{},
|
|
1948
|
+
100,
|
|
1949
|
+
"databases",
|
|
1950
|
+
)
|
|
1951
|
+
).databases;
|
|
1952
|
+
const localTablesDBs = localConfig.getTablesDBs();
|
|
2428
1953
|
|
|
2429
|
-
|
|
1954
|
+
const remoteDatabaseIds = new Set(remoteTablesDBs.map((db: any) => db.$id));
|
|
1955
|
+
const localTables = localConfig.getTables();
|
|
1956
|
+
const validTables = localTables.filter((table: any) =>
|
|
1957
|
+
remoteDatabaseIds.has(table.databaseId),
|
|
1958
|
+
);
|
|
1959
|
+
|
|
1960
|
+
localConfig.set("tables", validTables);
|
|
1961
|
+
|
|
1962
|
+
const validTablesDBs = localTablesDBs.filter((db: any) =>
|
|
1963
|
+
remoteDatabaseIds.has(db.$id),
|
|
1964
|
+
);
|
|
1965
|
+
localConfig.set("tablesDB", validTablesDBs);
|
|
1966
|
+
|
|
1967
|
+
success("Configuration resynced successfully.");
|
|
1968
|
+
console.log();
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
log("Checking for deleted tables ...");
|
|
1972
|
+
const localTablesDBs = localConfig.getTablesDBs();
|
|
1973
|
+
const localTables = localConfig.getTables();
|
|
1974
|
+
const tablesToDelete: any[] = [];
|
|
2430
1975
|
|
|
2431
|
-
|
|
2432
|
-
|
|
1976
|
+
for (const db of localTablesDBs) {
|
|
1977
|
+
try {
|
|
1978
|
+
const { tables: remoteTables } = await paginate(
|
|
1979
|
+
async (args: any) => {
|
|
1980
|
+
const tablesService = await getTablesDBService();
|
|
1981
|
+
return await tablesService.listTables(
|
|
1982
|
+
args.databaseId,
|
|
1983
|
+
args.queries || [],
|
|
1984
|
+
);
|
|
1985
|
+
},
|
|
1986
|
+
{
|
|
1987
|
+
databaseId: db.$id,
|
|
1988
|
+
},
|
|
1989
|
+
100,
|
|
1990
|
+
"tables",
|
|
1991
|
+
);
|
|
1992
|
+
|
|
1993
|
+
for (const remoteTable of remoteTables) {
|
|
1994
|
+
const localTable = localTables.find(
|
|
1995
|
+
(t: any) => t.$id === remoteTable.$id && t.databaseId === db.$id,
|
|
1996
|
+
);
|
|
1997
|
+
if (!localTable) {
|
|
1998
|
+
tablesToDelete.push({
|
|
1999
|
+
...remoteTable,
|
|
2000
|
+
databaseId: db.$id,
|
|
2001
|
+
databaseName: db.name,
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
} catch (e) {
|
|
2006
|
+
// Skip if database doesn't exist or other errors
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
if (tablesToDelete.length > 0) {
|
|
2011
|
+
log("Found tables that exist remotely but not locally:");
|
|
2012
|
+
const deletionChanges = tablesToDelete.map((table: any) => ({
|
|
2013
|
+
id: table.$id,
|
|
2014
|
+
action: chalk.red("deleting"),
|
|
2015
|
+
key: "Table",
|
|
2016
|
+
database: table.databaseName,
|
|
2017
|
+
remote: table.name,
|
|
2018
|
+
local: "(deleted locally)",
|
|
2019
|
+
}));
|
|
2020
|
+
drawTable(deletionChanges);
|
|
2433
2021
|
|
|
2022
|
+
if ((await getConfirmation()) === true) {
|
|
2023
|
+
for (const table of tablesToDelete) {
|
|
2434
2024
|
try {
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
teamId: team['$id'],
|
|
2442
|
-
name: team.name,
|
|
2443
|
-
parseOutput: false
|
|
2444
|
-
});
|
|
2025
|
+
log(
|
|
2026
|
+
`Deleting table ${table.name} ( ${table.$id} ) from database ${table.databaseName} ...`,
|
|
2027
|
+
);
|
|
2028
|
+
const tablesService = await getTablesDBService();
|
|
2029
|
+
await tablesService.deleteTable(table.databaseId, table.$id);
|
|
2030
|
+
success(`Deleted ${table.name} ( ${table.$id} )`);
|
|
2445
2031
|
} catch (e: any) {
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
response = await teamsCreate({
|
|
2450
|
-
teamId: team['$id'],
|
|
2451
|
-
name: team.name,
|
|
2452
|
-
parseOutput: false
|
|
2453
|
-
})
|
|
2454
|
-
} else {
|
|
2455
|
-
throw e;
|
|
2456
|
-
}
|
|
2032
|
+
error(
|
|
2033
|
+
`Failed to delete table ${table.name} ( ${table.$id} ): ${e.message}`,
|
|
2034
|
+
);
|
|
2457
2035
|
}
|
|
2036
|
+
}
|
|
2458
2037
|
}
|
|
2038
|
+
}
|
|
2459
2039
|
|
|
2460
|
-
|
|
2461
|
-
|
|
2040
|
+
if (cliConfig.all) {
|
|
2041
|
+
checkDeployConditions(localConfig);
|
|
2042
|
+
tables.push(...localConfig.getTables());
|
|
2043
|
+
} else {
|
|
2044
|
+
const answers = await inquirer.prompt(questionsPushTables);
|
|
2045
|
+
if (answers.tables) {
|
|
2046
|
+
const configTables = new Map();
|
|
2047
|
+
localConfig.getTables().forEach((c: any) => {
|
|
2048
|
+
configTables.set(`${c["databaseId"]}|${c["$id"]}`, c);
|
|
2049
|
+
});
|
|
2050
|
+
answers.tables.forEach((a: any) => {
|
|
2051
|
+
const table = configTables.get(a);
|
|
2052
|
+
tables.push(table);
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
if (tables.length === 0) {
|
|
2058
|
+
log("No tables found.");
|
|
2059
|
+
hint(
|
|
2060
|
+
`Use '${EXECUTABLE_NAME} pull tables' to synchronize existing one, or use '${EXECUTABLE_NAME} init table' to create a new one.`,
|
|
2061
|
+
);
|
|
2062
|
+
return;
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
if (
|
|
2066
|
+
!(await approveChanges(
|
|
2067
|
+
tables,
|
|
2068
|
+
async (args: any) => {
|
|
2069
|
+
const tablesService = await getTablesDBService();
|
|
2070
|
+
return await tablesService.getTable(args.databaseId, args.tableId);
|
|
2071
|
+
},
|
|
2072
|
+
KeysTable,
|
|
2073
|
+
"tableId",
|
|
2074
|
+
"tables",
|
|
2075
|
+
["columns", "indexes"],
|
|
2076
|
+
"databaseId",
|
|
2077
|
+
"databaseId",
|
|
2078
|
+
))
|
|
2079
|
+
) {
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
log("Pushing tables ...");
|
|
2084
|
+
|
|
2085
|
+
const pushInstance = await createPushInstance();
|
|
2086
|
+
const result = await pushInstance.pushTables(tables, { attempts });
|
|
2087
|
+
|
|
2088
|
+
const { successfullyPushed, errors } = result;
|
|
2089
|
+
|
|
2090
|
+
if (successfullyPushed === 0) {
|
|
2091
|
+
error("No tables were pushed.");
|
|
2092
|
+
} else {
|
|
2093
|
+
success(`Successfully pushed ${successfullyPushed} tables.`);
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
if (cliConfig.verbose) {
|
|
2097
|
+
errors.forEach((e) => console.error(e));
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2462
2100
|
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
}
|
|
2101
|
+
const pushCollection = async (): Promise<void> => {
|
|
2102
|
+
warn(
|
|
2103
|
+
`${EXECUTABLE_NAME} push collection has been deprecated. Please consider using '${EXECUTABLE_NAME} push tables' instead`,
|
|
2104
|
+
);
|
|
2105
|
+
const collections: any[] = [];
|
|
2466
2106
|
|
|
2467
|
-
|
|
2468
|
-
|
|
2107
|
+
if (cliConfig.all) {
|
|
2108
|
+
checkDeployConditions(localConfig);
|
|
2109
|
+
collections.push(...localConfig.getCollections());
|
|
2110
|
+
} else {
|
|
2111
|
+
const answers = await inquirer.prompt(questionsPushCollections);
|
|
2112
|
+
if (answers.collections) {
|
|
2113
|
+
const configCollections = new Map();
|
|
2114
|
+
localConfig.getCollections().forEach((c: any) => {
|
|
2115
|
+
configCollections.set(`${c["databaseId"]}|${c["$id"]}`, c);
|
|
2116
|
+
});
|
|
2117
|
+
answers.collections.forEach((a: any) => {
|
|
2118
|
+
const collection = configCollections.get(a);
|
|
2119
|
+
collections.push(collection);
|
|
2120
|
+
});
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
if (collections.length === 0) {
|
|
2125
|
+
log("No collections found.");
|
|
2126
|
+
hint(
|
|
2127
|
+
`Use '${EXECUTABLE_NAME} pull collections' to synchronize existing one, or use '${EXECUTABLE_NAME} init collection' to create a new one.`,
|
|
2128
|
+
);
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
// Add database names to collections for the class method
|
|
2133
|
+
collections.forEach((collection: any) => {
|
|
2134
|
+
const localDatabase = localConfig.getDatabase(collection.databaseId);
|
|
2135
|
+
collection.databaseName = localDatabase.name ?? collection.databaseId;
|
|
2136
|
+
});
|
|
2137
|
+
|
|
2138
|
+
if (
|
|
2139
|
+
!(await approveChanges(
|
|
2140
|
+
collections,
|
|
2141
|
+
async (args: any) => {
|
|
2142
|
+
const databasesService = await getDatabasesService();
|
|
2143
|
+
return await databasesService.getCollection(
|
|
2144
|
+
args.databaseId,
|
|
2145
|
+
args.collectionId,
|
|
2146
|
+
);
|
|
2147
|
+
},
|
|
2148
|
+
KeysCollection,
|
|
2149
|
+
"collectionId",
|
|
2150
|
+
"collections",
|
|
2151
|
+
["attributes", "indexes"],
|
|
2152
|
+
"databaseId",
|
|
2153
|
+
"databaseId",
|
|
2154
|
+
))
|
|
2155
|
+
) {
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
log("Pushing collections ...");
|
|
2160
|
+
|
|
2161
|
+
const pushInstance = await createPushInstance();
|
|
2162
|
+
const result = await pushInstance.pushCollections(collections);
|
|
2163
|
+
|
|
2164
|
+
const { successfullyPushed, errors } = result;
|
|
2165
|
+
|
|
2166
|
+
if (successfullyPushed === 0) {
|
|
2167
|
+
error("No collections were pushed.");
|
|
2168
|
+
} else {
|
|
2169
|
+
success(`Successfully pushed ${successfullyPushed} collections.`);
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
if (cliConfig.verbose) {
|
|
2173
|
+
errors.forEach((e) => console.error(e));
|
|
2174
|
+
}
|
|
2175
|
+
};
|
|
2469
2176
|
|
|
2470
|
-
|
|
2471
|
-
|
|
2177
|
+
const pushBucket = async (): Promise<void> => {
|
|
2178
|
+
let bucketIds: string[] = [];
|
|
2179
|
+
const configBuckets = localConfig.getBuckets();
|
|
2472
2180
|
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2181
|
+
if (cliConfig.all) {
|
|
2182
|
+
checkDeployConditions(localConfig);
|
|
2183
|
+
bucketIds.push(...configBuckets.map((b: any) => b.$id));
|
|
2184
|
+
}
|
|
2477
2185
|
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
}
|
|
2186
|
+
if (bucketIds.length === 0) {
|
|
2187
|
+
const answers = await inquirer.prompt(questionsPushBuckets);
|
|
2188
|
+
if (answers.buckets) {
|
|
2189
|
+
bucketIds.push(...answers.buckets);
|
|
2483
2190
|
}
|
|
2191
|
+
}
|
|
2484
2192
|
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2193
|
+
if (bucketIds.length === 0) {
|
|
2194
|
+
log("No buckets found.");
|
|
2195
|
+
hint(
|
|
2196
|
+
`Use '${EXECUTABLE_NAME} pull buckets' to synchronize existing one, or use '${EXECUTABLE_NAME} init bucket' to create a new one.`,
|
|
2197
|
+
);
|
|
2198
|
+
return;
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
let buckets: any[] = [];
|
|
2202
|
+
|
|
2203
|
+
for (const bucketId of bucketIds) {
|
|
2204
|
+
const idBuckets = configBuckets.filter((b: any) => b.$id === bucketId);
|
|
2205
|
+
buckets.push(...idBuckets);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
if (
|
|
2209
|
+
!(await approveChanges(
|
|
2210
|
+
buckets,
|
|
2211
|
+
async (args: any) => {
|
|
2212
|
+
const storageService = await getStorageService();
|
|
2213
|
+
return await storageService.getBucket(args.bucketId);
|
|
2214
|
+
},
|
|
2215
|
+
KeysStorage,
|
|
2216
|
+
"bucketId",
|
|
2217
|
+
"buckets",
|
|
2218
|
+
))
|
|
2219
|
+
) {
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
log("Pushing buckets ...");
|
|
2224
|
+
|
|
2225
|
+
const pushInstance = await createPushInstance();
|
|
2226
|
+
const result = await pushInstance.pushBuckets(buckets);
|
|
2227
|
+
|
|
2228
|
+
const { successfullyPushed, errors } = result;
|
|
2229
|
+
|
|
2230
|
+
if (successfullyPushed === 0) {
|
|
2231
|
+
error("No buckets were pushed.");
|
|
2232
|
+
} else {
|
|
2233
|
+
success(`Successfully pushed ${successfullyPushed} buckets.`);
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
if (cliConfig.verbose) {
|
|
2237
|
+
errors.forEach((e) => console.error(e));
|
|
2238
|
+
}
|
|
2239
|
+
};
|
|
2490
2240
|
|
|
2491
|
-
|
|
2241
|
+
const pushTeam = async (): Promise<void> => {
|
|
2242
|
+
let teamIds: string[] = [];
|
|
2243
|
+
const configTeams = localConfig.getTeams();
|
|
2492
2244
|
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2245
|
+
if (cliConfig.all) {
|
|
2246
|
+
checkDeployConditions(localConfig);
|
|
2247
|
+
teamIds.push(...configTeams.map((t: any) => t.$id));
|
|
2248
|
+
}
|
|
2497
2249
|
|
|
2498
|
-
|
|
2499
|
-
|
|
2250
|
+
if (teamIds.length === 0) {
|
|
2251
|
+
const answers = await inquirer.prompt(questionsPushTeams);
|
|
2252
|
+
if (answers.teams) {
|
|
2253
|
+
teamIds.push(...answers.teams);
|
|
2500
2254
|
}
|
|
2255
|
+
}
|
|
2501
2256
|
|
|
2502
|
-
|
|
2257
|
+
if (teamIds.length === 0) {
|
|
2258
|
+
log("No teams found.");
|
|
2259
|
+
hint(
|
|
2260
|
+
`Use '${EXECUTABLE_NAME} pull teams' to synchronize existing one, or use '${EXECUTABLE_NAME} init team' to create a new one.`,
|
|
2261
|
+
);
|
|
2262
|
+
return;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
let teams: any[] = [];
|
|
2266
|
+
|
|
2267
|
+
for (const teamId of teamIds) {
|
|
2268
|
+
const idTeams = configTeams.filter((t: any) => t.$id === teamId);
|
|
2269
|
+
teams.push(...idTeams);
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
if (
|
|
2273
|
+
!(await approveChanges(
|
|
2274
|
+
teams,
|
|
2275
|
+
async (args: any) => {
|
|
2276
|
+
const teamsService = await getTeamsService();
|
|
2277
|
+
return await teamsService.get(args.teamId);
|
|
2278
|
+
},
|
|
2279
|
+
KeysTeams,
|
|
2280
|
+
"teamId",
|
|
2281
|
+
"teams",
|
|
2282
|
+
))
|
|
2283
|
+
) {
|
|
2284
|
+
return;
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
log("Pushing teams ...");
|
|
2288
|
+
|
|
2289
|
+
const pushInstance = await createPushInstance();
|
|
2290
|
+
const result = await pushInstance.pushTeams(teams);
|
|
2291
|
+
|
|
2292
|
+
const { successfullyPushed, errors } = result;
|
|
2293
|
+
|
|
2294
|
+
if (successfullyPushed === 0) {
|
|
2295
|
+
error("No teams were pushed.");
|
|
2296
|
+
} else {
|
|
2297
|
+
success(`Successfully pushed ${successfullyPushed} teams.`);
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
if (cliConfig.verbose) {
|
|
2301
|
+
errors.forEach((e) => console.error(e));
|
|
2302
|
+
}
|
|
2303
|
+
};
|
|
2503
2304
|
|
|
2504
|
-
|
|
2505
|
-
|
|
2305
|
+
const pushMessagingTopic = async (): Promise<void> => {
|
|
2306
|
+
let topicsIds: string[] = [];
|
|
2307
|
+
const configTopics = localConfig.getMessagingTopics();
|
|
2506
2308
|
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
name: topic.name,
|
|
2517
|
-
subscribe: topic.subscribe,
|
|
2518
|
-
parseOutput: false
|
|
2519
|
-
});
|
|
2520
|
-
} catch (e: any) {
|
|
2521
|
-
if (Number(e.code) === 404) {
|
|
2522
|
-
log(`Topic ${topic.name} does not exist in the project. Creating ... `);
|
|
2523
|
-
|
|
2524
|
-
response = await messagingCreateTopic({
|
|
2525
|
-
topicId: topic['$id'],
|
|
2526
|
-
name: topic.name,
|
|
2527
|
-
subscribe: topic.subscribe,
|
|
2528
|
-
parseOutput: false
|
|
2529
|
-
})
|
|
2530
|
-
|
|
2531
|
-
success(`Created ${topic.name} ( ${topic['$id']} )`);
|
|
2532
|
-
} else {
|
|
2533
|
-
throw e;
|
|
2534
|
-
}
|
|
2535
|
-
}
|
|
2309
|
+
if (cliConfig.all) {
|
|
2310
|
+
checkDeployConditions(localConfig);
|
|
2311
|
+
topicsIds.push(...configTopics.map((b: any) => b.$id));
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
if (topicsIds.length === 0) {
|
|
2315
|
+
const answers = await inquirer.prompt(questionsPushMessagingTopics);
|
|
2316
|
+
if (answers.topics) {
|
|
2317
|
+
topicsIds.push(...answers.topics);
|
|
2536
2318
|
}
|
|
2319
|
+
}
|
|
2537
2320
|
|
|
2538
|
-
|
|
2539
|
-
|
|
2321
|
+
if (topicsIds.length === 0) {
|
|
2322
|
+
log("No topics found.");
|
|
2323
|
+
hint(
|
|
2324
|
+
`Use '${EXECUTABLE_NAME} pull topics' to synchronize existing one, or use '${EXECUTABLE_NAME} init topic' to create a new one.`,
|
|
2325
|
+
);
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
let topics: any[] = [];
|
|
2330
|
+
|
|
2331
|
+
for (const topicId of topicsIds) {
|
|
2332
|
+
const idTopic = configTopics.filter((b: any) => b.$id === topicId);
|
|
2333
|
+
topics.push(...idTopic);
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
if (
|
|
2337
|
+
!(await approveChanges(
|
|
2338
|
+
topics,
|
|
2339
|
+
async (args: any) => {
|
|
2340
|
+
const messagingService = await getMessagingService();
|
|
2341
|
+
return await messagingService.getTopic(args.topicId);
|
|
2342
|
+
},
|
|
2343
|
+
KeysTopics,
|
|
2344
|
+
"topicId",
|
|
2345
|
+
"topics",
|
|
2346
|
+
))
|
|
2347
|
+
) {
|
|
2348
|
+
return;
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
log("Pushing topics ...");
|
|
2352
|
+
|
|
2353
|
+
const pushInstance = await createPushInstance();
|
|
2354
|
+
const result = await pushInstance.pushMessagingTopics(topics);
|
|
2355
|
+
|
|
2356
|
+
const { successfullyPushed, errors } = result;
|
|
2357
|
+
|
|
2358
|
+
if (successfullyPushed === 0) {
|
|
2359
|
+
error("No topics were pushed.");
|
|
2360
|
+
} else {
|
|
2361
|
+
success(`Successfully pushed ${successfullyPushed} topics.`);
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
if (cliConfig.verbose) {
|
|
2365
|
+
errors.forEach((e) => console.error(e));
|
|
2366
|
+
}
|
|
2367
|
+
};
|
|
2540
2368
|
|
|
2541
2369
|
export const push = new Command("push")
|
|
2542
|
-
|
|
2543
|
-
|
|
2370
|
+
.description(commandDescriptions["push"])
|
|
2371
|
+
.action(actionRunner(() => pushResources({ skipDeprecated: true })));
|
|
2544
2372
|
|
|
2545
2373
|
push
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2374
|
+
.command("all")
|
|
2375
|
+
.description("Push all resource.")
|
|
2376
|
+
.action(
|
|
2377
|
+
actionRunner(() => {
|
|
2378
|
+
cliConfig.all = true;
|
|
2379
|
+
return pushResources({ skipDeprecated: true });
|
|
2380
|
+
}),
|
|
2381
|
+
);
|
|
2552
2382
|
|
|
2553
2383
|
push
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2384
|
+
.command("settings")
|
|
2385
|
+
.description("Push project name, services and auth settings")
|
|
2386
|
+
.action(actionRunner(pushSettings));
|
|
2557
2387
|
|
|
2558
2388
|
push
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2389
|
+
.command("function")
|
|
2390
|
+
.alias("functions")
|
|
2391
|
+
.description("Push functions in the current directory.")
|
|
2392
|
+
.option(`-f, --function-id <function-id>`, `ID of function to run`)
|
|
2393
|
+
.option(`-A, --async`, `Don't wait for functions deployments status`)
|
|
2394
|
+
.option("--no-code", "Don't push the function's code")
|
|
2395
|
+
.option("--with-variables", `Push function variables.`)
|
|
2396
|
+
.action(actionRunner(pushFunction));
|
|
2567
2397
|
|
|
2568
2398
|
push
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2399
|
+
.command("site")
|
|
2400
|
+
.alias("sites")
|
|
2401
|
+
.description("Push sites in the current directory.")
|
|
2402
|
+
.option(`-f, --site-id <site-id>`, `ID of site to run`)
|
|
2403
|
+
.option(`-A, --async`, `Don't wait for sites deployments status`)
|
|
2404
|
+
.option("--no-code", "Don't push the site's code")
|
|
2405
|
+
.option("--with-variables", `Push site variables.`)
|
|
2406
|
+
.action(actionRunner(pushSite));
|
|
2577
2407
|
|
|
2578
2408
|
push
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2409
|
+
.command("collection")
|
|
2410
|
+
.alias("collections")
|
|
2411
|
+
.description(
|
|
2412
|
+
"Push collections in the current project. (deprecated, please use 'push tables' instead)",
|
|
2413
|
+
)
|
|
2414
|
+
.option(
|
|
2415
|
+
`-a, --attempts <numberOfAttempts>`,
|
|
2416
|
+
`Max number of attempts before timing out. default: 30.`,
|
|
2417
|
+
)
|
|
2418
|
+
.action(actionRunner(pushCollection));
|
|
2584
2419
|
|
|
2585
2420
|
push
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2421
|
+
.command("table")
|
|
2422
|
+
.alias("tables")
|
|
2423
|
+
.description("Push tables in the current project.")
|
|
2424
|
+
.option(
|
|
2425
|
+
`-a, --attempts <numberOfAttempts>`,
|
|
2426
|
+
`Max number of attempts before timing out. default: 30.`,
|
|
2427
|
+
)
|
|
2428
|
+
.action(actionRunner(pushTable));
|
|
2591
2429
|
|
|
2592
2430
|
push
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2431
|
+
.command("bucket")
|
|
2432
|
+
.alias("buckets")
|
|
2433
|
+
.description("Push buckets in the current project.")
|
|
2434
|
+
.action(actionRunner(pushBucket));
|
|
2597
2435
|
|
|
2598
2436
|
push
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2437
|
+
.command("team")
|
|
2438
|
+
.alias("teams")
|
|
2439
|
+
.description("Push teams in the current project.")
|
|
2440
|
+
.action(actionRunner(pushTeam));
|
|
2603
2441
|
|
|
2604
2442
|
push
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2443
|
+
.command("topic")
|
|
2444
|
+
.alias("topics")
|
|
2445
|
+
.description("Push messaging topics in the current project.")
|
|
2446
|
+
.action(actionRunner(pushMessagingTopic));
|
|
2609
2447
|
|
|
2610
2448
|
export const deploy = new Command("deploy")
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2449
|
+
.description(`Removed. Use ${EXECUTABLE_NAME} push instead`)
|
|
2450
|
+
.action(
|
|
2451
|
+
actionRunner(async () => {
|
|
2452
|
+
warn(
|
|
2453
|
+
`${EXECUTABLE_NAME} deploy has been removed. Please use '${EXECUTABLE_NAME} push' instead`,
|
|
2454
|
+
);
|
|
2455
|
+
}),
|
|
2456
|
+
);
|