@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.
- package/Dockerfile +2 -0
- package/dist/src/commands/deploy/DeployCommand.js +7 -7
- package/dist/src/commands/deploy/DeployCommand.js.map +1 -1
- package/dist/src/commands/migrations/MigrationAmendCommand.js +10 -10
- package/dist/src/commands/migrations/MigrationAmendCommand.js.map +1 -1
- package/dist/src/commands/migrations/MigrationCreateCommand.js +2 -2
- package/dist/src/commands/migrations/MigrationCreateCommand.js.map +1 -1
- package/dist/src/commands/migrations/MigrationDescribeCommand.js +2 -2
- package/dist/src/commands/migrations/MigrationDescribeCommand.js.map +1 -1
- package/dist/src/commands/migrations/MigrationDiffCommand.js +9 -9
- package/dist/src/commands/migrations/MigrationDiffCommand.js.map +1 -1
- package/dist/src/commands/migrations/MigrationExecuteCommand.d.ts.map +1 -1
- package/dist/src/commands/migrations/MigrationExecuteCommand.js +64 -49
- package/dist/src/commands/migrations/MigrationExecuteCommand.js.map +1 -1
- package/dist/src/commands/migrations/MigrationExecuteHelper.d.ts +1 -1
- package/dist/src/commands/migrations/MigrationExecuteHelper.d.ts.map +1 -1
- package/dist/src/commands/migrations/MigrationExecuteHelper.js +6 -10
- package/dist/src/commands/migrations/MigrationExecuteHelper.js.map +1 -1
- package/dist/src/commands/migrations/MigrationRebaseCommand.js +4 -4
- package/dist/src/commands/migrations/MigrationRebaseCommand.js.map +1 -1
- package/dist/src/commands/migrations/MigrationStatusCommand.js +6 -6
- package/dist/src/commands/migrations/MigrationStatusCommand.js.map +1 -1
- package/dist/src/commands/migrations/MigrationValidationHelper.js +1 -1
- package/dist/src/commands/migrations/MigrationValidationHelper.js.map +1 -1
- package/dist/src/commands/migrations/SystemApiClientResolver.js +2 -2
- package/dist/src/commands/migrations/SystemApiClientResolver.js.map +1 -1
- package/dist/src/commands/misc/VersionCommand.js +1 -1
- package/dist/src/commands/misc/VersionCommand.js.map +1 -1
- package/dist/src/commands/project/ProjectCreateCommand.d.ts.map +1 -1
- package/dist/src/commands/project/ProjectCreateCommand.js +2 -3
- package/dist/src/commands/project/ProjectCreateCommand.js.map +1 -1
- package/dist/src/commands/project/ProjectPrintSchemaCommand.js +4 -4
- package/dist/src/commands/project/ProjectPrintSchemaCommand.js.map +1 -1
- package/dist/src/commands/project/ProjectValidateCommand.js +5 -5
- package/dist/src/commands/project/ProjectValidateCommand.js.map +1 -1
- package/dist/src/commands/tenant/CreateApiKeyCommand.js +3 -3
- package/dist/src/commands/tenant/CreateApiKeyCommand.js.map +1 -1
- package/dist/src/commands/tenant/InviteCommand.js +3 -3
- package/dist/src/commands/tenant/InviteCommand.js.map +1 -1
- package/dist/src/commands/tenant/ResetPasswordCommand.js +3 -3
- package/dist/src/commands/tenant/ResetPasswordCommand.js.map +1 -1
- package/dist/src/commands/tenant/SignInCommand.js +3 -3
- package/dist/src/commands/tenant/SignInCommand.js.map +1 -1
- package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.d.ts.map +1 -1
- package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.js +36 -29
- package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.js.map +1 -1
- package/dist/src/run.js +3 -3
- package/dist/src/run.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/utils/admin.d.ts.map +1 -1
- package/dist/src/utils/admin.js +5 -5
- package/dist/src/utils/admin.js.map +1 -1
- package/dist/src/utils/commands.js +1 -1
- package/dist/src/utils/commands.js.map +1 -1
- package/dist/src/utils/dockerCompose.d.ts +15 -0
- package/dist/src/utils/dockerCompose.d.ts.map +1 -0
- package/dist/src/utils/dockerCompose.js +22 -0
- package/dist/src/utils/dockerCompose.js.map +1 -0
- package/dist/src/utils/instance/interactiveUtils.js +2 -2
- package/dist/src/utils/instance/interactiveUtils.js.map +1 -1
- package/dist/src/utils/migrations.js +6 -6
- package/dist/src/utils/migrations.js.map +1 -1
- package/dist/src/utils/npm.js +6 -6
- package/dist/src/utils/npm.js.map +1 -1
- package/dist/src/utils/schema.js +1 -1
- package/dist/src/utils/schema.js.map +1 -1
- package/dist/src/utils/system/index.d.ts +1 -1
- package/dist/src/utils/system/index.d.ts.map +1 -1
- package/dist/src/utils/system/index.js +5 -2
- package/dist/src/utils/system/index.js.map +1 -1
- package/dist/src/utils/tenant.js +21 -21
- package/dist/src/utils/tenant.js.map +1 -1
- package/dist/src/utils/workspace.d.ts +3 -0
- package/dist/src/utils/workspace.d.ts.map +1 -0
- package/dist/src/utils/workspace.js +26 -0
- package/dist/src/utils/workspace.js.map +1 -0
- package/dist/src/utils/yaml.d.ts +8 -0
- package/dist/src/utils/yaml.d.ts.map +1 -0
- package/dist/src/utils/yaml.js +33 -0
- package/dist/src/utils/yaml.js.map +1 -0
- package/package.json +16 -12
- package/src/commands/migrations/MigrationExecuteCommand.ts +67 -50
- package/src/commands/migrations/MigrationExecuteHelper.ts +4 -8
- package/src/commands/project/ProjectCreateCommand.ts +1 -2
- package/src/commands/project/ProjectValidateCommand.ts +1 -1
- package/src/commands/workspace/WorkspaceUpdateApiCommand.ts +38 -36
- package/src/run.ts +1 -1
- package/src/utils/admin.ts +2 -1
- package/src/utils/dockerCompose.ts +38 -0
- package/src/utils/system/index.ts +5 -2
- package/src/utils/workspace.ts +22 -0
- package/src/utils/yaml.ts +37 -0
- 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.
|
|
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.
|
|
16
|
-
"@contember/config-loader": "^0.
|
|
17
|
-
"@contember/database-migrations": "^0.
|
|
18
|
-
"@contember/dic": "^0.
|
|
19
|
-
"@contember/engine-content-api": "^0.
|
|
20
|
-
"@contember/schema": "^0.
|
|
21
|
-
"@contember/schema-definition": "^0.
|
|
22
|
-
"@contember/schema-migrations": "^0.
|
|
23
|
-
"@contember/schema-utils": "^0.
|
|
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
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
throw `
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
}
|
|
77
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
85
|
+
await client.migrate(
|
|
86
86
|
migrations.map(it => it.localMigration),
|
|
87
87
|
force,
|
|
88
88
|
)
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
25
|
-
workspace.directory,
|
|
26
|
-
)
|
|
23
|
+
await updateNpmPackages(upgradablePackages.map(it => ({ name: it, version })), workspace.directory)
|
|
24
|
+
|
|
27
25
|
const prevVersion = workspace.apiVersion
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
const updatedYaml = await updateWorkspaceApiVersion(workspace, version)
|
|
27
|
+
|
|
28
|
+
if (updatedYaml) {
|
|
29
|
+
console.log(`${updatedYaml} updated`)
|
|
30
30
|
} else {
|
|
31
|
-
console.log('contember.
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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)
|
package/src/utils/admin.ts
CHANGED
|
@@ -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
|
|
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<
|
|
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
|
-
|
|
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
|
+
|