@contember/cli 0.12.0-alpha.9 → 1.0.0-alpha.0

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.
Files changed (93) hide show
  1. package/Dockerfile +2 -0
  2. package/dist/src/commands/deploy/DeployCommand.js +7 -7
  3. package/dist/src/commands/deploy/DeployCommand.js.map +1 -1
  4. package/dist/src/commands/migrations/MigrationAmendCommand.js +10 -10
  5. package/dist/src/commands/migrations/MigrationAmendCommand.js.map +1 -1
  6. package/dist/src/commands/migrations/MigrationCreateCommand.js +2 -2
  7. package/dist/src/commands/migrations/MigrationCreateCommand.js.map +1 -1
  8. package/dist/src/commands/migrations/MigrationDescribeCommand.js +2 -2
  9. package/dist/src/commands/migrations/MigrationDescribeCommand.js.map +1 -1
  10. package/dist/src/commands/migrations/MigrationDiffCommand.js +9 -9
  11. package/dist/src/commands/migrations/MigrationDiffCommand.js.map +1 -1
  12. package/dist/src/commands/migrations/MigrationExecuteCommand.d.ts.map +1 -1
  13. package/dist/src/commands/migrations/MigrationExecuteCommand.js +64 -49
  14. package/dist/src/commands/migrations/MigrationExecuteCommand.js.map +1 -1
  15. package/dist/src/commands/migrations/MigrationExecuteHelper.d.ts +1 -1
  16. package/dist/src/commands/migrations/MigrationExecuteHelper.d.ts.map +1 -1
  17. package/dist/src/commands/migrations/MigrationExecuteHelper.js +6 -10
  18. package/dist/src/commands/migrations/MigrationExecuteHelper.js.map +1 -1
  19. package/dist/src/commands/migrations/MigrationRebaseCommand.js +4 -4
  20. package/dist/src/commands/migrations/MigrationRebaseCommand.js.map +1 -1
  21. package/dist/src/commands/migrations/MigrationStatusCommand.js +6 -6
  22. package/dist/src/commands/migrations/MigrationStatusCommand.js.map +1 -1
  23. package/dist/src/commands/migrations/MigrationValidationHelper.js +1 -1
  24. package/dist/src/commands/migrations/MigrationValidationHelper.js.map +1 -1
  25. package/dist/src/commands/migrations/SystemApiClientResolver.js +2 -2
  26. package/dist/src/commands/migrations/SystemApiClientResolver.js.map +1 -1
  27. package/dist/src/commands/misc/VersionCommand.js +1 -1
  28. package/dist/src/commands/misc/VersionCommand.js.map +1 -1
  29. package/dist/src/commands/project/ProjectCreateCommand.d.ts.map +1 -1
  30. package/dist/src/commands/project/ProjectCreateCommand.js +2 -3
  31. package/dist/src/commands/project/ProjectCreateCommand.js.map +1 -1
  32. package/dist/src/commands/project/ProjectPrintSchemaCommand.js +4 -4
  33. package/dist/src/commands/project/ProjectPrintSchemaCommand.js.map +1 -1
  34. package/dist/src/commands/project/ProjectValidateCommand.js +5 -5
  35. package/dist/src/commands/project/ProjectValidateCommand.js.map +1 -1
  36. package/dist/src/commands/tenant/CreateApiKeyCommand.js +3 -3
  37. package/dist/src/commands/tenant/CreateApiKeyCommand.js.map +1 -1
  38. package/dist/src/commands/tenant/InviteCommand.js +3 -3
  39. package/dist/src/commands/tenant/InviteCommand.js.map +1 -1
  40. package/dist/src/commands/tenant/ResetPasswordCommand.js +3 -3
  41. package/dist/src/commands/tenant/ResetPasswordCommand.js.map +1 -1
  42. package/dist/src/commands/tenant/SignInCommand.js +3 -3
  43. package/dist/src/commands/tenant/SignInCommand.js.map +1 -1
  44. package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.d.ts.map +1 -1
  45. package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.js +36 -29
  46. package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.js.map +1 -1
  47. package/dist/src/run.js +3 -3
  48. package/dist/src/run.js.map +1 -1
  49. package/dist/src/tsconfig.tsbuildinfo +1 -1
  50. package/dist/src/utils/admin.d.ts.map +1 -1
  51. package/dist/src/utils/admin.js +5 -5
  52. package/dist/src/utils/admin.js.map +1 -1
  53. package/dist/src/utils/commands.js +1 -1
  54. package/dist/src/utils/commands.js.map +1 -1
  55. package/dist/src/utils/dockerCompose.d.ts +15 -0
  56. package/dist/src/utils/dockerCompose.d.ts.map +1 -0
  57. package/dist/src/utils/dockerCompose.js +22 -0
  58. package/dist/src/utils/dockerCompose.js.map +1 -0
  59. package/dist/src/utils/instance/interactiveUtils.js +2 -2
  60. package/dist/src/utils/instance/interactiveUtils.js.map +1 -1
  61. package/dist/src/utils/migrations.js +6 -6
  62. package/dist/src/utils/migrations.js.map +1 -1
  63. package/dist/src/utils/npm.js +6 -6
  64. package/dist/src/utils/npm.js.map +1 -1
  65. package/dist/src/utils/schema.js +1 -1
  66. package/dist/src/utils/schema.js.map +1 -1
  67. package/dist/src/utils/system/index.d.ts +1 -1
  68. package/dist/src/utils/system/index.d.ts.map +1 -1
  69. package/dist/src/utils/system/index.js +5 -2
  70. package/dist/src/utils/system/index.js.map +1 -1
  71. package/dist/src/utils/tenant.js +21 -21
  72. package/dist/src/utils/tenant.js.map +1 -1
  73. package/dist/src/utils/workspace.d.ts +3 -0
  74. package/dist/src/utils/workspace.d.ts.map +1 -0
  75. package/dist/src/utils/workspace.js +26 -0
  76. package/dist/src/utils/workspace.js.map +1 -0
  77. package/dist/src/utils/yaml.d.ts +8 -0
  78. package/dist/src/utils/yaml.d.ts.map +1 -0
  79. package/dist/src/utils/yaml.js +33 -0
  80. package/dist/src/utils/yaml.js.map +1 -0
  81. package/package.json +16 -12
  82. package/src/commands/migrations/MigrationExecuteCommand.ts +67 -50
  83. package/src/commands/migrations/MigrationExecuteHelper.ts +4 -8
  84. package/src/commands/project/ProjectCreateCommand.ts +1 -2
  85. package/src/commands/project/ProjectValidateCommand.ts +1 -1
  86. package/src/commands/workspace/WorkspaceUpdateApiCommand.ts +38 -36
  87. package/src/run.ts +1 -1
  88. package/src/utils/admin.ts +2 -1
  89. package/src/utils/dockerCompose.ts +38 -0
  90. package/src/utils/system/index.ts +5 -2
  91. package/src/utils/workspace.ts +22 -0
  92. package/src/utils/yaml.ts +37 -0
  93. package/types/yawn-yaml/index.d.ts +7 -0
@@ -0,0 +1,8 @@
1
+ import { JSONObject } from '@contember/cli-common/dist/src/utils/json';
2
+ export declare type JsonUpdateCallback<Value = JSONObject> = (data: Partial<Value>, utils: {
3
+ merge: (a: JSONObject, b: JSONObject) => JSONObject;
4
+ }) => Value;
5
+ export declare const updateYaml: <Value = JSONObject>(path: string, updater: JsonUpdateCallback<Value>, options?: {
6
+ createMissing?: boolean;
7
+ }) => Promise<void>;
8
+ //# sourceMappingURL=yaml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../../../src/utils/yaml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiB,MAAM,2CAA2C,CAAA;AAOrF,oBAAY,kBAAkB,CAAC,KAAK,GAAG,UAAU,IAAI,CACpD,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,EACpB,KAAK,EAAE;IAAE,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,KAAK,UAAU,CAAA;CAAE,KAC1D,KAAK,CAAA;AAEV,eAAO,MAAM,UAAU,6BAChB,MAAM,gDAEH;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,kBAoBpC,CAAA"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.updateYaml = void 0;
7
+ const fs_extra_1 = require("fs-extra");
8
+ const cjs_1 = __importDefault(require("yawn-yaml/cjs"));
9
+ const config_loader_1 = require("@contember/config-loader");
10
+ const js_yaml_1 = __importDefault(require("js-yaml"));
11
+ const promises_1 = require("fs/promises");
12
+ const updateYaml = async (path, updater, options = {}) => {
13
+ let config = '';
14
+ if (await (0, fs_extra_1.pathExists)(path)) {
15
+ config = await (0, promises_1.readFile)(path, { encoding: 'utf8' });
16
+ }
17
+ else if (options.createMissing !== true) {
18
+ throw new Error(`File ${path} does not exist.`);
19
+ }
20
+ let newConfig = '';
21
+ const mergeUtils = { merge: (a, b) => config_loader_1.Merger.merge(a, b) };
22
+ if (config) {
23
+ const yawn = new cjs_1.default(config);
24
+ yawn.json = updater(yawn.json, mergeUtils);
25
+ newConfig = yawn.yaml;
26
+ }
27
+ else {
28
+ newConfig = js_yaml_1.default.dump(updater({}, mergeUtils));
29
+ }
30
+ await (0, promises_1.writeFile)(path, newConfig, { encoding: 'utf8' });
31
+ };
32
+ exports.updateYaml = updateYaml;
33
+ //# sourceMappingURL=yaml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml.js","sourceRoot":"","sources":["../../../src/utils/yaml.ts"],"names":[],"mappings":";;;;;;AACA,uCAAqC;AACrC,wDAAgC;AAChC,4DAAiD;AACjD,sDAA4B;AAC5B,0CAAiD;AAO1C,MAAM,UAAU,GAAG,KAAK,EAC9B,IAAY,EACZ,OAAkC,EAClC,UAAuC,EAAE,EACxC,EAAE;IACH,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,IAAI,MAAM,IAAA,qBAAU,EAAC,IAAI,CAAC,EAAE;QAC3B,MAAM,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;KACnD;SAAM,IAAI,OAAO,CAAC,aAAa,KAAK,IAAI,EAAE;QAC1C,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,kBAAkB,CAAC,CAAA;KAC/C;IAED,IAAI,SAAS,GAAG,EAAE,CAAA;IAClB,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,CAAC,CAAa,EAAE,CAAa,EAAE,EAAE,CAAC,sBAAM,CAAC,KAAK,CAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;IACjG,IAAI,MAAM,EAAE;QACX,MAAM,IAAI,GAAG,IAAI,aAAI,CAAC,MAAM,CAAC,CAAA;QAC7B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QAC1C,SAAS,GAAG,IAAI,CAAC,IAAI,CAAA;KACrB;SAAM;QACN,SAAS,GAAG,iBAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAA;KAChD;IAED,MAAM,IAAA,oBAAS,EAAC,IAAI,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;AACvD,CAAC,CAAA;AAvBY,QAAA,UAAU,cAuBtB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contember/cli",
3
- "version": "0.12.0-alpha.9",
3
+ "version": "1.0.0-alpha.0",
4
4
  "license": "Apache-2.0",
5
5
  "bin": {
6
6
  "contember": "./dist/src/run.js"
@@ -9,28 +9,32 @@
9
9
  "test": "echo 'No tests'"
10
10
  },
11
11
  "devDependencies": {
12
- "@types/prompts": "^2.0.1"
12
+ "@types/prompts": "^2.0.1",
13
+ "@types/js-yaml": "^4.0.1",
14
+ "@types/fs-extra": "^9.0.3"
13
15
  },
14
16
  "dependencies": {
15
- "@contember/cli-common": "^0.12.0-alpha.9",
16
- "@contember/config-loader": "^0.12.0-alpha.9",
17
- "@contember/database-migrations": "^0.12.0-alpha.9",
18
- "@contember/dic": "^0.12.0-alpha.9",
19
- "@contember/engine-content-api": "^0.12.0-alpha.9",
20
- "@contember/schema": "^0.12.0-alpha.9",
21
- "@contember/schema-definition": "^0.12.0-alpha.9",
22
- "@contember/schema-migrations": "^0.12.0-alpha.9",
23
- "@contember/schema-utils": "^0.12.0-alpha.9",
17
+ "@contember/cli-common": "^1.0.0-alpha.0",
18
+ "@contember/config-loader": "^1.0.0-alpha.0",
19
+ "@contember/database-migrations": "^1.0.0-alpha.0",
20
+ "@contember/dic": "^1.0.0-alpha.0",
21
+ "@contember/engine-content-api": "^1.0.0-alpha.0",
22
+ "@contember/schema": "^1.0.0-alpha.0",
23
+ "@contember/schema-definition": "^1.0.0-alpha.0",
24
+ "@contember/schema-migrations": "^1.0.0-alpha.0",
25
+ "@contember/schema-utils": "^1.0.0-alpha.0",
24
26
  "@graphql-tools/merge": "^6.2.14",
25
27
  "chalk": "^4.1.0",
26
28
  "chalk-table": "^1.0.2",
27
29
  "get-port": "^5.0.0",
28
30
  "graphql": "^15.4.0",
29
31
  "graphql-request": "^3.3.0",
32
+ "js-yaml": "^4.1.0",
30
33
  "node-fetch": "^2.6.1",
31
34
  "pg": "^8.5.0",
32
35
  "prompts": "^2.2.1",
33
36
  "ts-node": "^10.2.0",
34
- "typescript": "^4.3.5"
37
+ "typescript": "^4.3.5",
38
+ "yawn-yaml": "^1.5.0"
35
39
  }
36
40
  }
@@ -1,4 +1,4 @@
1
- import { Command, CommandConfiguration, Input, Workspace } from '@contember/cli-common'
1
+ import { Command, CommandConfiguration, Input, validateProjectName, Workspace } from '@contember/cli-common'
2
2
  import { MigrationsContainerFactory } from '../../MigrationsContainer'
3
3
  import {
4
4
  configureExecuteMigrationCommand,
@@ -34,61 +34,78 @@ export class MigrationExecuteCommand extends Command<Args, Options> {
34
34
  const projectName = input.getArgument('project')
35
35
 
36
36
  const workspace = await Workspace.get(process.cwd())
37
- const project = await workspace.projects.getProject(projectName, { fuzzy: true })
38
- const migrationsDir = project.migrationsDir
39
- const container = new MigrationsContainerFactory(migrationsDir).create()
40
- const migrationArg = input.getArgument('migration')
41
37
 
42
- const instance = await interactiveResolveInstanceEnvironmentFromInput(workspace, input?.getOption('instance'))
43
- const apiToken = await interactiveResolveApiToken({ instance })
44
- const remoteProject = input?.getOption('remote-project') || project.name
45
- const tenantClient = TenantClient.create(instance.baseUrl, apiToken)
46
- await tenantClient.createProject(remoteProject, true)
47
- const systemClient = SystemClient.create(instance.baseUrl, remoteProject, apiToken)
48
-
49
- const force = input.getOption('force')
50
- const status = await resolveMigrationStatus(systemClient, container.migrationsResolver, force)
51
- if (status.errorMigrations.length > 0) {
52
- console.error(createMigrationStatusTable(status.errorMigrations))
53
- if (!force) {
54
- throw `Cannot execute migrations`
55
- }
38
+ const allProjects = projectName === '.'
39
+ if (!allProjects) {
40
+ validateProjectName(projectName)
41
+ }
42
+ const remoteProjectOption = input?.getOption('remote-project')
43
+ if (remoteProjectOption && allProjects) {
44
+ throw 'Option remote-project can be used only for a single project'
56
45
  }
46
+ const projects = allProjects
47
+ ? await workspace.projects.listProjects()
48
+ : [await workspace.projects.getProject(projectName, { fuzzy: true })]
49
+
50
+ let code = 0
51
+ for (const project of projects) {
52
+ const migrationsDir = project.migrationsDir
53
+ const container = new MigrationsContainerFactory(migrationsDir).create()
54
+ const migrationArg = input.getArgument('migration')
55
+
56
+ const instance = await interactiveResolveInstanceEnvironmentFromInput(workspace, input?.getOption('instance'))
57
+ const apiToken = await interactiveResolveApiToken({ instance })
58
+ const remoteProject = remoteProjectOption || project.name
59
+ const tenantClient = TenantClient.create(instance.baseUrl, apiToken)
60
+ await tenantClient.createProject(remoteProject, true)
61
+ const systemClient = SystemClient.create(instance.baseUrl, remoteProject, apiToken)
57
62
 
58
- const migrations = (() => {
59
- if (migrationArg) {
60
- const migration = findMigration(status.allMigrations, migrationArg)
61
- if (!migration) {
62
- throw `Undefined migration ${migrationArg}`
63
+ const force = input.getOption('force')
64
+ const status = await resolveMigrationStatus(systemClient, container.migrationsResolver, force)
65
+ if (status.errorMigrations.length > 0) {
66
+ console.error(createMigrationStatusTable(status.errorMigrations))
67
+ if (!force) {
68
+ throw `Cannot execute migrations`
63
69
  }
64
- switch (migration.state) {
65
- case MigrationState.EXECUTED_OK:
66
- throw `Migration ${migrationArg} is already executed`
67
- case MigrationState.TO_EXECUTE_ERROR:
68
- case MigrationState.EXECUTED_ERROR:
69
- case MigrationState.EXECUTED_MISSING:
70
- throw `Cannot execute migration ${migrationArg}: ${migration.errorMessage} (${migration.state})`
71
- case MigrationState.TO_EXECUTE_OK:
72
- return [migration]
73
- default:
74
- assertNever(migration)
70
+ }
71
+
72
+ const migrations = (() => {
73
+ if (migrationArg) {
74
+ const migration = findMigration(status.allMigrations, migrationArg)
75
+ if (!migration) {
76
+ throw `Undefined migration ${migrationArg}`
77
+ }
78
+ switch (migration.state) {
79
+ case MigrationState.EXECUTED_OK:
80
+ throw `Migration ${migrationArg} is already executed`
81
+ case MigrationState.TO_EXECUTE_ERROR:
82
+ case MigrationState.EXECUTED_ERROR:
83
+ case MigrationState.EXECUTED_MISSING:
84
+ throw `Cannot execute migration ${migrationArg}: ${migration.errorMessage} (${migration.state})`
85
+ case MigrationState.TO_EXECUTE_OK:
86
+ return [migration]
87
+ default:
88
+ assertNever(migration)
89
+ }
90
+ } else {
91
+ return status.migrationsToExecute
75
92
  }
76
- } else {
77
- return status.migrationsToExecute
93
+ })()
94
+ if (migrations.length === 0) {
95
+ console.log('No migrations to execute')
96
+ continue
78
97
  }
79
- })()
80
- if (migrations.length === 0) {
81
- console.log('No migrations to execute')
82
- return 0
83
- }
84
98
 
85
- return await executeMigrations({
86
- migrationDescriber: container.migrationDescriber,
87
- schemaVersionBuilder: container.schemaVersionBuilder,
88
- client: systemClient,
89
- migrations,
90
- requireConfirmation: !input.getOption('yes'),
91
- force: force,
92
- })
99
+ const singleCode = await executeMigrations({
100
+ migrationDescriber: container.migrationDescriber,
101
+ schemaVersionBuilder: container.schemaVersionBuilder,
102
+ client: systemClient,
103
+ migrations,
104
+ requireConfirmation: !input.getOption('yes'),
105
+ force: force,
106
+ })
107
+ code ||= singleCode
108
+ }
109
+ return code
93
110
  }
94
111
  }
@@ -49,7 +49,7 @@ export const executeMigrations = async ({
49
49
  schemaVersionBuilder: SchemaVersionBuilder
50
50
  migrationDescriber: MigrationDescriber
51
51
  force?: boolean
52
- }) => {
52
+ }): Promise<number> => {
53
53
  console.log('Will execute following migrations:')
54
54
  migrations.forEach(it => console.log(it.name))
55
55
  if (requireConfirmation) {
@@ -82,14 +82,10 @@ export const executeMigrations = async ({
82
82
  } while (true)
83
83
  }
84
84
 
85
- const result = await client.migrate(
85
+ await client.migrate(
86
86
  migrations.map(it => it.localMigration),
87
87
  force,
88
88
  )
89
- if (result.ok) {
90
- console.log('Migration executed')
91
- return 0
92
- }
93
- console.error(result.errors)
94
- return 1
89
+ console.log('Migration executed')
90
+ return 0
95
91
  }
@@ -22,8 +22,7 @@ export class ProjectCreateCommand extends Command<Args, Options> {
22
22
  const workspace = await Workspace.get(process.cwd())
23
23
 
24
24
  const template = input.getOption('template')
25
- const project = await workspace.projects.createProject(projectName, { template })
26
- await project.register()
25
+ await workspace.projects.createProject(projectName, { template })
27
26
 
28
27
  console.log(`Project ${projectName} created`)
29
28
  }
@@ -67,7 +67,7 @@ export class ProjectValidateCommand extends Command<Args, Options> {
67
67
  console.groupEnd()
68
68
  valid = valid && projectValid
69
69
  }
70
- if (invalidProjects) {
70
+ if (invalidProjects.length) {
71
71
  console.log('Following projects failed the validation:')
72
72
  invalidProjects.forEach(it => console.log(it))
73
73
  }
@@ -1,7 +1,7 @@
1
- import { Command, CommandConfiguration, Input } from '@contember/cli-common'
2
- import { Workspace } from '@contember/cli-common'
3
- import { updateMainDockerComposeConfig } from '@contember/cli-common'
1
+ import { Command, CommandConfiguration, Input, Workspace } from '@contember/cli-common'
4
2
  import { updateNpmPackages } from '../../utils/npm'
3
+ import { updateWorkspaceApiVersion } from '../../utils/workspace'
4
+ import { updateMainDockerComposeConfig } from '../../utils/dockerCompose'
5
5
 
6
6
  type Args = {
7
7
  version: string
@@ -11,7 +11,7 @@ type Options = {}
11
11
 
12
12
  export class WorkspaceUpdateApiCommand extends Command<Args, Options> {
13
13
  protected configure(configuration: CommandConfiguration<Args, Options>): void {
14
- configuration.description('Updates contember API version and all related packages')
14
+ configuration.description('Updates Contember API version and all related packages')
15
15
  configuration.argument('version')
16
16
  }
17
17
 
@@ -20,42 +20,44 @@ export class WorkspaceUpdateApiCommand extends Command<Args, Options> {
20
20
  const workspace = await Workspace.get(process.cwd())
21
21
  const upgradablePackages = ['@contember/schema', '@contember/schema-definition', '@contember/cli']
22
22
 
23
- await updateNpmPackages(
24
- upgradablePackages.map(it => ({ name: it, version })),
25
- workspace.directory,
26
- )
23
+ await updateNpmPackages(upgradablePackages.map(it => ({ name: it, version })), workspace.directory)
24
+
27
25
  const prevVersion = workspace.apiVersion
28
- if (await workspace.updateApiVersion(version)) {
29
- console.log('contember.workspace.yaml updated')
26
+ const updatedYaml = await updateWorkspaceApiVersion(workspace, version)
27
+
28
+ if (updatedYaml) {
29
+ console.log(`${updatedYaml} updated`)
30
30
  } else {
31
- console.log('contember.workspace.yaml not found, skipping')
31
+ console.log('contember.yaml not found, skipping')
32
32
  }
33
- console.log('Updating docker-compose')
34
- await updateMainDockerComposeConfig(workspace.directory, (data: any) => {
35
- const apiServiceName = data.services?.['contember'] ? 'contember' : 'api'
36
- if (!data.services?.[apiServiceName]) {
37
- console.log(`docker-compose.yaml file not found, skipping`)
38
- return
39
- }
40
- const expectedImage = `contember/contember:${prevVersion}`
41
- if (data.services[apiServiceName].image !== expectedImage) {
42
- console.log(
43
- `API image in docker-compose.yaml file is ${data.services[apiServiceName].image}, but ${expectedImage} is expected. Skipping`,
44
- )
45
- return data
46
- }
47
33
 
48
- return {
49
- ...data,
50
- services: {
51
- ...data.services,
52
- [apiServiceName]: {
53
- ...data.services?.[apiServiceName],
54
- image: `contember/contember:${version}`,
55
- },
56
- },
34
+ console.log('Updating docker-compose')
35
+ const getNewImage = (currentImage: string): string | null => {
36
+ for (const candidate of ['contember/engine', 'contember/contember', 'contember/cli']) {
37
+ if (prevVersion && currentImage === `${candidate}:${prevVersion}` || !prevVersion && currentImage.startsWith(`${candidate}:`)) {
38
+ return `${candidate}:${version}`
39
+ }
57
40
  }
58
- })
59
- console.log('API update successful')
41
+ return null
42
+ }
43
+ await updateMainDockerComposeConfig(workspace.directory, data => ({
44
+ ...data,
45
+ services: Object.fromEntries(Object.entries(data?.services ?? {}).map(([name, service]: [string, any]) => {
46
+ const newImage = getNewImage(service.image)
47
+ if (newImage) {
48
+ console.log(`docker-compose service ${service} updated`)
49
+ return [
50
+ name,
51
+ {
52
+ ...service,
53
+ image: newImage,
54
+ },
55
+ ]
56
+ }
57
+ return [name, service]
58
+ })),
59
+ }))
60
+ console.log('API versions updated')
61
+ console.log('Restart server to apply changes')
60
62
  }
61
63
  }
package/src/run.ts CHANGED
@@ -59,7 +59,7 @@ import {
59
59
  }
60
60
  const cliVersion = getPackageVersion()
61
61
  const app = new Application(commandManager, `Contember CLI version ${cliVersion}`)
62
- await app.run(process.argv)
62
+ await app.run(process.argv.slice(2))
63
63
  })().catch(e => {
64
64
  console.log(e)
65
65
  process.exit(1)
@@ -10,8 +10,9 @@ export class AdminClient {
10
10
 
11
11
  public async deploy(project: string, files: AdminFiles): Promise<void> {
12
12
  const response = await this.execute('_deploy', 'POST', { project, files })
13
+
13
14
  if (!response.ok) {
14
- throw 'Failed to deploy admin'
15
+ throw `Failed to deploy admin, POST request to ${this.url}/_deploy returned status ${response.status} ${response.statusText}`
15
16
  }
16
17
  }
17
18
 
@@ -0,0 +1,38 @@
1
+ import { join } from 'path'
2
+ import { pathExists } from 'fs-extra'
3
+ import { JsonUpdateCallback, updateYaml } from './yaml'
4
+
5
+ const MAIN_CONFIGS = ['docker-compose.yaml', 'docker-compose.yml']
6
+
7
+ export interface DockerComposeServiceConfig {
8
+ image?: string
9
+ command?: string
10
+ user?: string
11
+ environment?: Record<string, string>
12
+ ports?: (string | {})[] // todo long syntax
13
+ }
14
+
15
+ export interface DockerComposeConfig {
16
+ [key: string]: unknown
17
+
18
+ version?: string
19
+ services?: Record<string, DockerComposeServiceConfig>
20
+ }
21
+
22
+ const resolvePath = async (dir: string, possibleFileNames: string[], fallbackFileName: string): Promise<string> => {
23
+ for (const file of possibleFileNames) {
24
+ const path = join(dir, file)
25
+ if (await pathExists(path)) {
26
+ return path
27
+ }
28
+ }
29
+ return join(dir, fallbackFileName)
30
+ }
31
+
32
+ export const updateMainDockerComposeConfig = async (
33
+ dir: string,
34
+ updater: JsonUpdateCallback<DockerComposeConfig>,
35
+ ): Promise<void> => {
36
+ const path = process.env.COMPOSE_FILE || (await resolvePath(dir, MAIN_CONFIGS, MAIN_CONFIGS[0]))
37
+ return updateYaml(path, updater, { createMissing: true })
38
+ }
@@ -40,7 +40,7 @@ export class SystemClient {
40
40
  return new SystemClient(graphqlClient)
41
41
  }
42
42
 
43
- public async migrate(migrations: Migration[], force = false): Promise<MigrateResponse> {
43
+ public async migrate(migrations: Migration[], force = false): Promise<void> {
44
44
  const query = `
45
45
  mutation($migrations: [Migration!]!) {
46
46
  migrate: ${force ? 'forceMigrate' : 'migrate'}(migrations: $migrations) {
@@ -53,13 +53,16 @@ mutation($migrations: [Migration!]!) {
53
53
  }
54
54
  }
55
55
  `
56
- return (
56
+ const result = (
57
57
  await this.apiClient.request<{
58
58
  migrate: { ok: boolean; errors: { code: MigrateErrorCode; migration: string; message: string }[] }
59
59
  }>(query, {
60
60
  migrations,
61
61
  })
62
62
  ).migrate
63
+ if (!result.ok) {
64
+ throw result.errors
65
+ }
63
66
  }
64
67
 
65
68
  public async migrationDelete(version: string): Promise<void> {
@@ -0,0 +1,22 @@
1
+ import { pathExists } from 'fs-extra'
2
+ import { formatWorkspaceConfigPath, Workspace } from '@contember/cli-common'
3
+ import { updateYaml } from './yaml'
4
+
5
+ export const updateWorkspaceApiVersion = async (workspace: Workspace, newVersion: string): Promise<string | null> => {
6
+ const possiblePaths = formatWorkspaceConfigPath(workspace.directory)
7
+ for (const configPath of possiblePaths) {
8
+ if (await pathExists(configPath)) {
9
+ await updateYaml(configPath, data => {
10
+ return {
11
+ ...data,
12
+ api: {
13
+ ...(typeof data.api === 'object' ? data.api : {}),
14
+ version: newVersion,
15
+ },
16
+ }
17
+ })
18
+ return configPath.slice(workspace.directory.length)
19
+ }
20
+ }
21
+ return null
22
+ }
@@ -0,0 +1,37 @@
1
+ import { JSONObject, JSONPrimitive } from '@contember/cli-common/dist/src/utils/json'
2
+ import { pathExists } from 'fs-extra'
3
+ import YAWN from 'yawn-yaml/cjs'
4
+ import { Merger } from '@contember/config-loader'
5
+ import jsyaml from 'js-yaml'
6
+ import { readFile, writeFile } from 'fs/promises'
7
+
8
+ export type JsonUpdateCallback<Value = JSONObject> = (
9
+ data: Partial<Value>,
10
+ utils: { merge: (a: JSONObject, b: JSONObject) => JSONObject },
11
+ ) => Value
12
+
13
+ export const updateYaml = async <Value = JSONObject>(
14
+ path: string,
15
+ updater: JsonUpdateCallback<Value>,
16
+ options: { createMissing?: boolean } = {},
17
+ ) => {
18
+ let config = ''
19
+ if (await pathExists(path)) {
20
+ config = await readFile(path, { encoding: 'utf8' })
21
+ } else if (options.createMissing !== true) {
22
+ throw new Error(`File ${path} does not exist.`)
23
+ }
24
+
25
+ let newConfig = ''
26
+ const mergeUtils = { merge: (a: JSONObject, b: JSONObject) => Merger.merge<JSONPrimitive>(a, b) }
27
+ if (config) {
28
+ const yawn = new YAWN(config)
29
+ yawn.json = updater(yawn.json, mergeUtils)
30
+ newConfig = yawn.yaml
31
+ } else {
32
+ newConfig = jsyaml.dump(updater({}, mergeUtils))
33
+ }
34
+
35
+ await writeFile(path, newConfig, { encoding: 'utf8' })
36
+ }
37
+
@@ -0,0 +1,7 @@
1
+ declare module 'yawn-yaml/cjs' {
2
+ export default class YAWN {
3
+ json: any
4
+ readonly yaml: string
5
+ constructor(yaml: string)
6
+ }
7
+ }