@mittwald/cli 1.0.0-alpha.38 → 1.0.0-alpha.39
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 +35 -11
- package/dist/commands/ddev/init.d.ts +1 -0
- package/dist/commands/ddev/init.js +22 -4
- package/dist/commands/user/ssh-key/create.d.ts +2 -1
- package/dist/commands/user/ssh-key/create.js +27 -35
- package/dist/commands/user/ssh-key/import.d.ts +11 -0
- package/dist/commands/user/ssh-key/import.js +56 -0
- package/dist/lib/ddev/config.d.ts +12 -0
- package/dist/lib/ddev/config_builder.d.ts +1 -0
- package/dist/lib/ddev/config_builder.js +21 -1
- package/dist/rendering/process/components/ProcessStateIcon.js +2 -2
- package/dist/rendering/react/hooks/useIncreaseInkStdoutColumns.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -191,7 +191,7 @@ USAGE
|
|
|
191
191
|
* [`mw domain virtualhost delete VIRTUAL-HOST-ID`](#mw-domain-virtualhost-delete-virtual-host-id)
|
|
192
192
|
* [`mw domain virtualhost get INGRESS-ID`](#mw-domain-virtualhost-get-ingress-id)
|
|
193
193
|
* [`mw domain virtualhost list`](#mw-domain-virtualhost-list)
|
|
194
|
-
* [`mw help [
|
|
194
|
+
* [`mw help [COMMAND]`](#mw-help-command)
|
|
195
195
|
* [`mw login reset`](#mw-login-reset)
|
|
196
196
|
* [`mw login status`](#mw-login-status)
|
|
197
197
|
* [`mw login token`](#mw-login-token)
|
|
@@ -254,6 +254,7 @@ USAGE
|
|
|
254
254
|
* [`mw user ssh-key create`](#mw-user-ssh-key-create)
|
|
255
255
|
* [`mw user ssh-key delete ID`](#mw-user-ssh-key-delete-id)
|
|
256
256
|
* [`mw user ssh-key get KEY-ID`](#mw-user-ssh-key-get-key-id)
|
|
257
|
+
* [`mw user ssh-key import`](#mw-user-ssh-key-import)
|
|
257
258
|
* [`mw user ssh-key list`](#mw-user-ssh-key-list)
|
|
258
259
|
|
|
259
260
|
## `mw app copy [INSTALLATION-ID]`
|
|
@@ -3105,16 +3106,16 @@ FLAG DESCRIPTIONS
|
|
|
3105
3106
|
to persistently set a default project for all commands that accept this flag.
|
|
3106
3107
|
```
|
|
3107
3108
|
|
|
3108
|
-
## `mw help [
|
|
3109
|
+
## `mw help [COMMAND]`
|
|
3109
3110
|
|
|
3110
3111
|
Display help for mw.
|
|
3111
3112
|
|
|
3112
3113
|
```
|
|
3113
3114
|
USAGE
|
|
3114
|
-
$ mw help [
|
|
3115
|
+
$ mw help [COMMAND] [-n]
|
|
3115
3116
|
|
|
3116
3117
|
ARGUMENTS
|
|
3117
|
-
|
|
3118
|
+
COMMAND Command to show help for.
|
|
3118
3119
|
|
|
3119
3120
|
FLAGS
|
|
3120
3121
|
-n, --nested-commands Include all nested commands in the output.
|
|
@@ -3123,7 +3124,7 @@ DESCRIPTION
|
|
|
3123
3124
|
Display help for mw.
|
|
3124
3125
|
```
|
|
3125
3126
|
|
|
3126
|
-
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.0.
|
|
3127
|
+
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.0.16/src/commands/help.ts)_
|
|
3127
3128
|
|
|
3128
3129
|
## `mw login reset`
|
|
3129
3130
|
|
|
@@ -4679,14 +4680,14 @@ Create and import a new SSH key
|
|
|
4679
4680
|
|
|
4680
4681
|
```
|
|
4681
4682
|
USAGE
|
|
4682
|
-
$ mw user ssh-key create [-q] [--output <value>] [--no-passphrase] [--comment <value>]
|
|
4683
|
+
$ mw user ssh-key create [-q] [--expires <value>] [--output <value>] [--no-passphrase] [--comment <value>]
|
|
4683
4684
|
|
|
4684
4685
|
FLAGS
|
|
4685
|
-
-q, --quiet
|
|
4686
|
-
--comment=<value>
|
|
4687
|
-
--
|
|
4688
|
-
--no-passphrase
|
|
4689
|
-
--output=<value>
|
|
4686
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
4687
|
+
--comment=<value> A comment for the SSH key.
|
|
4688
|
+
--expires=<value> An interval after which the SSH key expires (examples: 30m, 30d, 1y).
|
|
4689
|
+
--no-passphrase Use this flag to not set a passphrase for the SSH key.
|
|
4690
|
+
--output=<value> [default: mstudio-cli] A filename in your ~/.ssh directory to write the SSH key to.
|
|
4690
4691
|
|
|
4691
4692
|
DESCRIPTION
|
|
4692
4693
|
Create and import a new SSH key
|
|
@@ -4742,6 +4743,29 @@ DESCRIPTION
|
|
|
4742
4743
|
Get a specific SSH key
|
|
4743
4744
|
```
|
|
4744
4745
|
|
|
4746
|
+
## `mw user ssh-key import`
|
|
4747
|
+
|
|
4748
|
+
Import an existing (local) SSH key
|
|
4749
|
+
|
|
4750
|
+
```
|
|
4751
|
+
USAGE
|
|
4752
|
+
$ mw user ssh-key import [-q] [--expires <value>] [--input <value>]
|
|
4753
|
+
|
|
4754
|
+
FLAGS
|
|
4755
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
4756
|
+
--expires=<value> An interval after which the SSH key expires (examples: 30m, 30d, 1y).
|
|
4757
|
+
--input=<value> [default: id_rsa.pub] A filename in your ~/.ssh directory containing the key to import.
|
|
4758
|
+
|
|
4759
|
+
DESCRIPTION
|
|
4760
|
+
Import an existing (local) SSH key
|
|
4761
|
+
|
|
4762
|
+
FLAG DESCRIPTIONS
|
|
4763
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
4764
|
+
|
|
4765
|
+
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
4766
|
+
scripts), you can use this flag to easily get the IDs of created resources for further processing.
|
|
4767
|
+
```
|
|
4768
|
+
|
|
4745
4769
|
## `mw user ssh-key list`
|
|
4746
4770
|
|
|
4747
4771
|
Get your stored ssh keys
|
|
@@ -15,6 +15,7 @@ export declare class Init extends ExecRenderBaseCommand<typeof Init, void> {
|
|
|
15
15
|
protected exec(): Promise<void>;
|
|
16
16
|
protected render(): React.ReactNode;
|
|
17
17
|
private addSSHCredentials;
|
|
18
|
+
private determineDDEVVersion;
|
|
18
19
|
private installMittwaldPlugin;
|
|
19
20
|
private initializeDDEVProject;
|
|
20
21
|
private determineProjectName;
|
|
@@ -14,6 +14,10 @@ import { renderDDEVConfig } from "../../lib/ddev/config_render.js";
|
|
|
14
14
|
import { loadDDEVConfig } from "../../lib/ddev/config_loader.js";
|
|
15
15
|
import { Value } from "../../rendering/react/components/Value.js";
|
|
16
16
|
import { ddevFlags } from "../../lib/ddev/flags.js";
|
|
17
|
+
import { exec } from "child_process";
|
|
18
|
+
import { promisify } from "util";
|
|
19
|
+
import { compareSemVer } from "semver-parser";
|
|
20
|
+
const execAsync = promisify(exec);
|
|
17
21
|
export class Init extends ExecRenderBaseCommand {
|
|
18
22
|
static summary = "Initialize a new ddev project in the current directory.";
|
|
19
23
|
static description = "This command initializes a new ddev configuration for an existing app installation in the current directory.\n" +
|
|
@@ -50,9 +54,10 @@ export class Init extends ExecRenderBaseCommand {
|
|
|
50
54
|
const appInstallationId = await this.withAppInstallationId(Init);
|
|
51
55
|
const r = makeProcessRenderer(this.flags, "Initializing DDEV project");
|
|
52
56
|
await assertDDEVIsInstalled(r);
|
|
57
|
+
const ddevVersion = await this.determineDDEVVersion(r);
|
|
53
58
|
const config = await this.writeMittwaldConfiguration(r, appInstallationId);
|
|
54
59
|
const projectName = await this.determineProjectName(r);
|
|
55
|
-
await this.initializeDDEVProject(r, config, projectName);
|
|
60
|
+
await this.initializeDDEVProject(r, config, projectName, ddevVersion);
|
|
56
61
|
await this.installMittwaldPlugin(r);
|
|
57
62
|
await this.addSSHCredentials(r);
|
|
58
63
|
await r.complete(_jsx(DDEVInitSuccess, {}));
|
|
@@ -66,6 +71,12 @@ export class Init extends ExecRenderBaseCommand {
|
|
|
66
71
|
"ssh",
|
|
67
72
|
]);
|
|
68
73
|
}
|
|
74
|
+
async determineDDEVVersion(r) {
|
|
75
|
+
const { stdout } = await execAsync("ddev --version");
|
|
76
|
+
const version = stdout.trim().replace(/^ddev version +/, "");
|
|
77
|
+
r.addInfo(_jsx(InfoDDEVVersion, { version: version }));
|
|
78
|
+
return version;
|
|
79
|
+
}
|
|
69
80
|
async installMittwaldPlugin(r) {
|
|
70
81
|
const { "override-mittwald-plugin": mittwaldPlugin } = this.flags;
|
|
71
82
|
await spawnInProcess(r, "installing mittwald plugin", "ddev", [
|
|
@@ -73,13 +84,17 @@ export class Init extends ExecRenderBaseCommand {
|
|
|
73
84
|
mittwaldPlugin,
|
|
74
85
|
]);
|
|
75
86
|
}
|
|
76
|
-
async initializeDDEVProject(r, config, projectName) {
|
|
77
|
-
|
|
87
|
+
async initializeDDEVProject(r, config, projectName, ddevVersion) {
|
|
88
|
+
const ddevFlags = [
|
|
78
89
|
"config",
|
|
79
90
|
"--project-name",
|
|
80
91
|
projectName,
|
|
81
92
|
...ddevConfigToFlags(config),
|
|
82
|
-
]
|
|
93
|
+
];
|
|
94
|
+
if (compareSemVer(ddevVersion, "1.22.7") < 0) {
|
|
95
|
+
ddevFlags.push("--create-docroot");
|
|
96
|
+
}
|
|
97
|
+
await spawnInProcess(r, "initializing DDEV project", "ddev", ddevFlags);
|
|
83
98
|
}
|
|
84
99
|
async determineProjectName(r) {
|
|
85
100
|
const { "project-name": projectName } = this.flags;
|
|
@@ -118,3 +133,6 @@ async function writeContentsToFile(filename, data) {
|
|
|
118
133
|
function InfoUsingExistingName({ name }) {
|
|
119
134
|
return (_jsxs(_Fragment, { children: ["using existing project name: ", _jsx(Value, { children: name })] }));
|
|
120
135
|
}
|
|
136
|
+
function InfoDDEVVersion({ version }) {
|
|
137
|
+
return (_jsxs(_Fragment, { children: ["detected DDEV version: ", _jsx(Value, { children: version })] }));
|
|
138
|
+
}
|
|
@@ -5,9 +5,10 @@ export default class Create extends ExecRenderBaseCommand<typeof Create, undefin
|
|
|
5
5
|
output: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
6
6
|
"no-passphrase": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
7
7
|
comment: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
-
|
|
8
|
+
expires: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
9
9
|
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
10
|
};
|
|
11
11
|
protected exec(): Promise<undefined>;
|
|
12
12
|
protected render(): null;
|
|
13
|
+
private getPassphrase;
|
|
13
14
|
}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Flags } from "@oclif/core";
|
|
3
3
|
import { assertStatus } from "@mittwald/api-client-commons";
|
|
4
|
-
import * as cp from "child_process";
|
|
5
4
|
import * as path from "path";
|
|
6
5
|
import * as os from "os";
|
|
7
6
|
import * as fs from "fs/promises";
|
|
8
|
-
import parseDuration from "parse-duration";
|
|
9
7
|
import { ExecRenderBaseCommand } from "../../../rendering/react/ExecRenderBaseCommand.js";
|
|
10
8
|
import { makeProcessRenderer, processFlags, } from "../../../rendering/process/process_flags.js";
|
|
11
9
|
import { Success } from "../../../rendering/react/components/Success.js";
|
|
12
10
|
import { Filename } from "../../../rendering/react/components/Filename.js";
|
|
13
11
|
import { Text } from "ink";
|
|
12
|
+
import { expirationDateFromFlagsOptional, expireFlags, } from "../../../lib/expires.js";
|
|
13
|
+
import { spawnInProcess } from "../../../rendering/process/process_exec.js";
|
|
14
14
|
export default class Create extends ExecRenderBaseCommand {
|
|
15
15
|
static description = "Create and import a new SSH key";
|
|
16
16
|
static flags = {
|
|
17
17
|
...processFlags,
|
|
18
|
+
...expireFlags("SSH key"),
|
|
18
19
|
output: Flags.string({
|
|
19
20
|
description: "A filename in your ~/.ssh directory to write the SSH key to.",
|
|
20
21
|
default: "mstudio-cli",
|
|
@@ -25,41 +26,21 @@ export default class Create extends ExecRenderBaseCommand {
|
|
|
25
26
|
comment: Flags.string({
|
|
26
27
|
description: "A comment for the SSH key.",
|
|
27
28
|
}),
|
|
28
|
-
expiresAt: Flags.string({
|
|
29
|
-
description: "Duration after which the SSH key should expire (example: '1y').",
|
|
30
|
-
}),
|
|
31
29
|
};
|
|
32
30
|
async exec() {
|
|
33
|
-
const { flags } = await this.parse(Create);
|
|
34
31
|
const cmd = "ssh-keygen";
|
|
35
|
-
const outputFile = path.join(os.homedir(), ".ssh", flags.output);
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
throw new Error("Invalid duration");
|
|
43
|
-
}
|
|
44
|
-
expiresAt = new Date();
|
|
45
|
-
expiresAt.setTime(new Date().getTime() + parsedDuration);
|
|
46
|
-
}
|
|
47
|
-
if (flags["no-passphrase"]) {
|
|
48
|
-
args.push("-N", "");
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
const passphrase = await process.addInput(_jsx(Text, { children: "enter passphrase for SSH key" }), true);
|
|
52
|
-
args.push("-N", passphrase);
|
|
32
|
+
const outputFile = path.join(os.homedir(), ".ssh", this.flags.output);
|
|
33
|
+
const r = makeProcessRenderer(this.flags, "Creating a new SSH key");
|
|
34
|
+
const expiresAt = expirationDateFromFlagsOptional(this.flags);
|
|
35
|
+
const passphrase = await this.getPassphrase(r);
|
|
36
|
+
const args = ["-t", "rsa", "-f", outputFile, "-N", passphrase];
|
|
37
|
+
if (this.flags.comment) {
|
|
38
|
+
args.push("-C", this.flags.comment);
|
|
53
39
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
cp.spawnSync(cmd, args, { stdio: "ignore" });
|
|
59
|
-
return await fs.readFile(outputFile + ".pub", "utf-8");
|
|
60
|
-
});
|
|
61
|
-
process.addInfo(_jsxs(Text, { children: ["ssh key saved to ", _jsx(Filename, { filename: outputFile }), "."] }));
|
|
62
|
-
await process.runStep("importing SSH key", async () => {
|
|
40
|
+
await spawnInProcess(r, "generating SSH key using ssh-keygen", cmd, args);
|
|
41
|
+
const publicKey = await fs.readFile(outputFile + ".pub", "utf-8");
|
|
42
|
+
r.addInfo(_jsx(InfoSSHKeySaved, { filename: outputFile }));
|
|
43
|
+
await r.runStep("importing SSH key", async () => {
|
|
63
44
|
const response = await this.apiClient.user.createSshKey({
|
|
64
45
|
data: {
|
|
65
46
|
publicKey,
|
|
@@ -67,11 +48,22 @@ export default class Create extends ExecRenderBaseCommand {
|
|
|
67
48
|
},
|
|
68
49
|
});
|
|
69
50
|
assertStatus(response, 201);
|
|
70
|
-
return response;
|
|
71
51
|
});
|
|
72
|
-
|
|
52
|
+
await r.complete(_jsx(SSHKeySuccess, {}));
|
|
73
53
|
}
|
|
74
54
|
render() {
|
|
75
55
|
return null;
|
|
76
56
|
}
|
|
57
|
+
async getPassphrase(r) {
|
|
58
|
+
if (this.flags["no-passphrase"]) {
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
return await r.addInput(_jsx(Text, { children: "enter passphrase for SSH key" }), true);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function SSHKeySuccess() {
|
|
65
|
+
return (_jsx(Success, { children: "Your SSH key was successfully created and imported to your user profile." }));
|
|
66
|
+
}
|
|
67
|
+
function InfoSSHKeySaved({ filename }) {
|
|
68
|
+
return (_jsxs(Text, { children: ["ssh key saved to ", _jsx(Filename, { filename: filename }), "."] }));
|
|
77
69
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ExecRenderBaseCommand } from "../../../rendering/react/ExecRenderBaseCommand.js";
|
|
2
|
+
export default class Import extends ExecRenderBaseCommand<typeof Import, undefined> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
input: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
6
|
+
expires: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
7
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
protected exec(): Promise<undefined>;
|
|
10
|
+
protected render(): null;
|
|
11
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Flags } from "@oclif/core";
|
|
3
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import * as os from "os";
|
|
6
|
+
import * as fs from "fs/promises";
|
|
7
|
+
import { ExecRenderBaseCommand } from "../../../rendering/react/ExecRenderBaseCommand.js";
|
|
8
|
+
import { makeProcessRenderer, processFlags, } from "../../../rendering/process/process_flags.js";
|
|
9
|
+
import { Success } from "../../../rendering/react/components/Success.js";
|
|
10
|
+
import { Filename } from "../../../rendering/react/components/Filename.js";
|
|
11
|
+
import { expirationDateFromFlagsOptional, expireFlags, } from "../../../lib/expires.js";
|
|
12
|
+
export default class Import extends ExecRenderBaseCommand {
|
|
13
|
+
static description = "Import an existing (local) SSH key";
|
|
14
|
+
static flags = {
|
|
15
|
+
...processFlags,
|
|
16
|
+
...expireFlags("SSH key"),
|
|
17
|
+
input: Flags.string({
|
|
18
|
+
description: "A filename in your ~/.ssh directory containing the key to import.",
|
|
19
|
+
default: "id_rsa.pub",
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
async exec() {
|
|
23
|
+
const inputFile = path.join(os.homedir(), ".ssh", this.flags.input);
|
|
24
|
+
const r = makeProcessRenderer(this.flags, "Importing an SSH key");
|
|
25
|
+
const expiresAt = expirationDateFromFlagsOptional(this.flags);
|
|
26
|
+
const publicKey = await fs.readFile(inputFile, "utf-8");
|
|
27
|
+
const publicKeyParts = publicKey.split(" ");
|
|
28
|
+
const keys = await r.runStep("retrieving existing SSH keys", async () => {
|
|
29
|
+
const response = await this.apiClient.user.listSshKeys();
|
|
30
|
+
assertStatus(response, 200);
|
|
31
|
+
return response.data;
|
|
32
|
+
});
|
|
33
|
+
const keyAlreadyExists = (keys.sshKeys ?? []).some(({ key }) => publicKeyParts.includes(key));
|
|
34
|
+
if (keyAlreadyExists) {
|
|
35
|
+
r.addInfo(_jsxs(_Fragment, { children: ["the SSH key ", _jsx(Filename, { filename: inputFile }), " is already imported."] }));
|
|
36
|
+
await r.complete(_jsx(SSHKeySuccess, {}));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await r.runStep("importing SSH key", async () => {
|
|
40
|
+
const response = await this.apiClient.user.createSshKey({
|
|
41
|
+
data: {
|
|
42
|
+
publicKey,
|
|
43
|
+
expiresAt: expiresAt?.toJSON(),
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
assertStatus(response, 201);
|
|
47
|
+
});
|
|
48
|
+
await r.complete(_jsx(SSHKeySuccess, {}));
|
|
49
|
+
}
|
|
50
|
+
render() {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function SSHKeySuccess() {
|
|
55
|
+
return (_jsx(Success, { children: "Your SSH key was successfully read and imported to your user profile." }));
|
|
56
|
+
}
|
|
@@ -15,7 +15,19 @@ export interface DDEVConfig {
|
|
|
15
15
|
web_environment: string[];
|
|
16
16
|
docroot: string;
|
|
17
17
|
database: DDEVDatabaseConfig;
|
|
18
|
+
hooks: DDEVHooks;
|
|
18
19
|
}
|
|
20
|
+
export type DDEVHookEvent = "start" | "import-db" | "import-files" | "composer" | "stop" | "config" | "exec" | "pull" | "push" | "snapshot" | "restore-snapshot";
|
|
21
|
+
export type DDEVHooks = {
|
|
22
|
+
[k in `pre-${DDEVHookEvent}`]?: DDEVHook[];
|
|
23
|
+
} & {
|
|
24
|
+
[k in `post-${DDEVHookEvent}`]?: DDEVHook[];
|
|
25
|
+
};
|
|
26
|
+
export type DDEVHook = {
|
|
27
|
+
exec: string;
|
|
28
|
+
} | {
|
|
29
|
+
"exec-host": string;
|
|
30
|
+
};
|
|
19
31
|
export interface DDEVDatabaseConfig {
|
|
20
32
|
type: string;
|
|
21
33
|
version: string;
|
|
@@ -4,6 +4,7 @@ export declare class DDEVConfigBuilder {
|
|
|
4
4
|
private apiClient;
|
|
5
5
|
constructor(apiClient: MittwaldAPIV2Client);
|
|
6
6
|
build(appInstallationId: string, type: string): Promise<Partial<DDEVConfig>>;
|
|
7
|
+
private buildHooks;
|
|
7
8
|
private determineDocumentRoot;
|
|
8
9
|
private determineProjectType;
|
|
9
10
|
private determineDatabaseVersion;
|
|
@@ -11,9 +11,10 @@ export class DDEVConfigBuilder {
|
|
|
11
11
|
async build(appInstallationId, type) {
|
|
12
12
|
const appInstallation = await this.getAppInstallation(appInstallationId);
|
|
13
13
|
const systemSoftwares = await this.buildSystemSoftwareVersionMap(appInstallation);
|
|
14
|
+
type = await this.determineProjectType(appInstallation, type);
|
|
14
15
|
return {
|
|
15
16
|
override_config: true,
|
|
16
|
-
type
|
|
17
|
+
type,
|
|
17
18
|
webserver_type: "apache-fpm",
|
|
18
19
|
php_version: this.determinePHPVersion(systemSoftwares),
|
|
19
20
|
database: await this.determineDatabaseVersion(appInstallation),
|
|
@@ -21,6 +22,25 @@ export class DDEVConfigBuilder {
|
|
|
21
22
|
web_environment: [
|
|
22
23
|
`MITTWALD_APP_INSTALLATION_ID=${appInstallation.shortId}`,
|
|
23
24
|
],
|
|
25
|
+
hooks: this.buildHooks(type),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
buildHooks(type) {
|
|
29
|
+
const postPull = [
|
|
30
|
+
{ "exec-host": "ddev config --project-name $DDEV_PROJECT" },
|
|
31
|
+
{ "exec-host": "ddev restart" },
|
|
32
|
+
];
|
|
33
|
+
if (type === "typo3") {
|
|
34
|
+
postPull.push({ exec: "typo3 cache:flush" }, { exec: "typo3 cache:warmup" });
|
|
35
|
+
}
|
|
36
|
+
if (type === "wordpress") {
|
|
37
|
+
postPull.push({ exec: "wp cache flush" });
|
|
38
|
+
}
|
|
39
|
+
if (type === "shopware6") {
|
|
40
|
+
postPull.push({ exec: "bin/console cache:clear" });
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
"post-pull": postPull,
|
|
24
44
|
};
|
|
25
45
|
}
|
|
26
46
|
async determineDocumentRoot(inst) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Text } from "ink";
|
|
3
3
|
export const ProcessStateIcon = ({ step }) => {
|
|
4
4
|
if (step.type === "info") {
|
|
5
|
-
return
|
|
5
|
+
return _jsx(Text, { children: "\uD83D\uDCA1 " });
|
|
6
6
|
}
|
|
7
7
|
else if (step.type === "confirm" || step.type === "input") {
|
|
8
8
|
return _jsx(Text, { children: "\u2753" });
|
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.39",
|
|
4
4
|
"description": "Hand-crafted CLI for the mittwald API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"pretty-bytes": "^6.1.0",
|
|
66
66
|
"react": "^18.2.0",
|
|
67
67
|
"semver": "^7.5.4",
|
|
68
|
+
"semver-parser": "^4.1.6",
|
|
68
69
|
"shell-escape": "^0.2.0",
|
|
69
70
|
"tempfile": "^5.0.0"
|
|
70
71
|
},
|