@mittwald/cli 1.11.2 → 1.13.1-beta.6

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 (64) hide show
  1. package/README.md +5 -0
  2. package/bin/dev.js +0 -0
  3. package/dist/commands/app/copy.d.ts +1 -0
  4. package/dist/commands/app/copy.js +6 -1
  5. package/dist/commands/app/create/node.d.ts +1 -1
  6. package/dist/commands/app/create/php-worker.d.ts +1 -1
  7. package/dist/commands/app/create/php.d.ts +1 -1
  8. package/dist/commands/app/create/python.d.ts +1 -1
  9. package/dist/commands/app/create/static.d.ts +1 -1
  10. package/dist/commands/app/dependency/update.js +4 -6
  11. package/dist/commands/app/dependency/versions.js +3 -3
  12. package/dist/commands/app/install/contao.d.ts +1 -1
  13. package/dist/commands/app/install/joomla.d.ts +1 -1
  14. package/dist/commands/app/install/matomo.d.ts +1 -1
  15. package/dist/commands/app/install/nextcloud.d.ts +1 -1
  16. package/dist/commands/app/install/shopware5.d.ts +1 -1
  17. package/dist/commands/app/install/shopware6.d.ts +1 -1
  18. package/dist/commands/app/install/typo3.d.ts +1 -1
  19. package/dist/commands/app/install/wordpress.d.ts +1 -1
  20. package/dist/commands/app/open.d.ts +3 -0
  21. package/dist/commands/app/open.js +35 -9
  22. package/dist/commands/container/logs.d.ts +1 -0
  23. package/dist/commands/container/logs.js +8 -0
  24. package/dist/commands/container/port-forward.js +2 -2
  25. package/dist/commands/container/run.d.ts +9 -0
  26. package/dist/commands/container/run.js +42 -4
  27. package/dist/commands/container/update.js +2 -2
  28. package/dist/commands/context/get.js +1 -0
  29. package/dist/commands/database/mysql/create.d.ts +1 -1
  30. package/dist/commands/database/mysql/create.js +3 -2
  31. package/dist/commands/ddev/init.js +2 -1
  32. package/dist/commands/org/invite/list-own.d.ts +1 -0
  33. package/dist/commands/org/membership/list-own.d.ts +1 -0
  34. package/dist/commands/project/create.js +12 -3
  35. package/dist/commands/stack/deploy.d.ts +2 -0
  36. package/dist/commands/stack/deploy.js +49 -6
  37. package/dist/lib/context/FlagSetBuilder.d.ts +1 -0
  38. package/dist/lib/context/FlagSetBuilder.js +7 -1
  39. package/dist/lib/intellij/config.test.js +9 -2
  40. package/dist/lib/resources/app/Installer.d.ts +1 -1
  41. package/dist/lib/resources/app/Installer.js +14 -1
  42. package/dist/lib/resources/app/flags.d.ts +3 -1
  43. package/dist/lib/resources/app/flags.js +12 -0
  44. package/dist/lib/resources/app/install.d.ts +1 -0
  45. package/dist/lib/resources/app/install.js +1 -0
  46. package/dist/lib/resources/app/versions.d.ts +7 -1
  47. package/dist/lib/resources/app/versions.js +35 -2
  48. package/dist/lib/resources/container/containerconfig.js +7 -1
  49. package/dist/lib/resources/container/containerconfig.test.d.ts +1 -0
  50. package/dist/lib/resources/container/containerconfig.test.js +25 -0
  51. package/dist/lib/resources/database/mysql/flags.js +1 -1
  52. package/dist/lib/resources/stack/env.d.ts +10 -0
  53. package/dist/lib/resources/stack/env.js +22 -0
  54. package/dist/lib/resources/stack/flags.js +16 -1
  55. package/dist/lib/resources/stack/template-loader.d.ts +18 -0
  56. package/dist/lib/resources/stack/template-loader.js +94 -0
  57. package/dist/lib/resources/stack/template-loader.test.d.ts +1 -0
  58. package/dist/lib/resources/stack/template-loader.test.js +125 -0
  59. package/dist/lib/units/PortMapping.d.ts +2 -0
  60. package/dist/lib/units/PortMapping.js +21 -6
  61. package/dist/lib/units/PortMapping.test.js +10 -0
  62. package/package.json +13 -9
  63. package/dist/commands/cronjob/execution/abort.d.ts +0 -18
  64. package/dist/commands/cronjob/execution/abort.js +0 -41
package/README.md CHANGED
@@ -42,6 +42,9 @@ using NPM; remember to run `npm upgrade -g @mittwald/cli` occasionally.
42
42
  $ npm install -g @mittwald/cli
43
43
  ```
44
44
 
45
+ Attention! When installing via `-g` flag, make sure you have nodejs >= 20.7.0
46
+ installed, as package definition is ignored for global installations!
47
+
45
48
  #### Any OS, using Docker
46
49
 
47
50
  There is also the
@@ -101,6 +104,7 @@ USAGE
101
104
  ...
102
105
  ```
103
106
 
107
+ <!-- prettier-ignore-start -->
104
108
  <!-- commands -->
105
109
  # Command Topics
106
110
 
@@ -130,3 +134,4 @@ USAGE
130
134
  * [`mw volume`](docs/volume.md) - Manage volumes
131
135
 
132
136
  <!-- commandsstop -->
137
+ <!-- prettier-ignore-end -->
package/bin/dev.js CHANGED
File without changes
@@ -10,6 +10,7 @@ export declare class Copy extends ExecRenderBaseCommand<typeof Copy, Result> {
10
10
  };
11
11
  static flags: {
12
12
  description: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
+ "install-path": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
14
  quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
15
  };
15
16
  protected exec(): Promise<Result>;
@@ -14,16 +14,21 @@ export class Copy extends ExecRenderBaseCommand {
14
14
  summary: "set a description for the new app installation",
15
15
  required: true,
16
16
  }),
17
+ "install-path": Flags.string({
18
+ summary: "set the installation path for the new app installation; if omitted, this will default to an autogenerated directory name",
19
+ required: false,
20
+ }),
17
21
  };
18
22
  async exec() {
19
23
  const appInstallationId = await this.withAppInstallationId(Copy);
20
- const { description } = this.flags;
24
+ const { description, "install-path": installPath } = this.flags;
21
25
  const p = makeProcessRenderer(this.flags, "Copying app installation");
22
26
  const result = await p.runStep("requesting app copy", async () => {
23
27
  const r = await this.apiClient.app.requestAppinstallationCopy({
24
28
  appInstallationId,
25
29
  data: {
26
30
  description,
31
+ installationPath: installPath,
27
32
  },
28
33
  });
29
34
  assertStatus(r, 201);
@@ -4,7 +4,7 @@ import { AppInstallationResult, AppInstaller } from "../../../lib/resources/app/
4
4
  export declare const nodeInstaller: AppInstaller<"site-title" | "entrypoint">;
5
5
  export default class InstallNode extends ExecRenderBaseCommand<typeof InstallNode, AppInstallationResult> {
6
6
  static description: string;
7
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("entrypoint" | ("wait" | "wait-timeout" | "site-title"))[]>>;
7
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("entrypoint" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
8
8
  protected exec(): Promise<AppInstallationResult>;
9
9
  protected render(result: AppInstallationResult): React.ReactNode;
10
10
  }
@@ -4,7 +4,7 @@ import { AppInstallationResult, AppInstaller } from "../../../lib/resources/app/
4
4
  export declare const phpWorkerInstaller: AppInstaller<"site-title" | "entrypoint">;
5
5
  export default class InstallPhpWorker extends ExecRenderBaseCommand<typeof InstallPhpWorker, AppInstallationResult> {
6
6
  static description: string;
7
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("entrypoint" | ("wait" | "wait-timeout" | "site-title"))[]>>;
7
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("entrypoint" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
8
8
  protected exec(): Promise<AppInstallationResult>;
9
9
  protected render(result: AppInstallationResult): React.ReactNode;
10
10
  }
@@ -4,7 +4,7 @@ import { AppInstallationResult, AppInstaller } from "../../../lib/resources/app/
4
4
  export declare const phpInstaller: AppInstaller<"site-title" | "document-root">;
5
5
  export default class InstallPhp extends ExecRenderBaseCommand<typeof InstallPhp, AppInstallationResult> {
6
6
  static description: string;
7
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("document-root" | ("wait" | "wait-timeout" | "site-title"))[]>>;
7
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("document-root" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
8
8
  protected exec(): Promise<AppInstallationResult>;
9
9
  protected render(result: AppInstallationResult): React.ReactNode;
10
10
  }
@@ -4,7 +4,7 @@ import { AppInstallationResult, AppInstaller } from "../../../lib/resources/app/
4
4
  export declare const pythonInstaller: AppInstaller<"site-title" | "entrypoint">;
5
5
  export default class InstallPython extends ExecRenderBaseCommand<typeof InstallPython, AppInstallationResult> {
6
6
  static description: string;
7
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("entrypoint" | ("wait" | "wait-timeout" | "site-title"))[]>>;
7
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("entrypoint" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
8
8
  protected exec(): Promise<AppInstallationResult>;
9
9
  protected render(result: AppInstallationResult): React.ReactNode;
10
10
  }
@@ -4,7 +4,7 @@ import { AppInstallationResult, AppInstaller } from "../../../lib/resources/app/
4
4
  export declare const staticInstaller: AppInstaller<"site-title" | "document-root">;
5
5
  export default class InstallStatic extends ExecRenderBaseCommand<typeof InstallStatic, AppInstallationResult> {
6
6
  static description: string;
7
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("document-root" | ("wait" | "wait-timeout" | "site-title"))[]>>;
7
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("document-root" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
8
8
  protected exec(): Promise<AppInstallationResult>;
9
9
  protected render(result: AppInstallationResult): React.ReactNode;
10
10
  }
@@ -5,7 +5,8 @@ import { makeProcessRenderer, processFlags, } from "../../../rendering/process/p
5
5
  import { Flags } from "@oclif/core";
6
6
  import { assertStatus } from "@mittwald/api-client-commons";
7
7
  import { Success } from "../../../rendering/react/components/Success.js";
8
- import { Range, SemVer } from "semver";
8
+ import { Range } from "semver";
9
+ import { compareVersionsBy } from "../../../lib/resources/app/versions.js";
9
10
  export default class Update extends ExecRenderBaseCommand {
10
11
  static summary = "Update the dependencies of an app";
11
12
  static args = { ...appInstallationArgs };
@@ -82,7 +83,7 @@ export default class Update extends ExecRenderBaseCommand {
82
83
  });
83
84
  assertStatus(r, 204);
84
85
  });
85
- process.complete(_jsx(Success, { children: "The dependencies of this app were successfully updated!" }));
86
+ await process.complete(_jsx(Success, { children: "The dependencies of this app were successfully updated!" }));
86
87
  }
87
88
  async getVersions(p, systemSoftware, versionRange) {
88
89
  const versions = await p.runStep(`fetching versions for ${systemSoftware.name}`, async () => {
@@ -95,10 +96,7 @@ export default class Update extends ExecRenderBaseCommand {
95
96
  assertStatus(r, 200);
96
97
  return r.data;
97
98
  });
98
- versions.sort((a, b) => {
99
- return (new SemVer(a.externalVersion).compare(new SemVer(b.externalVersion)) *
100
- -1);
101
- });
99
+ versions.sort(compareVersionsBy("internal"));
102
100
  return versions;
103
101
  }
104
102
  render() {
@@ -1,7 +1,7 @@
1
1
  import { assertStatus } from "@mittwald/api-client-commons";
2
2
  import { ListBaseCommand, } from "../../../lib/basecommands/ListBaseCommand.js";
3
- import { SemVer } from "semver";
4
3
  import { Args } from "@oclif/core";
4
+ import { compareVersionsBy } from "../../../lib/resources/app/versions.js";
5
5
  export class Versions extends ListBaseCommand {
6
6
  static description = "Get all available versions of a particular dependency";
7
7
  static args = {
@@ -13,7 +13,7 @@ export class Versions extends ListBaseCommand {
13
13
  static flags = {
14
14
  ...ListBaseCommand.baseFlags,
15
15
  };
16
- sorter = (a, b) => new SemVer(a.externalVersion).compare(b.externalVersion);
16
+ sorter = compareVersionsBy("internal");
17
17
  async getData() {
18
18
  const systemSoftwareName = this.args["systemsoftware"];
19
19
  const systemSoftwares = await this.apiClient.app.listSystemsoftwares({});
@@ -22,7 +22,7 @@ export class Versions extends ListBaseCommand {
22
22
  if (!systemSoftware) {
23
23
  throw new Error(`system software ${systemSoftwareName} not found`);
24
24
  }
25
- return await this.apiClient.app.listSystemsoftwareversions({
25
+ return this.apiClient.app.listSystemsoftwareversions({
26
26
  systemSoftwareId: systemSoftware.id,
27
27
  });
28
28
  }
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import { AppInstallationResult } from "../../../lib/resources/app/Installer.js";
4
4
  export default class InstallContao extends ExecRenderBaseCommand<typeof InstallContao, AppInstallationResult> {
5
5
  static description: string;
6
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "admin-firstname" | "admin-lastname" | ("wait" | "wait-timeout" | "site-title"))[]>>;
6
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "admin-firstname" | "admin-lastname" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
7
7
  protected exec(): Promise<AppInstallationResult>;
8
8
  protected render(result: AppInstallationResult): React.ReactNode;
9
9
  }
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import { AppInstallationResult } from "../../../lib/resources/app/Installer.js";
4
4
  export default class InstallJoomla extends ExecRenderBaseCommand<typeof InstallJoomla, AppInstallationResult> {
5
5
  static description: string;
6
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "admin-firstname" | "admin-lastname" | ("wait" | "wait-timeout" | "site-title"))[]>>;
6
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "admin-firstname" | "admin-lastname" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
7
7
  protected exec(): Promise<AppInstallationResult>;
8
8
  protected render(result: AppInstallationResult): React.ReactNode;
9
9
  }
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import { AppInstallationResult } from "../../../lib/resources/app/Installer.js";
4
4
  export default class InstallMatomo extends ExecRenderBaseCommand<typeof InstallMatomo, AppInstallationResult> {
5
5
  static description: string;
6
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | ("wait" | "wait-timeout" | "site-title"))[]>>;
6
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
7
7
  protected exec(): Promise<AppInstallationResult>;
8
8
  protected render(result: AppInstallationResult): React.ReactNode;
9
9
  }
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import { AppInstallationResult } from "../../../lib/resources/app/Installer.js";
4
4
  export default class InstallNextcloud extends ExecRenderBaseCommand<typeof InstallNextcloud, AppInstallationResult> {
5
5
  static description: string;
6
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | ("wait" | "wait-timeout" | "site-title"))[]>>;
6
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
7
7
  protected exec(): Promise<AppInstallationResult>;
8
8
  protected render(result: AppInstallationResult): React.ReactNode;
9
9
  }
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import { AppInstallationResult } from "../../../lib/resources/app/Installer.js";
4
4
  export default class InstallShopware5 extends ExecRenderBaseCommand<typeof InstallShopware5, AppInstallationResult> {
5
5
  static description: string;
6
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "admin-firstname" | "admin-lastname" | "shop-email" | "shop-lang" | "shop-currency" | ("wait" | "wait-timeout" | "site-title"))[]>>;
6
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "admin-firstname" | "admin-lastname" | "shop-email" | "shop-lang" | "shop-currency" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
7
7
  protected exec(): Promise<AppInstallationResult>;
8
8
  protected render(result: AppInstallationResult): React.ReactNode;
9
9
  }
@@ -4,7 +4,7 @@ import { AppInstallationResult, AppInstaller } from "../../../lib/resources/app/
4
4
  export declare const shopware6Installer: AppInstaller<"version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "admin-firstname" | "admin-lastname" | "site-title" | "shop-email" | "shop-lang" | "shop-currency">;
5
5
  export default class InstallShopware6 extends ExecRenderBaseCommand<typeof InstallShopware6, AppInstallationResult> {
6
6
  static description: string;
7
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "admin-firstname" | "admin-lastname" | "shop-email" | "shop-lang" | "shop-currency" | ("wait" | "wait-timeout" | "site-title"))[]>>;
7
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "admin-firstname" | "admin-lastname" | "shop-email" | "shop-lang" | "shop-currency" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
8
8
  protected exec(): Promise<AppInstallationResult>;
9
9
  protected render(result: AppInstallationResult): React.ReactNode;
10
10
  }
@@ -4,7 +4,7 @@ import { AppInstallationResult, AppInstaller } from "../../../lib/resources/app/
4
4
  export declare const typo3Installer: AppInstaller<"version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "site-title" | "install-mode">;
5
5
  export default class InstallTYPO3 extends ExecRenderBaseCommand<typeof InstallTYPO3, AppInstallationResult> {
6
6
  static description: string;
7
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "install-mode" | ("wait" | "wait-timeout" | "site-title"))[]>>;
7
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "install-mode" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
8
8
  protected exec(): Promise<AppInstallationResult>;
9
9
  protected render(result: AppInstallationResult): React.ReactNode;
10
10
  }
@@ -4,7 +4,7 @@ import { AppInstallationResult, AppInstaller } from "../../../lib/resources/app/
4
4
  export declare const wordpressInstaller: AppInstaller<"version" | "host" | "admin-user" | "admin-email" | "admin-pass" | "site-title">;
5
5
  export default class InstallWordPress extends ExecRenderBaseCommand<typeof InstallWordPress, AppInstallationResult> {
6
6
  static description: string;
7
- static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | ("wait" | "wait-timeout" | "site-title"))[]>>;
7
+ static flags: import("@oclif/core/interfaces").FlagInput<import("../../../lib/resources/app/flags.js").RelevantFlags<readonly ("version" | "host" | "admin-user" | "admin-email" | "admin-pass" | ("wait" | "wait-timeout" | "site-title" | "install-path" | "update-context"))[]>>;
8
8
  protected exec(): Promise<AppInstallationResult>;
9
9
  protected render(result: AppInstallationResult): React.ReactNode;
10
10
  }
@@ -5,5 +5,8 @@ export declare class Open extends ExtendedBaseCommand<typeof Open> {
5
5
  static args: {
6
6
  "installation-id": import("@oclif/core/interfaces").Arg<string>;
7
7
  };
8
+ static flags: {
9
+ backend: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ };
8
11
  run(): Promise<void>;
9
12
  }
@@ -3,27 +3,53 @@ import open from "open";
3
3
  import { appInstallationArgs, withAppInstallationId, } from "../../lib/resources/app/flags.js";
4
4
  import { ExtendedBaseCommand } from "../../lib/basecommands/ExtendedBaseCommand.js";
5
5
  import buildAppURLsFromIngressList from "../../lib/resources/app/buildAppURLsFromIngressList.js";
6
+ import { Flags } from "@oclif/core";
6
7
  export class Open extends ExtendedBaseCommand {
7
8
  static summary = "Open an app installation in the browser.";
8
9
  static description = "This command opens an app installation in the browser. For this to work, there needs to be at least one virtual host linked to the app installation.";
9
10
  static args = { ...appInstallationArgs };
11
+ static flags = {
12
+ backend: Flags.boolean({
13
+ summary: "open the backend of the app installation",
14
+ description: "If this flag is set, the backend of the app installation will be opened instead of the frontend. This flag is only available for some types of apps (like PHP and Node.js).",
15
+ default: false,
16
+ required: false,
17
+ }),
18
+ };
10
19
  async run() {
11
20
  const appInstallationId = await withAppInstallationId(this.apiClient, Open, this.flags, this.args, this.config);
12
21
  const installation = await this.apiClient.app.getAppinstallation({
13
22
  appInstallationId,
14
23
  });
15
24
  assertStatus(installation, 200);
16
- const domains = await this.apiClient.domain.ingressListIngresses({
17
- queryParameters: {
18
- projectId: installation.data.projectId,
19
- },
20
- });
21
- assertStatus(domains, 200);
22
- const urls = buildAppURLsFromIngressList(domains.data, installation.data.id);
25
+ const [appVersion, domains] = await Promise.all([
26
+ (async () => {
27
+ const appVersion = await this.apiClient.app.getAppversion({
28
+ appId: installation.data.appId,
29
+ appVersionId: installation.data.appVersion.desired,
30
+ });
31
+ assertStatus(appVersion, 200);
32
+ return appVersion.data;
33
+ })(),
34
+ (async () => {
35
+ const domains = await this.apiClient.domain.ingressListIngresses({
36
+ queryParameters: {
37
+ projectId: installation.data.projectId,
38
+ },
39
+ });
40
+ assertStatus(domains, 200);
41
+ return domains.data;
42
+ })(),
43
+ ]);
44
+ const urls = buildAppURLsFromIngressList(domains, installation.data.id);
23
45
  if (urls.length === 0) {
24
46
  throw new Error("This app installation is not linked to any virtual hosts.");
25
47
  }
26
- console.log("opening " + urls[0]);
27
- await open(urls[0]);
48
+ let url = urls[0];
49
+ if (this.flags.backend && appVersion.backendPathTemplate) {
50
+ url = appVersion.backendPathTemplate.replace("{domain}", url.replace(/\/$/, ""));
51
+ }
52
+ console.log("opening " + url);
53
+ await open(url);
28
54
  }
29
55
  }
@@ -5,6 +5,7 @@ export declare class Logs extends BaseCommand {
5
5
  static aliases: string[];
6
6
  static flags: {
7
7
  "no-pager": import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ tail: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
9
  "project-id": import("@oclif/core/interfaces").OptionFlag<string>;
9
10
  token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
11
  };
@@ -17,6 +17,11 @@ export class Logs extends BaseCommand {
17
17
  "no-pager": Flags.boolean({
18
18
  description: "Disable pager for output.",
19
19
  }),
20
+ tail: Flags.integer({
21
+ char: "t",
22
+ description: "Number of lines to show from the end of the logs (minimum: 1).",
23
+ min: 1,
24
+ }),
20
25
  };
21
26
  static args = {
22
27
  "container-id": Args.string({
@@ -31,6 +36,9 @@ export class Logs extends BaseCommand {
31
36
  const logsResp = await this.apiClient.container.getServiceLogs({
32
37
  stackId,
33
38
  serviceId,
39
+ queryParameters: {
40
+ ...(flags.tail && { tail: flags.tail }),
41
+ },
34
42
  });
35
43
  assertStatus(logsResp, 200);
36
44
  // This is to work around a bug which causes the response to
@@ -28,8 +28,8 @@ export class PortForward extends ExecRenderBaseCommand {
28
28
  required: true,
29
29
  }),
30
30
  port: PortMapping.arg({
31
- summary: "Port mapping in the format 'local-port:container-port'",
32
- description: "Specifies the port mapping between your local machine and the container. Format: 'local-port:container-port'. If not specified, available ports will be detected automatically.",
31
+ summary: "Port mapping in the format 'local-port:container-port' or 'port'",
32
+ description: "Specifies the port mapping between your local machine and the container. Format: 'local-port:container-port' or just 'port' (in which case the same port is used locally and in the container). If not specified, available ports will be detected automatically.",
33
33
  required: false,
34
34
  }),
35
35
  };
@@ -19,6 +19,8 @@ export declare class Run extends ExecRenderBaseCommand<typeof Run, Result> {
19
19
  "publish-all": import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
20
  volume: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
21
21
  "create-volumes": import("@oclif/core/interfaces").BooleanFlag<boolean>;
22
+ cpus: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
23
+ memory: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
22
24
  "project-id": import("@oclif/core/interfaces").OptionFlag<string>;
23
25
  quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
24
26
  };
@@ -46,6 +48,13 @@ export declare class Run extends ExecRenderBaseCommand<typeof Run, Result> {
46
48
  * or undefined if no specific command is set.
47
49
  */
48
50
  private buildContainerCommand;
51
+ /**
52
+ * Builds the deploy.resources structure from command line flags
53
+ *
54
+ * @returns The deploy configuration with resource limits, or undefined if no
55
+ * limits are specified
56
+ */
57
+ private buildDeployResources;
49
58
  /**
50
59
  * Builds a container service request from command line arguments and image
51
60
  * metadata
@@ -48,10 +48,10 @@ export class Run extends ExecRenderBaseCommand {
48
48
  required: false,
49
49
  }),
50
50
  publish: Flags.string({
51
- summary: "publish a container's port(s) to the host",
52
- description: "Map a container's port to a port on the host system. " +
53
- "Format: <host-port>:<container-port> or just <container-port> (in which case the host port will be automatically assigned). " +
54
- "For example, --publish 8080:80 maps port 80 in the container to port 8080 on the host. " +
51
+ summary: "publish a container's port(s)",
52
+ description: "Expose a container's port within the cluster. " +
53
+ "Format: <cluster-port>:<container-port> or just <port> (in which case the same port is used for both cluster and container). " +
54
+ "For example, --publish 8080:80 maps port 80 in the container to port 8080 within the cluster, while --publish 8080 exposes port 8080 as port 8080. " +
55
55
  "Use multiple --publish flags to publish multiple ports.\n\n" +
56
56
  "NOTE: Please note that the usual shorthand -p is not supported for this flag, as it would conflict with the --project flag.",
57
57
  required: false,
@@ -83,6 +83,19 @@ export class Run extends ExecRenderBaseCommand {
83
83
  required: false,
84
84
  default: false,
85
85
  }),
86
+ cpus: Flags.string({
87
+ summary: "set CPU limit for the container",
88
+ description: "Specify the number of CPUs available to the container (e.g., '0.5', '1', '2'). " +
89
+ "This is equivalent to the docker run --cpus flag or the deploy.resources.limits.cpus field in docker-compose.",
90
+ required: false,
91
+ }),
92
+ memory: Flags.string({
93
+ summary: "set memory limit for the container",
94
+ description: "Specify the maximum amount of memory the container can use (e.g., '512m', '1g', '2g'). " +
95
+ "This is equivalent to the docker run --memory flag or the deploy.resources.limits.memory field in docker-compose.",
96
+ required: false,
97
+ char: "m",
98
+ }),
86
99
  };
87
100
  static args = {
88
101
  image: Args.string({
@@ -180,6 +193,29 @@ export class Run extends ExecRenderBaseCommand {
180
193
  const command = [this.args.command, ...this.argv.slice(firstArg)];
181
194
  return command;
182
195
  }
196
+ /**
197
+ * Builds the deploy.resources structure from command line flags
198
+ *
199
+ * @returns The deploy configuration with resource limits, or undefined if no
200
+ * limits are specified
201
+ */
202
+ buildDeployResources() {
203
+ if (!this.flags.cpus && !this.flags.memory) {
204
+ return undefined;
205
+ }
206
+ const limits = {};
207
+ if (this.flags.cpus) {
208
+ limits.cpus = this.flags.cpus;
209
+ }
210
+ if (this.flags.memory) {
211
+ limits.memory = this.flags.memory;
212
+ }
213
+ return {
214
+ resources: {
215
+ limits,
216
+ },
217
+ };
218
+ }
183
219
  /**
184
220
  * Builds a container service request from command line arguments and image
185
221
  * metadata
@@ -198,6 +234,7 @@ export class Run extends ExecRenderBaseCommand {
198
234
  const environment = await parseEnvironmentVariables(this.flags.env, this.flags["env-file"]);
199
235
  const ports = getPortMappings(imageMeta, this.flags["publish-all"], this.flags.publish);
200
236
  const volumes = this.flags.volume;
237
+ const deploy = this.buildDeployResources();
201
238
  return {
202
239
  image,
203
240
  command,
@@ -206,6 +243,7 @@ export class Run extends ExecRenderBaseCommand {
206
243
  environment,
207
244
  ports,
208
245
  volumes,
246
+ deploy,
209
247
  };
210
248
  }
211
249
  async getImageAndMeta(projectId) {
@@ -50,8 +50,8 @@ export class Update extends ExecRenderBaseCommand {
50
50
  }),
51
51
  publish: Flags.string({
52
52
  summary: "update the container's port mappings",
53
- description: "Map a container's port to a port on the host system. " +
54
- "Format: <host-port>:<container-port> or just <container-port> (in which case the host port will be automatically assigned). " +
53
+ description: "Expose a container's port within the cluster. " +
54
+ "Format: <cluster-port>:<container-port> or just <port> (in which case the same port is used for both cluster and container). " +
55
55
  "Use multiple -p flags to publish multiple ports.",
56
56
  required: false,
57
57
  multiple: true,
@@ -42,6 +42,7 @@ const GetContext = ({ ctx }) => {
42
42
  "server-id",
43
43
  "org-id",
44
44
  "installation-id",
45
+ "stack-id",
45
46
  ]) {
46
47
  const value = usePromise(ctx.getContextValue.bind(ctx), [key]);
47
48
  if (value) {
@@ -13,7 +13,7 @@ export declare class Create extends ExecRenderBaseCommand<typeof Create, Result>
13
13
  "character-set": import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
14
  "user-password": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
15
  "user-external": import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
- "user-access-level": import("@oclif/core/interfaces").OptionFlag<"full" | "readonly", import("@oclif/core/interfaces").CustomOptions>;
16
+ "user-access-level": import("@oclif/core/interfaces").OptionFlag<"full", import("@oclif/core/interfaces").CustomOptions>;
17
17
  quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
18
  "project-id": import("@oclif/core/interfaces").OptionFlag<string>;
19
19
  };
@@ -30,7 +30,7 @@ export class Create extends ExecRenderBaseCommand {
30
30
  default: "utf8mb4",
31
31
  }),
32
32
  "user-password": Flags.string({
33
- summary: "the password to use for the default user (env: MYSQL_PWD)",
33
+ summary: "the password to use for the default user",
34
34
  env: "MYSQL_PWD",
35
35
  }),
36
36
  "user-external": Flags.boolean({
@@ -39,7 +39,8 @@ export class Create extends ExecRenderBaseCommand {
39
39
  }),
40
40
  "user-access-level": Flags.custom({
41
41
  summary: "the access level preset for the default user",
42
- options: ["full", "readonly"],
42
+ deprecated: true,
43
+ options: ["full"],
43
44
  default: "full",
44
45
  })(),
45
46
  };
@@ -46,7 +46,7 @@ export class Init extends ExecRenderBaseCommand {
46
46
  summary: "override the mittwald plugin",
47
47
  helpGroup: "Development",
48
48
  description: "This flag allows you to override the mittwald plugin that should be installed by default; this is useful for testing purposes",
49
- default: "mittwald/ddev",
49
+ default: "mittwald/ddev-mittwald",
50
50
  }),
51
51
  };
52
52
  static args = {
@@ -89,6 +89,7 @@ export class Init extends ExecRenderBaseCommand {
89
89
  async installMittwaldPlugin(r) {
90
90
  const { "override-mittwald-plugin": mittwaldPlugin } = this.flags;
91
91
  await spawnInProcess(r, "installing mittwald plugin", "ddev", [
92
+ "add-on",
92
93
  "get",
93
94
  mittwaldPlugin,
94
95
  ]);
@@ -33,6 +33,7 @@ export declare class List extends ListBaseCommand<typeof List, ResponseItem, Res
33
33
  creationDate: string;
34
34
  customerId: string;
35
35
  customerNumber: string;
36
+ deletionProhibitedBy?: ("hasOpenInvoices" | "hasActiveContracts" | "hasActiveExtensionSubscriptions" | "isActiveContributor")[] | undefined;
36
37
  executingUserRoles?: import("node_modules/@mittwald/api-client/dist/types/generated/v2/types.js").MittwaldAPIV2.Components.Schemas.CustomerRole[] | undefined;
37
38
  flags?: import("node_modules/@mittwald/api-client/dist/types/generated/v2/types.js").MittwaldAPIV2.Components.Schemas.CustomerCustomerFlag[] | undefined;
38
39
  isAllowedToPlaceOrders?: boolean | undefined;
@@ -33,6 +33,7 @@ export declare class ListOwn extends ListBaseCommand<typeof ListOwn, ResponseIte
33
33
  creationDate: string;
34
34
  customerId: string;
35
35
  customerNumber: string;
36
+ deletionProhibitedBy?: ("hasOpenInvoices" | "hasActiveContracts" | "hasActiveExtensionSubscriptions" | "isActiveContributor")[] | undefined;
36
37
  executingUserRoles?: import("node_modules/@mittwald/api-client/dist/types/generated/v2/types.js").MittwaldAPIV2.Components.Schemas.CustomerRole[] | undefined;
37
38
  flags?: import("node_modules/@mittwald/api-client/dist/types/generated/v2/types.js").MittwaldAPIV2.Components.Schemas.CustomerCustomerFlag[] | undefined;
38
39
  isAllowedToPlaceOrders?: boolean | undefined;