@mittwald/cli 1.0.0-alpha.43 → 1.0.0-alpha.44
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 +67 -2
- package/dist/BaseCommand.js +2 -0
- package/dist/commands/app/list-upgrade-candidates.d.ts +40 -0
- package/dist/commands/app/list-upgrade-candidates.js +37 -0
- package/dist/commands/app/upgrade.d.ts +17 -0
- package/dist/commands/app/upgrade.js +108 -0
- package/dist/lib/api_logging.d.ts +8 -0
- package/dist/lib/api_logging.js +20 -0
- package/dist/lib/app/Installer.js +2 -2
- package/dist/lib/app/upgrade.d.ts +1 -0
- package/dist/lib/app/upgrade.js +1 -0
- package/dist/lib/app/uuid.d.ts +8 -0
- package/dist/lib/app/uuid.js +13 -4
- package/dist/lib/app/versions.d.ts +4 -0
- package/dist/lib/app/versions.js +38 -2
- package/dist/lib/app/wait.d.ts +1 -1
- package/dist/lib/app/wait.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -136,8 +136,10 @@ USAGE
|
|
|
136
136
|
* [`mw app install typo3`](#mw-app-install-typo3)
|
|
137
137
|
* [`mw app install wordpress`](#mw-app-install-wordpress)
|
|
138
138
|
* [`mw app list`](#mw-app-list)
|
|
139
|
+
* [`mw app list-upgrade-candidates [INSTALLATION-ID]`](#mw-app-list-upgrade-candidates-installation-id)
|
|
139
140
|
* [`mw app ssh [INSTALLATION-ID]`](#mw-app-ssh-installation-id)
|
|
140
141
|
* [`mw app uninstall [INSTALLATION-ID]`](#mw-app-uninstall-installation-id)
|
|
142
|
+
* [`mw app upgrade [INSTALLATION-ID]`](#mw-app-upgrade-installation-id)
|
|
141
143
|
* [`mw app upload [INSTALLATION-ID]`](#mw-app-upload-installation-id)
|
|
142
144
|
* [`mw app versions [APP]`](#mw-app-versions-app)
|
|
143
145
|
* [`mw autocomplete [SHELL]`](#mw-autocomplete-shell)
|
|
@@ -1751,6 +1753,33 @@ FLAG DESCRIPTIONS
|
|
|
1751
1753
|
to persistently set a default project for all commands that accept this flag.
|
|
1752
1754
|
```
|
|
1753
1755
|
|
|
1756
|
+
## `mw app list-upgrade-candidates [INSTALLATION-ID]`
|
|
1757
|
+
|
|
1758
|
+
List upgrade candidates for an app installation.
|
|
1759
|
+
|
|
1760
|
+
```
|
|
1761
|
+
USAGE
|
|
1762
|
+
$ mw app list-upgrade-candidates [INSTALLATION-ID] [--columns <value> | -x] [--no-header | [--csv | --no-truncate]] [-o
|
|
1763
|
+
txt|json|yaml|csv | | ] [--no-relative-dates]
|
|
1764
|
+
|
|
1765
|
+
ARGUMENTS
|
|
1766
|
+
INSTALLATION-ID ID or short ID of an app installation; this argument is optional if a default app installation is set
|
|
1767
|
+
in the context
|
|
1768
|
+
|
|
1769
|
+
FLAGS
|
|
1770
|
+
-o, --output=<option> [default: txt] output in a more machine friendly format
|
|
1771
|
+
<options: txt|json|yaml|csv>
|
|
1772
|
+
-x, --extended show extra columns
|
|
1773
|
+
--columns=<value> only show provided columns (comma-separated)
|
|
1774
|
+
--csv output is csv format [alias: --output=csv]
|
|
1775
|
+
--no-header hide table header from output
|
|
1776
|
+
--no-relative-dates show dates in absolute format, not relative
|
|
1777
|
+
--no-truncate do not truncate output to fit screen
|
|
1778
|
+
|
|
1779
|
+
DESCRIPTION
|
|
1780
|
+
List upgrade candidates for an app installation.
|
|
1781
|
+
```
|
|
1782
|
+
|
|
1754
1783
|
## `mw app ssh [INSTALLATION-ID]`
|
|
1755
1784
|
|
|
1756
1785
|
Connect to an app via SSH
|
|
@@ -1826,6 +1855,42 @@ FLAG DESCRIPTIONS
|
|
|
1826
1855
|
scripts), you can use this flag to easily get the IDs of created resources for further processing.
|
|
1827
1856
|
```
|
|
1828
1857
|
|
|
1858
|
+
## `mw app upgrade [INSTALLATION-ID]`
|
|
1859
|
+
|
|
1860
|
+
Upgrade app installation to target version
|
|
1861
|
+
|
|
1862
|
+
```
|
|
1863
|
+
USAGE
|
|
1864
|
+
$ mw app upgrade [INSTALLATION-ID] [--target-version <value>] [-w] [-f] [-p <value>] [-q]
|
|
1865
|
+
|
|
1866
|
+
ARGUMENTS
|
|
1867
|
+
INSTALLATION-ID ID or short ID of an app installation; this argument is optional if a default app installation is set
|
|
1868
|
+
in the context
|
|
1869
|
+
|
|
1870
|
+
FLAGS
|
|
1871
|
+
-f, --force Do not ask for confirmation.
|
|
1872
|
+
-p, --project-id=<value> ID or short ID of a project; this flag is optional if a default project is set in the
|
|
1873
|
+
context
|
|
1874
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
1875
|
+
-w, --wait wait for the upgrade process to finish
|
|
1876
|
+
--target-version=<value> target version to upgrade app to; if omitted, target version will be prompted
|
|
1877
|
+
interactively
|
|
1878
|
+
|
|
1879
|
+
DESCRIPTION
|
|
1880
|
+
Upgrade app installation to target version
|
|
1881
|
+
|
|
1882
|
+
FLAG DESCRIPTIONS
|
|
1883
|
+
-p, --project-id=<value> ID or short ID of a project; this flag is optional if a default project is set in the context
|
|
1884
|
+
|
|
1885
|
+
May contain a short ID or a full ID of a project; you can also use the "mw context set --project-id=<VALUE>" command
|
|
1886
|
+
to persistently set a default project for all commands that accept this flag.
|
|
1887
|
+
|
|
1888
|
+
-q, --quiet suppress process output and only display a machine-readable summary.
|
|
1889
|
+
|
|
1890
|
+
This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
|
|
1891
|
+
scripts), you can use this flag to easily get the IDs of created resources for further processing.
|
|
1892
|
+
```
|
|
1893
|
+
|
|
1829
1894
|
## `mw app upload [INSTALLATION-ID]`
|
|
1830
1895
|
|
|
1831
1896
|
Upload the filesystem of an app to a project
|
|
@@ -1932,7 +1997,7 @@ EXAMPLES
|
|
|
1932
1997
|
$ mw autocomplete --refresh-cache
|
|
1933
1998
|
```
|
|
1934
1999
|
|
|
1935
|
-
_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.0.
|
|
2000
|
+
_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.0.17/src/commands/autocomplete/index.ts)_
|
|
1936
2001
|
|
|
1937
2002
|
## `mw backup create`
|
|
1938
2003
|
|
|
@@ -5200,7 +5265,7 @@ EXAMPLES
|
|
|
5200
5265
|
$ mw update --available
|
|
5201
5266
|
```
|
|
5202
5267
|
|
|
5203
|
-
_See code: [@oclif/plugin-update](https://github.com/oclif/plugin-update/blob/v4.2.
|
|
5268
|
+
_See code: [@oclif/plugin-update](https://github.com/oclif/plugin-update/blob/v4.2.11/src/commands/update.ts)_
|
|
5204
5269
|
|
|
5205
5270
|
## `mw user api-token create`
|
|
5206
5271
|
|
package/dist/BaseCommand.js
CHANGED
|
@@ -3,6 +3,7 @@ import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
|
3
3
|
import { configureAxiosRetry } from "./lib/api_retry.js";
|
|
4
4
|
import { configureConsistencyHandling } from "./lib/api_consistency.js";
|
|
5
5
|
import { getTokenFilename, readApiToken } from "./lib/auth/token.js";
|
|
6
|
+
import { configureAxiosLogging } from "./lib/api_logging.js";
|
|
6
7
|
export class BaseCommand extends Command {
|
|
7
8
|
authenticationRequired = true;
|
|
8
9
|
apiClient = MittwaldAPIV2Client.newUnauthenticated();
|
|
@@ -16,6 +17,7 @@ export class BaseCommand extends Command {
|
|
|
16
17
|
this.apiClient = MittwaldAPIV2Client.newWithToken(token);
|
|
17
18
|
this.apiClient.axios.defaults.headers["User-Agent"] =
|
|
18
19
|
`mittwald-cli/${this.config.version}`;
|
|
20
|
+
configureAxiosLogging(this.apiClient.axios);
|
|
19
21
|
configureAxiosRetry(this.apiClient.axios);
|
|
20
22
|
configureConsistencyHandling(this.apiClient.axios);
|
|
21
23
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Simplify } from "@mittwald/api-client-commons";
|
|
2
|
+
import { ListBaseCommand } from "../../ListBaseCommand.js";
|
|
3
|
+
import { MittwaldAPIV2, MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
4
|
+
import { ListColumns } from "../../Formatter.js";
|
|
5
|
+
type ResponseItem = Simplify<MittwaldAPIV2.Paths.V2AppsAppIdVersions.Get.Responses.$200.Content.ApplicationJson[number]>;
|
|
6
|
+
type Response = Awaited<ReturnType<MittwaldAPIV2Client["app"]["listAppversions"]>>;
|
|
7
|
+
export default class List extends ListBaseCommand<typeof List, ResponseItem, Response> {
|
|
8
|
+
static description: string;
|
|
9
|
+
static args: {
|
|
10
|
+
"installation-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
11
|
+
};
|
|
12
|
+
static flags: {
|
|
13
|
+
columns?: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined> | undefined;
|
|
14
|
+
csv?: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean> | undefined;
|
|
15
|
+
extended?: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean> | undefined;
|
|
16
|
+
filter?: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined> | undefined;
|
|
17
|
+
'no-header'?: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean> | undefined;
|
|
18
|
+
'no-truncate'?: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean> | undefined;
|
|
19
|
+
output: import("@oclif/core/lib/interfaces/parser.js").FlagProps & {
|
|
20
|
+
type: "option";
|
|
21
|
+
helpValue?: string | undefined;
|
|
22
|
+
options?: readonly string[] | undefined;
|
|
23
|
+
multiple?: boolean | undefined;
|
|
24
|
+
multipleNonGreedy?: boolean | undefined;
|
|
25
|
+
delimiter?: "," | undefined;
|
|
26
|
+
allowStdin?: boolean | "only" | undefined;
|
|
27
|
+
} & {
|
|
28
|
+
parse: import("@oclif/core/lib/interfaces/parser.js").FlagParser<string | undefined, string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
29
|
+
defaultHelp?: import("@oclif/core/lib/interfaces/parser.js").FlagDefaultHelp<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
30
|
+
input: string[];
|
|
31
|
+
default?: import("@oclif/core/lib/interfaces/parser.js").FlagDefault<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
32
|
+
};
|
|
33
|
+
sort?: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined> | undefined;
|
|
34
|
+
"no-relative-dates": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
35
|
+
};
|
|
36
|
+
protected getData(): Promise<Response>;
|
|
37
|
+
protected mapData(data: ResponseItem[]): Promise<ResponseItem[]>;
|
|
38
|
+
protected getColumns(): ListColumns<ResponseItem>;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { appInstallationArgs, withAppInstallationId, } from "../../lib/app/flags.js";
|
|
2
|
+
import { ListBaseCommand } from "../../ListBaseCommand.js";
|
|
3
|
+
import { getAppInstallationFromUuid } from "../../lib/app/uuid.js";
|
|
4
|
+
import { sortArrayByExternalVersion } from "../../lib/app/versions.js";
|
|
5
|
+
export default class List extends ListBaseCommand {
|
|
6
|
+
static description = "List upgrade candidates for an app installation.";
|
|
7
|
+
static args = {
|
|
8
|
+
...appInstallationArgs,
|
|
9
|
+
};
|
|
10
|
+
static flags = {
|
|
11
|
+
...ListBaseCommand.baseFlags,
|
|
12
|
+
};
|
|
13
|
+
async getData() {
|
|
14
|
+
const appInstallationId = await withAppInstallationId(this.apiClient, List, this.flags, this.args, this.config);
|
|
15
|
+
const currentAppInstallation = await getAppInstallationFromUuid(this.apiClient, appInstallationId);
|
|
16
|
+
if (currentAppInstallation.appVersion.current === undefined) {
|
|
17
|
+
throw new Error("current app version could not be determined");
|
|
18
|
+
}
|
|
19
|
+
return await this.apiClient.app.listUpdateCandidatesForAppversion({
|
|
20
|
+
appId: currentAppInstallation.appId,
|
|
21
|
+
baseAppVersionId: currentAppInstallation.appVersion.current,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async mapData(data) {
|
|
25
|
+
return sortArrayByExternalVersion(data);
|
|
26
|
+
}
|
|
27
|
+
getColumns() {
|
|
28
|
+
return {
|
|
29
|
+
externalVersion: {
|
|
30
|
+
header: "Version",
|
|
31
|
+
get: (i) => {
|
|
32
|
+
return i.externalVersion;
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ExecRenderBaseCommand } from "../../rendering/react/ExecRenderBaseCommand.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
export declare class UpgradeApp extends ExecRenderBaseCommand<typeof UpgradeApp, void> {
|
|
4
|
+
static description: string;
|
|
5
|
+
static args: {
|
|
6
|
+
"installation-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
|
+
"project-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
|
|
11
|
+
"target-version": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
|
+
wait: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
13
|
+
force: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
protected exec(): Promise<void>;
|
|
16
|
+
protected render(): ReactNode;
|
|
17
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsxs as _jsxs, Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ExecRenderBaseCommand } from "../../rendering/react/ExecRenderBaseCommand.js";
|
|
3
|
+
import { appInstallationArgs, withAppInstallationId, } from "../../lib/app/flags.js";
|
|
4
|
+
import { projectFlags } from "../../lib/project/flags.js";
|
|
5
|
+
import { Flags, ux } from "@oclif/core";
|
|
6
|
+
import { Text } from "ink";
|
|
7
|
+
import { getAppFromUuid, getAppInstallationFromUuid, getAppVersionFromUuid, } from "../../lib/app/uuid.js";
|
|
8
|
+
import { getAllUpgradeCandidatesFromAppInstallationId, getAvailableTargetAppVersionFromExternalVersion, getLatestAvailableTargetAppVersionForAppVersionUpgradeCandidates, } from "../../lib/app/versions.js";
|
|
9
|
+
import { makeProcessRenderer, processFlags, } from "../../rendering/process/process_flags.js";
|
|
10
|
+
import { Success } from "../../rendering/react/components/Success.js";
|
|
11
|
+
import { waitUntilAppStateHasNormalized } from "../../lib/app/wait.js";
|
|
12
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
13
|
+
export class UpgradeApp extends ExecRenderBaseCommand {
|
|
14
|
+
static description = "Upgrade app installation to target version";
|
|
15
|
+
static args = {
|
|
16
|
+
...appInstallationArgs,
|
|
17
|
+
};
|
|
18
|
+
static flags = {
|
|
19
|
+
"target-version": Flags.string({
|
|
20
|
+
description: "target version to upgrade app to; if omitted, target version will be prompted interactively",
|
|
21
|
+
}),
|
|
22
|
+
wait: Flags.boolean({
|
|
23
|
+
description: "wait for the upgrade process to finish",
|
|
24
|
+
char: "w",
|
|
25
|
+
}),
|
|
26
|
+
force: Flags.boolean({
|
|
27
|
+
char: "f",
|
|
28
|
+
description: "Do not ask for confirmation.",
|
|
29
|
+
}),
|
|
30
|
+
...projectFlags,
|
|
31
|
+
...processFlags,
|
|
32
|
+
};
|
|
33
|
+
async exec() {
|
|
34
|
+
const process = makeProcessRenderer(this.flags, "App upgrade");
|
|
35
|
+
const appInstallationId = await withAppInstallationId(this.apiClient, UpgradeApp, this.flags, this.args, this.config), currentAppInstallation = await getAppInstallationFromUuid(this.apiClient, appInstallationId), currentApp = await getAppFromUuid(this.apiClient, currentAppInstallation.appId), targetAppVersionCandidates = await getAllUpgradeCandidatesFromAppInstallationId(this.apiClient, currentAppInstallation.id);
|
|
36
|
+
if (currentAppInstallation.appVersion.current === undefined) {
|
|
37
|
+
process.error("Current version could not be determined properly.");
|
|
38
|
+
ux.exit(1);
|
|
39
|
+
}
|
|
40
|
+
const currentAppVersion = await getAppVersionFromUuid(this.apiClient, currentApp.id, currentAppInstallation.appVersion.current);
|
|
41
|
+
if (targetAppVersionCandidates.length == 0) {
|
|
42
|
+
process.addInfo(_jsxs(Text, { children: ["Your ", currentApp.name, " ", currentAppVersion.externalVersion, " is already Up-To-Date. \u2705"] }));
|
|
43
|
+
process.complete(_jsx(_Fragment, {}));
|
|
44
|
+
ux.exit(0);
|
|
45
|
+
}
|
|
46
|
+
let targetAppVersion;
|
|
47
|
+
if (this.flags["target-version"] == "latest") {
|
|
48
|
+
targetAppVersion =
|
|
49
|
+
await getLatestAvailableTargetAppVersionForAppVersionUpgradeCandidates(this.apiClient, currentApp.id, currentAppVersion.id);
|
|
50
|
+
}
|
|
51
|
+
else if (this.flags["target-version"]) {
|
|
52
|
+
const targetVersionMatchFromCandidates = targetAppVersionCandidates.find((targetAppVersionCandidate) => targetAppVersionCandidate.externalVersion ===
|
|
53
|
+
this.flags["target-version"]);
|
|
54
|
+
if (targetVersionMatchFromCandidates) {
|
|
55
|
+
targetAppVersion = targetVersionMatchFromCandidates;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
process.addInfo(_jsx(Text, { children: "The given target upgrade version does not seem to be a valid upgrade candidate." }));
|
|
59
|
+
targetAppVersion = await forceTargetVersionSelection(process, this.apiClient, targetAppVersionCandidates, currentApp, currentAppVersion);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
targetAppVersion = await forceTargetVersionSelection(process, this.apiClient, targetAppVersionCandidates, currentApp, currentAppVersion);
|
|
64
|
+
}
|
|
65
|
+
if (!targetAppVersion) {
|
|
66
|
+
process.error("Target app version could not be determined properly.");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!this.flags.force) {
|
|
70
|
+
const confirmed = await process.addConfirmation(_jsxs(Text, { children: ["Confirm upgrading ", currentApp.name, " ", currentAppVersion.externalVersion, " (", currentAppInstallation.description, ") to version", " ", targetAppVersion.externalVersion] }));
|
|
71
|
+
if (!confirmed) {
|
|
72
|
+
process.addInfo(_jsx(Text, { children: "Upgrade will not be triggered." }));
|
|
73
|
+
process.complete(_jsx(_Fragment, {}));
|
|
74
|
+
ux.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
process.addInfo(_jsxs(Text, { children: ["Commencing upgrade of ", currentApp.name, " ", currentAppVersion.externalVersion, " (", currentAppInstallation.description, ") to Version", " ", targetAppVersion.externalVersion, "."] }));
|
|
79
|
+
}
|
|
80
|
+
const patchAppTriggerResponse = await this.apiClient.app.patchAppinstallation({
|
|
81
|
+
appInstallationId,
|
|
82
|
+
data: { appVersionId: targetAppVersion.id },
|
|
83
|
+
});
|
|
84
|
+
assertStatus(patchAppTriggerResponse, 204);
|
|
85
|
+
let successText;
|
|
86
|
+
if (this.flags.wait) {
|
|
87
|
+
await waitUntilAppStateHasNormalized(this.apiClient, process, appInstallationId, "waiting for app upgrade to be done");
|
|
88
|
+
successText =
|
|
89
|
+
"The upgrade finished successfully. Please check if everything is in its place. 🔎";
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
successText = "The upgrade has been started. Buckle up! 🚀";
|
|
93
|
+
}
|
|
94
|
+
await process.complete(_jsx(Success, { children: successText }));
|
|
95
|
+
}
|
|
96
|
+
render() {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function forceTargetVersionSelection(process, apiClient, targetAppVersionCandidates, currentApp, currentAppVersion) {
|
|
101
|
+
const targetAppVersionString = await process.addSelect(`Please select target upgrade for your ${currentApp.name} ${currentAppVersion.externalVersion} from one of the following`, [
|
|
102
|
+
...targetAppVersionCandidates.map((targetAppVersionCandidate) => ({
|
|
103
|
+
value: targetAppVersionCandidate.externalVersion,
|
|
104
|
+
label: `${targetAppVersionCandidate.externalVersion}`,
|
|
105
|
+
})),
|
|
106
|
+
]);
|
|
107
|
+
return await getAvailableTargetAppVersionFromExternalVersion(apiClient, currentApp.id, currentAppVersion.id, targetAppVersionString);
|
|
108
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AxiosInstance } from "@mittwald/api-client-commons";
|
|
2
|
+
/**
|
|
3
|
+
* Configure logging for Axios requests and responses using the `debug` module.
|
|
4
|
+
*
|
|
5
|
+
* Run the CLI with `DEBUG=mw:api:client:*` to see the logs. Keep in mind that
|
|
6
|
+
* this will also log sensitive information in request bodies or headers.
|
|
7
|
+
*/
|
|
8
|
+
export declare function configureAxiosLogging(axios: AxiosInstance): void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import debug from "debug";
|
|
2
|
+
/**
|
|
3
|
+
* Configure logging for Axios requests and responses using the `debug` module.
|
|
4
|
+
*
|
|
5
|
+
* Run the CLI with `DEBUG=mw:api:client:*` to see the logs. Keep in mind that
|
|
6
|
+
* this will also log sensitive information in request bodies or headers.
|
|
7
|
+
*/
|
|
8
|
+
export function configureAxiosLogging(axios) {
|
|
9
|
+
const baseDebugger = debug("mw:api:client");
|
|
10
|
+
const reqDebugger = baseDebugger.extend("request");
|
|
11
|
+
const resDebugger = baseDebugger.extend("response");
|
|
12
|
+
axios.interceptors.request.use((config) => {
|
|
13
|
+
reqDebugger("%s %s requested with %O", config.method?.toUpperCase(), config.url, config.data);
|
|
14
|
+
return config;
|
|
15
|
+
});
|
|
16
|
+
axios.interceptors.response.use((response) => {
|
|
17
|
+
resDebugger("%s %s responded with %o %O", response.config.method?.toUpperCase(), response.config.url, response.status + " " + response.statusText, response.data);
|
|
18
|
+
return response;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -4,7 +4,7 @@ import { withProjectId } from "../project/flags.js";
|
|
|
4
4
|
import { autofillFlags, provideSupportedFlags, } from "./flags.js";
|
|
5
5
|
import { normalizeToAppVersionUuid } from "./versions.js";
|
|
6
6
|
import { triggerAppInstallation } from "./install.js";
|
|
7
|
-
import {
|
|
7
|
+
import { waitUntilAppStateHasNormalized } from "./wait.js";
|
|
8
8
|
import { Success } from "../../rendering/react/components/Success.js";
|
|
9
9
|
export class AppInstaller {
|
|
10
10
|
appId;
|
|
@@ -36,7 +36,7 @@ export class AppInstaller {
|
|
|
36
36
|
const appInstallationId = await triggerAppInstallation(apiClient, process, projectId, flags, appVersion);
|
|
37
37
|
let successText;
|
|
38
38
|
if (flags.wait) {
|
|
39
|
-
await
|
|
39
|
+
await waitUntilAppStateHasNormalized(apiClient, process, appInstallationId, "waiting for app installation to be ready");
|
|
40
40
|
successText = `Your ${this.appName} installation is now complete. Have fun! 🎉`;
|
|
41
41
|
}
|
|
42
42
|
else {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/lib/app/uuid.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MittwaldAPIV2, MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
2
|
+
type AppAppInstallation = MittwaldAPIV2.Components.Schemas.AppAppInstallation;
|
|
2
3
|
type AppAppVersion = MittwaldAPIV2.Components.Schemas.AppAppVersion;
|
|
3
4
|
type AppApp = MittwaldAPIV2.Components.Schemas.AppApp;
|
|
4
5
|
/**
|
|
@@ -16,6 +17,13 @@ export declare function getAppFromUuid(apiClient: MittwaldAPIV2Client, appId: st
|
|
|
16
17
|
* @param appVersionId
|
|
17
18
|
*/
|
|
18
19
|
export declare function getAppVersionFromUuid(apiClient: MittwaldAPIV2Client, appId: string, appVersionId: string): Promise<AppAppVersion>;
|
|
20
|
+
/**
|
|
21
|
+
* Lookup an appInstallation by its UUID
|
|
22
|
+
*
|
|
23
|
+
* @param apiClient
|
|
24
|
+
* @param appInstallationId
|
|
25
|
+
*/
|
|
26
|
+
export declare function getAppInstallationFromUuid(apiClient: MittwaldAPIV2Client, appInstallationId: string): Promise<AppAppInstallation>;
|
|
19
27
|
/**
|
|
20
28
|
* Lookup an app by its human readable name
|
|
21
29
|
*
|
package/dist/lib/app/uuid.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isUuid } from "../../normalize_id.js";
|
|
2
1
|
import { assertStatus, } from "@mittwald/api-client";
|
|
3
2
|
/**
|
|
4
3
|
* Lookup an app by its UUID
|
|
@@ -19,9 +18,6 @@ export async function getAppFromUuid(apiClient, appId) {
|
|
|
19
18
|
* @param appVersionId
|
|
20
19
|
*/
|
|
21
20
|
export async function getAppVersionFromUuid(apiClient, appId, appVersionId) {
|
|
22
|
-
if (!isUuid(appId) && !isUuid(appVersionId)) {
|
|
23
|
-
throw new Error("Given UUID not valid.");
|
|
24
|
-
}
|
|
25
21
|
const appVersion = await apiClient.app.getAppversion({
|
|
26
22
|
appId: appId,
|
|
27
23
|
appVersionId: appVersionId,
|
|
@@ -29,6 +25,19 @@ export async function getAppVersionFromUuid(apiClient, appId, appVersionId) {
|
|
|
29
25
|
assertStatus(appVersion, 200);
|
|
30
26
|
return appVersion.data;
|
|
31
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Lookup an appInstallation by its UUID
|
|
30
|
+
*
|
|
31
|
+
* @param apiClient
|
|
32
|
+
* @param appInstallationId
|
|
33
|
+
*/
|
|
34
|
+
export async function getAppInstallationFromUuid(apiClient, appInstallationId) {
|
|
35
|
+
const appInstallation = await apiClient.app.getAppinstallation({
|
|
36
|
+
appInstallationId: appInstallationId,
|
|
37
|
+
});
|
|
38
|
+
assertStatus(appInstallation, 200);
|
|
39
|
+
return appInstallation.data;
|
|
40
|
+
}
|
|
32
41
|
/**
|
|
33
42
|
* Convert an app name in a format suitable for fuzzy comparison (ignore casing,
|
|
34
43
|
* punctuation, etc.)
|
|
@@ -3,5 +3,9 @@ import { ProcessRenderer } from "../../rendering/process/process.js";
|
|
|
3
3
|
type AppVersion = MittwaldAPIV2.Components.Schemas.AppAppVersion;
|
|
4
4
|
export declare function normalizeToAppVersionUuid(apiClient: MittwaldAPIV2Client, version: string, process: ProcessRenderer, appUuid: string): Promise<MittwaldAPIV2.Components.Schemas.AppAppVersion>;
|
|
5
5
|
export declare function getLatestAvailableAppVersionForApp(apiClient: MittwaldAPIV2Client, appId: string): Promise<AppVersion | undefined>;
|
|
6
|
+
export declare function getAllUpgradeCandidatesFromAppInstallationId(apiClient: MittwaldAPIV2Client, appInstallationId: string): Promise<AppVersion[]>;
|
|
7
|
+
export declare function getLatestAvailableTargetAppVersionForAppVersionUpgradeCandidates(apiClient: MittwaldAPIV2Client, appId: string, baseAppVersionId: string): Promise<AppVersion | undefined>;
|
|
8
|
+
export declare function getAvailableTargetAppVersionFromExternalVersion(apiClient: MittwaldAPIV2Client, appId: string, baseAppVersionId: string, targetExternalVersion: string): Promise<AppVersion | undefined>;
|
|
6
9
|
export declare function getAppVersionUuidFromAppVersion(apiClient: MittwaldAPIV2Client, appId: string, appVersion: string | undefined): Promise<AppVersion | undefined>;
|
|
10
|
+
export declare function sortArrayByExternalVersion(versions: AppVersion[]): AppVersion[];
|
|
7
11
|
export {};
|
package/dist/lib/app/versions.js
CHANGED
|
@@ -3,7 +3,8 @@ import { assertStatus } from "@mittwald/api-client-commons";
|
|
|
3
3
|
import { gt } from "semver";
|
|
4
4
|
import { Value } from "../../rendering/react/components/Value.js";
|
|
5
5
|
import { Text } from "ink";
|
|
6
|
-
import { getAppNameFromUuid } from "./uuid.js";
|
|
6
|
+
import { getAppInstallationFromUuid, getAppNameFromUuid } from "./uuid.js";
|
|
7
|
+
import { compare } from "semver";
|
|
7
8
|
export async function normalizeToAppVersionUuid(apiClient, version, process, appUuid) {
|
|
8
9
|
let appVersion;
|
|
9
10
|
if (version && version !== "latest") {
|
|
@@ -35,7 +36,39 @@ export async function getLatestAvailableAppVersionForApp(apiClient, appId) {
|
|
|
35
36
|
}
|
|
36
37
|
return versions.data.find((item) => item.internalVersion === latestVersion);
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
+
export async function getAllUpgradeCandidatesFromAppInstallationId(apiClient, appInstallationId) {
|
|
40
|
+
const currentAppInstallation = await getAppInstallationFromUuid(apiClient, appInstallationId), updateCandidates = await apiClient.app.listUpdateCandidatesForAppversion({
|
|
41
|
+
appId: currentAppInstallation.appId,
|
|
42
|
+
baseAppVersionId: currentAppInstallation.appVersion.current,
|
|
43
|
+
});
|
|
44
|
+
assertStatus(updateCandidates, 200);
|
|
45
|
+
return sortArrayByExternalVersion(updateCandidates.data);
|
|
46
|
+
}
|
|
47
|
+
export async function getLatestAvailableTargetAppVersionForAppVersionUpgradeCandidates(apiClient, appId, baseAppVersionId) {
|
|
48
|
+
const versions = await apiClient.app.listUpdateCandidatesForAppversion({
|
|
49
|
+
appId,
|
|
50
|
+
baseAppVersionId,
|
|
51
|
+
});
|
|
52
|
+
assertStatus(versions, 200);
|
|
53
|
+
if (versions.data.length === 0) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
let latestVersion;
|
|
57
|
+
for (const version of versions.data) {
|
|
58
|
+
if (gt(version.internalVersion, latestVersion?.internalVersion ?? "0.0.0")) {
|
|
59
|
+
latestVersion = version;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return latestVersion;
|
|
63
|
+
}
|
|
64
|
+
export async function getAvailableTargetAppVersionFromExternalVersion(apiClient, appId, baseAppVersionId, targetExternalVersion) {
|
|
65
|
+
const versions = await apiClient.app.listUpdateCandidatesForAppversion({
|
|
66
|
+
appId,
|
|
67
|
+
baseAppVersionId,
|
|
68
|
+
});
|
|
69
|
+
assertStatus(versions, 200);
|
|
70
|
+
return versions.data.find((item) => item.externalVersion === targetExternalVersion);
|
|
71
|
+
}
|
|
39
72
|
export async function getAppVersionUuidFromAppVersion(apiClient, appId, appVersion) {
|
|
40
73
|
const versions = await apiClient.app.listAppversions({
|
|
41
74
|
appId,
|
|
@@ -47,3 +80,6 @@ export async function getAppVersionUuidFromAppVersion(apiClient, appId, appVersi
|
|
|
47
80
|
return versions.data.find((item) => item.internalVersion === appVersion ||
|
|
48
81
|
item.externalVersion === appVersion);
|
|
49
82
|
}
|
|
83
|
+
export function sortArrayByExternalVersion(versions) {
|
|
84
|
+
return versions.sort((a, b) => compare(b.externalVersion, a.externalVersion));
|
|
85
|
+
}
|
package/dist/lib/app/wait.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
2
2
|
import { ProcessRenderer } from "../../rendering/process/process.js";
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function waitUntilAppStateHasNormalized(apiClient: MittwaldAPIV2Client, process: ProcessRenderer, appInstallationId: string, label: string): Promise<void>;
|
package/dist/lib/app/wait.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { waitUntil } from "../wait.js";
|
|
3
3
|
import { Text } from "ink";
|
|
4
|
-
export async function
|
|
5
|
-
const stepWaiting = process.addStep(_jsx(Text, { children:
|
|
4
|
+
export async function waitUntilAppStateHasNormalized(apiClient, process, appInstallationId, label) {
|
|
5
|
+
const stepWaiting = process.addStep(_jsx(Text, { children: label }));
|
|
6
6
|
await waitUntil(async () => {
|
|
7
7
|
const installationResponse = await apiClient.app.getAppinstallation({
|
|
8
8
|
appInstallationId,
|