@mittwald/cli 1.0.0-alpha.19 → 1.0.0-alpha.20
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 +889 -56
- package/dist/esm/commands/app/install/contao.d.ts +11 -0
- package/dist/esm/commands/app/install/contao.js +24 -0
- package/dist/esm/commands/app/install/joomla.d.ts +11 -0
- package/dist/esm/commands/app/install/joomla.js +23 -0
- package/dist/esm/commands/app/install/matomo.d.ts +11 -0
- package/dist/esm/commands/app/install/matomo.js +21 -0
- package/dist/esm/commands/app/install/node.d.ts +11 -0
- package/dist/esm/commands/app/install/node.js +13 -0
- package/dist/esm/commands/app/install/php.d.ts +11 -0
- package/dist/esm/commands/app/install/php.js +13 -0
- package/dist/esm/commands/app/install/shopware5.d.ts +11 -0
- package/dist/esm/commands/app/install/shopware5.js +26 -0
- package/dist/esm/commands/app/install/shopware6.d.ts +11 -0
- package/dist/esm/commands/app/install/shopware6.js +26 -0
- package/dist/esm/commands/app/install/typo3.d.ts +11 -0
- package/dist/esm/commands/app/install/typo3.js +22 -0
- package/dist/esm/commands/app/install/wordpress.d.ts +4 -16
- package/dist/esm/commands/app/install/wordpress.js +16 -107
- package/dist/esm/commands/app/versions.js +1 -1
- package/dist/esm/commands/org/invite.d.ts +1 -2
- package/dist/esm/commands/org/invite.js +3 -16
- package/dist/esm/commands/project/backup/create.d.ts +18 -0
- package/dist/esm/commands/project/backup/create.js +59 -0
- package/dist/esm/commands/project/backup/delete.d.ts +13 -0
- package/dist/esm/commands/project/backup/delete.js +21 -0
- package/dist/esm/commands/project/backup/download.d.ts +27 -0
- package/dist/esm/commands/project/backup/download.js +177 -0
- package/dist/esm/commands/project/backup/get.d.ts +11 -2
- package/dist/esm/commands/project/backup/get.js +26 -5
- package/dist/esm/commands/project/backup/list.d.ts +9 -9
- package/dist/esm/commands/project/backupschedule/list.d.ts +13 -7
- package/dist/esm/commands/project/backupschedule/list.js +15 -7
- package/dist/esm/commands/project/create.d.ts +2 -1
- package/dist/esm/commands/project/create.js +3 -6
- package/dist/esm/lib/app/Installer.d.ts +21 -0
- package/dist/esm/lib/app/Installer.js +49 -0
- package/dist/esm/lib/app/flags.d.ts +25 -0
- package/dist/esm/lib/app/flags.js +190 -1
- package/dist/esm/lib/app/install.d.ts +4 -0
- package/dist/esm/lib/app/install.js +20 -0
- package/dist/esm/lib/app/{appVersionHelpers.d.ts → versions.d.ts} +3 -0
- package/dist/esm/lib/app/{appVersionHelpers.js → versions.js} +18 -0
- package/dist/esm/lib/app/wait.d.ts +3 -0
- package/dist/esm/lib/app/wait.js +19 -0
- package/dist/esm/lib/expires.d.ts +11 -0
- package/dist/esm/lib/expires.js +31 -0
- package/dist/esm/lib/password.d.ts +2 -0
- package/dist/esm/lib/password.js +20 -0
- package/dist/esm/lib/project/hooks.d.ts +3 -0
- package/dist/esm/lib/project/hooks.js +11 -0
- package/dist/esm/lib/project/ingress.d.ts +2 -0
- package/dist/esm/lib/project/ingress.js +16 -0
- package/dist/esm/lib/project/shortId.d.ts +2 -0
- package/dist/esm/lib/project/shortId.js +11 -0
- package/dist/esm/lib/projectbackup/hooks.d.ts +5 -0
- package/dist/esm/lib/projectbackup/hooks.js +19 -0
- package/dist/esm/lib/viewhelpers/size.d.ts +2 -1
- package/dist/esm/lib/viewhelpers/size.js +2 -2
- package/dist/esm/lib/wait.d.ts +4 -0
- package/dist/esm/lib/wait.js +13 -2
- package/dist/esm/rendering/process/components/ProcessStateSummary.js +3 -0
- package/dist/esm/rendering/process/process.d.ts +2 -0
- package/dist/esm/rendering/process/process.js +4 -0
- package/dist/esm/rendering/react/components/ProjectBackup/ProjectBackupDetails.d.ts +6 -0
- package/dist/esm/rendering/react/components/ProjectBackup/ProjectBackupDetails.js +29 -0
- package/dist/esm/rendering/react/components/ProjectBackup/ProjectBackupStatus.d.ts +6 -0
- package/dist/esm/rendering/react/components/ProjectBackup/ProjectBackupStatus.js +8 -0
- package/package.json +1 -1
- package/dist/esm/commands/project/backupschedule/get.d.ts +0 -3
- package/dist/esm/commands/project/backupschedule/get.js +0 -6
- package/dist/esm/generated/backup/getProjectBackup.d.ts +0 -16
- package/dist/esm/generated/backup/getProjectBackup.js +0 -25
- package/dist/esm/generated/backup/getProjectBackupSchedule.d.ts +0 -16
- package/dist/esm/generated/backup/getProjectBackupSchedule.js +0 -25
- package/dist/esm/generated/backup/listProjectBackupSchedules.d.ts +0 -13
- package/dist/esm/generated/backup/listProjectBackupSchedules.js +0 -24
- package/dist/esm/generated/backup/listProjectBackups.d.ts +0 -13
- package/dist/esm/generated/backup/listProjectBackups.js +0 -24
- /package/dist/esm/lib/app/{appHelpers.d.ts → uuid.d.ts} +0 -0
- /package/dist/esm/lib/app/{appHelpers.js → uuid.js} +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ExecRenderBaseCommand } from "../../../rendering/react/ExecRenderBaseCommand.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { ProcessRenderer } from "../../../rendering/process/process.js";
|
|
4
|
+
import { AxiosResponseHeaders, RawAxiosResponseHeaders } from "@mittwald/api-client-commons";
|
|
5
|
+
type Result = {
|
|
6
|
+
outputFilename: string;
|
|
7
|
+
};
|
|
8
|
+
export declare class Download extends ExecRenderBaseCommand<typeof Download, Result> {
|
|
9
|
+
static description: string;
|
|
10
|
+
static args: {
|
|
11
|
+
"backup-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
static flags: {
|
|
14
|
+
output: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
15
|
+
format: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
16
|
+
password: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
17
|
+
"generate-password": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
18
|
+
"prompt-password": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
19
|
+
resume: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
20
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
21
|
+
};
|
|
22
|
+
protected getPassword(p: ProcessRenderer): Promise<string | undefined>;
|
|
23
|
+
protected exec(): Promise<Result>;
|
|
24
|
+
protected getFilename(headers: RawAxiosResponseHeaders | AxiosResponseHeaders): string;
|
|
25
|
+
protected render(executionResult: Result): ReactNode;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ExecRenderBaseCommand } from "../../../rendering/react/ExecRenderBaseCommand.js";
|
|
3
|
+
import { Args, Flags } from "@oclif/core";
|
|
4
|
+
import { makeProcessRenderer, processFlags, } from "../../../rendering/process/process_flags.js";
|
|
5
|
+
import crypto from "crypto";
|
|
6
|
+
import { Text } from "ink";
|
|
7
|
+
import { Value } from "../../../rendering/react/components/Value.js";
|
|
8
|
+
import { assertStatus, } from "@mittwald/api-client-commons";
|
|
9
|
+
import { waitUntil } from "../../../lib/wait.js";
|
|
10
|
+
import axios from "axios";
|
|
11
|
+
import * as fs from "fs";
|
|
12
|
+
import { formatBytes } from "../../../lib/viewhelpers/size.js";
|
|
13
|
+
import { Success } from "../../../rendering/react/components/Success.js";
|
|
14
|
+
export class Download extends ExecRenderBaseCommand {
|
|
15
|
+
static description = "Download a backup to your local disk";
|
|
16
|
+
static args = {
|
|
17
|
+
"backup-id": Args.string({
|
|
18
|
+
required: true,
|
|
19
|
+
description: "the ID of the Backup to download.",
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
static flags = {
|
|
23
|
+
...processFlags,
|
|
24
|
+
output: Flags.string({
|
|
25
|
+
description: "the file to write the backup to; if omitted, the filename will be determined by the server.",
|
|
26
|
+
}),
|
|
27
|
+
format: Flags.string({
|
|
28
|
+
description: "the file format to download the backup in.",
|
|
29
|
+
options: ["tar", "zip"],
|
|
30
|
+
default: "tar",
|
|
31
|
+
}),
|
|
32
|
+
password: Flags.string({
|
|
33
|
+
summary: "the password to encrypt the backup with.",
|
|
34
|
+
description: `\
|
|
35
|
+
CAUTION #1: this is not stored anywhere.
|
|
36
|
+
CAUTION #2: it is dangerous to use this option, as the password might be stored in your shell history.`,
|
|
37
|
+
exclusive: ["generate-password", "prompt-password"],
|
|
38
|
+
}),
|
|
39
|
+
"generate-password": Flags.boolean({
|
|
40
|
+
summary: "generate a random password to encrypt the backup with.",
|
|
41
|
+
description: "CAUTION: this is not stored anywhere.",
|
|
42
|
+
exclusive: ["password", "prompt-password"],
|
|
43
|
+
}),
|
|
44
|
+
"prompt-password": Flags.boolean({
|
|
45
|
+
summary: "prompt for a password to encrypt the backup with.",
|
|
46
|
+
description: "CAUTION: this is not stored anywhere.",
|
|
47
|
+
exclusive: ["password", "generate-password"],
|
|
48
|
+
}),
|
|
49
|
+
resume: Flags.boolean({
|
|
50
|
+
summary: "resume a previously interrupted download.",
|
|
51
|
+
dependsOn: ["output"],
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
async getPassword(p) {
|
|
55
|
+
if (this.flags.password) {
|
|
56
|
+
return this.flags.password;
|
|
57
|
+
}
|
|
58
|
+
if (this.flags["generate-password"]) {
|
|
59
|
+
const password = await p.runStep("generating password", async () => {
|
|
60
|
+
return crypto.randomBytes(32).toString("ascii").substring(0, 32);
|
|
61
|
+
});
|
|
62
|
+
p.addInfo(_jsxs(Text, { children: ["generated password: ", _jsx(Value, { children: password })] }));
|
|
63
|
+
return password;
|
|
64
|
+
}
|
|
65
|
+
if (this.flags["prompt-password"]) {
|
|
66
|
+
return await p.addInput(_jsx(Text, { children: "enter backup password" }), true);
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
async exec() {
|
|
71
|
+
const p = makeProcessRenderer(this.flags, "Downloading backup");
|
|
72
|
+
const projectBackupId = this.args["backup-id"];
|
|
73
|
+
const { format } = this.flags;
|
|
74
|
+
const password = await this.getPassword(p);
|
|
75
|
+
const backup = await p.runStep("fetching backup", async () => {
|
|
76
|
+
const r = await this.apiClient.backup.getProjectBackup({
|
|
77
|
+
pathParameters: { projectBackupId },
|
|
78
|
+
});
|
|
79
|
+
assertStatus(r, 200);
|
|
80
|
+
return r.data;
|
|
81
|
+
});
|
|
82
|
+
if (backup.export && backup.export.phase !== "Expired") {
|
|
83
|
+
p.addInfo(_jsx(Text, { children: "backup download is already prepared" }));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
await p.runStep("preparing backup download", async () => {
|
|
87
|
+
const r = await this.apiClient.backup.createProjectBackupExport({
|
|
88
|
+
pathParameters: { projectBackupId },
|
|
89
|
+
data: {
|
|
90
|
+
format: format,
|
|
91
|
+
password,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
assertStatus(r, 204);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const backupExport = await p.runStep("waiting for backup download to be ready", () => {
|
|
98
|
+
return waitUntil(async () => {
|
|
99
|
+
const r = await this.apiClient.backup.getProjectBackup({
|
|
100
|
+
pathParameters: { projectBackupId },
|
|
101
|
+
});
|
|
102
|
+
assertStatus(r, 200);
|
|
103
|
+
if (r.data.export?.phase === "Completed") {
|
|
104
|
+
return r.data.export;
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}, 3600);
|
|
108
|
+
});
|
|
109
|
+
if (!backupExport.downloadURL) {
|
|
110
|
+
throw new Error("backup download is not ready");
|
|
111
|
+
}
|
|
112
|
+
const reqConfig = { responseType: "stream" };
|
|
113
|
+
if (this.flags.resume &&
|
|
114
|
+
this.flags.output &&
|
|
115
|
+
fs.existsSync(this.flags.output)) {
|
|
116
|
+
const stat = fs.statSync(this.flags.output);
|
|
117
|
+
const range = `bytes=${stat.size}-`;
|
|
118
|
+
reqConfig.headers = { Range: range };
|
|
119
|
+
p.addInfo(_jsxs(Text, { children: ["resuming download starting at ", _jsx(Value, { children: stat.size }), " bytes"] }));
|
|
120
|
+
}
|
|
121
|
+
const downloadStep = p.addStep("downloading backup");
|
|
122
|
+
const resp = await axios(backupExport.downloadURL, reqConfig);
|
|
123
|
+
const size = parseInt(resp.headers["content-length"] || "0", 10);
|
|
124
|
+
let downloaded = 0;
|
|
125
|
+
const outputFilename = this.getFilename(resp.headers);
|
|
126
|
+
const outputStream = fs.createWriteStream(outputFilename, {
|
|
127
|
+
flags: this.flags.resume ? "a" : undefined,
|
|
128
|
+
});
|
|
129
|
+
resp.data.on("data", (chunk) => {
|
|
130
|
+
downloaded += chunk.length;
|
|
131
|
+
downloadStep.progress(formatBytes(downloaded, {
|
|
132
|
+
minimumFractionDigits: 2,
|
|
133
|
+
maximumFractionDigits: 2,
|
|
134
|
+
}) +
|
|
135
|
+
" of " +
|
|
136
|
+
formatBytes(size, {
|
|
137
|
+
minimumFractionDigits: 2,
|
|
138
|
+
maximumFractionDigits: 2,
|
|
139
|
+
}));
|
|
140
|
+
outputStream.write(chunk);
|
|
141
|
+
});
|
|
142
|
+
await new Promise((res) => {
|
|
143
|
+
resp.data.on("end", () => {
|
|
144
|
+
downloadStep.complete();
|
|
145
|
+
res();
|
|
146
|
+
});
|
|
147
|
+
resp.data.on("error", (err) => {
|
|
148
|
+
downloadStep.error(err);
|
|
149
|
+
res();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
p.complete(_jsxs(Success, { children: ["The backup was successfully downloaded to", " ", _jsx(Value, { children: outputFilename })] }));
|
|
153
|
+
return { outputFilename };
|
|
154
|
+
}
|
|
155
|
+
getFilename(headers) {
|
|
156
|
+
if (this.flags.output) {
|
|
157
|
+
return this.flags.output;
|
|
158
|
+
}
|
|
159
|
+
const disposition = headers["content-disposition"];
|
|
160
|
+
if (disposition) {
|
|
161
|
+
const match = disposition.match(/filename=("?)(.*)\1/);
|
|
162
|
+
if (match) {
|
|
163
|
+
return match[2];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (this.flags.format === "tar") {
|
|
167
|
+
return "backup.tar.gz";
|
|
168
|
+
}
|
|
169
|
+
return "backup.zip";
|
|
170
|
+
}
|
|
171
|
+
render(executionResult) {
|
|
172
|
+
if (this.flags.quiet) {
|
|
173
|
+
return executionResult.outputFilename;
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { RenderBaseCommand } from "../../../rendering/react/RenderBaseCommand.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
export default class Get extends RenderBaseCommand<typeof Get> {
|
|
4
|
+
static description: string;
|
|
5
|
+
static args: {
|
|
6
|
+
"backup-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
[x: string]: import("@oclif/core/lib/interfaces/parser.js").CompletableFlag<any>;
|
|
10
|
+
};
|
|
11
|
+
protected render(): ReactNode;
|
|
3
12
|
}
|
|
@@ -1,6 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { RenderBaseCommand } from "../../../rendering/react/RenderBaseCommand.js";
|
|
3
|
+
import { useProjectBackup } from "../../../lib/projectbackup/hooks.js";
|
|
4
|
+
import { Args } from "@oclif/core";
|
|
5
|
+
import { ProjectBackupDetails } from "../../../rendering/react/components/ProjectBackup/ProjectBackupDetails.js";
|
|
6
|
+
import { RenderJson } from "../../../rendering/react/json/RenderJson.js";
|
|
7
|
+
import { GetBaseCommand } from "../../../GetBaseCommand.js";
|
|
8
|
+
import { Box } from "ink";
|
|
9
|
+
export default class Get extends RenderBaseCommand {
|
|
10
|
+
static description = "show details of a backup.";
|
|
11
|
+
static args = {
|
|
12
|
+
"backup-id": Args.string({
|
|
13
|
+
required: true,
|
|
14
|
+
description: "The ID of the Backup to show.",
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
static flags = {
|
|
18
|
+
...GetBaseCommand.baseFlags,
|
|
19
|
+
};
|
|
20
|
+
render() {
|
|
21
|
+
const projectBackup = useProjectBackup(this.args["backup-id"]);
|
|
22
|
+
if (this.flags.output === "json") {
|
|
23
|
+
return _jsx(RenderJson, { name: "projectBackup", data: projectBackup });
|
|
24
|
+
}
|
|
25
|
+
return (_jsx(Box, { marginBottom: 1, children: _jsx(ProjectBackupDetails, { projectBackup: projectBackup }) }));
|
|
26
|
+
}
|
|
6
27
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { Simplify } from "@mittwald/api-client-commons";
|
|
2
|
-
import { MittwaldAPIV2
|
|
1
|
+
import { Response, Simplify } from "@mittwald/api-client-commons";
|
|
2
|
+
import { MittwaldAPIV2 } from "@mittwald/api-client";
|
|
3
3
|
import { SuccessfulResponse } from "../../../types.js";
|
|
4
4
|
import { ListBaseCommand } from "../../../ListBaseCommand.js";
|
|
5
5
|
import { ListColumns } from "../../../Formatter.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export declare class List extends ListBaseCommand<typeof List,
|
|
6
|
+
import BackupProjectBackup = MittwaldAPIV2.Components.Schemas.BackupProjectBackup;
|
|
7
|
+
type ListResponse = Response<BackupProjectBackup[]>;
|
|
8
|
+
type ListItem = Simplify<BackupProjectBackup>;
|
|
9
|
+
export declare class List extends ListBaseCommand<typeof List, ListItem, ListResponse> {
|
|
10
10
|
static description: string;
|
|
11
11
|
static args: {};
|
|
12
12
|
static flags: {
|
|
13
13
|
[x: string]: import("@oclif/core/lib/interfaces/parser.js").CompletableFlag<any> | import("@oclif/core/lib/interfaces/parser.js").OptionFlag<unknown>;
|
|
14
14
|
};
|
|
15
|
-
protected mapData(data: SuccessfulResponse<
|
|
16
|
-
getData(): Promise<
|
|
17
|
-
protected getColumns(data:
|
|
15
|
+
protected mapData(data: SuccessfulResponse<ListResponse, 200>["data"]): ListItem[] | Promise<ListItem[]>;
|
|
16
|
+
getData(): Promise<ListResponse>;
|
|
17
|
+
protected getColumns(data: ListItem[]): ListColumns<ListItem>;
|
|
18
18
|
}
|
|
19
19
|
export {};
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { Simplify } from "@mittwald/api-client-commons";
|
|
2
|
-
import { MittwaldAPIV2 } from "@mittwald/api-client";
|
|
2
|
+
import { MittwaldAPIV2, MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
3
3
|
import { SuccessfulResponse } from "../../../types.js";
|
|
4
|
-
import { GeneratedBackupListProjectBackupSchedules, Response } from "../../../generated/backup/listProjectBackupSchedules.js";
|
|
5
|
-
import { PathParams } from "../../../generated/backup/listProjectBackups.js";
|
|
6
4
|
import { ListColumns } from "../../../Formatter.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
import { ListBaseCommand } from "../../../ListBaseCommand.js";
|
|
6
|
+
import BackupProjectBackupSchedule = MittwaldAPIV2.Components.Schemas.BackupProjectBackupSchedule;
|
|
7
|
+
type ResponseItem = Simplify<BackupProjectBackupSchedule>;
|
|
8
|
+
type Response = Awaited<ReturnType<MittwaldAPIV2Client["backup"]["listProjectBackupSchedules"]>>;
|
|
9
|
+
export declare class List extends ListBaseCommand<typeof List, ResponseItem, Response> {
|
|
10
|
+
static description: string;
|
|
11
|
+
static args: {};
|
|
12
|
+
static flags: {
|
|
13
|
+
[x: string]: import("@oclif/core/lib/interfaces/parser.js").CompletableFlag<any> | import("@oclif/core/lib/interfaces/parser.js").OptionFlag<unknown>;
|
|
14
|
+
};
|
|
15
|
+
getData(): Promise<Response>;
|
|
16
|
+
protected mapData(data: SuccessfulResponse<Response, 200>["data"]): BackupProjectBackupSchedule[];
|
|
11
17
|
protected getColumns(data: ResponseItem[]): ListColumns<ResponseItem>;
|
|
12
18
|
}
|
|
13
19
|
export {};
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export
|
|
1
|
+
import { ListBaseCommand } from "../../../ListBaseCommand.js";
|
|
2
|
+
import { projectFlags, withProjectId } from "../../../lib/project/flags.js";
|
|
3
|
+
export class List extends ListBaseCommand {
|
|
4
|
+
static description = "List backup schedules belonging to a given project.";
|
|
5
|
+
static args = {};
|
|
6
|
+
static flags = {
|
|
7
|
+
...ListBaseCommand.baseFlags,
|
|
8
|
+
...projectFlags,
|
|
9
|
+
};
|
|
10
|
+
async getData() {
|
|
11
|
+
const projectId = await withProjectId(this.apiClient, this.flags, this.args, this.config);
|
|
12
|
+
return await this.apiClient.backup.listProjectBackupSchedules({
|
|
13
|
+
pathParameters: { projectId },
|
|
14
|
+
});
|
|
15
|
+
}
|
|
4
16
|
mapData(data) {
|
|
5
17
|
return data;
|
|
6
18
|
}
|
|
7
|
-
async mapParams(input) {
|
|
8
|
-
input.projectId = await normalizeProjectIdToUuid(this.apiClient, input.projectId);
|
|
9
|
-
return super.mapParams(input);
|
|
10
|
-
}
|
|
11
19
|
getColumns(data) {
|
|
12
20
|
const baseColumns = super.getColumns(data);
|
|
13
21
|
return {
|
|
@@ -6,8 +6,9 @@ export default class Create extends ExecRenderBaseCommand<typeof Create, {
|
|
|
6
6
|
static description: string;
|
|
7
7
|
static flags: {
|
|
8
8
|
description: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
9
|
-
wait: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
9
|
"update-context": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
|
+
wait: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
|
+
"wait-timeout": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
11
12
|
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
12
13
|
};
|
|
13
14
|
protected exec(): Promise<{
|
|
@@ -7,22 +7,19 @@ import { Text } from "ink";
|
|
|
7
7
|
import { Success } from "../../rendering/react/components/Success.js";
|
|
8
8
|
import { Value } from "../../rendering/react/components/Value.js";
|
|
9
9
|
import { makeProcessRenderer, processFlags, } from "../../rendering/process/process_flags.js";
|
|
10
|
-
import { waitUntil } from "../../lib/wait.js";
|
|
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
13
|
static description = "Get the details of a project";
|
|
14
14
|
static flags = {
|
|
15
15
|
...serverFlags,
|
|
16
16
|
...processFlags,
|
|
17
|
+
...waitFlags,
|
|
17
18
|
description: Flags.string({
|
|
18
19
|
char: "d",
|
|
19
20
|
required: true,
|
|
20
21
|
description: "A description for the project.",
|
|
21
22
|
}),
|
|
22
|
-
wait: Flags.boolean({
|
|
23
|
-
char: "w",
|
|
24
|
-
description: "Wait for the project to be ready.",
|
|
25
|
-
}),
|
|
26
23
|
"update-context": Flags.boolean({
|
|
27
24
|
description: "Update the CLI context to use the newly created project",
|
|
28
25
|
}),
|
|
@@ -52,7 +49,7 @@ export default class Create extends ExecRenderBaseCommand {
|
|
|
52
49
|
projectResponse.data.readiness === "ready") {
|
|
53
50
|
return true;
|
|
54
51
|
}
|
|
55
|
-
});
|
|
52
|
+
}, this.flags["wait-timeout"]);
|
|
56
53
|
stepWaiting.complete();
|
|
57
54
|
}
|
|
58
55
|
if (flags["update-context"]) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ArgOutput, OutputFlags } from "@oclif/core/lib/interfaces/parser.js";
|
|
2
|
+
import { AvailableFlagName, RelevantFlagInput } from "./flags.js";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
5
|
+
import { Config } from "@oclif/core";
|
|
6
|
+
export interface AppInstallationResult {
|
|
7
|
+
appInstallationId: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class AppInstaller<TFlagName extends AvailableFlagName> {
|
|
10
|
+
readonly appId: string;
|
|
11
|
+
readonly appName: string;
|
|
12
|
+
readonly appSupportedFlags: readonly TFlagName[];
|
|
13
|
+
readonly description: string;
|
|
14
|
+
private static makeDescription;
|
|
15
|
+
constructor(appId: string, appName: string, appSupportedFlags: readonly TFlagName[]);
|
|
16
|
+
get flags(): RelevantFlagInput<readonly TFlagName[]>;
|
|
17
|
+
exec(apiClient: MittwaldAPIV2Client, args: ArgOutput, flags: OutputFlags<RelevantFlagInput<(TFlagName | "version" | "wait")[]>>, config: Config): Promise<AppInstallationResult>;
|
|
18
|
+
render(result: AppInstallationResult, flags: {
|
|
19
|
+
quiet: boolean;
|
|
20
|
+
}): React.ReactNode;
|
|
21
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { makeProcessRenderer } from "../../rendering/process/process_flags.js";
|
|
3
|
+
import { withProjectId } from "../project/flags.js";
|
|
4
|
+
import { autofillFlags, provideSupportedFlags, } from "./flags.js";
|
|
5
|
+
import { normalizeToAppVersionUuid } from "./versions.js";
|
|
6
|
+
import { triggerAppInstallation } from "./install.js";
|
|
7
|
+
import { waitUntilAppIsInstalled } from "./wait.js";
|
|
8
|
+
import { Success } from "../../rendering/react/components/Success.js";
|
|
9
|
+
export class AppInstaller {
|
|
10
|
+
appId;
|
|
11
|
+
appName;
|
|
12
|
+
appSupportedFlags;
|
|
13
|
+
description;
|
|
14
|
+
static makeDescription(appName) {
|
|
15
|
+
return `Creates new ${appName} Installation.`;
|
|
16
|
+
}
|
|
17
|
+
constructor(appId, appName, appSupportedFlags) {
|
|
18
|
+
this.appId = appId;
|
|
19
|
+
this.appName = appName;
|
|
20
|
+
this.appSupportedFlags = appSupportedFlags;
|
|
21
|
+
this.description = AppInstaller.makeDescription(appName);
|
|
22
|
+
}
|
|
23
|
+
get flags() {
|
|
24
|
+
return provideSupportedFlags(this.appSupportedFlags, this.appName);
|
|
25
|
+
}
|
|
26
|
+
async exec(apiClient, args, flags, config) {
|
|
27
|
+
const process = makeProcessRenderer(flags, `Installing ${this.appName}`);
|
|
28
|
+
const projectId = await withProjectId(apiClient, flags, args, config);
|
|
29
|
+
await autofillFlags(apiClient, process, this.appSupportedFlags, flags, projectId, this.appName);
|
|
30
|
+
const appVersion = await normalizeToAppVersionUuid(apiClient, flags.version, process, this.appId);
|
|
31
|
+
const [appInstallationId, eventId] = await triggerAppInstallation(apiClient, process, projectId, flags, appVersion);
|
|
32
|
+
let successText;
|
|
33
|
+
if (flags.wait) {
|
|
34
|
+
await waitUntilAppIsInstalled(apiClient, process, appInstallationId, eventId);
|
|
35
|
+
successText = `Your ${this.appName} installation is now complete. Have fun! 🎉`;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
successText = `Your ${this.appName} installation has started. Have fun when it's ready! 🎉`;
|
|
39
|
+
}
|
|
40
|
+
process.complete(_jsx(Success, { children: successText }));
|
|
41
|
+
return { appInstallationId };
|
|
42
|
+
}
|
|
43
|
+
render(result, flags) {
|
|
44
|
+
if (flags.quiet) {
|
|
45
|
+
return result.appInstallationId;
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
2
|
+
import { ProcessRenderer } from "../../rendering/process/process.js";
|
|
3
|
+
import { ProcessFlags } from "../../rendering/process/process_flags.js";
|
|
4
|
+
import { BooleanFlag, FlagInput, OptionFlag, OutputFlags } from "@oclif/core/lib/interfaces/parser.js";
|
|
1
5
|
export declare const appInstallationFlags: {
|
|
2
6
|
"installation-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
3
7
|
};
|
|
8
|
+
export type AvailableFlagName = keyof AvailableFlags;
|
|
9
|
+
interface AvailableFlags {
|
|
10
|
+
version: OptionFlag<string>;
|
|
11
|
+
host: OptionFlag<string | undefined>;
|
|
12
|
+
"admin-user": OptionFlag<string | undefined>;
|
|
13
|
+
"admin-email": OptionFlag<string | undefined>;
|
|
14
|
+
"admin-pass": OptionFlag<string | undefined>;
|
|
15
|
+
"admin-firstname": OptionFlag<string | undefined>;
|
|
16
|
+
"admin-lastname": OptionFlag<string | undefined>;
|
|
17
|
+
"site-title": OptionFlag<string | undefined>;
|
|
18
|
+
"shop-email": OptionFlag<string | undefined>;
|
|
19
|
+
"shop-lang": OptionFlag<string | undefined>;
|
|
20
|
+
"shop-currency": OptionFlag<string | undefined>;
|
|
21
|
+
"install-mode": OptionFlag<string>;
|
|
22
|
+
wait: BooleanFlag<boolean | undefined>;
|
|
23
|
+
}
|
|
24
|
+
export type RelevantFlags<TFlags extends readonly AvailableFlagName[]> = ProcessFlags & Pick<AvailableFlags, TFlags[number]>;
|
|
25
|
+
export type RelevantFlagInput<TFlags extends readonly AvailableFlagName[]> = FlagInput<RelevantFlags<TFlags>>;
|
|
26
|
+
export declare function provideSupportedFlags<TFlagNames extends readonly AvailableFlagName[]>(requestedFlagNames: TFlagNames, appName: string): RelevantFlagInput<TFlagNames>;
|
|
27
|
+
export declare function autofillFlags(apiClient: MittwaldAPIV2Client, process: ProcessRenderer, necessaryFlags: readonly AvailableFlagName[], flags: Partial<OutputFlags<RelevantFlagInput<AvailableFlagName[]>>>, projectId: string, appName: string): Promise<void>;
|
|
28
|
+
export {};
|