@contember/cli 1.3.0-alpha.7 → 1.3.0-beta.1

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 (110) hide show
  1. package/Dockerfile +1 -1
  2. package/build.sh +1 -0
  3. package/contember-docker.sh +0 -0
  4. package/dist/src/commands/deploy/DeployCommand.d.ts +2 -2
  5. package/dist/src/commands/deploy/DeployCommand.d.ts.map +1 -1
  6. package/dist/src/commands/migrations/MigrationAmendCommand.d.ts +2 -2
  7. package/dist/src/commands/migrations/MigrationAmendCommand.d.ts.map +1 -1
  8. package/dist/src/commands/migrations/MigrationAmendCommand.js +1 -1
  9. package/dist/src/commands/migrations/MigrationAmendCommand.js.map +1 -1
  10. package/dist/src/commands/migrations/MigrationCreateHelper.d.ts +2 -2
  11. package/dist/src/commands/migrations/MigrationCreateHelper.d.ts.map +1 -1
  12. package/dist/src/commands/migrations/MigrationDescribeCommand.d.ts +3 -4
  13. package/dist/src/commands/migrations/MigrationDescribeCommand.d.ts.map +1 -1
  14. package/dist/src/commands/migrations/MigrationDescribeCommand.js +1 -31
  15. package/dist/src/commands/migrations/MigrationDescribeCommand.js.map +1 -1
  16. package/dist/src/commands/migrations/MigrationDiffCommand.d.ts +2 -2
  17. package/dist/src/commands/migrations/MigrationDiffCommand.d.ts.map +1 -1
  18. package/dist/src/commands/migrations/MigrationExecuteCommand.d.ts +3 -3
  19. package/dist/src/commands/migrations/MigrationExecuteCommand.d.ts.map +1 -1
  20. package/dist/src/commands/migrations/MigrationExecuteCommand.js +7 -26
  21. package/dist/src/commands/migrations/MigrationExecuteCommand.js.map +1 -1
  22. package/dist/src/commands/migrations/MigrationExecuteHelper.d.ts +1 -1
  23. package/dist/src/commands/migrations/MigrationExecuteHelper.d.ts.map +1 -1
  24. package/dist/src/commands/migrations/MigrationRebaseCommand.d.ts +2 -2
  25. package/dist/src/commands/migrations/MigrationRebaseCommand.d.ts.map +1 -1
  26. package/dist/src/commands/migrations/MigrationStatusCommand.d.ts +2 -2
  27. package/dist/src/commands/migrations/MigrationStatusCommand.d.ts.map +1 -1
  28. package/dist/src/commands/migrations/MigrationValidationHelper.d.ts.map +1 -1
  29. package/dist/src/commands/migrations/MigrationValidationHelper.js +8 -2
  30. package/dist/src/commands/migrations/MigrationValidationHelper.js.map +1 -1
  31. package/dist/src/commands/project/ProjectCreateCommand.d.ts +2 -2
  32. package/dist/src/commands/project/ProjectCreateCommand.d.ts.map +1 -1
  33. package/dist/src/commands/project/ProjectGenerateDocumentation.d.ts +2 -2
  34. package/dist/src/commands/project/ProjectGenerateDocumentation.d.ts.map +1 -1
  35. package/dist/src/commands/project/ProjectPrintSchemaCommand.d.ts +3 -2
  36. package/dist/src/commands/project/ProjectPrintSchemaCommand.d.ts.map +1 -1
  37. package/dist/src/commands/project/ProjectPrintSchemaCommand.js +8 -5
  38. package/dist/src/commands/project/ProjectPrintSchemaCommand.js.map +1 -1
  39. package/dist/src/commands/project/ProjectValidateCommand.d.ts +2 -2
  40. package/dist/src/commands/project/ProjectValidateCommand.d.ts.map +1 -1
  41. package/dist/src/commands/tenant/CreateApiKeyCommand.d.ts +2 -2
  42. package/dist/src/commands/tenant/CreateApiKeyCommand.d.ts.map +1 -1
  43. package/dist/src/commands/tenant/InviteCommand.d.ts +2 -2
  44. package/dist/src/commands/tenant/InviteCommand.d.ts.map +1 -1
  45. package/dist/src/commands/tenant/ResetPasswordCommand.d.ts +2 -2
  46. package/dist/src/commands/tenant/ResetPasswordCommand.d.ts.map +1 -1
  47. package/dist/src/commands/tenant/SignInCommand.d.ts +2 -2
  48. package/dist/src/commands/tenant/SignInCommand.d.ts.map +1 -1
  49. package/dist/src/commands/transfer/ExportCommand.d.ts +2 -2
  50. package/dist/src/commands/transfer/ExportCommand.d.ts.map +1 -1
  51. package/dist/src/commands/transfer/ImportCommand.d.ts +2 -2
  52. package/dist/src/commands/transfer/ImportCommand.d.ts.map +1 -1
  53. package/dist/src/commands/transfer/TransferCommand.d.ts +2 -2
  54. package/dist/src/commands/transfer/TransferCommand.d.ts.map +1 -1
  55. package/dist/src/commands/transfer/utils.d.ts +1 -1
  56. package/dist/src/commands/transfer/utils.d.ts.map +1 -1
  57. package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.d.ts +2 -2
  58. package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.d.ts.map +1 -1
  59. package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.js +9 -7
  60. package/dist/src/commands/workspace/WorkspaceUpdateApiCommand.js.map +1 -1
  61. package/dist/src/run.js +4 -0
  62. package/dist/src/run.js.map +1 -1
  63. package/dist/src/tsconfig.tsbuildinfo +1 -1
  64. package/dist/src/utils/admin.d.ts +1 -1
  65. package/dist/src/utils/admin.d.ts.map +1 -1
  66. package/dist/src/utils/checkVersions.d.ts +3 -0
  67. package/dist/src/utils/checkVersions.d.ts.map +1 -0
  68. package/dist/src/utils/checkVersions.js +83 -0
  69. package/dist/src/utils/checkVersions.js.map +1 -0
  70. package/dist/src/utils/dockerCompose.d.ts +3 -0
  71. package/dist/src/utils/dockerCompose.d.ts.map +1 -1
  72. package/dist/src/utils/dockerCompose.js +45 -4
  73. package/dist/src/utils/dockerCompose.js.map +1 -1
  74. package/dist/src/utils/instance/environment.d.ts +1 -1
  75. package/dist/src/utils/instance/environment.d.ts.map +1 -1
  76. package/dist/src/utils/migrations.d.ts +3 -3
  77. package/dist/src/utils/migrations.d.ts.map +1 -1
  78. package/dist/src/utils/migrations.js +13 -5
  79. package/dist/src/utils/migrations.js.map +1 -1
  80. package/dist/src/utils/schema/collectReferences.d.ts +2 -2
  81. package/dist/src/utils/schema/collectReferences.d.ts.map +1 -1
  82. package/dist/src/utils/system/index.d.ts +2 -2
  83. package/dist/src/utils/system/index.d.ts.map +1 -1
  84. package/dist/src/utils/system/index.js +1 -1
  85. package/dist/src/utils/system/index.js.map +1 -1
  86. package/dist/src/utils/tenant.d.ts +2 -2
  87. package/dist/src/utils/tenant.d.ts.map +1 -1
  88. package/dist/src/utils/yaml.d.ts +1 -1
  89. package/dist/src/utils/yaml.d.ts.map +1 -1
  90. package/package.json +13 -11
  91. package/src/commands/migrations/MigrationAmendCommand.ts +1 -1
  92. package/src/commands/migrations/MigrationDescribeCommand.ts +3 -37
  93. package/src/commands/migrations/MigrationExecuteCommand.ts +11 -29
  94. package/src/commands/migrations/MigrationValidationHelper.ts +9 -3
  95. package/src/commands/project/ProjectPrintSchemaCommand.ts +10 -6
  96. package/src/commands/workspace/WorkspaceUpdateApiCommand.ts +10 -8
  97. package/src/run.ts +7 -1
  98. package/src/utils/checkVersions.ts +58 -0
  99. package/src/utils/dockerCompose.ts +20 -3
  100. package/src/utils/migrations.ts +12 -4
  101. package/dist/src/utils/commands.d.ts +0 -21
  102. package/dist/src/utils/commands.d.ts.map +0 -1
  103. package/dist/src/utils/commands.js +0 -57
  104. package/dist/src/utils/commands.js.map +0 -1
  105. package/dist/src/utils/npm.d.ts +0 -6
  106. package/dist/src/utils/npm.d.ts.map +0 -1
  107. package/dist/src/utils/npm.js +0 -62
  108. package/dist/src/utils/npm.js.map +0 -1
  109. package/src/utils/commands.ts +0 -65
  110. package/src/utils/npm.ts +0 -63
@@ -1,4 +1,4 @@
1
- import { Command, CommandConfiguration, Input, validateProjectName, Workspace } from '@contember/cli-common'
1
+ import { Command, CommandConfiguration, Input, Workspace } from '@contember/cli-common'
2
2
  import { MigrationsContainerFactory } from '../../MigrationsContainer'
3
3
  import {
4
4
  configureExecuteMigrationCommand,
@@ -6,18 +6,18 @@ import {
6
6
  executeMigrations,
7
7
  resolveMigrationStatus,
8
8
  } from './MigrationExecuteHelper'
9
- import { createMigrationStatusTable, findMigration, MigrationState } from '../../utils/migrations'
10
- import { assertNever } from '../../utils/assertNever'
9
+ import { createMigrationStatusTable } from '../../utils/migrations'
11
10
  import { interactiveResolveInstanceEnvironmentFromInput } from '../../utils/instance'
12
11
  import { interactiveResolveApiToken, TenantClient } from '../../utils/tenant'
13
12
  import { SystemClient } from '../../utils/system'
13
+ import { MigrationVersionHelper } from '@contember/schema-migrations'
14
14
 
15
15
  type Args = {
16
16
  project?: string
17
- migration?: string
18
17
  }
19
18
 
20
19
  type Options = ExecuteMigrationOptions & {
20
+ until?: string
21
21
  force: boolean
22
22
  }
23
23
 
@@ -33,8 +33,8 @@ export class MigrationExecuteCommand extends Command<Args, Options> {
33
33
  if (!this.workspace.isSingleProjectMode()) {
34
34
  configuration.argument('project')
35
35
  }
36
- configuration.argument('migration').optional()
37
36
  configuration.option('force').description('Ignore migrations order and missing migrations (dev only)')
37
+ configuration.option('until').valueRequired().description('Execute all migrations leading up to, and inclusive of, a specified migration')
38
38
  configureExecuteMigrationCommand(configuration)
39
39
  }
40
40
 
@@ -51,12 +51,10 @@ export class MigrationExecuteCommand extends Command<Args, Options> {
51
51
  const projects = allProjects
52
52
  ? await workspace.projects.listProjects()
53
53
  : [await workspace.projects.getProject(projectName, { fuzzy: true })]
54
-
55
54
  let code = 0
56
55
  for (const project of projects) {
57
56
  const migrationsDir = project.migrationsDir
58
57
  const container = new MigrationsContainerFactory(migrationsDir).create()
59
- const migrationArg = input.getArgument('migration')
60
58
 
61
59
  const instance = await interactiveResolveInstanceEnvironmentFromInput(workspace, input?.getOption('instance'))
62
60
  const apiToken = await interactiveResolveApiToken({ workspace, instance })
@@ -73,29 +71,13 @@ export class MigrationExecuteCommand extends Command<Args, Options> {
73
71
  throw `Cannot execute migrations`
74
72
  }
75
73
  }
74
+ const until = input.getOption('until')
75
+ const untilNormalized = until ? MigrationVersionHelper.extractVersion(until) : null
76
+
77
+ const migrations = untilNormalized
78
+ ? status.migrationsToExecute.filter(it => it.version <= MigrationVersionHelper.extractVersion(untilNormalized))
79
+ : status.migrationsToExecute
76
80
 
77
- const migrations = (() => {
78
- if (migrationArg) {
79
- const migration = findMigration(status.allMigrations, migrationArg)
80
- if (!migration) {
81
- throw `Undefined migration ${migrationArg}`
82
- }
83
- switch (migration.state) {
84
- case MigrationState.EXECUTED_OK:
85
- throw `Migration ${migrationArg} is already executed`
86
- case MigrationState.TO_EXECUTE_ERROR:
87
- case MigrationState.EXECUTED_ERROR:
88
- case MigrationState.EXECUTED_MISSING:
89
- throw `Cannot execute migration ${migrationArg}: ${migration.errorMessage} (${migration.state})`
90
- case MigrationState.TO_EXECUTE_OK:
91
- return [migration]
92
- default:
93
- assertNever(migration)
94
- }
95
- } else {
96
- return status.migrationsToExecute
97
- }
98
- })()
99
81
  if (migrations.length === 0) {
100
82
  console.log('No migrations to execute')
101
83
  continue
@@ -1,6 +1,7 @@
1
1
  import { Schema } from '@contember/schema'
2
- import { Migration, MigrationDescriber, SchemaMigrator, SchemaUpdateError } from '@contember/schema-migrations'
2
+ import { Migration, MigrationDescriber, MigrationVersionHelper, SchemaMigrator, SchemaUpdateError } from '@contember/schema-migrations'
3
3
  import { validateSchemaAndPrintErrors } from '../../utils/schema'
4
+ import { SchemaValidatorSkippedErrors } from '@contember/schema-utils'
4
5
 
5
6
  export const validateMigrations = async (
6
7
  initialSchema: Schema,
@@ -10,10 +11,11 @@ export const validateMigrations = async (
10
11
  ): Promise<boolean> => {
11
12
  let migratedSchema = initialSchema
12
13
  let projectValid = true
14
+ let skippedErrors: SchemaValidatorSkippedErrors[] = []
13
15
  for (const migration of await migrations) {
14
16
  try {
15
17
  // just a check that it does not fail
16
- await describer.describeModifications(migratedSchema, migration, 'system') // schema name not important here
18
+ describer.describeModifications(migratedSchema, migration)
17
19
 
18
20
  migratedSchema = migrator.applyModifications(migratedSchema, migration.modifications, migration.formatVersion)
19
21
  } catch (e) {
@@ -23,7 +25,11 @@ export const validateMigrations = async (
23
25
  throw e
24
26
  }
25
27
  const errorMessage = `Migration ${migration.name} produces invalid schema:`
26
- projectValid = validateSchemaAndPrintErrors(migratedSchema, errorMessage, migration.skippedErrors)
28
+ skippedErrors = [
29
+ ...skippedErrors.filter(it => it.skipUntil && MigrationVersionHelper.extractVersion(it.skipUntil) >= migration.version),
30
+ ...migration.skippedErrors ?? [],
31
+ ]
32
+ projectValid = validateSchemaAndPrintErrors(migratedSchema, errorMessage, skippedErrors)
27
33
  && projectValid
28
34
  }
29
35
  return projectValid
@@ -12,6 +12,7 @@ import {
12
12
  import { DocumentNode, printSchema } from 'graphql'
13
13
  import { mergeSchemas } from '@graphql-tools/schema'
14
14
  import { loadSchema } from '../../utils/project/loadSchema'
15
+ import { normalizeSchema } from '@contember/schema-utils'
15
16
 
16
17
  type Args = {
17
18
  project?: string
@@ -19,6 +20,7 @@ type Args = {
19
20
 
20
21
  type Options = {
21
22
  role?: string[]
23
+ normalize?: boolean
22
24
  format?: 'graphql' | 'introspection' | 'schema'
23
25
  }
24
26
 
@@ -36,6 +38,7 @@ export class ProjectPrintSchemaCommand extends Command<Args, Options> {
36
38
  }
37
39
  configuration.option('format').valueRequired().description('graphql|introspection|schema')
38
40
  configuration.option('role').valueArray()
41
+ configuration.option('normalize').valueNone()
39
42
  }
40
43
 
41
44
  protected async execute(input: Input<Args, Options>): Promise<number> {
@@ -50,23 +53,24 @@ export class ProjectPrintSchemaCommand extends Command<Args, Options> {
50
53
  }
51
54
  const permissionFactory = new PermissionFactory()
52
55
  const inputRoles = input.getOption('role')
53
- const permissions = permissionFactory.create(schema, inputRoles || ['admin'])
56
+ const schemaNormalized = input.getOption('normalize') ? normalizeSchema(schema) : schema
57
+ const permissions = permissionFactory.create(schemaNormalized, inputRoles || ['admin'])
54
58
  const schemaBuilderFactory = new GraphQlSchemaBuilderFactory()
55
- const authorizator = new Authorizator(permissions, schema.acl.customPrimary ?? false)
59
+ const authorizator = new Authorizator(permissions, schemaNormalized.acl.customPrimary ?? false)
56
60
  const introspection = new IntrospectionSchemaFactory(
57
- schema.model,
58
- new EntityRulesResolver(schema.validation, schema.model),
61
+ schemaNormalized.model,
62
+ new EntityRulesResolver(schemaNormalized.validation, schemaNormalized.model),
59
63
  authorizator,
60
64
  )
61
65
  if (format === 'schema') {
62
66
  if (inputRoles) {
63
67
  throw `--roles option is not supported for "schema" format`
64
68
  }
65
- console.log(JSON.stringify(schema, null, '\t'))
69
+ console.log(JSON.stringify(schemaNormalized, null, '\t'))
66
70
  } else if (format === 'introspection') {
67
71
  console.log(JSON.stringify(introspection.create(), null, '\t'))
68
72
  } else if (format === 'graphql') {
69
- const contentSchema = schemaBuilderFactory.create(schema.model, authorizator).build()
73
+ const contentSchema = schemaBuilderFactory.create(schemaNormalized.model, authorizator).build()
70
74
  const introspectionSchemaFactory = new IntrospectionSchemaDefinitionFactory(introspection)
71
75
  const introspectionSchema = introspectionSchemaFactory.create()
72
76
  const gqlSchema = mergeSchemas({
@@ -1,7 +1,6 @@
1
1
  import { Command, CommandConfiguration, Input, Workspace } from '@contember/cli-common'
2
- import { updateNpmPackages } from '../../utils/npm'
3
2
  import { updateWorkspaceApiVersion } from '../../utils/workspace'
4
- import { updateMainDockerComposeConfig } from '../../utils/dockerCompose'
3
+ import { contemberDockerImages, updateMainDockerComposeConfig } from '../../utils/dockerCompose'
5
4
 
6
5
  type Args = {
7
6
  version: string
@@ -24,11 +23,14 @@ export class WorkspaceUpdateApiCommand extends Command<Args, Options> {
24
23
  protected async execute(input: Input<Args, Options>): Promise<void> {
25
24
  const version = input.getArgument('version')
26
25
  const workspace = this.workspace
27
- const upgradablePackages = ['@contember/schema', '@contember/schema-definition', '@contember/cli']
26
+ const packageWorkspace = await workspace.resolvePackageWorkspace()
28
27
 
29
- await updateNpmPackages(upgradablePackages.map(it => ({ name: it, version })), workspace.directory)
28
+ await packageWorkspace.updateEverywhere({
29
+ '@contember/schema': version,
30
+ '@contember/schema-definition': version,
31
+ '@contember/cli': version,
32
+ })
30
33
 
31
- const prevVersion = workspace.apiVersion
32
34
  const updatedYaml = await updateWorkspaceApiVersion(workspace, version)
33
35
 
34
36
  if (updatedYaml) {
@@ -39,8 +41,8 @@ export class WorkspaceUpdateApiCommand extends Command<Args, Options> {
39
41
 
40
42
  console.log('Updating docker-compose')
41
43
  const getNewImage = (currentImage: string): string | null => {
42
- for (const candidate of ['contember/engine', 'contember/contember', 'contember/cli']) {
43
- if (prevVersion && currentImage === `${candidate}:${prevVersion}` || !prevVersion && currentImage.startsWith(`${candidate}:`)) {
44
+ for (const candidate of contemberDockerImages) {
45
+ if (currentImage.startsWith(`${candidate}:`)) {
44
46
  return `${candidate}:${version}`
45
47
  }
46
48
  }
@@ -51,7 +53,7 @@ export class WorkspaceUpdateApiCommand extends Command<Args, Options> {
51
53
  services: Object.fromEntries(Object.entries(data?.services ?? {}).map(([name, service]: [string, any]) => {
52
54
  const newImage = getNewImage(service.image)
53
55
  if (newImage) {
54
- console.log(`docker-compose service ${service} updated`)
56
+ console.log(`docker-compose service ${name} updated`)
55
57
  return [
56
58
  name,
57
59
  {
package/src/run.ts CHANGED
@@ -21,10 +21,16 @@ import {
21
21
  } from './commands'
22
22
  import { ExportCommand } from './commands/transfer/ExportCommand'
23
23
  import { ImportCommand } from './commands/transfer/ImportCommand'
24
- import { TransferCommand } from './commands/transfer/TransferCommand';
24
+ import { TransferCommand } from './commands/transfer/TransferCommand'
25
+ import { checkVersions } from './utils/checkVersions';
25
26
 
26
27
  (async () => {
27
28
  const workspace = await Workspace.get(process.cwd())
29
+
30
+ if (!process.env.CONTEMBER_SKIP_VERSION_CHECK) {
31
+ await checkVersions(workspace)
32
+ }
33
+
28
34
  const commands: CommandFactoryList = {
29
35
  ['deploy']: () => new DeployCommand(workspace),
30
36
  ['version']: () => new VersionCommand(),
@@ -0,0 +1,58 @@
1
+ import { getPackageVersion, Workspace } from '@contember/cli-common'
2
+ import { join, relative } from 'node:path'
3
+ import * as semver from 'semver'
4
+ import { contemberDockerImages, tryReadMainDockerComposeConfig } from './dockerCompose'
5
+
6
+ export const checkVersions = async (workspace: Workspace) => {
7
+ const cliVersion = getPackageVersion()
8
+ const packageWorkspace = await workspace.resolvePackageWorkspace()
9
+ const errors: string[] = []
10
+
11
+ for (const packageName of ['@contember/schema', '@contember/schema-definition']) {
12
+ const installedPackages = await packageWorkspace.findInstalledDependencies(packageName)
13
+ for (const pckg of installedPackages) {
14
+ const jsonPath = relative(workspace.directory, join(pckg.defined.pckg.dir, 'package.json'))
15
+
16
+ if (!pckg.installed) {
17
+ errors.push(`Package ${packageName} defined in ${jsonPath} is not installed.`)
18
+ continue
19
+ }
20
+ if (!semver.satisfies(pckg.installed.version, pckg.defined.version)) {
21
+ errors.push(`Package ${packageName}@${pckg.installed.version} does not match constraint ${pckg.defined.version} defined in ${jsonPath}.`)
22
+ continue
23
+ }
24
+ if (cliVersion !== pckg.installed.version) {
25
+ errors.push(`Package ${packageName}@${pckg.installed.version} does not match version of CLI ${cliVersion}.`)
26
+ }
27
+ }
28
+ }
29
+ const dockerCompose = await tryReadMainDockerComposeConfig(workspace.directory)
30
+
31
+ if (!dockerCompose) {
32
+ errors.push('docker-compose.yaml not found.')
33
+ } else {
34
+ for (const [name, def] of Object.entries(dockerCompose.services ?? {})) {
35
+ if (!def.image) {
36
+ continue
37
+ }
38
+ const [image, version] = def.image.split(':')
39
+ if (!version || !contemberDockerImages.includes(image)) {
40
+ continue
41
+ }
42
+ const versionParts = version.split(/[.-]/)
43
+ if (versionParts[versionParts.length - 1] === 'debian') {
44
+ versionParts.pop()
45
+ }
46
+ const cliVersionParts = cliVersion.split(/[.-]/).slice(0, versionParts.length)
47
+ if (versionParts.join('.') !== cliVersionParts.join('.')) {
48
+ errors.push(`Docker service ${name} with image ${image}:${version} does not match version of CLI ${cliVersion}.`)
49
+ }
50
+ }
51
+ }
52
+
53
+ if (errors.length) {
54
+ throw `${errors.map(it => `${it}`).join('\n')}
55
+
56
+ Please make sure all dependencies are up to date.\nIf you are really certain about the compatibility, you can disable this version check by running the CLI with the CONTEMBER_SKIP_VERSION_CHECK=1 environment variable`
57
+ }
58
+ }
@@ -1,6 +1,8 @@
1
1
  import { join } from 'node:path'
2
2
  import { pathExists } from '@contember/cli-common'
3
3
  import { JsonUpdateCallback, updateYaml } from './yaml'
4
+ import jsyaml from 'js-yaml'
5
+ import * as fs from 'node:fs/promises'
4
6
 
5
7
  const MAIN_CONFIGS = ['docker-compose.yaml', 'docker-compose.yml']
6
8
 
@@ -19,20 +21,35 @@ export interface DockerComposeConfig {
19
21
  services?: Record<string, DockerComposeServiceConfig>
20
22
  }
21
23
 
22
- const resolvePath = async (dir: string, possibleFileNames: string[], fallbackFileName: string): Promise<string> => {
24
+ const resolvePath = async (dir: string, possibleFileNames: string[]): Promise<string | null> => {
23
25
  for (const file of possibleFileNames) {
24
26
  const path = join(dir, file)
25
27
  if (await pathExists(path)) {
26
28
  return path
27
29
  }
28
30
  }
29
- return join(dir, fallbackFileName)
31
+ return null
32
+ }
33
+
34
+ export const resolveMainDockerComposeConfig = async (dir: string): Promise<string | null> => {
35
+ return resolvePath(dir, MAIN_CONFIGS)
36
+ }
37
+
38
+ export const tryReadMainDockerComposeConfig = async (dir: string): Promise<DockerComposeConfig | null> => {
39
+ const path = await resolveMainDockerComposeConfig(dir)
40
+ if (!path) {
41
+ return null
42
+ }
43
+ return jsyaml.load(await fs.readFile(path, 'utf8')) as DockerComposeConfig
30
44
  }
31
45
 
32
46
  export const updateMainDockerComposeConfig = async (
33
47
  dir: string,
34
48
  updater: JsonUpdateCallback<DockerComposeConfig>,
35
49
  ): Promise<void> => {
36
- const path = process.env.COMPOSE_FILE || (await resolvePath(dir, MAIN_CONFIGS, MAIN_CONFIGS[0]))
50
+ const path = process.env.COMPOSE_FILE || (await resolvePath(dir, MAIN_CONFIGS)) || join(dir, MAIN_CONFIGS[0])
37
51
  return updateYaml(path, updater, { createMissing: true })
38
52
  }
53
+
54
+
55
+ export const contemberDockerImages = ['contember/engine', 'contember/engine-ee', 'contember/cli']
@@ -10,6 +10,7 @@ import chalk from 'chalk'
10
10
  import { Schema } from '@contember/schema'
11
11
  import chalkTable from 'chalk-table'
12
12
  import { assertNever } from './assertNever'
13
+ import { dummySchemaDatabaseMetadata } from '@contember/schema-utils'
13
14
 
14
15
  export const getLatestMigration = async (migrationsResolver: MigrationsResolver): Promise<Migration | null> => {
15
16
  const migrations = await migrationsResolver.getMigrations()
@@ -28,16 +29,23 @@ export const findMigration = <M extends { version: string }>(migrations: M[], ve
28
29
  it => MigrationVersionHelper.extractVersion(it.version) === MigrationVersionHelper.extractVersion(version),
29
30
  ) || null
30
31
 
31
- export const printMigrationDescription = async function (
32
+ export const printMigrationDescription = function (
32
33
  migrationsDescriber: MigrationDescriber,
33
34
  schema: Schema,
34
35
  migration: Migration,
35
36
  options: { sqlOnly?: boolean; noSql?: boolean },
36
37
  ) {
37
- const description = await migrationsDescriber.describeModifications(schema, migration, 'system') // schema name cannot be determined
38
- description.forEach(({ modification, sql, description }) => {
38
+ const description = migrationsDescriber.describeModifications(schema, migration)
39
+ description.forEach(({ modification, getSql, description }) => {
40
+ const sql = getSql({
41
+ systemSchema: 'system',
42
+ databaseMetadata: dummySchemaDatabaseMetadata,
43
+ invalidateDatabaseMetadata: () => null,
44
+ })
39
45
  if (options.sqlOnly) {
40
- console.log(sql)
46
+ if (sql.trim()) {
47
+ console.log(sql)
48
+ }
41
49
  } else {
42
50
  const color = description.isDestructive ? chalk.red : chalk.blue
43
51
  console.group(color(`${description.message} [${modification.modification}]`))
@@ -1,21 +0,0 @@
1
- /// <reference types="node" />
2
- import { ChildProcessWithoutNullStreams } from 'node:child_process';
3
- import { Readable, Writable } from 'node:stream';
4
- export declare type RunningCommand = {
5
- child: ChildProcessWithoutNullStreams;
6
- output: Promise<string>;
7
- };
8
- export declare const runCommand: (command: string, args: (string | undefined)[], options: {
9
- cwd: string;
10
- stdin?: Readable;
11
- stdout?: Writable;
12
- stderr?: Writable;
13
- env?: NodeJS.ProcessEnv;
14
- detached?: boolean;
15
- }) => RunningCommand;
16
- export declare class ChildProcessError extends Error {
17
- readonly exitCode: number | null;
18
- readonly stderr: string;
19
- constructor(exitCode: number | null, stderr: string);
20
- }
21
- //# sourceMappingURL=commands.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../src/utils/commands.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,8BAA8B,EAAS,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGhD,oBAAY,cAAc,GAAG;IAAE,KAAK,EAAE,8BAA8B,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAA;AAC/F,eAAO,MAAM,UAAU,YACb,MAAM,QACT,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,WACnB;IACR,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,MAAM,CAAC,EAAE,QAAQ,CAAA;IACjB,MAAM,CAAC,EAAE,QAAQ,CAAA;IACjB,GAAG,CAAC,EAAE,OAAO,UAAU,CAAA;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;CAClB,KACC,cA0CF,CAAA;AAED,qBAAa,iBAAkB,SAAQ,KAAK;aACf,QAAQ,EAAE,MAAM,GAAG,IAAI;aAAkB,MAAM,EAAE,MAAM;gBAAvD,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAkB,MAAM,EAAE,MAAM;CAGnF"}
@@ -1,57 +0,0 @@
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.ChildProcessError = exports.runCommand = void 0;
7
- const node_child_process_1 = require("node:child_process");
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const runCommand = (command, args, options) => {
10
- const args2 = args.filter((it) => it !== undefined);
11
- if (!process.env.DISABLE_COMMAND_PRINTING) {
12
- console.error(chalk_1.default.gray(`$ ${command} ${args2.map(it => `'${it.replace(/'/g, `'\\''`)}'`).join(' ')}`));
13
- }
14
- const child = (0, node_child_process_1.spawn)(command, args2, {
15
- cwd: options.cwd,
16
- env: { ...process.env, ...(options.env || {}) },
17
- detached: options.detached,
18
- });
19
- if (options.stdin) {
20
- options.stdin.pipe(child.stdin);
21
- }
22
- let stdout = '';
23
- let stderr = '';
24
- child.stdout.on('data', (chunk) => {
25
- stdout += chunk.toString();
26
- });
27
- child.stderr.on('data', (chunk) => {
28
- stderr += chunk.toString();
29
- });
30
- if (options.stdout) {
31
- child.stdout.pipe(options.stdout);
32
- }
33
- if (options.stderr) {
34
- child.stderr.pipe(options.stderr);
35
- }
36
- const output = new Promise((resolve, reject) => {
37
- child.on('exit', (exitCode) => {
38
- if (exitCode === 0) {
39
- resolve(stdout);
40
- }
41
- else {
42
- reject(new ChildProcessError(exitCode, stderr));
43
- }
44
- });
45
- });
46
- return { output, child };
47
- };
48
- exports.runCommand = runCommand;
49
- class ChildProcessError extends Error {
50
- constructor(exitCode, stderr) {
51
- super(`Command has failed(${exitCode}): ${stderr} `);
52
- this.exitCode = exitCode;
53
- this.stderr = stderr;
54
- }
55
- }
56
- exports.ChildProcessError = ChildProcessError;
57
- //# sourceMappingURL=commands.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../src/utils/commands.ts"],"names":[],"mappings":";;;;;;AAAA,2DAA0E;AAE1E,kDAAyB;AAGlB,MAAM,UAAU,GAAG,CACzB,OAAe,EACf,IAA4B,EAC5B,OAOC,EACgB,EAAE;IACnB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC,CAAA;IACjE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE;QAC1C,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,IAAI,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;KACxG;IACD,MAAM,KAAK,GAAG,IAAA,0BAAK,EAAC,OAAO,EAAE,KAAK,EAAE;QACnC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE;QAC/C,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC1B,CAAC,CAAA;IACF,IAAI,OAAO,CAAC,KAAK,EAAE;QAClB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;KAC/B;IAED,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,IAAI,MAAM,GAAG,EAAE,CAAA;IAEf,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAQ,EAAE;QACvC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAA;IAC3B,CAAC,CAAC,CAAA;IAEF,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAQ,EAAE;QACvC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAA;IAC3B,CAAC,CAAC,CAAA;IACF,IAAI,OAAO,CAAC,MAAM,EAAE;QACnB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;KACjC;IACD,IAAI,OAAO,CAAC,MAAM,EAAE;QACnB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;KACjC;IAED,MAAM,MAAM,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtD,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAQ,EAAE;YACnC,IAAI,QAAQ,KAAK,CAAC,EAAE;gBACnB,OAAO,CAAC,MAAM,CAAC,CAAA;aACf;iBAAM;gBACN,MAAM,CAAC,IAAI,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;aAC/C;QACF,CAAC,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;AACzB,CAAC,CAAA;AArDY,QAAA,UAAU,cAqDtB;AAED,MAAa,iBAAkB,SAAQ,KAAK;IAC3C,YAA4B,QAAuB,EAAkB,MAAc;QAClF,KAAK,CAAC,sBAAsB,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAA;QADzB,aAAQ,GAAR,QAAQ,CAAe;QAAkB,WAAM,GAAN,MAAM,CAAQ;IAEnF,CAAC;CACD;AAJD,8CAIC"}
@@ -1,6 +0,0 @@
1
- export interface NpmPackageUpdate {
2
- name: string;
3
- version: string;
4
- }
5
- export declare const updateNpmPackages: (packages: NpmPackageUpdate[], workspaceDirectory: string) => Promise<void>;
6
- //# sourceMappingURL=npm.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"npm.d.ts","sourceRoot":"","sources":["../../../src/utils/npm.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CACf;AAqBD,eAAO,MAAM,iBAAiB,aAAoB,gBAAgB,EAAE,sBAAsB,MAAM,kBAiC/F,CAAA"}
@@ -1,62 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateNpmPackages = void 0;
4
- const cli_common_1 = require("@contember/cli-common");
5
- const node_path_1 = require("node:path");
6
- const commands_1 = require("./commands");
7
- const cli_common_2 = require("@contember/cli-common");
8
- const install = async (hasYarn, packages, isDev, dir) => {
9
- const [cmd, ...args] = hasYarn
10
- ? ['yarn', 'add', isDev ? '--dev' : undefined, '--ignore-workspace-root-check']
11
- : ['npm', 'install', isDev ? '--save-dev' : '--save'];
12
- const label = isDev ? 'devDependencies' : 'dependencies';
13
- if (packages.length === 0) {
14
- console.log(`No npm ${label} to update.`);
15
- return;
16
- }
17
- console.log(`Updating npm ${label}: ${packages.join(', ')}`);
18
- const { output } = (0, commands_1.runCommand)(cmd, [...args, ...packages], {
19
- cwd: dir,
20
- stderr: process.stderr,
21
- stdout: process.stdout,
22
- });
23
- await output;
24
- console.log('npm update done');
25
- };
26
- const updateNpmPackages = async (packages, workspaceDirectory) => {
27
- const hasYarn = await (0, cli_common_1.pathExists)((0, node_path_1.join)(workspaceDirectory, 'yarn.lock'));
28
- const processPackageFile = async (dir) => {
29
- const packageJsonFile = (0, node_path_1.join)(dir, 'package.json');
30
- if (!(await (0, cli_common_1.pathExists)(packageJsonFile))) {
31
- return;
32
- }
33
- // eslint-disable-next-line @typescript-eslint/no-var-requires
34
- const packageJson = require(packageJsonFile);
35
- const isRoot = workspaceDirectory === dir;
36
- const upgradeDeps = async (type) => {
37
- const deps = packageJson[type] || {};
38
- const packagesToUpdate = packages.filter(it => !!deps[it.name]).map(it => `${it.name}@${it.version}`);
39
- await install(hasYarn, packagesToUpdate, type === 'devDependencies', dir);
40
- };
41
- await upgradeDeps('dependencies');
42
- await upgradeDeps('devDependencies');
43
- if (hasYarn && isRoot && packageJson.workspaces) {
44
- const dirsPromise = packageJson.workspaces.map(async (it) => {
45
- if (it.substr(-1) === '*') {
46
- const baseDir = it.substring(0, it.length - 1);
47
- return await (0, cli_common_2.listDirectories)(baseDir);
48
- }
49
- else {
50
- return [(0, node_path_1.join)(dir, it)];
51
- }
52
- });
53
- const workspaceDirs = (await Promise.all(dirsPromise)).flatMap(it => it);
54
- for (const dir of workspaceDirs) {
55
- await processPackageFile(dir);
56
- }
57
- }
58
- };
59
- await processPackageFile(workspaceDirectory);
60
- };
61
- exports.updateNpmPackages = updateNpmPackages;
62
- //# sourceMappingURL=npm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"npm.js","sourceRoot":"","sources":["../../../src/utils/npm.ts"],"names":[],"mappings":"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"}
@@ -1,65 +0,0 @@
1
- import { ChildProcessWithoutNullStreams, spawn } from 'node:child_process'
2
- import { Readable, Writable } from 'node:stream'
3
- import chalk from 'chalk'
4
-
5
- export type RunningCommand = { child: ChildProcessWithoutNullStreams; output: Promise<string> }
6
- export const runCommand = (
7
- command: string,
8
- args: (string | undefined)[],
9
- options: {
10
- cwd: string
11
- stdin?: Readable
12
- stdout?: Writable
13
- stderr?: Writable
14
- env?: NodeJS.ProcessEnv
15
- detached?: boolean
16
- },
17
- ): RunningCommand => {
18
- const args2 = args.filter((it): it is string => it !== undefined)
19
- if (!process.env.DISABLE_COMMAND_PRINTING) {
20
- console.error(chalk.gray(`$ ${command} ${args2.map(it => `'${it.replace(/'/g, `'\\''`)}'`).join(' ')}`))
21
- }
22
- const child = spawn(command, args2, {
23
- cwd: options.cwd,
24
- env: { ...process.env, ...(options.env || {}) },
25
- detached: options.detached,
26
- })
27
- if (options.stdin) {
28
- options.stdin.pipe(child.stdin)
29
- }
30
-
31
- let stdout = ''
32
- let stderr = ''
33
-
34
- child.stdout.on('data', (chunk): void => {
35
- stdout += chunk.toString()
36
- })
37
-
38
- child.stderr.on('data', (chunk): void => {
39
- stderr += chunk.toString()
40
- })
41
- if (options.stdout) {
42
- child.stdout.pipe(options.stdout)
43
- }
44
- if (options.stderr) {
45
- child.stderr.pipe(options.stderr)
46
- }
47
-
48
- const output = new Promise<string>((resolve, reject) => {
49
- child.on('exit', (exitCode): void => {
50
- if (exitCode === 0) {
51
- resolve(stdout)
52
- } else {
53
- reject(new ChildProcessError(exitCode, stderr))
54
- }
55
- })
56
- })
57
-
58
- return { output, child }
59
- }
60
-
61
- export class ChildProcessError extends Error {
62
- constructor(public readonly exitCode: number | null, public readonly stderr: string) {
63
- super(`Command has failed(${exitCode}): ${stderr} `)
64
- }
65
- }