Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "app update" command to modify entrypoint/documentroot/... #520

Merged
merged 17 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ USAGE
* [`mw app list-upgrade-candidates [INSTALLATION-ID]`](#mw-app-list-upgrade-candidates-installation-id)
* [`mw app ssh [INSTALLATION-ID]`](#mw-app-ssh-installation-id)
* [`mw app uninstall [INSTALLATION-ID]`](#mw-app-uninstall-installation-id)
* [`mw app update [INSTALLATION-ID]`](#mw-app-update-installation-id)
* [`mw app upgrade [INSTALLATION-ID]`](#mw-app-upgrade-installation-id)
* [`mw app upload [INSTALLATION-ID]`](#mw-app-upload-installation-id)
* [`mw app versions [APP]`](#mw-app-versions-app)
Expand Down Expand Up @@ -2027,6 +2028,45 @@ FLAG DESCRIPTIONS
scripts), you can use this flag to easily get the IDs of created resources for further processing.
```

## `mw app update [INSTALLATION-ID]`

Update properties of an app installation (use 'upgrade' to update the app version)

```
USAGE
$ mw app update [INSTALLATION-ID] [-q] [--description <value>] [--entrypoint <value>] [--document-root <value>]

ARGUMENTS
INSTALLATION-ID ID or short ID of an app installation; this argument is optional if a default app installation is set
in the context.

FLAGS
-q, --quiet suppress process output and only display a machine-readable summary.
--description=<value> update the description of the app installation
--document-root=<value> update the document root of the app installation
--entrypoint=<value> update the entrypoint of the app installation (Python and Node.js only)

FLAG DESCRIPTIONS
-q, --quiet suppress process output and only display a machine-readable summary.

This flag controls if you want to see the process output or only a summary. When using mw non-interactively (e.g. in
scripts), you can use this flag to easily get the IDs of created resources for further processing.

--description=<value> update the description of the app installation

This flag updates the description of the app installation. If omitted, the description will not be changed.

--document-root=<value> update the document root of the app installation

Updates the document root of the app installation. If omitted, the document root will not be changed. Note that not
all apps support this field.

--entrypoint=<value> update the entrypoint of the app installation (Python and Node.js only)

Updates the entrypoint of the app installation. If omitted, the entrypoint will not be changed. Note that this field
is only available for some types of apps (like Python and Node.js).
```

## `mw app upgrade [INSTALLATION-ID]`

Upgrade app installation to target version
Expand Down
137 changes: 137 additions & 0 deletions src/commands/app/update.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { ExecRenderBaseCommand } from "../../lib/basecommands/ExecRenderBaseCommand.js";
import React, { ReactNode } from "react";
import {
appInstallationArgs,
withAppInstallationId,
} from "../../lib/resources/app/flags.js";
import {
makeProcessRenderer,
processFlags,
} from "../../rendering/process/process_flags.js";
import { MittwaldAPIV2 } from "@mittwald/api-client";
import { Success } from "../../rendering/react/components/Success.js";
import { Value } from "../../rendering/react/components/Value.js";
import { Flags } from "@oclif/core";
import { CommandFlags } from "../../lib/basecommands/CommandFlags.js";

type AppSavedUserInput = MittwaldAPIV2.Components.Schemas.AppSavedUserInput;
type AppAppUpdatePolicy = MittwaldAPIV2.Components.Schemas.AppAppUpdatePolicy;

/**
* This is a carefully selected subset of the "patchAppinstallation" request
* body; the type needs to be inlined, because it's not exported from the API
* client.
*/
type UpdateBody = {
customDocumentRoot?: string;
description?: string;
updatePolicy?: AppAppUpdatePolicy;
userInputs?: AppSavedUserInput[];
};

export class Update extends ExecRenderBaseCommand<typeof Update, void> {
static summary =
"Update properties of an app installation (use 'upgrade' to update the app version)";
static args = { ...appInstallationArgs };
static flags = {
...processFlags,
description: Flags.string({
summary: "update the description of the app installation",
description:
"This flag updates the description of the app installation. If omitted, the description will not be changed.",
default: undefined,
required: false,
}),
entrypoint: Flags.string({
summary:
"update the entrypoint of the app installation (Python and Node.js only)",
description:
"Updates the entrypoint of the app installation. If omitted, the entrypoint will not be changed. Note that this field is only available for some types of apps (like Python and Node.js).",
required: false,
default: undefined,
}),
"document-root": Flags.string({
summary: "update the document root of the app installation",
description:
"Updates the document root of the app installation. If omitted, the document root will not be changed. Note that not all apps support this field.",
required: false,
default: undefined,
}),
};

protected async exec(): Promise<void> {
const p = makeProcessRenderer(this.flags, "Updating app installation");
const appInstallationId = await withAppInstallationId(
this.apiClient,
Update,
this.flags,
this.args,
this.config,
);

const [updateBody, info] = buildUpdateBodyFromFlags(this.flags);

info.forEach((i) => p.addInfo(i));

if (Object.keys(updateBody).length === 0) {
p.addInfo("skipping update");
await p.complete(<Success>No changes to apply</Success>);
return;
}

this.debug("updating app installation: %O", updateBody);

await p.runStep("updating app", async () => {
await this.apiClient.app.patchAppinstallation({
appInstallationId,
data: updateBody,
});
});

await p.complete(<Success>App installation successfully updated</Success>);
}

protected render(): React.ReactNode {
return undefined;
}
}

function buildUpdateBodyFromFlags(
flags: CommandFlags<typeof Update>,
): [UpdateBody, ReactNode[]] {
const updateBody: UpdateBody = {};
const info: ReactNode[] = [];

if (flags.entrypoint) {
info.push(<UpdateFieldInfo name="entrypoint" value={flags.entrypoint} />);
updateBody.userInputs = [
...(updateBody.userInputs || []),
{
name: "entrypoint",
value: flags.entrypoint,
},
];
}

if (flags["document-root"]) {
info.push(
<UpdateFieldInfo name="document root" value={flags["document-root"]} />,
);
updateBody.customDocumentRoot = flags["document-root"];
}

if (flags.description !== undefined) {
info.push(<UpdateFieldInfo name="description" value={flags.description} />);
updateBody.description = flags.description;
}

return [updateBody, info];
}

function UpdateFieldInfo({ name, value }: { name: string; value: string }) {
return (
<>
setting {name} to <Value>{value}</Value>
</>
);
}
Loading