@mittwald/cli 1.0.0-alpha.20 → 1.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -27
- package/dist/esm/BaseCommand.js +1 -0
- package/dist/esm/commands/app/copy.d.ts +1 -0
- package/dist/esm/commands/app/copy.js +1 -0
- package/dist/esm/commands/app/dependency/list.js +1 -1
- package/dist/esm/commands/app/dependency/versions.js +1 -1
- package/dist/esm/commands/app/install/php.js +1 -1
- package/dist/esm/commands/app/list.d.ts +1 -1
- package/dist/esm/commands/app/list.js +1 -1
- package/dist/esm/commands/database/mysql/create.d.ts +1 -0
- package/dist/esm/commands/database/mysql/create.js +1 -1
- package/dist/esm/commands/database/mysql/list.d.ts +1 -1
- package/dist/esm/commands/database/mysql/list.js +1 -1
- package/dist/esm/commands/database/redis/create.d.ts +1 -0
- package/dist/esm/commands/database/redis/create.js +1 -1
- package/dist/esm/commands/database/redis/list.d.ts +1 -1
- package/dist/esm/commands/database/redis/list.js +1 -1
- package/dist/esm/commands/database/redis/versions.d.ts +2 -2
- package/dist/esm/commands/database/redis/versions.js +2 -2
- package/dist/esm/commands/domain/list.d.ts +1 -1
- package/dist/esm/commands/domain/list.js +1 -1
- package/dist/esm/commands/domain/ownership/list.d.ts +10 -3
- package/dist/esm/commands/domain/ownership/list.js +17 -3
- package/dist/esm/commands/domain/virtualhost/create.d.ts +1 -0
- package/dist/esm/commands/domain/virtualhost/create.js +1 -1
- package/dist/esm/commands/domain/virtualhost/list.d.ts +1 -0
- package/dist/esm/commands/domain/virtualhost/list.js +1 -1
- package/dist/esm/commands/mail/address/create.d.ts +1 -0
- package/dist/esm/commands/mail/address/create.js +1 -1
- package/dist/esm/commands/mail/address/list.d.ts +1 -1
- package/dist/esm/commands/mail/address/list.js +1 -1
- package/dist/esm/commands/org/delete.d.ts +1 -1
- package/dist/esm/commands/org/delete.js +1 -1
- package/dist/esm/commands/org/get.d.ts +1 -1
- package/dist/esm/commands/org/get.js +1 -1
- package/dist/esm/commands/org/invite/list.d.ts +1 -1
- package/dist/esm/commands/org/invite/list.js +1 -1
- package/dist/esm/commands/org/invite.d.ts +1 -0
- package/dist/esm/commands/org/invite.js +1 -1
- package/dist/esm/commands/org/membership/list.d.ts +1 -1
- package/dist/esm/commands/org/membership/list.js +1 -1
- package/dist/esm/commands/project/backup/create.d.ts +1 -0
- package/dist/esm/commands/project/backup/create.js +1 -1
- package/dist/esm/commands/project/backup/list.d.ts +1 -1
- package/dist/esm/commands/project/backup/list.js +1 -1
- package/dist/esm/commands/project/backupschedule/list.d.ts +1 -1
- package/dist/esm/commands/project/backupschedule/list.js +1 -1
- package/dist/esm/commands/project/create.d.ts +1 -0
- package/dist/esm/commands/project/create.js +2 -2
- package/dist/esm/commands/project/cronjob/list.d.ts +1 -1
- package/dist/esm/commands/project/cronjob/list.js +1 -1
- package/dist/esm/commands/project/delete.d.ts +1 -1
- package/dist/esm/commands/project/delete.js +1 -1
- package/dist/esm/commands/project/filesystem/usage.d.ts +1 -1
- package/dist/esm/commands/project/filesystem/usage.js +1 -1
- package/dist/esm/commands/project/get.d.ts +1 -1
- package/dist/esm/commands/project/get.js +2 -2
- package/dist/esm/commands/project/list.d.ts +10 -2
- package/dist/esm/commands/project/list.js +10 -2
- package/dist/esm/commands/project/ssh.d.ts +1 -1
- package/dist/esm/commands/project/ssh.js +1 -1
- package/dist/esm/commands/project/update.d.ts +1 -1
- package/dist/esm/commands/project/update.js +1 -1
- package/dist/esm/lib/app/Installer.js +1 -1
- package/dist/esm/lib/context_flags.d.ts +20 -9
- package/dist/esm/lib/context_flags.js +25 -2
- package/dist/esm/lib/database/mysql/flags.js +1 -1
- package/dist/esm/lib/database/redis/flags.js +1 -1
- package/dist/esm/lib/handleError.js +3 -20
- package/dist/esm/lib/org/flags.d.ts +11 -3
- package/dist/esm/lib/project/flags.d.ts +11 -3
- package/dist/esm/lib/server/flags.d.ts +11 -3
- package/dist/esm/rendering/react/ExecRenderBaseCommand.js +11 -1
- package/dist/esm/rendering/react/components/ErrorBox.js +27 -1
- package/package.json +37 -3
- package/dist/esm/commands/project/list-react.d.ts +0 -11
- package/dist/esm/commands/project/list-react.js +0 -42
- package/dist/esm/generated/domain/listDomainOwnerships.d.ts +0 -13
- package/dist/esm/generated/domain/listDomainOwnerships.js +0 -21
|
@@ -8,7 +8,7 @@ export class List extends ListBaseCommand {
|
|
|
8
8
|
...projectFlags,
|
|
9
9
|
};
|
|
10
10
|
async getData() {
|
|
11
|
-
const projectId = await withProjectId(this.apiClient, this.flags, this.args, this.config);
|
|
11
|
+
const projectId = await withProjectId(this.apiClient, List, this.flags, this.args, this.config);
|
|
12
12
|
return await this.apiClient.backup.listProjectBackupSchedules({
|
|
13
13
|
pathParameters: { projectId },
|
|
14
14
|
});
|
|
@@ -10,6 +10,7 @@ export default class Create extends ExecRenderBaseCommand<typeof Create, {
|
|
|
10
10
|
wait: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
11
|
"wait-timeout": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
12
|
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
13
|
+
"server-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
|
|
13
14
|
};
|
|
14
15
|
protected exec(): Promise<{
|
|
15
16
|
projectId: string;
|
|
@@ -10,7 +10,7 @@ import { makeProcessRenderer, processFlags, } from "../../rendering/process/proc
|
|
|
10
10
|
import { waitFlags, waitUntil } from "../../lib/wait.js";
|
|
11
11
|
import { Context } from "../../lib/context.js";
|
|
12
12
|
export default class Create extends ExecRenderBaseCommand {
|
|
13
|
-
static description = "
|
|
13
|
+
static description = "Create a new project";
|
|
14
14
|
static flags = {
|
|
15
15
|
...serverFlags,
|
|
16
16
|
...processFlags,
|
|
@@ -28,7 +28,7 @@ export default class Create extends ExecRenderBaseCommand {
|
|
|
28
28
|
const { flags } = await this.parse(Create);
|
|
29
29
|
const { description } = flags;
|
|
30
30
|
const process = makeProcessRenderer(flags, "Creating project");
|
|
31
|
-
const serverId = await withServerId(this.apiClient, flags, {}, this.config);
|
|
31
|
+
const serverId = await withServerId(this.apiClient, Create, flags, {}, this.config);
|
|
32
32
|
const stepCreating = process.addStep(_jsx(Text, { children: "creating a new project" }));
|
|
33
33
|
const result = await this.apiClient.project.createProject({
|
|
34
34
|
pathParameters: { serverId },
|
|
@@ -10,7 +10,7 @@ export declare class List extends ListBaseCommand<typeof List, ResponseItem, Res
|
|
|
10
10
|
static description: string;
|
|
11
11
|
static args: {};
|
|
12
12
|
static flags: {
|
|
13
|
-
|
|
13
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
|
|
14
14
|
};
|
|
15
15
|
getData(): Promise<Response>;
|
|
16
16
|
protected mapData(data: SuccessfulResponse<Response, 200>["data"]): ResponseItem[] | Promise<ResponseItem[]>;
|
|
@@ -10,7 +10,7 @@ export class List extends ListBaseCommand {
|
|
|
10
10
|
};
|
|
11
11
|
async getData() {
|
|
12
12
|
const pathParams = {
|
|
13
|
-
projectId: await withProjectId(this.apiClient, this.flags, this.args, this.config),
|
|
13
|
+
projectId: await withProjectId(this.apiClient, List, this.flags, this.args, this.config),
|
|
14
14
|
};
|
|
15
15
|
return await this.apiClient.cronjob.listCronjobs({
|
|
16
16
|
pathParameters: pathParams,
|
|
@@ -7,7 +7,7 @@ export default class Delete extends DeleteBaseCommand<typeof Delete> {
|
|
|
7
7
|
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
8
|
};
|
|
9
9
|
static args: {
|
|
10
|
-
|
|
10
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
11
11
|
};
|
|
12
12
|
protected deleteResource(): Promise<void>;
|
|
13
13
|
protected mapResourceId(id: string): Promise<string>;
|
|
@@ -8,7 +8,7 @@ export default class Delete extends DeleteBaseCommand {
|
|
|
8
8
|
static flags = { ...DeleteBaseCommand.baseFlags };
|
|
9
9
|
static args = { ...projectArgs };
|
|
10
10
|
async deleteResource() {
|
|
11
|
-
const projectId = await withProjectId(this.apiClient, {}, this.args, this.config);
|
|
11
|
+
const projectId = await withProjectId(this.apiClient, Delete, {}, this.args, this.config);
|
|
12
12
|
const response = await this.apiClient.project.deleteProject({
|
|
13
13
|
pathParameters: { projectId },
|
|
14
14
|
});
|
|
@@ -8,7 +8,7 @@ export declare class Usage extends RenderBaseCommand<typeof Usage> {
|
|
|
8
8
|
human: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
9
9
|
};
|
|
10
10
|
static args: {
|
|
11
|
-
|
|
11
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
12
12
|
};
|
|
13
13
|
protected render(): ReactNode;
|
|
14
14
|
}
|
|
@@ -22,7 +22,7 @@ export class Usage extends RenderBaseCommand {
|
|
|
22
22
|
};
|
|
23
23
|
static args = { ...projectArgs };
|
|
24
24
|
render() {
|
|
25
|
-
const projectId = usePromise(() => withProjectId(this.apiClient, this.flags, this.args, this.config), []);
|
|
25
|
+
const projectId = usePromise(() => withProjectId(this.apiClient, Usage, this.flags, this.args, this.config), []);
|
|
26
26
|
const project = usePromise((id) => this.apiClient.project.getProject({ pathParameters: { id } }), [projectId]);
|
|
27
27
|
const projectDiskUsage = usePromise((id) => this.apiClient.projectFileSystem.getDiskUsage({
|
|
28
28
|
pathParameters: { projectId: id },
|
|
@@ -7,7 +7,7 @@ export declare class Get extends RenderBaseCommand<typeof Get> {
|
|
|
7
7
|
[x: string]: import("@oclif/core/lib/interfaces/parser.js").CompletableFlag<any>;
|
|
8
8
|
};
|
|
9
9
|
static args: {
|
|
10
|
-
|
|
10
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
11
11
|
};
|
|
12
12
|
protected formatter: GetFormatter;
|
|
13
13
|
protected render(): ReactNode;
|
|
@@ -66,12 +66,12 @@ const GetProject = ({ response }) => {
|
|
|
66
66
|
return (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: sections }));
|
|
67
67
|
};
|
|
68
68
|
export class Get extends RenderBaseCommand {
|
|
69
|
-
static description = "Get a
|
|
69
|
+
static description = "Get details of a project";
|
|
70
70
|
static flags = { ...GetBaseCommand.baseFlags };
|
|
71
71
|
static args = { ...projectArgs };
|
|
72
72
|
formatter = new GetFormatter(new ComponentPrinter((r) => _jsx(GetProject, { response: r })));
|
|
73
73
|
render() {
|
|
74
|
-
const projectId = usePromise(() => withProjectId(this.apiClient, this.flags, this.args, this.config), []);
|
|
74
|
+
const projectId = usePromise(() => withProjectId(this.apiClient, Get, this.flags, this.args, this.config), []);
|
|
75
75
|
const projectResponse = usePromise((id) => this.apiClient.project.getProject({ pathParameters: { id } }), [projectId]);
|
|
76
76
|
assertStatus(projectResponse, 200);
|
|
77
77
|
if (this.flags.output === "json") {
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { Simplify } from "@mittwald/api-client-commons";
|
|
2
2
|
import { ListColumns } from "../../Formatter.js";
|
|
3
|
-
import { MittwaldAPIV2, MittwaldAPIV2Client as MittwaldAPIClient } from "@mittwald/api-client";
|
|
3
|
+
import { MittwaldAPIV2, MittwaldAPIV2Client, MittwaldAPIV2Client as MittwaldAPIClient } from "@mittwald/api-client";
|
|
4
4
|
import { GeneratedProjectListProjects } from "../../generated/project/listProjects.js";
|
|
5
5
|
import { SuccessfulResponse } from "../../types.js";
|
|
6
|
+
import { ListBaseCommand } from "../../ListBaseCommand.js";
|
|
6
7
|
type ProjectResponse = Awaited<ReturnType<MittwaldAPIClient["project"]["listProjects"]>>;
|
|
7
8
|
type ProjectResponseItem = Simplify<MittwaldAPIV2.Paths.V2Projects.Get.Responses.$200.Content.ApplicationJson[number]>;
|
|
8
|
-
|
|
9
|
+
type Response = Awaited<ReturnType<MittwaldAPIV2Client["project"]["listProjects"]>>;
|
|
10
|
+
export declare class List extends ListBaseCommand<typeof GeneratedProjectListProjects, ProjectResponseItem, Response> {
|
|
11
|
+
static description: string;
|
|
12
|
+
static args: {};
|
|
13
|
+
static flags: {
|
|
14
|
+
[x: string]: import("@oclif/core/lib/interfaces/parser.js").CompletableFlag<any>;
|
|
15
|
+
};
|
|
16
|
+
getData(): Promise<Response>;
|
|
9
17
|
protected mapData(data: SuccessfulResponse<ProjectResponse, 200>["data"]): ProjectResponseItem[];
|
|
10
18
|
protected getColumns(ignoredData: ProjectResponseItem[]): ListColumns<ProjectResponseItem>;
|
|
11
19
|
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
1
|
+
import { ListBaseCommand } from "../../ListBaseCommand.js";
|
|
2
|
+
export class List extends ListBaseCommand {
|
|
3
|
+
static description = "List all projects that you have access to";
|
|
4
|
+
static args = {};
|
|
5
|
+
static flags = {
|
|
6
|
+
...ListBaseCommand.baseFlags,
|
|
7
|
+
};
|
|
8
|
+
async getData() {
|
|
9
|
+
return await this.apiClient.project.listProjects();
|
|
10
|
+
}
|
|
3
11
|
mapData(data) {
|
|
4
12
|
return data;
|
|
5
13
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseCommand } from "../../BaseCommand.js";
|
|
|
2
2
|
export default class Ssh extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static args: {
|
|
5
|
-
|
|
5
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
6
6
|
};
|
|
7
7
|
run(): Promise<void>;
|
|
8
8
|
}
|
|
@@ -7,7 +7,7 @@ export default class Ssh extends BaseCommand {
|
|
|
7
7
|
static args = { ...projectArgs };
|
|
8
8
|
async run() {
|
|
9
9
|
const { args } = await this.parse(Ssh);
|
|
10
|
-
const id = await withProjectId(this.apiClient, {}, args, this.config);
|
|
10
|
+
const id = await withProjectId(this.apiClient, Ssh, {}, args, this.config);
|
|
11
11
|
const projectResponse = await this.apiClient.project.getProject({
|
|
12
12
|
pathParameters: { id },
|
|
13
13
|
});
|
|
@@ -2,7 +2,7 @@ import { BaseCommand } from "../../BaseCommand.js";
|
|
|
2
2
|
export default class Update extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static args: {
|
|
5
|
-
|
|
5
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
6
6
|
};
|
|
7
7
|
run(): Promise<void>;
|
|
8
8
|
}
|
|
@@ -5,7 +5,7 @@ export default class Update extends BaseCommand {
|
|
|
5
5
|
static args = { ...projectArgs };
|
|
6
6
|
async run() {
|
|
7
7
|
const { args } = await this.parse(Update);
|
|
8
|
-
const id = await withProjectId(this.apiClient, {}, args, this.config);
|
|
8
|
+
const id = await withProjectId(this.apiClient, Update, {}, args, this.config);
|
|
9
9
|
console.log("updating project ", id);
|
|
10
10
|
console.log("TODO: Implement me");
|
|
11
11
|
}
|
|
@@ -25,7 +25,7 @@ export class AppInstaller {
|
|
|
25
25
|
}
|
|
26
26
|
async exec(apiClient, args, flags, config) {
|
|
27
27
|
const process = makeProcessRenderer(flags, `Installing ${this.appName}`);
|
|
28
|
-
const projectId = await withProjectId(apiClient, flags, args, config);
|
|
28
|
+
const projectId = await withProjectId(apiClient, "flag", flags, args, config);
|
|
29
29
|
await autofillFlags(apiClient, process, this.appSupportedFlags, flags, projectId, this.appName);
|
|
30
30
|
const appVersion = await normalizeToAppVersionUuid(apiClient, flags.version, process, this.appId);
|
|
31
31
|
const [appInstallationId, eventId] = await triggerAppInstallation(apiClient, process, projectId, flags, appVersion);
|
|
@@ -2,17 +2,28 @@ import { Config } from "@oclif/core";
|
|
|
2
2
|
import { Arg, ArgOutput, FlagOutput, OptionFlag } from "@oclif/core/lib/interfaces/parser.js";
|
|
3
3
|
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
4
4
|
import { AlphabetLowercase } from "@oclif/core/lib/interfaces/index.js";
|
|
5
|
-
type
|
|
6
|
-
|
|
5
|
+
type FlagIDType<N extends string> = `${N}-id`;
|
|
6
|
+
type ContextFlags<N extends string, TID extends string = FlagIDType<N>> = {
|
|
7
|
+
[k in TID]: OptionFlag<string>;
|
|
7
8
|
};
|
|
8
|
-
type ContextArgs = {
|
|
9
|
-
[k
|
|
9
|
+
type ContextArgs<N extends string, TID extends string = FlagIDType<N>> = {
|
|
10
|
+
[k in TID]: Arg<string>;
|
|
10
11
|
};
|
|
11
|
-
|
|
12
|
-
flags:
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
type CommandType<N extends string, TID extends string = FlagIDType<N>> = {
|
|
13
|
+
flags: {
|
|
14
|
+
[k in TID]: OptionFlag<string>;
|
|
15
|
+
};
|
|
16
|
+
} | {
|
|
17
|
+
args: {
|
|
18
|
+
[k in TID]: Arg<string>;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type FlagSet<TName extends string> = {
|
|
22
|
+
name: TName;
|
|
23
|
+
flags: ContextFlags<TName>;
|
|
24
|
+
args: ContextArgs<TName>;
|
|
25
|
+
withId: (apiClient: MittwaldAPIV2Client, command: CommandType<TName> | "flag" | "arg", flags: FlagOutput, args: ArgOutput, cfg: Config) => Promise<string>;
|
|
15
26
|
};
|
|
16
27
|
export type NormalizeFn = (apiClient: MittwaldAPIV2Client, id: string) => string | Promise<string>;
|
|
17
|
-
export declare function makeFlagSet(name:
|
|
28
|
+
export declare function makeFlagSet<TName extends string>(name: TName, char: AlphabetLowercase, normalize?: NormalizeFn): FlagSet<TName>;
|
|
18
29
|
export {};
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { Args, Flags } from "@oclif/core";
|
|
2
2
|
import { Context } from "./context.js";
|
|
3
|
+
class MissingFlagError extends Error {
|
|
4
|
+
constructor(name, flagName) {
|
|
5
|
+
super(`No ${name} ID given. Please specify one with --${flagName} or set a default ${name} with 'mittwald context set --${flagName} <${flagName}>'`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
class MissingArgError extends Error {
|
|
9
|
+
constructor(name, flagName) {
|
|
10
|
+
super(`No ${name} ID given. Please specify one as positional argument or set a default ${name} with 'mittwald context set --${flagName} <${flagName}>'`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
3
13
|
export function makeFlagSet(name, char, normalize = (_, id) => id) {
|
|
4
14
|
const flagName = `${name}-id`;
|
|
5
15
|
const flags = {
|
|
@@ -24,7 +34,7 @@ export function makeFlagSet(name, char, normalize = (_, id) => id) {
|
|
|
24
34
|
}
|
|
25
35
|
return undefined;
|
|
26
36
|
};
|
|
27
|
-
const withId = async (apiClient, flags, args, cfg) => {
|
|
37
|
+
const withId = async (apiClient, commandType, flags, args, cfg) => {
|
|
28
38
|
const idInput = idFromArgsOrFlag(flags, args);
|
|
29
39
|
if (idInput) {
|
|
30
40
|
return normalize(apiClient, idInput);
|
|
@@ -33,9 +43,22 @@ export function makeFlagSet(name, char, normalize = (_, id) => id) {
|
|
|
33
43
|
if (idFromContext) {
|
|
34
44
|
return idFromContext;
|
|
35
45
|
}
|
|
36
|
-
|
|
46
|
+
if (commandType === "flag") {
|
|
47
|
+
throw new MissingFlagError(name, flagName);
|
|
48
|
+
}
|
|
49
|
+
if (commandType === "arg") {
|
|
50
|
+
throw new MissingArgError(name, flagName);
|
|
51
|
+
}
|
|
52
|
+
if ("flags" in commandType && flagName in commandType.flags) {
|
|
53
|
+
throw new MissingFlagError(name, flagName);
|
|
54
|
+
}
|
|
55
|
+
if ("args" in commandType && flagName in commandType.args) {
|
|
56
|
+
throw new MissingArgError(name, flagName);
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`No ${name} ID given. Please consult the --help page of this command or set a default ${name} with 'mittwald context set --${flagName} <${flagName}>'`);
|
|
37
59
|
};
|
|
38
60
|
return {
|
|
61
|
+
name,
|
|
39
62
|
flags,
|
|
40
63
|
args,
|
|
41
64
|
withId,
|
|
@@ -35,7 +35,7 @@ export async function withMySQLId(apiClient, flags, args, cfg) {
|
|
|
35
35
|
if (isUuid(candidate)) {
|
|
36
36
|
return candidate;
|
|
37
37
|
}
|
|
38
|
-
const projectId = await withProjectId(apiClient, flags, args, cfg);
|
|
38
|
+
const projectId = await withProjectId(apiClient, "flag", flags, args, cfg);
|
|
39
39
|
const databases = await apiClient.database.listMysqlDatabases({
|
|
40
40
|
pathParameters: { projectId },
|
|
41
41
|
});
|
|
@@ -22,7 +22,7 @@ export async function withRedisId(apiClient, flags, args, cfg) {
|
|
|
22
22
|
if (isUuid(candidate)) {
|
|
23
23
|
return candidate;
|
|
24
24
|
}
|
|
25
|
-
const projectId = await withProjectId(apiClient, flags, args, cfg);
|
|
25
|
+
const projectId = await withProjectId(apiClient, "flag", flags, args, cfg);
|
|
26
26
|
const databases = await apiClient.database.listRedisDatabases({
|
|
27
27
|
pathParameters: { projectId },
|
|
28
28
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import oclif from "@oclif/core";
|
|
2
1
|
import { ApiClientError } from "@mittwald/api-client-commons";
|
|
3
|
-
import {
|
|
2
|
+
import { ExitError } from "@oclif/core/lib/errors/index.js";
|
|
4
3
|
import { renderError } from "../rendering/react/error.js";
|
|
5
4
|
export const handleError = (error) => {
|
|
6
5
|
if (!isUnexpectedError(error)) {
|
|
@@ -11,24 +10,8 @@ export const handleError = (error) => {
|
|
|
11
10
|
process.exit(error.oclif.exit);
|
|
12
11
|
return;
|
|
13
12
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
process.exit(1);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
if (error instanceof ApiClientError) {
|
|
20
|
-
const responseJson = JSON.stringify(error.response?.data, undefined, 2);
|
|
21
|
-
const errorMessage = `\
|
|
22
|
-
${error.message}
|
|
23
|
-
|
|
24
|
-
Response:
|
|
25
|
-
─────────
|
|
26
|
-
${responseJson}`;
|
|
27
|
-
error = new Error(errorMessage, {
|
|
28
|
-
cause: error,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
oclif.Errors.handle(error);
|
|
13
|
+
renderError(error);
|
|
14
|
+
process.exit(1);
|
|
32
15
|
};
|
|
33
16
|
export function isUnexpectedError(err) {
|
|
34
17
|
return !isValidationError(err);
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
export declare const orgFlags: {
|
|
2
|
-
|
|
2
|
+
"org-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
|
|
3
3
|
}, orgArgs: {
|
|
4
|
-
|
|
5
|
-
}, withOrgId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client,
|
|
4
|
+
"org-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
5
|
+
}, withOrgId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client, command: "flag" | "arg" | ({
|
|
6
|
+
flags: {
|
|
7
|
+
"org-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
|
|
8
|
+
};
|
|
9
|
+
} | {
|
|
10
|
+
args: {
|
|
11
|
+
"org-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
12
|
+
};
|
|
13
|
+
}), flags: import("@oclif/core/lib/interfaces/parser.js").FlagOutput, args: import("@oclif/core/lib/interfaces/parser.js").ArgOutput, cfg: import("@oclif/core").Config) => Promise<string>;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
export declare const projectFlags: {
|
|
2
|
-
|
|
2
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
|
|
3
3
|
}, projectArgs: {
|
|
4
|
-
|
|
5
|
-
}, withProjectId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client,
|
|
4
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
5
|
+
}, withProjectId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client, command: "flag" | "arg" | ({
|
|
6
|
+
flags: {
|
|
7
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
|
|
8
|
+
};
|
|
9
|
+
} | {
|
|
10
|
+
args: {
|
|
11
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
12
|
+
};
|
|
13
|
+
}), flags: import("@oclif/core/lib/interfaces/parser.js").FlagOutput, args: import("@oclif/core/lib/interfaces/parser.js").ArgOutput, cfg: import("@oclif/core").Config) => Promise<string>;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
export declare const serverFlags: {
|
|
2
|
-
|
|
2
|
+
"server-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
|
|
3
3
|
}, serverArgs: {
|
|
4
|
-
|
|
5
|
-
}, withServerId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client,
|
|
4
|
+
"server-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
5
|
+
}, withServerId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client, command: "flag" | "arg" | ({
|
|
6
|
+
flags: {
|
|
7
|
+
"server-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
|
|
8
|
+
};
|
|
9
|
+
} | {
|
|
10
|
+
args: {
|
|
11
|
+
"server-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
12
|
+
};
|
|
13
|
+
}), flags: import("@oclif/core/lib/interfaces/parser.js").FlagOutput, args: import("@oclif/core/lib/interfaces/parser.js").ArgOutput, cfg: import("@oclif/core").Config) => Promise<string>;
|
|
@@ -4,12 +4,22 @@ import { render, Text } from "ink";
|
|
|
4
4
|
import { RenderContextProvider } from "./context.js";
|
|
5
5
|
import { ExtendedBaseCommand } from "../../ExtendedBaseCommand.js";
|
|
6
6
|
const RenderComponent = (p) => (_jsx(_Fragment, { children: p.render() }));
|
|
7
|
+
function wrapRender(fn) {
|
|
8
|
+
return (result) => {
|
|
9
|
+
const innerResult = fn(result);
|
|
10
|
+
if (typeof innerResult === "string") {
|
|
11
|
+
return _jsx(Text, { children: innerResult });
|
|
12
|
+
}
|
|
13
|
+
return innerResult;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
7
16
|
export class ExecRenderBaseCommand extends ExtendedBaseCommand {
|
|
8
17
|
async run() {
|
|
9
18
|
const result = await this.exec();
|
|
19
|
+
const wrappedRender = wrapRender(this.render.bind(this));
|
|
10
20
|
render(_jsx(RenderContextProvider, { value: {
|
|
11
21
|
apiClient: this.apiClient,
|
|
12
22
|
renderAsJson: false,
|
|
13
|
-
}, children: _jsx(Suspense, { fallback: _jsx(Text, { children: "Loading..." }), children: _jsx(RenderComponent, { render: () =>
|
|
23
|
+
}, children: _jsx(Suspense, { fallback: _jsx(Text, { children: "Loading..." }), children: _jsx(RenderComponent, { render: () => wrappedRender(result) }) }) }));
|
|
14
24
|
}
|
|
15
25
|
}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import Link from "ink-link";
|
|
4
4
|
import { FailedFlagValidationError, RequiredArgsError, } from "@oclif/core/lib/parser/errors.js";
|
|
5
|
+
import { ApiClientError, } from "@mittwald/api-client-commons";
|
|
5
6
|
const color = "red";
|
|
6
7
|
const issueURL = "https://github.com/mittwald/cli/issues/new";
|
|
7
8
|
const boxProps = {
|
|
@@ -12,8 +13,11 @@ const boxProps = {
|
|
|
12
13
|
paddingX: 1,
|
|
13
14
|
rowGap: 1,
|
|
14
15
|
};
|
|
16
|
+
const ErrorStack = ({ err }) => {
|
|
17
|
+
return (_jsxs(Box, { marginX: 2, marginY: 1, flexDirection: "column", rowGap: 1, children: [_jsx(Text, { color: color, dimColor: true, bold: true, children: "ERROR STACK TRACE" }), _jsx(Text, { color: color, dimColor: true, children: "Please provide this when opening a bug report." }), _jsx(Text, { color: color, dimColor: true, children: err.stack })] }));
|
|
18
|
+
};
|
|
15
19
|
const GenericError = ({ err, withStack, }) => {
|
|
16
|
-
return (_jsxs(_Fragment, { children: [_jsxs(Box, { ...boxProps, borderColor: color, children: [_jsx(Text, { color: color, bold: true, underline: true, children: "ERROR" }), _jsx(Text, { color: color, children: "An error occurred while executing this command:" }), _jsx(Box, { marginX: 2, children: _jsx(Text, { color: color, children: err.toString() }) }), _jsxs(Text, { color: color, children: ["If you believe this to be a bug, please open an issue at", " ", _jsx(Link, { url: issueURL, children: issueURL }), "."] })] }), withStack && "stack" in err ?
|
|
20
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Box, { ...boxProps, borderColor: color, children: [_jsx(Text, { color: color, bold: true, underline: true, children: "ERROR" }), _jsx(Text, { color: color, children: "An error occurred while executing this command:" }), _jsx(Box, { marginX: 2, children: _jsx(Text, { color: color, children: err.toString() }) }), _jsxs(Text, { color: color, children: ["If you believe this to be a bug, please open an issue at", " ", _jsx(Link, { url: issueURL, children: issueURL }), "."] })] }), withStack && "stack" in err ? _jsx(ErrorStack, { err: err }) : undefined] }));
|
|
17
21
|
};
|
|
18
22
|
const InvalidFlagsError = ({ err }) => {
|
|
19
23
|
const color = "yellow";
|
|
@@ -23,6 +27,25 @@ const InvalidArgsError = ({ err }) => {
|
|
|
23
27
|
const color = "yellow";
|
|
24
28
|
return (_jsxs(Box, { ...boxProps, borderColor: color, children: [_jsx(Text, { color: color, bold: true, underline: true, children: "INVALID COMMAND ARGUMENTS" }), _jsxs(Text, { color: color, children: ["The arguments that you provided for this command were invalid.", " ", err.message] })] }));
|
|
25
29
|
};
|
|
30
|
+
const RequestHeaders = ({ headers }) => {
|
|
31
|
+
const lines = headers.trim().split("\r\n");
|
|
32
|
+
const requestLine = lines.shift();
|
|
33
|
+
const values = lines.map((line) => line.split(": ", 2));
|
|
34
|
+
const maxKeyLength = Math.max(...values.map(([key]) => key.length));
|
|
35
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, underline: true, children: requestLine }), values.map(([key, value]) => (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { dimColor: true, children: [key.toLowerCase().padEnd(maxKeyLength, " "), " "] }), _jsx(Text, { bold: true, children: key === "x-access-token" ? "[redacted]" : value })] }, key)))] }));
|
|
36
|
+
};
|
|
37
|
+
const Response = ({ status, statusText, body, headers }) => {
|
|
38
|
+
const keys = Object.keys(headers);
|
|
39
|
+
const maxKeyLength = Math.max(...keys.map((key) => key.length));
|
|
40
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, underline: true, children: [status, " ", statusText] }, "status"), keys.map((key) => (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { dimColor: true, children: [key.toLowerCase().padEnd(maxKeyLength, " "), " "] }), _jsx(Text, { bold: true, children: key === "x-access-token" ? "[redacted]" : headers[key] })] }, key))), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: JSON.stringify(body, undefined, 2) }) }, "body")] }));
|
|
41
|
+
};
|
|
42
|
+
const HttpMessages = ({ err }) => {
|
|
43
|
+
const response = err.response ? (_jsx(Response, { status: err.response.status, statusText: err.response.statusText, body: err.response.data, headers: err.response.headers })) : (_jsx(Text, { children: "no response received" }));
|
|
44
|
+
return (_jsxs(Box, { marginX: 2, marginY: 1, flexDirection: "column", rowGap: 1, children: [_jsx(RequestHeaders, { headers: err.request._header }), response] }));
|
|
45
|
+
};
|
|
46
|
+
const ApiError = ({ err, withStack, withHTTPMessages }) => {
|
|
47
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Box, { ...boxProps, children: [_jsx(Text, { color: color, bold: true, underline: true, children: "API CLIENT ERROR" }), _jsxs(Text, { color: color, children: ["An error occurred while communicating with the API: ", err.message] }), _jsx(Text, { children: JSON.stringify(err.response?.data, undefined, 2) })] }), withHTTPMessages === "full" ? _jsx(HttpMessages, { err: err }) : undefined, withStack && "stack" in err ? _jsx(ErrorStack, { err: err }) : undefined] }));
|
|
48
|
+
};
|
|
26
49
|
/**
|
|
27
50
|
* Render an error to the terminal.
|
|
28
51
|
*
|
|
@@ -37,6 +60,9 @@ export const ErrorBox = ({ err }) => {
|
|
|
37
60
|
else if (err instanceof RequiredArgsError) {
|
|
38
61
|
return _jsx(InvalidArgsError, { err: err });
|
|
39
62
|
}
|
|
63
|
+
else if (err instanceof ApiClientError) {
|
|
64
|
+
return _jsx(ApiError, { err: err, withStack: true, withHTTPMessages: "body" });
|
|
65
|
+
}
|
|
40
66
|
else if (err instanceof Error) {
|
|
41
67
|
return _jsx(GenericError, { err: err, withStack: true });
|
|
42
68
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mittwald/cli",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.21",
|
|
4
4
|
"description": "Hand-crafted CLI for the mittwald API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -118,7 +118,15 @@
|
|
|
118
118
|
"topicSeparator": " ",
|
|
119
119
|
"topics": {
|
|
120
120
|
"app": {
|
|
121
|
-
"description": "Manage apps, and app installations in your projects"
|
|
121
|
+
"description": "Manage apps, and app installations in your projects",
|
|
122
|
+
"subtopics": {
|
|
123
|
+
"install": {
|
|
124
|
+
"description": "Install apps in your projects"
|
|
125
|
+
},
|
|
126
|
+
"dependency": {
|
|
127
|
+
"description": "Manage the system dependencies of your apps"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
122
130
|
},
|
|
123
131
|
"article": {
|
|
124
132
|
"description": "Query available hosting articles"
|
|
@@ -148,7 +156,33 @@
|
|
|
148
156
|
"description": "Manage your organizations, and also any kinds of user memberships concerning these organizations."
|
|
149
157
|
},
|
|
150
158
|
"project": {
|
|
151
|
-
"description": "Manage your projects, and also any kinds of user memberships concerning these projects."
|
|
159
|
+
"description": "Manage your projects, and also any kinds of user memberships concerning these projects.",
|
|
160
|
+
"subtopics": {
|
|
161
|
+
"backup": {
|
|
162
|
+
"description": "Manage backups of your projects"
|
|
163
|
+
},
|
|
164
|
+
"backupschedule": {
|
|
165
|
+
"description": "Manage backup schedules of your projects"
|
|
166
|
+
},
|
|
167
|
+
"cronjob": {
|
|
168
|
+
"description": "Manage cronjobs of your projects"
|
|
169
|
+
},
|
|
170
|
+
"filesystem": {
|
|
171
|
+
"description": "Interact with the filesystem of your project"
|
|
172
|
+
},
|
|
173
|
+
"invite": {
|
|
174
|
+
"description": "Invite users to your projects and manage their invitations"
|
|
175
|
+
},
|
|
176
|
+
"membership": {
|
|
177
|
+
"description": "Control who gets to work on your projects, and who doesn't"
|
|
178
|
+
},
|
|
179
|
+
"sftp-user": {
|
|
180
|
+
"description": "Manage SFTP users of your projects"
|
|
181
|
+
},
|
|
182
|
+
"ssh-user": {
|
|
183
|
+
"description": "Manage SSH users of your projects"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
152
186
|
},
|
|
153
187
|
"server": {
|
|
154
188
|
"description": "Manage your servers"
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { RenderBaseCommand } from "../../rendering/react/RenderBaseCommand.js";
|
|
3
|
-
export default class List extends RenderBaseCommand<typeof List> {
|
|
4
|
-
static flags: {
|
|
5
|
-
columns: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
6
|
-
extended: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
7
|
-
noTruncate: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
|
-
wait: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<any>;
|
|
9
|
-
};
|
|
10
|
-
protected render(): React.ReactNode;
|
|
11
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { assertStatus } from "@mittwald/api-client-commons";
|
|
3
|
-
import { usePromise } from "@mittwald/react-use-promise";
|
|
4
|
-
import { RenderBaseCommand } from "../../rendering/react/RenderBaseCommand.js";
|
|
5
|
-
import { useRenderContext } from "../../rendering/react/context.js";
|
|
6
|
-
import { Table } from "../../rendering/react/components/Table/index.js";
|
|
7
|
-
import { UsePromiseRenderSetup } from "../../rendering/setup/usePromiseSetup.js";
|
|
8
|
-
import { TableRenderSetup } from "../../rendering/setup/TableRenderSetup.js";
|
|
9
|
-
import { ProjectStatus } from "../../rendering/react/components/Project/ProjectStatus.js";
|
|
10
|
-
const usePromiseSetup = new UsePromiseRenderSetup();
|
|
11
|
-
const tableSetupInstance = new TableRenderSetup();
|
|
12
|
-
export default class List extends RenderBaseCommand {
|
|
13
|
-
static flags = {
|
|
14
|
-
...usePromiseSetup.flags,
|
|
15
|
-
...tableSetupInstance.flags,
|
|
16
|
-
...RenderBaseCommand.buildFlags(),
|
|
17
|
-
};
|
|
18
|
-
render() {
|
|
19
|
-
const { apiClient } = useRenderContext();
|
|
20
|
-
const tableSetup = tableSetupInstance.getSetup(this.flags);
|
|
21
|
-
const usePromiseOptions = usePromiseSetup.getSetup(this.flags);
|
|
22
|
-
const projects = usePromise(apiClient.project.listProjects, [], usePromiseOptions);
|
|
23
|
-
assertStatus(projects, 200);
|
|
24
|
-
return (_jsx(Table, { data: projects.data, setup: tableSetup, columns: {
|
|
25
|
-
id: {
|
|
26
|
-
isUuid: true,
|
|
27
|
-
},
|
|
28
|
-
shortId: {
|
|
29
|
-
minWidth: 8,
|
|
30
|
-
},
|
|
31
|
-
customerId: {
|
|
32
|
-
isUuid: true,
|
|
33
|
-
extended: true,
|
|
34
|
-
},
|
|
35
|
-
description: {},
|
|
36
|
-
status: {
|
|
37
|
-
render: (project) => _jsx(ProjectStatus, { project: project }),
|
|
38
|
-
},
|
|
39
|
-
createdAt: {},
|
|
40
|
-
} }));
|
|
41
|
-
}
|
|
42
|
-
}
|