@quantum-hub/qhubctl 2.2.2-next.1 → 2.2.3-next.1
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 +4 -2
- package/dist/commands/compress.d.ts +1 -1
- package/dist/commands/compress.js +15 -15
- package/dist/commands/datapool-upload.d.ts +1 -1
- package/dist/commands/datapool-upload.js +35 -35
- package/dist/commands/get-context.d.ts +1 -1
- package/dist/commands/get-context.js +5 -5
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +33 -29
- package/dist/commands/list-contexts.d.ts +1 -1
- package/dist/commands/list-contexts.js +21 -13
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.js +16 -16
- package/dist/commands/logout.d.ts +1 -1
- package/dist/commands/logout.js +10 -10
- package/dist/commands/openapi.d.ts +1 -1
- package/dist/commands/openapi.js +112 -94
- package/dist/commands/run.d.ts +3 -3
- package/dist/commands/run.js +37 -34
- package/dist/commands/serve.d.ts +1 -1
- package/dist/commands/serve.js +30 -19
- package/dist/commands/services-build-logs.d.ts +2 -2
- package/dist/commands/services-build-logs.js +26 -26
- package/dist/commands/services-build-status.d.ts +1 -1
- package/dist/commands/services-build-status.js +21 -21
- package/dist/commands/services-list.d.ts +1 -1
- package/dist/commands/services-list.js +20 -17
- package/dist/commands/set-context.d.ts +1 -1
- package/dist/commands/set-context.js +18 -16
- package/dist/commands/up.d.ts +1 -1
- package/dist/commands/up.js +50 -48
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/command.js +2 -2
- package/dist/lib/config-dir.js +3 -3
- package/dist/lib/debug.js +1 -1
- package/dist/lib/entrypoint-resolver.js +15 -15
- package/dist/lib/error.js +4 -4
- package/dist/lib/fetch.js +3 -1
- package/dist/lib/init-user-input.d.ts +1 -1
- package/dist/lib/init-user-input.js +28 -26
- package/dist/lib/output.d.ts +2 -2
- package/dist/lib/output.js +3 -3
- package/dist/lib/random-name.js +147 -147
- package/dist/lib/random-string.js +2 -2
- package/dist/lib/repository.js +5 -5
- package/dist/lib/stream-to-blob.d.ts +1 -1
- package/dist/lib/stream-to-blob.js +5 -5
- package/dist/lib/up/get-description.js +8 -8
- package/dist/lib/up/ignore.js +8 -8
- package/dist/lib/up/qhubignore-help.js +10 -10
- package/dist/lib/up/required-files.js +17 -12
- package/dist/lib/up/source.d.ts +2 -2
- package/dist/lib/up/source.js +7 -7
- package/dist/lib/up/zip.js +8 -8
- package/dist/main.js +3 -3
- package/dist/model/command.d.ts +2 -2
- package/dist/model/command.js +9 -9
- package/dist/model/managed-service-config.d.ts +1 -1
- package/dist/model/user-config.js +1 -1
- package/dist/program.d.ts +1 -1
- package/dist/program.js +24 -24
- package/dist/service/auth-service.d.ts +3 -3
- package/dist/service/auth-service.js +11 -9
- package/dist/service/command-service.d.ts +1 -1
- package/dist/service/quantum-hub-service.d.ts +3 -3
- package/dist/service/quantum-hub-service.js +34 -20
- package/dist/service/service-config-service.d.ts +1 -1
- package/dist/service/service-config-service.js +8 -8
- package/dist/service/user-config-service.d.ts +1 -1
- package/dist/service/user-config-service.js +7 -7
- package/dist/service/user-service.d.ts +2 -2
- package/dist/service/user-service.js +4 -4
- package/package.json +9 -3
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { input } from
|
|
2
|
-
import { Command } from
|
|
3
|
-
import { error, spinner, stdout } from
|
|
4
|
-
import { requireAuth } from
|
|
5
|
-
import QuantumHubService from
|
|
6
|
-
import { readServiceConfig } from
|
|
1
|
+
import { input } from "@inquirer/prompts";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { error, spinner, stdout } from "../lib/output.js";
|
|
4
|
+
import { requireAuth } from "../model/command.js";
|
|
5
|
+
import QuantumHubService from "../service/quantum-hub-service.js";
|
|
6
|
+
import { readServiceConfig } from "../service/service-config-service.js";
|
|
7
7
|
const SEVERITY_COLUMN_WIDTH = 7;
|
|
8
|
-
const COLUMN_GAP =
|
|
9
|
-
const ANSI_RESET =
|
|
8
|
+
const COLUMN_GAP = " ";
|
|
9
|
+
const ANSI_RESET = "\x1b[0m";
|
|
10
10
|
const ANSI_BY_SEVERITY = {
|
|
11
|
-
DEBUG:
|
|
12
|
-
WARNING:
|
|
13
|
-
ERROR:
|
|
11
|
+
DEBUG: "\x1b[2m",
|
|
12
|
+
WARNING: "\x1b[33m",
|
|
13
|
+
ERROR: "\x1b[31m",
|
|
14
14
|
};
|
|
15
15
|
export function formatLogEntry(entry, opts) {
|
|
16
|
-
const timestamp = entry.timestamp ??
|
|
17
|
-
const severity = entry.severity ??
|
|
18
|
-
const message = entry.message ??
|
|
19
|
-
const paddedSeverity = severity.padEnd(SEVERITY_COLUMN_WIDTH,
|
|
16
|
+
const timestamp = entry.timestamp ?? "-";
|
|
17
|
+
const severity = entry.severity ?? "INFO";
|
|
18
|
+
const message = entry.message ?? "";
|
|
19
|
+
const paddedSeverity = severity.padEnd(SEVERITY_COLUMN_WIDTH, " ");
|
|
20
20
|
const ansi = opts.isTTY ? ANSI_BY_SEVERITY[severity] : undefined;
|
|
21
21
|
const severityCell = ansi ? `${ansi}${paddedSeverity}${ANSI_RESET}` : paddedSeverity;
|
|
22
22
|
return `${timestamp}${COLUMN_GAP}${severityCell}${COLUMN_GAP}${message}`;
|
|
@@ -26,11 +26,11 @@ Examples:
|
|
|
26
26
|
$ qhubctl services build-logs
|
|
27
27
|
$ qhubctl services build-logs --id <serviceId>
|
|
28
28
|
$ qhubctl services build-logs --id <serviceId> --json`;
|
|
29
|
-
export const servicesBuildLogsCommand = new Command(
|
|
30
|
-
.description(
|
|
31
|
-
.option(
|
|
32
|
-
.option(
|
|
33
|
-
.addHelpText(
|
|
29
|
+
export const servicesBuildLogsCommand = new Command("build-logs")
|
|
30
|
+
.description("Show the build logs of a service.")
|
|
31
|
+
.option("--id <value>", "The ID of the service (reads from qhub.json if omitted)")
|
|
32
|
+
.option("--json", "Output in JSON format", false)
|
|
33
|
+
.addHelpText("after", EXAMPLES)
|
|
34
34
|
.action(async (opts) => {
|
|
35
35
|
const userConfig = await requireAuth({ printContext: !opts.json });
|
|
36
36
|
const quantumHubService = new QuantumHubService(userConfig);
|
|
@@ -46,7 +46,7 @@ export const servicesBuildLogsCommand = new Command('build-logs')
|
|
|
46
46
|
}
|
|
47
47
|
if (!serviceId) {
|
|
48
48
|
try {
|
|
49
|
-
serviceId = await input({ message:
|
|
49
|
+
serviceId = await input({ message: "Enter the service ID:" });
|
|
50
50
|
}
|
|
51
51
|
catch {
|
|
52
52
|
// user cancelled (Ctrl+C)
|
|
@@ -54,25 +54,25 @@ export const servicesBuildLogsCommand = new Command('build-logs')
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
if (!serviceId?.trim()) {
|
|
57
|
-
error(
|
|
57
|
+
error("No service ID provided.");
|
|
58
58
|
}
|
|
59
|
-
const spin = spinner(
|
|
59
|
+
const spin = spinner("Loading build logs");
|
|
60
60
|
let logs;
|
|
61
61
|
try {
|
|
62
62
|
logs = await quantumHubService.getBuildLogs(serviceId);
|
|
63
63
|
}
|
|
64
64
|
catch (err) {
|
|
65
|
-
spin.fail(
|
|
65
|
+
spin.fail("Failed to load build logs");
|
|
66
66
|
error(err instanceof Error ? err.message : String(err));
|
|
67
67
|
}
|
|
68
|
-
spin.succeed(
|
|
68
|
+
spin.succeed("Build logs loaded");
|
|
69
69
|
if (opts.json) {
|
|
70
70
|
stdout(JSON.stringify(logs, null, 2));
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
if (logs.length === 0) {
|
|
74
74
|
stdout();
|
|
75
|
-
stdout(
|
|
75
|
+
stdout("No build logs available.");
|
|
76
76
|
stdout();
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import { Command } from "commander";
|
|
2
2
|
export declare const servicesBuildStatusCommand: Command;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { input } from
|
|
2
|
-
import { Command } from
|
|
3
|
-
import { error, spinner, stdout } from
|
|
4
|
-
import { requireAuth } from
|
|
5
|
-
import QuantumHubService from
|
|
6
|
-
import { readServiceConfig } from
|
|
1
|
+
import { input } from "@inquirer/prompts";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { error, spinner, stdout } from "../lib/output.js";
|
|
4
|
+
import { requireAuth } from "../model/command.js";
|
|
5
|
+
import QuantumHubService from "../service/quantum-hub-service.js";
|
|
6
|
+
import { readServiceConfig } from "../service/service-config-service.js";
|
|
7
7
|
const EXAMPLES = `
|
|
8
8
|
Examples:
|
|
9
9
|
$ qhubctl services build-status
|
|
10
10
|
$ qhubctl services build-status --id <serviceId>
|
|
11
11
|
$ qhubctl services build-status --id <serviceId> --json`;
|
|
12
|
-
export const servicesBuildStatusCommand = new Command(
|
|
13
|
-
.description(
|
|
14
|
-
.option(
|
|
15
|
-
.option(
|
|
16
|
-
.addHelpText(
|
|
12
|
+
export const servicesBuildStatusCommand = new Command("build-status")
|
|
13
|
+
.description("Show the build status of a service.")
|
|
14
|
+
.option("--id <value>", "The ID of the service (reads from qhub.json if omitted)")
|
|
15
|
+
.option("--json", "Output in JSON format", false)
|
|
16
|
+
.addHelpText("after", EXAMPLES)
|
|
17
17
|
.action(async (opts) => {
|
|
18
18
|
const userConfig = await requireAuth({ printContext: !opts.json });
|
|
19
19
|
const quantumHubService = new QuantumHubService(userConfig);
|
|
@@ -29,7 +29,7 @@ export const servicesBuildStatusCommand = new Command('build-status')
|
|
|
29
29
|
}
|
|
30
30
|
if (!serviceId) {
|
|
31
31
|
try {
|
|
32
|
-
serviceId = await input({ message:
|
|
32
|
+
serviceId = await input({ message: "Enter the service ID:" });
|
|
33
33
|
}
|
|
34
34
|
catch {
|
|
35
35
|
// user cancelled (Ctrl+C)
|
|
@@ -37,31 +37,31 @@ export const servicesBuildStatusCommand = new Command('build-status')
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
if (!serviceId?.trim()) {
|
|
40
|
-
error(
|
|
40
|
+
error("No service ID provided.");
|
|
41
41
|
}
|
|
42
|
-
const spin = spinner(
|
|
42
|
+
const spin = spinner("Loading build status");
|
|
43
43
|
let buildJob;
|
|
44
44
|
try {
|
|
45
45
|
buildJob = await quantumHubService.getBuildJob(serviceId);
|
|
46
46
|
}
|
|
47
47
|
catch (err) {
|
|
48
|
-
spin.fail(
|
|
48
|
+
spin.fail("Failed to load build status");
|
|
49
49
|
error(err instanceof Error ? err.message : String(err));
|
|
50
50
|
}
|
|
51
|
-
spin.succeed(
|
|
51
|
+
spin.succeed("Build status loaded");
|
|
52
52
|
if (opts.json) {
|
|
53
53
|
stdout(JSON.stringify(buildJob, null, 2));
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
56
|
stdout();
|
|
57
57
|
stdout(`Service ID: ${serviceId}`);
|
|
58
|
-
stdout(`Status: ${buildJob.status ??
|
|
59
|
-
stdout(`Step: ${buildJob.step ??
|
|
60
|
-
stdout(`Started: ${buildJob.createdAt ??
|
|
61
|
-
stdout(`Finished: ${buildJob.finishedAt ??
|
|
58
|
+
stdout(`Status: ${buildJob.status ?? "N/A"}`);
|
|
59
|
+
stdout(`Step: ${buildJob.step ?? "N/A"}`);
|
|
60
|
+
stdout(`Started: ${buildJob.createdAt ?? "N/A"}`);
|
|
61
|
+
stdout(`Finished: ${buildJob.finishedAt ?? "N/A"}`);
|
|
62
62
|
if (buildJob.validationResult) {
|
|
63
63
|
const v = buildJob.validationResult;
|
|
64
|
-
stdout(`Validation: ${v.state ??
|
|
64
|
+
stdout(`Validation: ${v.state ?? "N/A"}`);
|
|
65
65
|
if (v.summary) {
|
|
66
66
|
stdout(` Summary: ${v.summary}`);
|
|
67
67
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import { Command } from "commander";
|
|
2
2
|
export declare const servicesListCommand: Command;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Command } from
|
|
2
|
-
import Table from
|
|
3
|
-
import { spinner, stdout, warn } from
|
|
4
|
-
import { requireAuth } from
|
|
5
|
-
import QuantumHubService from
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import Table from "tty-table";
|
|
3
|
+
import { spinner, stdout, warn } from "../lib/output.js";
|
|
4
|
+
import { requireAuth } from "../model/command.js";
|
|
5
|
+
import QuantumHubService from "../service/quantum-hub-service.js";
|
|
6
6
|
const EXAMPLES = `
|
|
7
7
|
Examples:
|
|
8
8
|
$ qhubctl services list
|
|
@@ -10,27 +10,30 @@ Examples:
|
|
|
10
10
|
$ qhubctl services list --name "my-service"
|
|
11
11
|
$ qhubctl services list --name "my-service" --json
|
|
12
12
|
$ qhubctl services list --json --all`;
|
|
13
|
-
export const servicesListCommand = new Command(
|
|
14
|
-
.description(
|
|
15
|
-
.option(
|
|
16
|
-
.option(
|
|
17
|
-
.option(
|
|
18
|
-
.addHelpText(
|
|
13
|
+
export const servicesListCommand = new Command("list")
|
|
14
|
+
.description("List all services of the current context.")
|
|
15
|
+
.option("--json", "Output in JSON format", false)
|
|
16
|
+
.option("--name <value>", "Filter services by name (case-insensitive full match)")
|
|
17
|
+
.option("--all", "Display all service properties (only available with --json)", false)
|
|
18
|
+
.addHelpText("after", EXAMPLES)
|
|
19
19
|
.action(async (opts) => {
|
|
20
20
|
// suppress "Current context: ..." line when outputting JSON
|
|
21
21
|
const userConfig = await requireAuth({ printContext: !opts.json });
|
|
22
22
|
const quantumHubService = new QuantumHubService(userConfig);
|
|
23
23
|
if (opts.all && !opts.json) {
|
|
24
|
-
warn(
|
|
24
|
+
warn("The --all flag can only be used with --json output. Continuing without --all.");
|
|
25
25
|
}
|
|
26
|
-
const spin = spinner(
|
|
26
|
+
const spin = spinner("Loading services");
|
|
27
27
|
let services = await quantumHubService.getServices();
|
|
28
|
-
spin.succeed(
|
|
28
|
+
spin.succeed("Services loaded");
|
|
29
29
|
if (opts.name) {
|
|
30
30
|
const nameFilter = opts.name.toLowerCase();
|
|
31
|
-
services = services.filter(service => service.name?.toLowerCase() === nameFilter);
|
|
31
|
+
services = services.filter((service) => service.name?.toLowerCase() === nameFilter);
|
|
32
32
|
}
|
|
33
|
-
const tableData = services.map(service => ({
|
|
33
|
+
const tableData = services.map((service) => ({
|
|
34
|
+
id: service.id,
|
|
35
|
+
name: service.name,
|
|
36
|
+
}));
|
|
34
37
|
if (opts.json) {
|
|
35
38
|
stdout(JSON.stringify(opts.all ? services : tableData, null, 2));
|
|
36
39
|
return;
|
|
@@ -41,7 +44,7 @@ export const servicesListCommand = new Command('list')
|
|
|
41
44
|
];
|
|
42
45
|
const t = Table(header, tableData);
|
|
43
46
|
const contextName = userConfig.context?.displayName;
|
|
44
|
-
const filterInfo = opts.name ? ` (filtered by name: "${opts.name}")` :
|
|
47
|
+
const filterInfo = opts.name ? ` (filtered by name: "${opts.name}")` : "";
|
|
45
48
|
stdout(`Available services for ${contextName}${filterInfo}:`);
|
|
46
49
|
stdout(t.render());
|
|
47
50
|
stdout();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import { Command } from "commander";
|
|
2
2
|
export declare const setContextCommand: Command;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { select } from
|
|
2
|
-
import { Command } from
|
|
3
|
-
import { error, spinner, stdout } from
|
|
4
|
-
import { configDir, requireAuth } from
|
|
5
|
-
import QuantumHubService from
|
|
6
|
-
import { writeUserConfig } from
|
|
1
|
+
import { select } from "@inquirer/prompts";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { error, spinner, stdout } from "../lib/output.js";
|
|
4
|
+
import { configDir, requireAuth } from "../model/command.js";
|
|
5
|
+
import QuantumHubService from "../service/quantum-hub-service.js";
|
|
6
|
+
import { writeUserConfig } from "../service/user-config-service.js";
|
|
7
7
|
function getPromptOptions(accounts) {
|
|
8
|
-
return accounts.map(account => ({
|
|
9
|
-
name: account.isOrganization
|
|
8
|
+
return accounts.map((account) => ({
|
|
9
|
+
name: account.isOrganization
|
|
10
|
+
? `${account.displayName} (Organization)`
|
|
11
|
+
: (account.displayName ?? account.id ?? ""),
|
|
10
12
|
value: account,
|
|
11
13
|
}));
|
|
12
14
|
}
|
|
@@ -14,26 +16,26 @@ const EXAMPLES = `
|
|
|
14
16
|
Examples:
|
|
15
17
|
$ qhubctl set-context
|
|
16
18
|
$ qhubctl set-context <context-id>`;
|
|
17
|
-
export const setContextCommand = new Command(
|
|
18
|
-
.description(
|
|
19
|
-
.argument(
|
|
20
|
-
.addHelpText(
|
|
19
|
+
export const setContextCommand = new Command("set-context")
|
|
20
|
+
.description("Set the current context, i.e., the personal or organization account you are currently working with.")
|
|
21
|
+
.argument("[contextId]", "The ID of the context to switch to")
|
|
22
|
+
.addHelpText("after", EXAMPLES)
|
|
21
23
|
.action(async (contextId) => {
|
|
22
24
|
const userConfig = await requireAuth();
|
|
23
25
|
const quantumHubService = new QuantumHubService(userConfig);
|
|
24
26
|
if (!contextId) {
|
|
25
|
-
const spin = spinner(
|
|
27
|
+
const spin = spinner("Loading available contexts");
|
|
26
28
|
const accounts = await quantumHubService.getAccounts();
|
|
27
|
-
spin.succeed(
|
|
29
|
+
spin.succeed("Contexts loaded");
|
|
28
30
|
const response = await select({
|
|
29
31
|
choices: getPromptOptions(accounts),
|
|
30
|
-
message:
|
|
32
|
+
message: "Choose a context",
|
|
31
33
|
default: accounts[0],
|
|
32
34
|
});
|
|
33
35
|
contextId = response.id;
|
|
34
36
|
}
|
|
35
37
|
const accounts = await quantumHubService.getAccounts();
|
|
36
|
-
const selectedContext = accounts.find(account => account.id === contextId);
|
|
38
|
+
const selectedContext = accounts.find((account) => account.id === contextId);
|
|
37
39
|
if (!selectedContext) {
|
|
38
40
|
error(`Context with id "${contextId}" not found.`);
|
|
39
41
|
}
|
package/dist/commands/up.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import { Command } from "commander";
|
|
2
2
|
export declare const upCommand: Command;
|
package/dist/commands/up.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { confirm, input, password } from
|
|
2
|
-
import { HubPlatform } from
|
|
3
|
-
import { waitUntil } from
|
|
4
|
-
import { Command } from
|
|
5
|
-
import fs from
|
|
6
|
-
import path from
|
|
7
|
-
import { error, spinner, stdout, warn } from
|
|
8
|
-
import { streamToBlob } from
|
|
9
|
-
import { getDescriptionText } from
|
|
10
|
-
import { QHUBIGNORE_HELP } from
|
|
11
|
-
import { enforceRequiredFiles } from
|
|
12
|
-
import { buildServiceSource, isRegistrySource, resolveRegistryCredentials } from
|
|
13
|
-
import { zipProjectFolder } from
|
|
14
|
-
import { requireAuth } from
|
|
15
|
-
import QuantumHubService from
|
|
16
|
-
import { readServiceConfig, writeServiceConfig } from
|
|
1
|
+
import { confirm, input, password } from "@inquirer/prompts";
|
|
2
|
+
import { HubPlatform } from "@quantum-hub/qhub-api/platform";
|
|
3
|
+
import { waitUntil } from "async-wait-until";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { error, spinner, stdout, warn } from "../lib/output.js";
|
|
8
|
+
import { streamToBlob } from "../lib/stream-to-blob.js";
|
|
9
|
+
import { getDescriptionText } from "../lib/up/get-description.js";
|
|
10
|
+
import { QHUBIGNORE_HELP } from "../lib/up/qhubignore-help.js";
|
|
11
|
+
import { enforceRequiredFiles } from "../lib/up/required-files.js";
|
|
12
|
+
import { buildServiceSource, isRegistrySource, resolveRegistryCredentials, } from "../lib/up/source.js";
|
|
13
|
+
import { zipProjectFolder } from "../lib/up/zip.js";
|
|
14
|
+
import { requireAuth } from "../model/command.js";
|
|
15
|
+
import QuantumHubService from "../service/quantum-hub-service.js";
|
|
16
|
+
import { readServiceConfig, writeServiceConfig } from "../service/service-config-service.js";
|
|
17
17
|
/**
|
|
18
18
|
* Prints an error message and exits. Service-layer errors already carry a resolved message.
|
|
19
19
|
*/
|
|
@@ -21,13 +21,13 @@ function fail(err) {
|
|
|
21
21
|
error(err instanceof Error ? err.message : String(err));
|
|
22
22
|
}
|
|
23
23
|
async function getOpenapi() {
|
|
24
|
-
const openapiYamlPath = path.join(process.cwd(),
|
|
25
|
-
const openapiYmlPath = path.join(process.cwd(),
|
|
24
|
+
const openapiYamlPath = path.join(process.cwd(), "openapi.yaml");
|
|
25
|
+
const openapiYmlPath = path.join(process.cwd(), "openapi.yml");
|
|
26
26
|
let openapi = undefined;
|
|
27
27
|
if (fs.existsSync(openapiYamlPath))
|
|
28
|
-
openapi = fs.createReadStream(openapiYamlPath,
|
|
28
|
+
openapi = fs.createReadStream(openapiYamlPath, "utf8");
|
|
29
29
|
else if (fs.existsSync(openapiYmlPath))
|
|
30
|
-
openapi = fs.createReadStream(openapiYmlPath,
|
|
30
|
+
openapi = fs.createReadStream(openapiYmlPath, "utf8");
|
|
31
31
|
if (openapi)
|
|
32
32
|
return streamToBlob(openapi);
|
|
33
33
|
return undefined;
|
|
@@ -64,19 +64,20 @@ async function buildServiceJob(qhubService, service, silentMode) {
|
|
|
64
64
|
if (!silentMode) {
|
|
65
65
|
if (buildJob.step !== currentStep) {
|
|
66
66
|
if (buildJob.step === HubPlatform.BuildJobDto.Step.BuildImage) {
|
|
67
|
-
spin ??= spinner(
|
|
67
|
+
spin ??= spinner("Building Image (1/2)");
|
|
68
68
|
}
|
|
69
69
|
else if (buildJob.step === HubPlatform.BuildJobDto.Step.PushImage) {
|
|
70
70
|
if (spin) {
|
|
71
71
|
spin.succeed();
|
|
72
72
|
spin = undefined;
|
|
73
73
|
}
|
|
74
|
-
spin = spinner(
|
|
74
|
+
spin = spinner("Pushing Image (2/2)");
|
|
75
75
|
}
|
|
76
76
|
currentStep = buildJob.step;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
return buildJob.status === HubPlatform.BuildJobDto.Status.Success ||
|
|
79
|
+
return (buildJob.status === HubPlatform.BuildJobDto.Status.Success ||
|
|
80
|
+
buildJob.status === HubPlatform.BuildJobDto.Status.Failure);
|
|
80
81
|
}, {
|
|
81
82
|
intervalBetweenAttempts: 5000,
|
|
82
83
|
timeout: silentMode ? 60 * 60 * 1000 : 20 * 60 * 1000,
|
|
@@ -84,7 +85,7 @@ async function buildServiceJob(qhubService, service, silentMode) {
|
|
|
84
85
|
}
|
|
85
86
|
catch (err) {
|
|
86
87
|
spin?.fail();
|
|
87
|
-
throw new Error(
|
|
88
|
+
throw new Error("Error while waiting for the build job to finish: " + err, { cause: err });
|
|
88
89
|
}
|
|
89
90
|
if (spin) {
|
|
90
91
|
if (buildJob?.status === HubPlatform.BuildJobDto.Status.Success)
|
|
@@ -96,7 +97,7 @@ async function buildServiceJob(qhubService, service, silentMode) {
|
|
|
96
97
|
return buildJob;
|
|
97
98
|
}
|
|
98
99
|
async function createService(qhubService, serviceConfig, source, metadata, sourceCode, silentMode, noSaveId = false, customName) {
|
|
99
|
-
const spin = silentMode ? undefined : spinner(
|
|
100
|
+
const spin = silentMode ? undefined : spinner("Creating service");
|
|
100
101
|
const configToUse = { ...serviceConfig };
|
|
101
102
|
if (customName)
|
|
102
103
|
configToUse.name = customName;
|
|
@@ -109,10 +110,10 @@ async function createService(qhubService, serviceConfig, source, metadata, sourc
|
|
|
109
110
|
return service;
|
|
110
111
|
}
|
|
111
112
|
async function updateService(qhubService, serviceConfig, source, metadata, sourceCode, silentMode) {
|
|
112
|
-
const spin = silentMode ? undefined : spinner(
|
|
113
|
+
const spin = silentMode ? undefined : spinner("Updating service");
|
|
113
114
|
// A registry source is set via the platform's update-source operation; a file
|
|
114
115
|
// source uploads a fresh code archive. Either way the optional metadata follows.
|
|
115
|
-
if (source.type ===
|
|
116
|
+
if (source.type === "registry") {
|
|
116
117
|
await qhubService.updateServiceSource(serviceConfig.serviceId, source);
|
|
117
118
|
await uploadServiceMetadata(qhubService, serviceConfig, metadata);
|
|
118
119
|
spin?.succeed();
|
|
@@ -133,11 +134,11 @@ async function resolveCredentialsInteractively(opts, silentMode) {
|
|
|
133
134
|
if (credentials.username || silentMode) {
|
|
134
135
|
return credentials;
|
|
135
136
|
}
|
|
136
|
-
const username = await input({ message:
|
|
137
|
+
const username = await input({ message: "Registry username (leave blank for a public image)" });
|
|
137
138
|
if (!username) {
|
|
138
139
|
return credentials;
|
|
139
140
|
}
|
|
140
|
-
const registryPassword = await password({ message:
|
|
141
|
+
const registryPassword = await password({ message: "Registry password" });
|
|
141
142
|
return { username, password: registryPassword };
|
|
142
143
|
}
|
|
143
144
|
/**
|
|
@@ -145,10 +146,10 @@ async function resolveCredentialsInteractively(opts, silentMode) {
|
|
|
145
146
|
* names in the project. Purely informational; never throws.
|
|
146
147
|
*/
|
|
147
148
|
function warnAboutDeprecations(serviceConfig) {
|
|
148
|
-
if (!(
|
|
149
|
+
if (!("descriptionFile" in serviceConfig)) {
|
|
149
150
|
stdout('Warning: Since version 2.14.0, the "description" property in qhub.json has changed to "descriptionFile".\nFor more information, visit: https://docs.hub.kipu-quantum.com/qhub-json-reference.html\n');
|
|
150
151
|
}
|
|
151
|
-
const deprecatedOpenapiFile = path.join(process.cwd(),
|
|
152
|
+
const deprecatedOpenapiFile = path.join(process.cwd(), "openapi-spec.yml");
|
|
152
153
|
if (fs.existsSync(deprecatedOpenapiFile)) {
|
|
153
154
|
warn('You are having the deprecated file "openapi-spec.yml" in your project. Please consider renaming it to "openapi.yaml".');
|
|
154
155
|
}
|
|
@@ -171,7 +172,7 @@ async function resolveServiceExists(qhubService, serviceConfig) {
|
|
|
171
172
|
}
|
|
172
173
|
if (!serviceExistsInPlatform) {
|
|
173
174
|
stdout(`We could not find a service with id '${serviceConfig.serviceId}' in the current context!`);
|
|
174
|
-
const createNewService = await confirm({ message:
|
|
175
|
+
const createNewService = await confirm({ message: "Do you want to create a new service?" });
|
|
175
176
|
if (!createNewService)
|
|
176
177
|
process.exit(0);
|
|
177
178
|
}
|
|
@@ -212,18 +213,19 @@ async function resolveServiceSource(serviceConfig, opts, silentMode) {
|
|
|
212
213
|
*/
|
|
213
214
|
function reportBuildResult(buildJob, serviceExistsInPlatform) {
|
|
214
215
|
if (buildJob?.status === HubPlatform.BuildJobDto.Status.Success) {
|
|
215
|
-
stdout(`Service ${serviceExistsInPlatform ?
|
|
216
|
+
stdout(`Service ${serviceExistsInPlatform ? "updated" : "created"} \u{1F680}`);
|
|
216
217
|
}
|
|
217
218
|
else if (buildJob?.status === HubPlatform.BuildJobDto.Status.Failure) {
|
|
218
219
|
const { validationResult } = buildJob;
|
|
219
|
-
let reason =
|
|
220
|
-
if (validationResult?.state === HubPlatform.ValidationResult.State.Error &&
|
|
220
|
+
let reason = "Failed creating service";
|
|
221
|
+
if (validationResult?.state === HubPlatform.ValidationResult.State.Error &&
|
|
222
|
+
validationResult.summary) {
|
|
221
223
|
reason = `${reason}: ${validationResult.summary}`;
|
|
222
224
|
}
|
|
223
225
|
error(reason);
|
|
224
226
|
}
|
|
225
227
|
else {
|
|
226
|
-
error(
|
|
228
|
+
error("Still pending, please check the platform UI to determine the status");
|
|
227
229
|
}
|
|
228
230
|
}
|
|
229
231
|
const EXAMPLES = `
|
|
@@ -233,15 +235,15 @@ Examples:
|
|
|
233
235
|
$ qhubctl up --name "my-custom-service-name"
|
|
234
236
|
$ qhubctl up --name "test-service" --no-save-id
|
|
235
237
|
$ qhubctl up --image ghcr.io/acme/my-service:1.2.3`;
|
|
236
|
-
export const upCommand = new Command(
|
|
238
|
+
export const upCommand = new Command("up")
|
|
237
239
|
.description(`Creates or updates a service.\n\n${QHUBIGNORE_HELP}`)
|
|
238
|
-
.option(
|
|
239
|
-
.option(
|
|
240
|
-
.option(
|
|
241
|
-
.option(
|
|
242
|
-
.option(
|
|
243
|
-
.option(
|
|
244
|
-
.addHelpText(
|
|
240
|
+
.option("--silent", "Suppresses all outputs, helpful when executed in a CI/CD pipeline.", false)
|
|
241
|
+
.option("--no-save-id", "Prevents storing the created service ID in qhub.json file.")
|
|
242
|
+
.option("--name <value>", "Override the service name from qhub.json with a custom name.")
|
|
243
|
+
.option("--image <ref>", 'Deploy a pre-built image from a container registry, given as registry/repo:tag (the tag defaults to "latest").')
|
|
244
|
+
.option("--registry-username <value>", "Username to pull a private registry image. Falls back to the QHUB_REGISTRY_USERNAME environment variable.")
|
|
245
|
+
.option("--registry-password <value>", "Password to pull a private registry image. Falls back to the QHUB_REGISTRY_PASSWORD environment variable.")
|
|
246
|
+
.addHelpText("after", EXAMPLES)
|
|
245
247
|
.action(async (opts) => {
|
|
246
248
|
const userConfig = await requireAuth();
|
|
247
249
|
const qhubService = new QuantumHubService(userConfig);
|
|
@@ -255,10 +257,10 @@ export const upCommand = new Command('up')
|
|
|
255
257
|
// Metadata (openapi + description) is independent of the source kind.
|
|
256
258
|
const metadata = await getServiceMetadata();
|
|
257
259
|
// Only a file source ships local code; a registry source is pre-built.
|
|
258
|
-
const sourceCode = source.type ===
|
|
260
|
+
const sourceCode = source.type === "file" ? await zipProjectFolder("./") : undefined;
|
|
259
261
|
// The platform has no rename operation, so --name only takes effect on create.
|
|
260
262
|
if (serviceExistsInPlatform && opts.name && !silentMode) {
|
|
261
|
-
warn(
|
|
263
|
+
warn("Ignoring --name: the service name cannot be changed on update.");
|
|
262
264
|
}
|
|
263
265
|
let service;
|
|
264
266
|
try {
|
|
@@ -271,9 +273,9 @@ export const upCommand = new Command('up')
|
|
|
271
273
|
}
|
|
272
274
|
// A registry source is pre-built — the platform runs no build job, so
|
|
273
275
|
// success is reported immediately. A file source must wait for the build.
|
|
274
|
-
if (source.type !==
|
|
276
|
+
if (source.type !== "file") {
|
|
275
277
|
if (!silentMode)
|
|
276
|
-
stdout(`Service ${serviceExistsInPlatform ?
|
|
278
|
+
stdout(`Service ${serviceExistsInPlatform ? "updated" : "created"} \u{1F680}`);
|
|
277
279
|
return;
|
|
278
280
|
}
|
|
279
281
|
const buildJob = await buildServiceJob(qhubService, service, silentMode);
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { program } from
|
|
1
|
+
export { program } from "./program.js";
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { program } from
|
|
1
|
+
export { program } from "./program.js";
|
package/dist/lib/command.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execFile } from
|
|
2
|
-
import { promisify } from
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
3
|
const execFileAsync = promisify(execFile);
|
|
4
4
|
export const executeAsyncCommand = (file, args) => execFileAsync(file, args);
|
package/dist/lib/config-dir.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import os from
|
|
2
|
-
import path from
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
3
|
/**
|
|
4
4
|
* Resolves the user-scoped config directory for qhubctl.
|
|
5
5
|
* Equivalent to oclif's `this.config.configDir` (driven by `oclif.dirname = "qhubctl"`).
|
|
6
6
|
* On all platforms this follows XDG convention: ~/.config/qhubctl
|
|
7
7
|
*/
|
|
8
|
-
export const configDir = path.join(os.homedir(),
|
|
8
|
+
export const configDir = path.join(os.homedir(), ".config", "qhubctl");
|
package/dist/lib/debug.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const debugEnabled = () => Boolean(process.env.DEBUG && process.env.DEBUG !==
|
|
1
|
+
export const debugEnabled = () => Boolean(process.env.DEBUG && process.env.DEBUG !== "");
|