@mittwald/cli 1.4.4 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +3 -0
  2. package/dist/commands/container/delete.d.ts +15 -0
  3. package/dist/commands/container/delete.js +39 -0
  4. package/dist/commands/container/list.d.ts +23 -0
  5. package/dist/commands/container/list.js +53 -0
  6. package/dist/commands/container/logs.d.ts +14 -0
  7. package/dist/commands/container/logs.js +47 -0
  8. package/dist/commands/container/recreate.d.ts +20 -0
  9. package/dist/commands/container/recreate.js +72 -0
  10. package/dist/commands/container/restart.d.ts +18 -0
  11. package/dist/commands/container/restart.js +40 -0
  12. package/dist/commands/container/run.d.ts +57 -0
  13. package/dist/commands/container/run.js +224 -0
  14. package/dist/commands/container/start.d.ts +18 -0
  15. package/dist/commands/container/start.js +40 -0
  16. package/dist/commands/container/stop.d.ts +18 -0
  17. package/dist/commands/container/stop.js +40 -0
  18. package/dist/commands/context/set.d.ts +1 -0
  19. package/dist/commands/context/set.js +8 -0
  20. package/dist/commands/cronjob/execution/logs.js +6 -24
  21. package/dist/commands/cronjob/list.d.ts +2 -3
  22. package/dist/commands/domain/virtualhost/create.d.ts +1 -0
  23. package/dist/commands/domain/virtualhost/create.js +12 -0
  24. package/dist/commands/extension/install.js +4 -3
  25. package/dist/commands/extension/list-installed.js +4 -3
  26. package/dist/commands/registry/create.d.ts +20 -0
  27. package/dist/commands/registry/create.js +77 -0
  28. package/dist/commands/registry/delete.d.ts +13 -0
  29. package/dist/commands/registry/delete.js +21 -0
  30. package/dist/commands/registry/list.d.ts +23 -0
  31. package/dist/commands/registry/list.js +33 -0
  32. package/dist/commands/registry/update.d.ts +20 -0
  33. package/dist/commands/registry/update.js +73 -0
  34. package/dist/commands/stack/delete.d.ts +16 -0
  35. package/dist/commands/stack/delete.js +54 -0
  36. package/dist/commands/stack/deploy.d.ts +18 -0
  37. package/dist/commands/stack/deploy.js +75 -0
  38. package/dist/commands/stack/list.d.ts +24 -0
  39. package/dist/commands/stack/list.js +60 -0
  40. package/dist/commands/stack/ps.d.ts +23 -0
  41. package/dist/commands/stack/ps.js +51 -0
  42. package/dist/lib/basecommands/DeleteBaseCommand.js +1 -1
  43. package/dist/lib/basecommands/ExtendedBaseCommand.d.ts +1 -0
  44. package/dist/lib/basecommands/ExtendedBaseCommand.js +4 -0
  45. package/dist/lib/context/Context.d.ts +5 -2
  46. package/dist/lib/context/Context.js +10 -1
  47. package/dist/lib/context/FlagSetBuilder.d.ts +3 -4
  48. package/dist/lib/context/FlagSetBuilder.js +22 -15
  49. package/dist/lib/resources/container/flags.d.ts +13 -0
  50. package/dist/lib/resources/container/flags.js +34 -0
  51. package/dist/lib/resources/org/flags.js +7 -1
  52. package/dist/lib/resources/server/flags.js +7 -1
  53. package/dist/lib/resources/stack/enrich.d.ts +4 -0
  54. package/dist/lib/resources/stack/enrich.js +55 -0
  55. package/dist/lib/resources/stack/env.d.ts +1 -0
  56. package/dist/lib/resources/stack/env.js +11 -0
  57. package/dist/lib/resources/stack/flags.d.ts +5 -0
  58. package/dist/lib/resources/stack/flags.js +2 -0
  59. package/dist/lib/resources/stack/loader.d.ts +5 -0
  60. package/dist/lib/resources/stack/loader.js +47 -0
  61. package/dist/lib/resources/stack/loader.test.d.ts +1 -0
  62. package/dist/lib/resources/stack/loader.test.js +51 -0
  63. package/dist/lib/resources/stack/sanitize.d.ts +10 -0
  64. package/dist/lib/resources/stack/sanitize.js +43 -0
  65. package/dist/lib/resources/stack/types.d.ts +12 -0
  66. package/dist/lib/resources/stack/types.js +1 -0
  67. package/dist/lib/util/pager.d.ts +7 -0
  68. package/dist/lib/util/pager.js +21 -0
  69. package/dist/rendering/process/process.d.ts +1 -1
  70. package/dist/rendering/process/process_fancy.d.ts +1 -1
  71. package/dist/rendering/process/process_fancy.js +2 -1
  72. package/dist/rendering/process/process_flags.js +1 -1
  73. package/dist/rendering/process/process_quiet.d.ts +1 -1
  74. package/dist/rendering/process/process_quiet.js +3 -0
  75. package/package.json +21 -17
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from "react";
2
+ import { ExecRenderBaseCommand } from "../../lib/basecommands/ExecRenderBaseCommand.js";
3
+ type Result = {
4
+ serviceId: string;
5
+ };
6
+ export declare class Start extends ExecRenderBaseCommand<typeof Start, Result> {
7
+ static summary: string;
8
+ static flags: {
9
+ "project-id": import("@oclif/core/interfaces").OptionFlag<string>;
10
+ quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ static args: {
13
+ "container-id": import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
14
+ };
15
+ protected exec(): Promise<Result>;
16
+ protected render({ serviceId }: Result): ReactNode;
17
+ }
18
+ export {};
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Args } from "@oclif/core";
3
+ import { ExecRenderBaseCommand } from "../../lib/basecommands/ExecRenderBaseCommand.js";
4
+ import { makeProcessRenderer, processFlags, } from "../../rendering/process/process_flags.js";
5
+ import { projectFlags } from "../../lib/resources/project/flags.js";
6
+ import { withContainerAndStackId } from "../../lib/resources/container/flags.js";
7
+ import assertSuccess from "../../lib/apiutil/assert_success.js";
8
+ import { Success } from "../../rendering/react/components/Success.js";
9
+ import { Value } from "../../rendering/react/components/Value.js";
10
+ export class Start extends ExecRenderBaseCommand {
11
+ static summary = "Starts a stopped container.";
12
+ static flags = {
13
+ ...processFlags,
14
+ ...projectFlags,
15
+ };
16
+ static args = {
17
+ "container-id": Args.string({
18
+ description: "ID or short ID of the container to start",
19
+ required: true,
20
+ }),
21
+ };
22
+ async exec() {
23
+ const p = makeProcessRenderer(this.flags, "Starting a container");
24
+ const [serviceId, stackId] = await withContainerAndStackId(this.apiClient, Start, this.flags, this.args, this.config);
25
+ await p.runStep("starting container", async () => {
26
+ const r = await this.apiClient.container.startService({
27
+ serviceId,
28
+ stackId,
29
+ });
30
+ assertSuccess(r);
31
+ });
32
+ await p.complete(_jsxs(Success, { children: ["Container ", _jsx(Value, { children: serviceId }), " was successfully started."] }));
33
+ return { serviceId };
34
+ }
35
+ render({ serviceId }) {
36
+ if (this.flags.quiet) {
37
+ return serviceId;
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from "react";
2
+ import { ExecRenderBaseCommand } from "../../lib/basecommands/ExecRenderBaseCommand.js";
3
+ type Result = {
4
+ serviceId: string;
5
+ };
6
+ export declare class Stop extends ExecRenderBaseCommand<typeof Stop, Result> {
7
+ static summary: string;
8
+ static flags: {
9
+ "project-id": import("@oclif/core/interfaces").OptionFlag<string>;
10
+ quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ static args: {
13
+ "container-id": import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
14
+ };
15
+ protected exec(): Promise<Result>;
16
+ protected render({ serviceId }: Result): ReactNode;
17
+ }
18
+ export {};
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Args } from "@oclif/core";
3
+ import { ExecRenderBaseCommand } from "../../lib/basecommands/ExecRenderBaseCommand.js";
4
+ import { makeProcessRenderer, processFlags, } from "../../rendering/process/process_flags.js";
5
+ import { projectFlags } from "../../lib/resources/project/flags.js";
6
+ import { withContainerAndStackId } from "../../lib/resources/container/flags.js";
7
+ import assertSuccess from "../../lib/apiutil/assert_success.js";
8
+ import { Success } from "../../rendering/react/components/Success.js";
9
+ import { Value } from "../../rendering/react/components/Value.js";
10
+ export class Stop extends ExecRenderBaseCommand {
11
+ static summary = "Stops a running container.";
12
+ static flags = {
13
+ ...processFlags,
14
+ ...projectFlags,
15
+ };
16
+ static args = {
17
+ "container-id": Args.string({
18
+ description: "ID or short ID of the container to stop",
19
+ required: true,
20
+ }),
21
+ };
22
+ async exec() {
23
+ const p = makeProcessRenderer(this.flags, "Stopping a container");
24
+ const [serviceId, stackId] = await withContainerAndStackId(this.apiClient, Stop, this.flags, this.args, this.config);
25
+ await p.runStep("stopping container", async () => {
26
+ const r = await this.apiClient.container.stopService({
27
+ serviceId,
28
+ stackId,
29
+ });
30
+ assertSuccess(r);
31
+ });
32
+ await p.complete(_jsxs(Success, { children: ["Container ", _jsx(Value, { children: serviceId }), " was successfully stopped."] }));
33
+ return { serviceId };
34
+ }
35
+ render({ serviceId }) {
36
+ if (this.flags.quiet) {
37
+ return serviceId;
38
+ }
39
+ }
40
+ }
@@ -7,6 +7,7 @@ export declare class Set extends BaseCommand {
7
7
  "server-id": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
8
  "org-id": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
9
  "installation-id": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ "stack-id": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
11
  };
11
12
  run(): Promise<void>;
12
13
  }
@@ -18,6 +18,10 @@ export class Set extends BaseCommand {
18
18
  description: "ID or short ID of an app installation",
19
19
  aliases: ["app-id", "app-installation-id"],
20
20
  }),
21
+ "stack-id": Flags.string({
22
+ description: "ID of a container stack",
23
+ aliases: ["container-stack-id"],
24
+ }),
21
25
  };
22
26
  async run() {
23
27
  const { flags } = await this.parse(Set);
@@ -40,5 +44,9 @@ export class Set extends BaseCommand {
40
44
  const installationId = await ctx.setAppInstallationId(flags["installation-id"]);
41
45
  this.log(`Set installation ID to ${installationId}`);
42
46
  }
47
+ if (flags["stack-id"]) {
48
+ const stackId = await ctx.setStackId(flags["stack-id"]);
49
+ this.log(`Set stack ID to ${stackId}`);
50
+ }
43
51
  }
44
52
  }
@@ -2,9 +2,7 @@ import { GetBaseCommand } from "../../../lib/basecommands/GetBaseCommand.js";
2
2
  import { Args, Flags } from "@oclif/core";
3
3
  import { BaseCommand } from "../../../lib/basecommands/BaseCommand.js";
4
4
  import { assertStatus } from "@mittwald/api-client-commons";
5
- import * as cp from "child_process";
6
- import * as fs from "fs";
7
- import tempfile from "tempfile";
5
+ import { printToPager } from "../../../lib/util/pager.js";
8
6
  export class Logs extends BaseCommand {
9
7
  static summary = "Get the log output of a cronjob execution.";
10
8
  static description = "This command prints the log output of a cronjob execution. " +
@@ -46,29 +44,13 @@ export class Logs extends BaseCommand {
46
44
  if (!projectId) {
47
45
  throw new Error("Cronjob has no project ID");
48
46
  }
49
- // TODO: Replace this with a call to the actual "getFileContent" method,
50
- // once we support passing the required query parameters.
51
- const response = await this.apiClient.axios.get(`/v2/projects/${projectId}/filesystem/files/raw`, {
52
- params: {
53
- file: execution.data.logPath,
54
- inline: "true",
55
- },
47
+ const response = await this.apiClient.projectFileSystem.getFileContent({
48
+ projectId,
49
+ queryParameters: { file: execution.data.logPath, inline: true },
56
50
  });
57
- // await this.apiClient.projectFileSystem.getFileContent({
58
- // projectId ,
59
- // queryParameters: { file: execution.data.logPath, inline: true },
60
- // });
51
+ assertStatus(response, 200);
61
52
  if (usePager) {
62
- const t = tempfile();
63
- try {
64
- fs.writeFileSync(t, response.data);
65
- cp.spawnSync(process.env.PAGER || "less", [t], {
66
- stdio: "inherit",
67
- });
68
- }
69
- finally {
70
- fs.unlinkSync(t);
71
- }
53
+ printToPager(response.data);
72
54
  }
73
55
  else {
74
56
  this.log(response.data);
@@ -1,10 +1,9 @@
1
1
  import { Simplify } from "@mittwald/api-client-commons";
2
2
  import { MittwaldAPIV2, MittwaldAPIV2Client } from "@mittwald/api-client";
3
3
  import { ListBaseCommand } from "../../lib/basecommands/ListBaseCommand.js";
4
- import { ListColumns } from "../../rendering/formatter/ListFormatter.js";
4
+ import { ListColumns } from "../../rendering/formatter/Table.js";
5
5
  type ResponseItem = Simplify<MittwaldAPIV2.Paths.V2ProjectsProjectIdCronjobs.Get.Responses.$200.Content.ApplicationJson[number]>;
6
- export type PathParams = MittwaldAPIV2.Paths.V2ProjectsProjectIdCronjobs.Get.Parameters.Path;
7
- export type Response = Awaited<ReturnType<MittwaldAPIV2Client["cronjob"]["listCronjobs"]>>;
6
+ type Response = Awaited<ReturnType<MittwaldAPIV2Client["cronjob"]["listCronjobs"]>>;
8
7
  export declare class List extends ListBaseCommand<typeof List, ResponseItem, Response> {
9
8
  static description: string;
10
9
  static aliases: string[];
@@ -15,6 +15,7 @@ export default class Create extends ExecRenderBaseCommand<typeof Create, CreateR
15
15
  hostname: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
16
16
  "path-to-app": import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
17
  "path-to-url": import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
+ "path-to-container": import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
19
  "project-id": import("@oclif/core/interfaces").OptionFlag<string>;
19
20
  quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
21
  };
@@ -42,6 +42,11 @@ export default class Create extends ExecRenderBaseCommand {
42
42
  multiple: true,
43
43
  description: "This flag can be used to map a specific URL path to an external URL; the value for this flag should be the URL path and the external URL, separated by a colon, e.g. /:https://redirect.example. You can specify this flag multiple times to map multiple paths to different external URLs, and also combine it with the other --path-to-* flags.",
44
44
  }),
45
+ "path-to-container": Flags.string({
46
+ summary: "add a path mapping to a container",
47
+ multiple: true,
48
+ description: "This flag can be used to map a specific URL path to a container; the value for this flag should be the URL path, the container ID and the target port, each separated by a colon, e.g. /:3ecaf1a9-6eb4-4869-b811-8a13c3a2e745:80/tcp. You can specify this flag multiple times to map multiple paths to different containers, and also combine it with the other --path-to-* flags.",
49
+ }),
45
50
  };
46
51
  async exec() {
47
52
  const projectId = await this.withProjectId(Create);
@@ -56,6 +61,13 @@ export default class Create extends ExecRenderBaseCommand {
56
61
  const [path, url] = pathToUrl.split(":");
57
62
  paths.push({ path, target: { url } });
58
63
  }
64
+ for (const pathToContainer of this.flags["path-to-container"] ?? []) {
65
+ const [path, container, portProtocol] = pathToContainer.split(":", 3);
66
+ paths.push({
67
+ path,
68
+ target: { container: { id: container, portProtocol } },
69
+ });
70
+ }
59
71
  const { id: ingressId } = await process.runStep("creating ingress", async () => {
60
72
  const response = await this.apiClient.domain.ingressCreateIngress({
61
73
  data: {
@@ -4,7 +4,7 @@ import { makeProcessRenderer, processFlags, } from "../../rendering/process/proc
4
4
  import { Args, Flags } from "@oclif/core";
5
5
  import { assertStatus } from "@mittwald/api-client";
6
6
  import { Text } from "ink";
7
- import { contextIDNormalizers } from "../../lib/context/Context.js";
7
+ import Context, { contextIDNormalizers } from "../../lib/context/Context.js";
8
8
  export default class Install extends ExecRenderBaseCommand {
9
9
  static description = "Install an extension in a project or organization";
10
10
  static flags = {
@@ -39,13 +39,14 @@ export default class Install extends ExecRenderBaseCommand {
39
39
  assertStatus(response, 200);
40
40
  return response.data;
41
41
  });
42
+ const ctx = new Context(this.apiClient, this.config);
42
43
  if (orgId !== undefined) {
43
44
  const normalizer = contextIDNormalizers["org-id"];
44
- orgId = await normalizer(this.apiClient, orgId);
45
+ orgId = await normalizer(this.apiClient, orgId, ctx);
45
46
  }
46
47
  if (projectId !== undefined) {
47
48
  const normalizer = contextIDNormalizers["project-id"];
48
- projectId = await normalizer(this.apiClient, projectId);
49
+ projectId = await normalizer(this.apiClient, projectId, ctx);
49
50
  }
50
51
  if (!consent) {
51
52
  p.addInfo(_jsxs(Text, { children: ["This extension requires access to the following scopes:", " ", ext.scopes.join(", "), ". Please confirm your consent, or run the command with the --consent flag."] }));
@@ -1,7 +1,7 @@
1
1
  import { assertStatus } from "@mittwald/api-client-commons";
2
2
  import { ListBaseCommand } from "../../lib/basecommands/ListBaseCommand.js";
3
3
  import { Flags } from "@oclif/core";
4
- import { contextIDNormalizers } from "../../lib/context/Context.js";
4
+ import Context, { contextIDNormalizers } from "../../lib/context/Context.js";
5
5
  export class ListInstalled extends ListBaseCommand {
6
6
  static description = "List installed extensions in an organization or project.";
7
7
  static args = {};
@@ -18,13 +18,14 @@ export class ListInstalled extends ListBaseCommand {
18
18
  };
19
19
  async getData() {
20
20
  let { "org-id": orgId, "project-id": projectId } = this.flags;
21
+ const ctx = new Context(this.apiClient, this.config);
21
22
  if (orgId) {
22
23
  const normalizer = contextIDNormalizers["org-id"];
23
- orgId = await normalizer(this.apiClient, orgId);
24
+ orgId = await normalizer(this.apiClient, orgId, ctx);
24
25
  }
25
26
  if (projectId) {
26
27
  const normalizer = contextIDNormalizers["project-id"];
27
- projectId = await normalizer(this.apiClient, projectId);
28
+ projectId = await normalizer(this.apiClient, projectId, ctx);
28
29
  }
29
30
  return await this.apiClient.marketplace.extensionListExtensionInstances({
30
31
  queryParameters: {
@@ -0,0 +1,20 @@
1
+ import { ExecRenderBaseCommand } from "../../lib/basecommands/ExecRenderBaseCommand.js";
2
+ import { ReactNode } from "react";
3
+ type Result = {
4
+ registryId: string;
5
+ };
6
+ export declare class Create extends ExecRenderBaseCommand<typeof Create, Result> {
7
+ static summary: string;
8
+ static flags: {
9
+ uri: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ description: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ username: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ password: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ "project-id": import("@oclif/core/interfaces").OptionFlag<string>;
15
+ };
16
+ protected exec(): Promise<Result>;
17
+ protected render({ registryId }: Result): ReactNode;
18
+ private getPassword;
19
+ }
20
+ export {};
@@ -0,0 +1,77 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ExecRenderBaseCommand } from "../../lib/basecommands/ExecRenderBaseCommand.js";
3
+ import { makeProcessRenderer, processFlags, } from "../../rendering/process/process_flags.js";
4
+ import { assertStatus } from "@mittwald/api-client-commons";
5
+ import { Success } from "../../rendering/react/components/Success.js";
6
+ import { Value } from "../../rendering/react/components/Value.js";
7
+ import { projectFlags } from "../../lib/resources/project/flags.js";
8
+ import { Flags } from "@oclif/core";
9
+ import { Text } from "ink";
10
+ export class Create extends ExecRenderBaseCommand {
11
+ static summary = "Create a new container registry";
12
+ static flags = {
13
+ ...projectFlags,
14
+ ...processFlags,
15
+ uri: Flags.string({
16
+ summary: "uri of the registry",
17
+ required: true,
18
+ }),
19
+ description: Flags.string({
20
+ summary: "description of the registry",
21
+ required: true,
22
+ }),
23
+ username: Flags.string({
24
+ summary: "username for registry authentication",
25
+ required: false,
26
+ }),
27
+ password: Flags.string({
28
+ summary: "password for registry authentication",
29
+ required: false,
30
+ description: "If omitted but username is provided, the command will prompt interactively for a password.\n\nCAUTION: providing this flag may log your password in your shell history!",
31
+ }),
32
+ };
33
+ async exec() {
34
+ const process = makeProcessRenderer(this.flags, "Creating a new container registry");
35
+ const projectId = await this.withProjectId(Create);
36
+ const { uri, description, username } = this.flags;
37
+ const registryCreationPayload = {
38
+ uri,
39
+ description,
40
+ };
41
+ if (username) {
42
+ const password = await this.getPassword(process);
43
+ registryCreationPayload.credentials = {
44
+ username,
45
+ password,
46
+ };
47
+ }
48
+ const { id: registryId } = await process.runStep("creating container registry", async () => {
49
+ const r = await this.apiClient.container.createRegistry({
50
+ projectId,
51
+ data: registryCreationPayload,
52
+ });
53
+ assertStatus(r, 201);
54
+ return r.data;
55
+ });
56
+ const registry = await process.runStep("checking newly created container registry", async () => {
57
+ const r = await this.apiClient.container.getRegistry({
58
+ registryId,
59
+ });
60
+ assertStatus(r, 200);
61
+ return r.data;
62
+ });
63
+ await process.complete(_jsxs(Success, { children: ["The container registry \"", _jsx(Value, { children: registry.description }), "\" at", " ", _jsx(Value, { children: registry.uri }), " was successfully created."] }));
64
+ return { registryId };
65
+ }
66
+ render({ registryId }) {
67
+ if (this.flags.quiet) {
68
+ return registryId;
69
+ }
70
+ }
71
+ async getPassword(process) {
72
+ if (this.flags.password) {
73
+ return this.flags.password;
74
+ }
75
+ return await process.addInput(_jsx(Text, { children: "enter registry password" }), true);
76
+ }
77
+ }
@@ -0,0 +1,13 @@
1
+ import { DeleteBaseCommand } from "../../lib/basecommands/DeleteBaseCommand.js";
2
+ export default class Delete extends DeleteBaseCommand<typeof Delete> {
3
+ static description: string;
4
+ static resourceName: string;
5
+ static flags: {
6
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ static args: {
10
+ "registry-id": import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
11
+ };
12
+ protected deleteResource(): Promise<void>;
13
+ }
@@ -0,0 +1,21 @@
1
+ import { DeleteBaseCommand } from "../../lib/basecommands/DeleteBaseCommand.js";
2
+ import assertSuccess from "../../lib/apiutil/assert_success.js";
3
+ import { Args } from "@oclif/core";
4
+ export default class Delete extends DeleteBaseCommand {
5
+ static description = "Delete a container registry";
6
+ static resourceName = "container registry";
7
+ static flags = { ...DeleteBaseCommand.baseFlags };
8
+ static args = {
9
+ "registry-id": Args.string({
10
+ summary: "id of the container registry to delete",
11
+ required: true,
12
+ }),
13
+ };
14
+ async deleteResource() {
15
+ const registryId = this.args["registry-id"];
16
+ const response = await this.apiClient.container.deleteRegistry({
17
+ registryId,
18
+ });
19
+ assertSuccess(response);
20
+ }
21
+ }
@@ -0,0 +1,23 @@
1
+ import { Simplify } from "@mittwald/api-client-commons";
2
+ import { MittwaldAPIV2, MittwaldAPIV2Client } from "@mittwald/api-client";
3
+ import { ListBaseCommand } from "../../lib/basecommands/ListBaseCommand.js";
4
+ import { ListColumns } from "../../rendering/formatter/Table.js";
5
+ type ContainerRegistry = MittwaldAPIV2.Components.Schemas.ContainerRegistry;
6
+ type ResponseItem = Simplify<ContainerRegistry>;
7
+ type Response = Awaited<ReturnType<MittwaldAPIV2Client["container"]["listRegistries"]>>;
8
+ export declare class List extends ListBaseCommand<typeof List, ResponseItem, Response> {
9
+ static description: string;
10
+ static args: {};
11
+ static flags: {
12
+ "project-id": import("@oclif/core/interfaces").OptionFlag<string>;
13
+ output: import("@oclif/core/interfaces").OptionFlag<"json" | "txt" | "yaml" | "csv" | "tsv">;
14
+ extended: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ "no-header": import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ "no-truncate": import("@oclif/core/interfaces").BooleanFlag<boolean>;
17
+ "no-relative-dates": import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ "csv-separator": import("@oclif/core/interfaces").OptionFlag<"," | ";">;
19
+ };
20
+ getData(): Promise<Response>;
21
+ protected getColumns(data: ResponseItem[]): ListColumns<ResponseItem>;
22
+ }
23
+ export {};
@@ -0,0 +1,33 @@
1
+ import { ListBaseCommand } from "../../lib/basecommands/ListBaseCommand.js";
2
+ import { projectFlags } from "../../lib/resources/project/flags.js";
3
+ export class List extends ListBaseCommand {
4
+ static description = "List container registries.";
5
+ static args = {};
6
+ static flags = {
7
+ ...ListBaseCommand.baseFlags,
8
+ ...projectFlags,
9
+ };
10
+ async getData() {
11
+ const projectId = await this.withProjectId(List);
12
+ return this.apiClient.container.listRegistries({ projectId });
13
+ }
14
+ getColumns(data) {
15
+ const { id } = super.getColumns(data);
16
+ return {
17
+ id,
18
+ description: {},
19
+ uri: {
20
+ header: "URI",
21
+ },
22
+ credentials: {
23
+ header: "Credentials",
24
+ get: (registry) => {
25
+ if (!registry.credentials) {
26
+ return "";
27
+ }
28
+ return `${registry.credentials.username} (${registry.credentials.valid ? "valid" : "invalid"})`;
29
+ },
30
+ },
31
+ };
32
+ }
33
+ }
@@ -0,0 +1,20 @@
1
+ import { ExecRenderBaseCommand } from "../../lib/basecommands/ExecRenderBaseCommand.js";
2
+ import { ReactNode } from "react";
3
+ type UpdateResult = void;
4
+ export default class Update extends ExecRenderBaseCommand<typeof Update, UpdateResult> {
5
+ static description: string;
6
+ static args: {
7
+ "registry-id": import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
8
+ };
9
+ static flags: {
10
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ uri: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ username: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ password: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ };
16
+ protected exec(): Promise<void>;
17
+ protected render(): ReactNode;
18
+ private getPassword;
19
+ }
20
+ export {};
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ExecRenderBaseCommand } from "../../lib/basecommands/ExecRenderBaseCommand.js";
3
+ import { Args, Flags } from "@oclif/core";
4
+ import { makeProcessRenderer, processFlags, } from "../../rendering/process/process_flags.js";
5
+ import { Success } from "../../rendering/react/components/Success.js";
6
+ import assertSuccess from "../../lib/apiutil/assert_success.js";
7
+ import { Text } from "ink";
8
+ export default class Update extends ExecRenderBaseCommand {
9
+ static description = "Update an existing container registry";
10
+ static args = {
11
+ "registry-id": Args.string({
12
+ summary: "id of the container registry to update",
13
+ required: true,
14
+ }),
15
+ };
16
+ static flags = {
17
+ ...processFlags,
18
+ description: Flags.string({
19
+ summary: "new description for the registry",
20
+ }),
21
+ uri: Flags.string({
22
+ summary: "new uri for the registry",
23
+ }),
24
+ username: Flags.string({
25
+ summary: "username for registry authentication",
26
+ }),
27
+ password: Flags.string({
28
+ summary: "password for registry authentication",
29
+ description: "If omitted but username is provided, the command will prompt interactively for a password.\n\nCAUTION: providing this flag may log your password in your shell history!",
30
+ }),
31
+ };
32
+ async exec() {
33
+ const registryId = this.args["registry-id"];
34
+ const process = makeProcessRenderer(this.flags, "Updating container registry");
35
+ const { description, uri, username } = this.flags;
36
+ const registryUpdatePayload = {};
37
+ if (description) {
38
+ registryUpdatePayload.description = description;
39
+ }
40
+ if (uri) {
41
+ registryUpdatePayload.uri = uri;
42
+ }
43
+ if (username) {
44
+ const password = await this.getPassword(process);
45
+ registryUpdatePayload.credentials = {
46
+ username,
47
+ password,
48
+ };
49
+ }
50
+ if (Object.keys(registryUpdatePayload).length == 0) {
51
+ await process.complete(_jsx(Success, { children: "Nothing to change. Have a good day!" }));
52
+ return;
53
+ }
54
+ await process.runStep("Updating container registry", async () => {
55
+ const response = await this.apiClient.container.updateRegistry({
56
+ registryId,
57
+ data: registryUpdatePayload,
58
+ });
59
+ assertSuccess(response);
60
+ });
61
+ await process.complete(_jsx(Success, { children: "Your container registry has successfully been updated." }));
62
+ return;
63
+ }
64
+ render() {
65
+ return true;
66
+ }
67
+ async getPassword(process) {
68
+ if (this.flags.password) {
69
+ return this.flags.password;
70
+ }
71
+ return await process.addInput(_jsx(Text, { children: "enter registry password" }), true);
72
+ }
73
+ }
@@ -0,0 +1,16 @@
1
+ import { DeleteBaseCommand } from "../../lib/basecommands/DeleteBaseCommand.js";
2
+ export default class Delete extends DeleteBaseCommand<typeof Delete> {
3
+ static description: string;
4
+ static resourceName: string;
5
+ static aliases: string[];
6
+ static flags: {
7
+ "with-volumes": import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ };
11
+ static args: {
12
+ "stack-id": import("@oclif/core/interfaces").Arg<string>;
13
+ };
14
+ protected deleteResource(): Promise<void>;
15
+ protected deleteVolumes(stackId: string, projectId: string): Promise<void>;
16
+ }