alpic 0.0.0-dev.ff7eedf → 0.0.0-dev.ffd67d5
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 +40 -0
- package/bin/run.js +5 -0
- package/dist/__tests__/audit.e2e.test.d.ts +1 -0
- package/dist/__tests__/audit.e2e.test.js +557 -0
- package/dist/__tests__/audit.e2e.test.js.map +1 -0
- package/dist/__tests__/auth.e2e.test.d.ts +1 -0
- package/dist/__tests__/auth.e2e.test.js +157 -0
- package/dist/__tests__/auth.e2e.test.js.map +1 -0
- package/dist/__tests__/deploy-flags.e2e.test.d.ts +1 -0
- package/dist/__tests__/deploy-flags.e2e.test.js +188 -0
- package/dist/__tests__/deploy-flags.e2e.test.js.map +1 -0
- package/dist/__tests__/deploy.e2e.test.d.ts +1 -0
- package/dist/__tests__/deploy.e2e.test.js +180 -0
- package/dist/__tests__/deploy.e2e.test.js.map +1 -0
- package/dist/__tests__/deployment-inspect.e2e.test.d.ts +1 -0
- package/dist/__tests__/deployment-inspect.e2e.test.js +114 -0
- package/dist/__tests__/deployment-inspect.e2e.test.js.map +1 -0
- package/dist/__tests__/deployment-list.e2e.test.d.ts +1 -0
- package/dist/__tests__/deployment-list.e2e.test.js +116 -0
- package/dist/__tests__/deployment-list.e2e.test.js.map +1 -0
- package/dist/__tests__/deployment-logs.e2e.test.d.ts +1 -0
- package/dist/__tests__/deployment-logs.e2e.test.js +255 -0
- package/dist/__tests__/deployment-logs.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.js +259 -0
- package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.js +139 -0
- package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.js +150 -0
- package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.js +342 -0
- package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-validation.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-validation.test.js +20 -0
- package/dist/__tests__/environment-variable/environment-variable-validation.test.js.map +1 -0
- package/dist/__tests__/fixtures/demo-project/index.d.ts +1 -0
- package/dist/__tests__/fixtures/demo-project/index.js +4 -0
- package/dist/__tests__/fixtures/demo-project/index.js.map +1 -0
- package/dist/__tests__/git-flags.e2e.test.d.ts +1 -0
- package/dist/__tests__/git-flags.e2e.test.js +124 -0
- package/dist/__tests__/git-flags.e2e.test.js.map +1 -0
- package/dist/__tests__/git.e2e.test.d.ts +1 -0
- package/dist/__tests__/git.e2e.test.js +221 -0
- package/dist/__tests__/git.e2e.test.js.map +1 -0
- package/dist/__tests__/link.e2e.test.d.ts +1 -0
- package/dist/__tests__/link.e2e.test.js +279 -0
- package/dist/__tests__/link.e2e.test.js.map +1 -0
- package/dist/__tests__/logs.e2e.test.d.ts +1 -0
- package/dist/__tests__/logs.e2e.test.js +227 -0
- package/dist/__tests__/logs.e2e.test.js.map +1 -0
- package/dist/__tests__/mock-server.d.ts +44 -0
- package/dist/__tests__/mock-server.js +784 -0
- package/dist/__tests__/mock-server.js.map +1 -0
- package/dist/__tests__/publish.e2e.test.d.ts +1 -0
- package/dist/__tests__/publish.e2e.test.js +505 -0
- package/dist/__tests__/publish.e2e.test.js.map +1 -0
- package/dist/__tests__/tunnel.e2e.test.d.ts +1 -0
- package/dist/__tests__/tunnel.e2e.test.js +61 -0
- package/dist/__tests__/tunnel.e2e.test.js.map +1 -0
- package/dist/__tests__/utils.d.ts +73 -0
- package/dist/__tests__/utils.js +284 -0
- package/dist/__tests__/utils.js.map +1 -0
- package/dist/api.d.ts +3 -0
- package/dist/api.js +22 -0
- package/dist/api.js.map +1 -0
- package/dist/commands/audit.d.ts +14 -0
- package/dist/commands/audit.js +49 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/deploy.d.ts +15 -0
- package/dist/commands/deploy.js +121 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/deployment/inspect.d.ts +11 -0
- package/dist/commands/deployment/inspect.js +91 -0
- package/dist/commands/deployment/inspect.js.map +1 -0
- package/dist/commands/deployment/list.d.ts +11 -0
- package/dist/commands/deployment/list.js +97 -0
- package/dist/commands/deployment/list.js.map +1 -0
- package/dist/commands/deployment/logs.d.ts +12 -0
- package/dist/commands/deployment/logs.js +50 -0
- package/dist/commands/deployment/logs.js.map +1 -0
- package/dist/commands/environment-variable/add.d.ts +14 -0
- package/dist/commands/environment-variable/add.js +47 -0
- package/dist/commands/environment-variable/add.js.map +1 -0
- package/dist/commands/environment-variable/list.d.ts +9 -0
- package/dist/commands/environment-variable/list.js +45 -0
- package/dist/commands/environment-variable/list.js.map +1 -0
- package/dist/commands/environment-variable/remove.d.ts +11 -0
- package/dist/commands/environment-variable/remove.js +33 -0
- package/dist/commands/environment-variable/remove.js.map +1 -0
- package/dist/commands/environment-variable/update.d.ts +13 -0
- package/dist/commands/environment-variable/update.js +41 -0
- package/dist/commands/environment-variable/update.js.map +1 -0
- package/dist/commands/git/connect.d.ts +10 -0
- package/dist/commands/git/connect.js +60 -0
- package/dist/commands/git/connect.js.map +1 -0
- package/dist/commands/git/disconnect.d.ts +9 -0
- package/dist/commands/git/disconnect.js +45 -0
- package/dist/commands/git/disconnect.js.map +1 -0
- package/dist/commands/{hello.d.ts → git.d.ts} +1 -1
- package/dist/commands/git.js +17 -0
- package/dist/commands/git.js.map +1 -0
- package/dist/commands/link.d.ts +17 -0
- package/dist/commands/link.js +101 -0
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.js +21 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +6 -0
- package/dist/commands/logout.js +20 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/logs.d.ts +16 -0
- package/dist/commands/logs.js +96 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/publish.d.ts +15 -0
- package/dist/commands/publish.js +51 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/telemetry/disable.d.ts +5 -0
- package/dist/commands/telemetry/disable.js +14 -0
- package/dist/commands/telemetry/disable.js.map +1 -0
- package/dist/commands/telemetry/enable.d.ts +5 -0
- package/dist/commands/telemetry/enable.js +13 -0
- package/dist/commands/telemetry/enable.js.map +1 -0
- package/dist/commands/telemetry/status.d.ts +5 -0
- package/dist/commands/telemetry/status.js +19 -0
- package/dist/commands/telemetry/status.js.map +1 -0
- package/dist/commands/tunnel.d.ts +9 -0
- package/dist/commands/tunnel.js +96 -0
- package/dist/commands/tunnel.js.map +1 -0
- package/dist/commands/whoami.d.ts +6 -0
- package/dist/commands/whoami.js +13 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/env.d.ts +4 -0
- package/dist/env.js +10 -0
- package/dist/env.js.map +1 -0
- package/dist/lib/alpic-command.d.ts +6 -0
- package/dist/lib/alpic-command.js +25 -0
- package/dist/lib/alpic-command.js.map +1 -0
- package/dist/lib/archive.d.ts +7 -0
- package/dist/lib/archive.js +51 -0
- package/dist/lib/archive.js.map +1 -0
- package/dist/lib/audit.d.ts +16 -0
- package/dist/lib/audit.js +244 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/auth/auth.d.ts +3 -0
- package/dist/lib/auth/auth.js +39 -0
- package/dist/lib/auth/auth.js.map +1 -0
- package/dist/lib/auth/oauth/client.d.ts +28 -0
- package/dist/lib/auth/oauth/client.js +110 -0
- package/dist/lib/auth/oauth/client.js.map +1 -0
- package/dist/lib/auth/oauth/constants.d.ts +2 -0
- package/dist/lib/auth/oauth/constants.js +3 -0
- package/dist/lib/auth/oauth/constants.js.map +1 -0
- package/dist/lib/auth/oauth/server/assets/alpic-mountain.png +0 -0
- package/dist/lib/auth/oauth/server/assets/authorize.html +195 -0
- package/dist/lib/auth/oauth/server/assets/callback.html +88 -0
- package/dist/lib/auth/oauth/server/index.d.ts +8 -0
- package/dist/lib/auth/oauth/server/index.js +105 -0
- package/dist/lib/auth/oauth/server/index.js.map +1 -0
- package/dist/lib/auth/whoami.d.ts +1 -0
- package/dist/lib/auth/whoami.js +45 -0
- package/dist/lib/auth/whoami.js.map +1 -0
- package/dist/lib/base-workflow.d.ts +10 -0
- package/dist/lib/base-workflow.js +22 -0
- package/dist/lib/base-workflow.js.map +1 -0
- package/dist/lib/config.d.ts +12 -0
- package/dist/lib/config.js +32 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/deployment.d.ts +88 -0
- package/dist/lib/deployment.js +150 -0
- package/dist/lib/deployment.js.map +1 -0
- package/dist/lib/environment-variable.d.ts +37 -0
- package/dist/lib/environment-variable.js +299 -0
- package/dist/lib/environment-variable.js.map +1 -0
- package/dist/lib/git.d.ts +22 -0
- package/dist/lib/git.js +131 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/global-store.d.ts +28 -0
- package/dist/lib/global-store.js +76 -0
- package/dist/lib/global-store.js.map +1 -0
- package/dist/lib/link.d.ts +83 -0
- package/dist/lib/link.js +387 -0
- package/dist/lib/link.js.map +1 -0
- package/dist/lib/logs.d.ts +20 -0
- package/dist/lib/logs.js +86 -0
- package/dist/lib/logs.js.map +1 -0
- package/dist/lib/publish.d.ts +22 -0
- package/dist/lib/publish.js +185 -0
- package/dist/lib/publish.js.map +1 -0
- package/dist/lib/resolve.d.ts +6 -0
- package/dist/lib/resolve.js +26 -0
- package/dist/lib/resolve.js.map +1 -0
- package/dist/lib/table.d.ts +8 -0
- package/dist/lib/table.js +27 -0
- package/dist/lib/table.js.map +1 -0
- package/dist/lib/telemetry.d.ts +7 -0
- package/dist/lib/telemetry.js +66 -0
- package/dist/lib/telemetry.js.map +1 -0
- package/dist/lib/upload.d.ts +1 -0
- package/dist/lib/upload.js +14 -0
- package/dist/lib/upload.js.map +1 -0
- package/dist/lib/utils.d.ts +4 -0
- package/dist/lib/utils.js +45 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/utils.test.d.ts +1 -0
- package/dist/lib/utils.test.js +27 -0
- package/dist/lib/utils.test.js.map +1 -0
- package/dist/posthog.d.ts +3 -0
- package/dist/posthog.js +10 -0
- package/dist/posthog.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -12
- package/dist/commands/hello.js +0 -10
- package/dist/commands/hello.js.map +0 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
export type Flags = {
|
|
3
|
+
"non-interactive"?: boolean;
|
|
4
|
+
};
|
|
5
|
+
export declare abstract class BaseWorkflow<F extends Flags = Flags> {
|
|
6
|
+
readonly flags: F;
|
|
7
|
+
constructor(flags: F);
|
|
8
|
+
protected confirm(options: p.ConfirmOptions, defaultValue?: boolean): Promise<boolean | symbol>;
|
|
9
|
+
protected isNonInteractive(): boolean;
|
|
10
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import * as ci from "ci-info";
|
|
3
|
+
export class BaseWorkflow {
|
|
4
|
+
flags;
|
|
5
|
+
constructor(flags) {
|
|
6
|
+
this.flags = flags;
|
|
7
|
+
}
|
|
8
|
+
confirm(options, defaultValue = true) {
|
|
9
|
+
if (this.isNonInteractive()) {
|
|
10
|
+
return Promise.resolve(defaultValue);
|
|
11
|
+
}
|
|
12
|
+
return p.confirm(options);
|
|
13
|
+
}
|
|
14
|
+
isNonInteractive() {
|
|
15
|
+
if (this.flags["non-interactive"])
|
|
16
|
+
return true;
|
|
17
|
+
if (process.env.VITEST)
|
|
18
|
+
return false;
|
|
19
|
+
return ci.isCI ?? false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=base-workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-workflow.js","sourceRoot":"","sources":["../../src/lib/base-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAM9B,MAAM,OAAgB,YAAY;IACJ;IAA5B,YAA4B,KAAQ;QAAR,UAAK,GAAL,KAAK,CAAG;IAAG,CAAC;IAE9B,OAAO,CAAC,OAAyB,EAAE,eAAwB,IAAI;QACvE,IAAI,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;YAC5B,OAAO,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAES,gBAAgB;QACxB,IAAI,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC;YAAE,OAAO,IAAI,CAAC;QAC/C,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAErC,OAAO,EAAE,CAAC,IAAI,IAAI,KAAK,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ProjectConfig } from "../types.js";
|
|
2
|
+
export declare const config: {
|
|
3
|
+
load: () => {
|
|
4
|
+
projectId: string;
|
|
5
|
+
teamId: string;
|
|
6
|
+
teamName: string | undefined;
|
|
7
|
+
projectName: string;
|
|
8
|
+
environmentId: string | undefined;
|
|
9
|
+
environmentName: string | undefined;
|
|
10
|
+
} | null;
|
|
11
|
+
save: (projectConfig: ProjectConfig) => void;
|
|
12
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const getProjectJsonPath = () => join(process.cwd(), ".alpic", "project.json");
|
|
4
|
+
export const config = {
|
|
5
|
+
load: () => {
|
|
6
|
+
const path = getProjectJsonPath();
|
|
7
|
+
if (!existsSync(path)) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
let raw;
|
|
11
|
+
try {
|
|
12
|
+
raw = JSON.parse(readFileSync(path, "utf8"));
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
throw new Error(`Failed to load project config: ${error.message}`);
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
projectId: raw.projectId,
|
|
19
|
+
teamId: raw.teamId,
|
|
20
|
+
teamName: raw.teamName,
|
|
21
|
+
projectName: raw.projectName ?? raw.projectId,
|
|
22
|
+
environmentId: raw.environmentId,
|
|
23
|
+
environmentName: raw.environmentName,
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
save: (projectConfig) => {
|
|
27
|
+
const path = getProjectJsonPath();
|
|
28
|
+
mkdirSync(join(process.cwd(), ".alpic"), { recursive: true });
|
|
29
|
+
writeFileSync(path, JSON.stringify(projectConfig, null, 2));
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,MAAM,kBAAkB,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;AAE/E,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,GAAG,EAAE;QACT,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,GAAmE,CAAC;QACxE,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAG1C,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,kCAAmC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QAChF,CAAC;QACD,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,SAAS;YAC7C,aAAa,EAAE,GAAG,CAAC,aAAa;YAChC,eAAe,EAAE,GAAG,CAAC,eAAe;SACrC,CAAC;IACJ,CAAC;IACD,IAAI,EAAE,CAAC,aAA4B,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC;QAClC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { RouterOutput } from "@alpic-ai/api";
|
|
2
|
+
export declare const colorizeDeploymentStatus: (text: string) => import("chalk").ChalkInstance | ((value: string) => string);
|
|
3
|
+
export declare function formatElapsed(ms: number): string;
|
|
4
|
+
export declare function calculateDeploymentDuration(deployment: {
|
|
5
|
+
startedAt?: Date | null;
|
|
6
|
+
completedAt?: Date | null;
|
|
7
|
+
}): number | null;
|
|
8
|
+
export declare function fetchDeployment(deploymentId: string): Promise<{
|
|
9
|
+
id: string;
|
|
10
|
+
status: "failed" | "ongoing" | "deployed" | "canceled";
|
|
11
|
+
sourceRef: string | null;
|
|
12
|
+
sourceCommitId: string | null;
|
|
13
|
+
sourceCommitMessage: string | null;
|
|
14
|
+
authorUsername: string | null;
|
|
15
|
+
authorAvatarUrl: string | null;
|
|
16
|
+
startedAt: Date | null;
|
|
17
|
+
completedAt: Date | null;
|
|
18
|
+
environmentId: string;
|
|
19
|
+
environmentName: string;
|
|
20
|
+
isCurrent: boolean;
|
|
21
|
+
deploymentPageUrl: string | null;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function fetchLatestDeploymentForEnvironment(environmentId: string): Promise<{
|
|
24
|
+
id: string;
|
|
25
|
+
status: "failed" | "ongoing" | "deployed" | "canceled";
|
|
26
|
+
sourceRef: string | null;
|
|
27
|
+
sourceCommitId: string | null;
|
|
28
|
+
sourceCommitMessage: string | null;
|
|
29
|
+
authorUsername: string | null;
|
|
30
|
+
authorAvatarUrl: string | null;
|
|
31
|
+
startedAt: Date | null;
|
|
32
|
+
completedAt: Date | null;
|
|
33
|
+
environmentId: string;
|
|
34
|
+
environmentName: string;
|
|
35
|
+
isCurrent: boolean;
|
|
36
|
+
deploymentPageUrl: string | null;
|
|
37
|
+
}>;
|
|
38
|
+
export declare function resolveDeploymentId(flags: {
|
|
39
|
+
"deployment-id"?: string;
|
|
40
|
+
"environment-id"?: string;
|
|
41
|
+
}): Promise<string>;
|
|
42
|
+
export declare function waitForDeployment(deployment: RouterOutput["deployments"]["get"]["v1"]): Promise<{
|
|
43
|
+
id: string;
|
|
44
|
+
status: "failed" | "ongoing" | "deployed" | "canceled";
|
|
45
|
+
sourceRef: string | null;
|
|
46
|
+
sourceCommitId: string | null;
|
|
47
|
+
sourceCommitMessage: string | null;
|
|
48
|
+
authorUsername: string | null;
|
|
49
|
+
authorAvatarUrl: string | null;
|
|
50
|
+
startedAt: Date | null;
|
|
51
|
+
completedAt: Date | null;
|
|
52
|
+
environmentId: string;
|
|
53
|
+
environmentName: string;
|
|
54
|
+
isCurrent: boolean;
|
|
55
|
+
deploymentPageUrl: string | null;
|
|
56
|
+
}>;
|
|
57
|
+
type DeploymentLogEntry = {
|
|
58
|
+
timestamp?: Date;
|
|
59
|
+
content?: string;
|
|
60
|
+
};
|
|
61
|
+
export declare function printDeploymentLog(log: DeploymentLogEntry, { noColor }?: {
|
|
62
|
+
noColor?: boolean;
|
|
63
|
+
}): void;
|
|
64
|
+
export declare function followDeploymentLogs(deploymentId: string, initialLogs: DeploymentLogEntry[], { noColor }?: {
|
|
65
|
+
noColor?: boolean;
|
|
66
|
+
}): Promise<void>;
|
|
67
|
+
export declare function deployAndWait({ initial, startedAt, }: {
|
|
68
|
+
initial: RouterOutput["deployments"]["get"]["v1"];
|
|
69
|
+
startedAt: number;
|
|
70
|
+
}): Promise<{
|
|
71
|
+
deployment: {
|
|
72
|
+
id: string;
|
|
73
|
+
status: "failed" | "ongoing" | "deployed" | "canceled";
|
|
74
|
+
sourceRef: string | null;
|
|
75
|
+
sourceCommitId: string | null;
|
|
76
|
+
sourceCommitMessage: string | null;
|
|
77
|
+
authorUsername: string | null;
|
|
78
|
+
authorAvatarUrl: string | null;
|
|
79
|
+
startedAt: Date | null;
|
|
80
|
+
completedAt: Date | null;
|
|
81
|
+
environmentId: string;
|
|
82
|
+
environmentName: string;
|
|
83
|
+
isCurrent: boolean;
|
|
84
|
+
deploymentPageUrl: string | null;
|
|
85
|
+
};
|
|
86
|
+
elapsedMs: number;
|
|
87
|
+
}>;
|
|
88
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { stripVTControlCharacters } from "node:util";
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { api } from "../api.js";
|
|
5
|
+
import { formatLogTimestamp } from "./logs.js";
|
|
6
|
+
import { resolveEnvironmentId } from "./resolve.js";
|
|
7
|
+
export const colorizeDeploymentStatus = (text) => {
|
|
8
|
+
switch (text) {
|
|
9
|
+
case "deployed":
|
|
10
|
+
return chalk.green;
|
|
11
|
+
case "ongoing":
|
|
12
|
+
return chalk.yellow;
|
|
13
|
+
case "failed":
|
|
14
|
+
return chalk.red;
|
|
15
|
+
case "canceled":
|
|
16
|
+
return chalk.gray;
|
|
17
|
+
default:
|
|
18
|
+
return (value) => value;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const FINAL_STATUSES = new Set(["deployed", "failed", "canceled"]);
|
|
22
|
+
const FIFTEEN_MINUTES_IN_MS = 15 * 60 * 1000;
|
|
23
|
+
export function formatElapsed(ms) {
|
|
24
|
+
const totalSeconds = Math.floor(ms / 1000);
|
|
25
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
26
|
+
const seconds = totalSeconds % 60;
|
|
27
|
+
return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
28
|
+
}
|
|
29
|
+
export function calculateDeploymentDuration(deployment) {
|
|
30
|
+
if (!deployment.startedAt || !deployment.completedAt) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return deployment.completedAt.getTime() - deployment.startedAt.getTime();
|
|
34
|
+
}
|
|
35
|
+
export async function fetchDeployment(deploymentId) {
|
|
36
|
+
const spinner = p.spinner();
|
|
37
|
+
spinner.start("Fetching deployment...");
|
|
38
|
+
const deployment = await api.deployments.get.v1({ deploymentId });
|
|
39
|
+
spinner.stop("Deployment found");
|
|
40
|
+
return deployment;
|
|
41
|
+
}
|
|
42
|
+
export async function fetchLatestDeploymentForEnvironment(environmentId) {
|
|
43
|
+
const spinner = p.spinner();
|
|
44
|
+
spinner.start("Fetching latest deployment...");
|
|
45
|
+
const environment = await api.environments.get.v1({ environmentId });
|
|
46
|
+
const deployments = await api.deployments.list.v1({
|
|
47
|
+
projectId: environment.projectId,
|
|
48
|
+
environmentId,
|
|
49
|
+
});
|
|
50
|
+
const latest = deployments[0];
|
|
51
|
+
if (!latest) {
|
|
52
|
+
spinner.stop("No deployments found");
|
|
53
|
+
throw new Error(`No deployments found for environment ${environmentId}.`);
|
|
54
|
+
}
|
|
55
|
+
spinner.stop("Deployment found");
|
|
56
|
+
return latest;
|
|
57
|
+
}
|
|
58
|
+
export async function resolveDeploymentId(flags) {
|
|
59
|
+
if (flags["deployment-id"]) {
|
|
60
|
+
return flags["deployment-id"];
|
|
61
|
+
}
|
|
62
|
+
const environmentId = resolveEnvironmentId(flags);
|
|
63
|
+
const deployment = await fetchLatestDeploymentForEnvironment(environmentId);
|
|
64
|
+
return deployment.id;
|
|
65
|
+
}
|
|
66
|
+
export async function waitForDeployment(deployment) {
|
|
67
|
+
if (FINAL_STATUSES.has(deployment.status)) {
|
|
68
|
+
return deployment;
|
|
69
|
+
}
|
|
70
|
+
const startedAt = deployment.startedAt?.getTime() ?? Date.now();
|
|
71
|
+
const waitStartedAt = Date.now();
|
|
72
|
+
let current = deployment;
|
|
73
|
+
const spinner = p.spinner();
|
|
74
|
+
spinner.start("Waiting for deployment to complete");
|
|
75
|
+
const elapsedInterval = setInterval(() => {
|
|
76
|
+
spinner.message(`Waiting for deployment to complete — ${formatElapsed(Date.now() - startedAt)}`);
|
|
77
|
+
}, 1000);
|
|
78
|
+
try {
|
|
79
|
+
while (!FINAL_STATUSES.has(current.status)) {
|
|
80
|
+
if (Date.now() - waitStartedAt >= FIFTEEN_MINUTES_IN_MS) {
|
|
81
|
+
throw new Error("Deployment did not reach a final state within 15 minutes.");
|
|
82
|
+
}
|
|
83
|
+
current = await api.deployments.get.v1({ deploymentId: current.id });
|
|
84
|
+
if (!FINAL_STATUSES.has(current.status)) {
|
|
85
|
+
await new Promise((resolve) => setTimeout(resolve, 3_000));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
spinner.stop(`Deployment is ${colorizeDeploymentStatus(current.status)(current.status)}`);
|
|
89
|
+
return current;
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
clearInterval(elapsedInterval);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const DEPLOYMENT_LOG_POLL_INTERVAL_MS = 5_000;
|
|
96
|
+
export function printDeploymentLog(log, { noColor = false } = {}) {
|
|
97
|
+
const ts = formatLogTimestamp(log.timestamp, noColor);
|
|
98
|
+
const rawContent = (log.content ?? "").trimEnd();
|
|
99
|
+
const content = noColor ? stripVTControlCharacters(rawContent) : rawContent;
|
|
100
|
+
process.stdout.write(`${ts} ${content}\n`);
|
|
101
|
+
}
|
|
102
|
+
export async function followDeploymentLogs(deploymentId, initialLogs, { noColor = false } = {}) {
|
|
103
|
+
let printedCount = initialLogs.length;
|
|
104
|
+
while (true) {
|
|
105
|
+
await new Promise((resolve) => setTimeout(resolve, DEPLOYMENT_LOG_POLL_INTERVAL_MS));
|
|
106
|
+
const result = await api.deployments.getLogs.v1({ deploymentId });
|
|
107
|
+
for (const log of result.logs.slice(printedCount)) {
|
|
108
|
+
printDeploymentLog(log, { noColor });
|
|
109
|
+
}
|
|
110
|
+
printedCount = result.logs.length;
|
|
111
|
+
if (!result.hasMoreLogs)
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export async function deployAndWait({ initial, startedAt, }) {
|
|
116
|
+
const spinner = p.spinner();
|
|
117
|
+
let deployment = initial;
|
|
118
|
+
const deploymentPageUrl = deployment.deploymentPageUrl;
|
|
119
|
+
if (deploymentPageUrl) {
|
|
120
|
+
p.note(`🔗 ${deploymentPageUrl}`, "View deployment details:", {
|
|
121
|
+
format: (line) => line,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
spinner.start("Deployment in progress");
|
|
125
|
+
const elapsedInterval = setInterval(() => {
|
|
126
|
+
const elapsed = formatElapsed(Date.now() - startedAt);
|
|
127
|
+
spinner.message(`Deployment in progress — ${elapsed}`);
|
|
128
|
+
}, 1000);
|
|
129
|
+
try {
|
|
130
|
+
while (deployment.status === "ongoing") {
|
|
131
|
+
const elapsedMs = Date.now() - startedAt;
|
|
132
|
+
if (elapsedMs >= FIFTEEN_MINUTES_IN_MS) {
|
|
133
|
+
throw new Error(`Deployment aborted after 15 minutes. View status: ${deploymentPageUrl}`);
|
|
134
|
+
}
|
|
135
|
+
deployment = await api.deployments.get.v1({
|
|
136
|
+
deploymentId: deployment.id,
|
|
137
|
+
});
|
|
138
|
+
if (deployment.status === "ongoing") {
|
|
139
|
+
await new Promise((resolve) => setTimeout(resolve, 10_000));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { deployment, elapsedMs: Date.now() - startedAt };
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
const message = deployment.status === "deployed" ? chalk.green("Deployment completed") : chalk.red("Deployment failed");
|
|
146
|
+
spinner.stop(message);
|
|
147
|
+
clearInterval(elapsedInterval);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=deployment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../src/lib/deployment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BaseWorkflow } from "./base-workflow.js";
|
|
2
|
+
export type EnvVar = {
|
|
3
|
+
key: string;
|
|
4
|
+
value: string;
|
|
5
|
+
isSecret: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type EnvironmentVariableWorkflowFlags = {
|
|
8
|
+
"non-interactive"?: boolean;
|
|
9
|
+
key?: string;
|
|
10
|
+
value?: string;
|
|
11
|
+
secret?: boolean;
|
|
12
|
+
"env-file"?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function isValidEnvironmentVariableKey(key: string): boolean;
|
|
15
|
+
export declare function fetchEnvironmentVariables(environmentId: string): Promise<{
|
|
16
|
+
id: string;
|
|
17
|
+
key: string;
|
|
18
|
+
value: string;
|
|
19
|
+
isSecret: boolean;
|
|
20
|
+
createdAt: Date;
|
|
21
|
+
}[]>;
|
|
22
|
+
export declare class EnvironmentVariableWorkflow extends BaseWorkflow<EnvironmentVariableWorkflowFlags> {
|
|
23
|
+
protected isNonInteractive(): boolean;
|
|
24
|
+
add(environmentId: string): Promise<void>;
|
|
25
|
+
update(environmentId: string): Promise<void>;
|
|
26
|
+
remove(environmentId: string): Promise<void>;
|
|
27
|
+
private resolveEnvironmentVariablesForAdd;
|
|
28
|
+
private resolveAddKey;
|
|
29
|
+
private resolveAddValue;
|
|
30
|
+
private resolveAddSecret;
|
|
31
|
+
private resolveUpdateInput;
|
|
32
|
+
private resolveUpdateKey;
|
|
33
|
+
private resolveUpdateValue;
|
|
34
|
+
private resolveUpdateSecret;
|
|
35
|
+
private resolveRemoveKey;
|
|
36
|
+
private promptRemoveKey;
|
|
37
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { environmentVariableSchema } from "@alpic-ai/api";
|
|
3
|
+
import * as p from "@clack/prompts";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { parse as parseEnvFile } from "envfile";
|
|
6
|
+
import { api } from "../api.js";
|
|
7
|
+
import { BaseWorkflow } from "./base-workflow.js";
|
|
8
|
+
export function isValidEnvironmentVariableKey(key) {
|
|
9
|
+
return environmentVariableSchema.shape.key.safeParse(key).success;
|
|
10
|
+
}
|
|
11
|
+
function pluralizeEnvVars(count) {
|
|
12
|
+
return `environment variable${count === 1 ? "" : "s"}`;
|
|
13
|
+
}
|
|
14
|
+
export async function fetchEnvironmentVariables(environmentId) {
|
|
15
|
+
const spinner = p.spinner();
|
|
16
|
+
spinner.start("Fetching environment variables...");
|
|
17
|
+
const environmentVariables = await api.environmentVariables.list.v1({
|
|
18
|
+
environmentId,
|
|
19
|
+
});
|
|
20
|
+
spinner.stop(`Found ${environmentVariables.length} ${pluralizeEnvVars(environmentVariables.length)}`);
|
|
21
|
+
return environmentVariables;
|
|
22
|
+
}
|
|
23
|
+
export class EnvironmentVariableWorkflow extends BaseWorkflow {
|
|
24
|
+
isNonInteractive() {
|
|
25
|
+
return this.flags["non-interactive"] || super.isNonInteractive();
|
|
26
|
+
}
|
|
27
|
+
async add(environmentId) {
|
|
28
|
+
const { "env-file": envFile, key, value } = this.flags;
|
|
29
|
+
if (envFile && (key || value)) {
|
|
30
|
+
throw new Error("--env-file cannot be used together with --key or --value.");
|
|
31
|
+
}
|
|
32
|
+
const environmentVariables = await this.resolveEnvironmentVariablesForAdd();
|
|
33
|
+
const spinner = p.spinner();
|
|
34
|
+
spinner.start(`Adding ${environmentVariables.length} ${pluralizeEnvVars(environmentVariables.length)}...`);
|
|
35
|
+
await api.environmentVariables.create.v1({
|
|
36
|
+
environmentId,
|
|
37
|
+
environmentVariables,
|
|
38
|
+
});
|
|
39
|
+
const count = environmentVariables.length;
|
|
40
|
+
spinner.stop(`Successfully added ${count} ${pluralizeEnvVars(count)}. ✅`);
|
|
41
|
+
}
|
|
42
|
+
async update(environmentId) {
|
|
43
|
+
const environmentVariables = await fetchEnvironmentVariables(environmentId);
|
|
44
|
+
if (environmentVariables.length === 0) {
|
|
45
|
+
throw new Error("No environment variables found in this environment.");
|
|
46
|
+
}
|
|
47
|
+
const updateInput = await this.resolveUpdateInput(environmentVariables);
|
|
48
|
+
const variable = environmentVariables.find((v) => v.key === updateInput.key);
|
|
49
|
+
if (!variable) {
|
|
50
|
+
throw new Error(`Environment variable "${updateInput.key}" not found.`);
|
|
51
|
+
}
|
|
52
|
+
const spinner = p.spinner();
|
|
53
|
+
spinner.start("Updating environment variable...");
|
|
54
|
+
await api.environmentVariables.update.v1({
|
|
55
|
+
environmentVariableId: variable.id,
|
|
56
|
+
key: variable.key,
|
|
57
|
+
value: updateInput.value,
|
|
58
|
+
isSecret: updateInput.isSecret ?? variable.isSecret,
|
|
59
|
+
});
|
|
60
|
+
spinner.stop(`Successfully updated ${chalk.cyan(updateInput.key)}. ✅`);
|
|
61
|
+
}
|
|
62
|
+
async remove(environmentId) {
|
|
63
|
+
const environmentVariables = await fetchEnvironmentVariables(environmentId);
|
|
64
|
+
if (environmentVariables.length === 0) {
|
|
65
|
+
throw new Error("No environment variables found in this environment.");
|
|
66
|
+
}
|
|
67
|
+
const resolvedKey = await this.resolveRemoveKey(environmentVariables);
|
|
68
|
+
const variable = environmentVariables.find((v) => v.key === resolvedKey);
|
|
69
|
+
if (!variable) {
|
|
70
|
+
throw new Error(`Environment variable "${resolvedKey}" not found.`);
|
|
71
|
+
}
|
|
72
|
+
const spinner = p.spinner();
|
|
73
|
+
spinner.start("Removing environment variable...");
|
|
74
|
+
await api.environmentVariables.delete.v1({
|
|
75
|
+
environmentVariableId: variable.id,
|
|
76
|
+
});
|
|
77
|
+
spinner.stop(`Successfully removed ${chalk.cyan(resolvedKey)}. ✅`);
|
|
78
|
+
}
|
|
79
|
+
async resolveEnvironmentVariablesForAdd() {
|
|
80
|
+
const { "env-file": envFile, key, value, secret } = this.flags;
|
|
81
|
+
if (envFile) {
|
|
82
|
+
const parsed = parseEnvFile(readFileSync(envFile, "utf8"));
|
|
83
|
+
const environmentVariables = Object.entries(parsed).map(([key, value]) => {
|
|
84
|
+
if (!isValidEnvironmentVariableKey(key)) {
|
|
85
|
+
throw new Error(`Invalid key "${key}" in env file: must start with a letter and contain only letters, numbers, and underscores.`);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
key,
|
|
89
|
+
value,
|
|
90
|
+
isSecret: secret ?? true,
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
if (environmentVariables.length === 0) {
|
|
94
|
+
throw new Error("No valid environment variables found in the provided file.");
|
|
95
|
+
}
|
|
96
|
+
return environmentVariables;
|
|
97
|
+
}
|
|
98
|
+
if (this.isNonInteractive()) {
|
|
99
|
+
if (!key || value === undefined) {
|
|
100
|
+
throw new Error("--key and --value are required in non-interactive mode.");
|
|
101
|
+
}
|
|
102
|
+
if (value.trim() === "") {
|
|
103
|
+
throw new Error("Value cannot be empty.");
|
|
104
|
+
}
|
|
105
|
+
if (!isValidEnvironmentVariableKey(key)) {
|
|
106
|
+
throw new Error(`Invalid key "${key}": must start with a letter and contain only letters, numbers, and underscores.`);
|
|
107
|
+
}
|
|
108
|
+
return [{ key, value, isSecret: secret ?? true }];
|
|
109
|
+
}
|
|
110
|
+
const resolvedKey = await this.resolveAddKey(key);
|
|
111
|
+
const resolvedValue = await this.resolveAddValue(value);
|
|
112
|
+
const isSecret = await this.resolveAddSecret();
|
|
113
|
+
return [{ key: resolvedKey, value: resolvedValue, isSecret }];
|
|
114
|
+
}
|
|
115
|
+
async resolveAddKey(key) {
|
|
116
|
+
const trimmed = key?.trim();
|
|
117
|
+
if (trimmed !== undefined && trimmed !== "") {
|
|
118
|
+
if (!isValidEnvironmentVariableKey(trimmed)) {
|
|
119
|
+
throw new Error(`Invalid key "${trimmed}": must start with a letter and contain only letters, numbers, and underscores.`);
|
|
120
|
+
}
|
|
121
|
+
return trimmed;
|
|
122
|
+
}
|
|
123
|
+
const resolvedKey = await p.text({
|
|
124
|
+
message: "Variable key",
|
|
125
|
+
validate: (v) => {
|
|
126
|
+
const trimmed = v?.trim();
|
|
127
|
+
if (trimmed === undefined || trimmed === "") {
|
|
128
|
+
return "Key is required";
|
|
129
|
+
}
|
|
130
|
+
if (!isValidEnvironmentVariableKey(trimmed)) {
|
|
131
|
+
return "Key must start with a letter and contain only letters, numbers, and underscores";
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
if (p.isCancel(resolvedKey)) {
|
|
137
|
+
throw new Error("Cancelled.");
|
|
138
|
+
}
|
|
139
|
+
return resolvedKey.trim();
|
|
140
|
+
}
|
|
141
|
+
async resolveAddValue(value) {
|
|
142
|
+
const trimmed = value?.trim();
|
|
143
|
+
if (trimmed === "") {
|
|
144
|
+
throw new Error("Value cannot be empty.");
|
|
145
|
+
}
|
|
146
|
+
if (trimmed !== undefined) {
|
|
147
|
+
return trimmed;
|
|
148
|
+
}
|
|
149
|
+
const resolvedValue = await p.password({
|
|
150
|
+
message: "Variable value",
|
|
151
|
+
validate: (v) => (v === undefined || v.trim() === "" ? "Value is required" : undefined),
|
|
152
|
+
});
|
|
153
|
+
if (p.isCancel(resolvedValue)) {
|
|
154
|
+
throw new Error("Cancelled.");
|
|
155
|
+
}
|
|
156
|
+
return resolvedValue.trim();
|
|
157
|
+
}
|
|
158
|
+
async resolveAddSecret() {
|
|
159
|
+
if (this.flags.secret !== undefined) {
|
|
160
|
+
return this.flags.secret;
|
|
161
|
+
}
|
|
162
|
+
const secretAnswer = await p.confirm({
|
|
163
|
+
message: "Mark as secret?",
|
|
164
|
+
initialValue: true,
|
|
165
|
+
});
|
|
166
|
+
if (p.isCancel(secretAnswer)) {
|
|
167
|
+
throw new Error("Cancelled.");
|
|
168
|
+
}
|
|
169
|
+
return secretAnswer;
|
|
170
|
+
}
|
|
171
|
+
async resolveUpdateInput(environmentVariables) {
|
|
172
|
+
const { key, value, secret } = this.flags;
|
|
173
|
+
if (this.isNonInteractive()) {
|
|
174
|
+
if (key === undefined || (value === undefined && secret === undefined)) {
|
|
175
|
+
throw new Error("--key and one of --value or --secret/--no-secret are required in non-interactive mode.");
|
|
176
|
+
}
|
|
177
|
+
if (value !== undefined && value.trim() === "") {
|
|
178
|
+
throw new Error("Value cannot be empty.");
|
|
179
|
+
}
|
|
180
|
+
return { key, value, isSecret: secret };
|
|
181
|
+
}
|
|
182
|
+
const resolvedKey = await this.resolveUpdateKey(environmentVariables);
|
|
183
|
+
const resolvedValue = await this.resolveUpdateValue(resolvedKey);
|
|
184
|
+
const resolvedSecret = await this.resolveUpdateSecret(environmentVariables, resolvedKey);
|
|
185
|
+
return { key: resolvedKey, value: resolvedValue, isSecret: resolvedSecret };
|
|
186
|
+
}
|
|
187
|
+
async resolveUpdateKey(environmentVariables) {
|
|
188
|
+
const { key } = this.flags;
|
|
189
|
+
const trimmed = key?.trim();
|
|
190
|
+
if (trimmed !== undefined && trimmed !== "") {
|
|
191
|
+
return trimmed;
|
|
192
|
+
}
|
|
193
|
+
const selectedKey = await p.select({
|
|
194
|
+
message: "Select a variable to update",
|
|
195
|
+
options: environmentVariables.map((variable) => ({
|
|
196
|
+
value: variable.key,
|
|
197
|
+
label: variable.key,
|
|
198
|
+
hint: variable.isSecret ? "<secret>" : variable.value,
|
|
199
|
+
})),
|
|
200
|
+
});
|
|
201
|
+
if (p.isCancel(selectedKey)) {
|
|
202
|
+
throw new Error("Cancelled.");
|
|
203
|
+
}
|
|
204
|
+
return selectedKey;
|
|
205
|
+
}
|
|
206
|
+
async resolveUpdateValue(resolvedKey) {
|
|
207
|
+
const { value } = this.flags;
|
|
208
|
+
if (this.isNonInteractive()) {
|
|
209
|
+
if (value === undefined) {
|
|
210
|
+
p.log.info("No value provided, keeping the current value.");
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
const trimmed = value.trim();
|
|
214
|
+
if (trimmed === "") {
|
|
215
|
+
throw new Error("Value cannot be empty.");
|
|
216
|
+
}
|
|
217
|
+
return trimmed;
|
|
218
|
+
}
|
|
219
|
+
if (value !== undefined) {
|
|
220
|
+
const trimmed = value.trim();
|
|
221
|
+
if (trimmed === "") {
|
|
222
|
+
throw new Error("Value cannot be empty.");
|
|
223
|
+
}
|
|
224
|
+
return trimmed;
|
|
225
|
+
}
|
|
226
|
+
const resolvedValue = (await p.password({
|
|
227
|
+
message: `New value for ${chalk.cyan(resolvedKey)}`,
|
|
228
|
+
})); // When user doesn't provide a value, the prompt returns undefined.
|
|
229
|
+
if (p.isCancel(resolvedValue)) {
|
|
230
|
+
throw new Error("Cancelled.");
|
|
231
|
+
}
|
|
232
|
+
if (resolvedValue === undefined || resolvedValue.trim() === "") {
|
|
233
|
+
p.log.info("No value provided, keeping the current value.");
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
return resolvedValue.trim();
|
|
237
|
+
}
|
|
238
|
+
async resolveUpdateSecret(environmentVariables, key) {
|
|
239
|
+
const { secret } = this.flags;
|
|
240
|
+
if (this.isNonInteractive()) {
|
|
241
|
+
return secret;
|
|
242
|
+
}
|
|
243
|
+
const variable = environmentVariables.find((item) => item.key === key);
|
|
244
|
+
if (!variable) {
|
|
245
|
+
throw new Error(`Environment variable "${key}" not found.`);
|
|
246
|
+
}
|
|
247
|
+
const secretAnswer = await p.select({
|
|
248
|
+
message: "Mark as secret?",
|
|
249
|
+
initialValue: variable.isSecret,
|
|
250
|
+
options: [
|
|
251
|
+
{
|
|
252
|
+
value: true,
|
|
253
|
+
label: variable.isSecret ? "Yes (current)" : "Yes",
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
value: false,
|
|
257
|
+
label: variable.isSecret ? "No" : "No (current)",
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
});
|
|
261
|
+
if (p.isCancel(secretAnswer)) {
|
|
262
|
+
throw new Error("Cancelled.");
|
|
263
|
+
}
|
|
264
|
+
return secretAnswer;
|
|
265
|
+
}
|
|
266
|
+
async resolveRemoveKey(environmentVariables) {
|
|
267
|
+
const { key } = this.flags;
|
|
268
|
+
if (this.isNonInteractive()) {
|
|
269
|
+
if (!key) {
|
|
270
|
+
throw new Error("--key is required in non-interactive mode.");
|
|
271
|
+
}
|
|
272
|
+
return key;
|
|
273
|
+
}
|
|
274
|
+
const selectedKey = key ?? (await this.promptRemoveKey(environmentVariables));
|
|
275
|
+
const confirmed = await p.confirm({
|
|
276
|
+
message: `Remove ${chalk.cyan(selectedKey)}?`,
|
|
277
|
+
initialValue: false,
|
|
278
|
+
});
|
|
279
|
+
if (p.isCancel(confirmed) || !confirmed) {
|
|
280
|
+
throw new Error("Cancelled.");
|
|
281
|
+
}
|
|
282
|
+
return selectedKey;
|
|
283
|
+
}
|
|
284
|
+
async promptRemoveKey(environmentVariables) {
|
|
285
|
+
const selectedKey = await p.select({
|
|
286
|
+
message: "Select a variable to remove",
|
|
287
|
+
options: environmentVariables.map((variable) => ({
|
|
288
|
+
value: variable.key,
|
|
289
|
+
label: variable.key,
|
|
290
|
+
hint: variable.isSecret ? "<secret>" : variable.value,
|
|
291
|
+
})),
|
|
292
|
+
});
|
|
293
|
+
if (p.isCancel(selectedKey)) {
|
|
294
|
+
throw new Error("Cancelled.");
|
|
295
|
+
}
|
|
296
|
+
return selectedKey;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=environment-variable.js.map
|