@quantum-hub/qhubctl 1.2.0 → 1.3.0
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 +136 -20
- package/dist/client/kqh/models/UpdateWorkflowServiceRequest.js +0 -11
- package/dist/commands/compress.d.ts +2 -0
- package/dist/commands/compress.js +23 -0
- package/dist/commands/datapool-upload.d.ts +2 -0
- package/dist/commands/datapool-upload.js +184 -0
- package/dist/commands/get-context.d.ts +2 -0
- package/dist/commands/get-context.js +12 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +66 -0
- package/dist/commands/list-contexts.d.ts +2 -0
- package/dist/commands/list-contexts.js +28 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +59 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +20 -0
- package/dist/commands/openapi.d.ts +2 -0
- package/dist/commands/openapi.js +244 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +126 -0
- package/dist/commands/serve.d.ts +2 -0
- package/dist/commands/serve.js +35 -0
- package/dist/commands/services.d.ts +2 -0
- package/dist/commands/services.js +48 -0
- package/dist/commands/set-context.d.ts +2 -0
- package/dist/commands/set-context.js +52 -0
- package/dist/commands/up.d.ts +2 -0
- package/dist/commands/up.js +161 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/config-dir.d.ts +6 -0
- package/dist/lib/config-dir.js +8 -0
- package/dist/lib/entrypoint-resolver.js +2 -2
- package/dist/lib/output.d.ts +14 -0
- package/dist/lib/output.js +22 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +8 -0
- package/dist/model/command.d.ts +14 -11
- package/dist/model/command.js +44 -40
- package/dist/program.d.ts +2 -0
- package/dist/program.js +47 -0
- package/dist/service/command-service.d.ts +1 -5
- package/dist/service/command-service.js +1 -5
- package/dist/service/quantum-hub-service.d.ts +1 -3
- package/dist/service/quantum-hub-service.js +2 -2
- package/package.json +30 -61
- package/bin/dev.cmd +0 -3
- package/bin/dev.js +0 -17
- package/bin/run.cmd +0 -3
- package/bin/run.js +0 -12
- package/dist/commands/compress/index.d.ts +0 -6
- package/dist/commands/compress/index.js +0 -25
- package/dist/commands/datapool/upload.d.ts +0 -23
- package/dist/commands/datapool/upload.js +0 -260
- package/dist/commands/get-context/index.d.ts +0 -6
- package/dist/commands/get-context/index.js +0 -10
- package/dist/commands/init/index.d.ts +0 -10
- package/dist/commands/init/index.js +0 -75
- package/dist/commands/list-contexts/index.d.ts +0 -9
- package/dist/commands/list-contexts/index.js +0 -30
- package/dist/commands/login/index.d.ts +0 -10
- package/dist/commands/login/index.js +0 -62
- package/dist/commands/logout/index.d.ts +0 -6
- package/dist/commands/logout/index.js +0 -18
- package/dist/commands/openapi/index.d.ts +0 -26
- package/dist/commands/openapi/index.js +0 -307
- package/dist/commands/run/index.d.ts +0 -18
- package/dist/commands/run/index.js +0 -150
- package/dist/commands/serve/index.d.ts +0 -11
- package/dist/commands/serve/index.js +0 -51
- package/dist/commands/services/index.d.ts +0 -14
- package/dist/commands/services/index.js +0 -65
- package/dist/commands/set-context/index.d.ts +0 -17
- package/dist/commands/set-context/index.js +0 -59
- package/dist/commands/up/index.d.ts +0 -19
- package/dist/commands/up/index.js +0 -190
- package/oclif.manifest.json +0 -548
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { waitUntil } from 'async-wait-until';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { BuildJobDtoStatusEnum, BuildJobDtoStepEnum, ValidationResultStateEnum } from '../client/kqh/index.js';
|
|
7
|
+
import { streamToBlob } from '../lib/stream-to-blob.js';
|
|
8
|
+
import { getDescriptionText } from '../lib/up/get-description.js';
|
|
9
|
+
import { zipProjectFolder } from '../lib/up/zip.js';
|
|
10
|
+
import { error, spinner, stdout, warn } from '../lib/output.js';
|
|
11
|
+
import { requireAuth } from '../model/command.js';
|
|
12
|
+
import QuantumHubService from '../service/quantum-hub-service.js';
|
|
13
|
+
import { readServiceConfig, writeServiceConfig } from '../service/service-config-service.js';
|
|
14
|
+
async function getOpenapi() {
|
|
15
|
+
const openapiYamlPath = path.join(process.cwd(), 'openapi.yaml');
|
|
16
|
+
const openapiYmlPath = path.join(process.cwd(), 'openapi.yml');
|
|
17
|
+
let openapi = undefined;
|
|
18
|
+
if (fs.existsSync(openapiYamlPath))
|
|
19
|
+
openapi = fs.createReadStream(openapiYamlPath, 'utf8');
|
|
20
|
+
else if (fs.existsSync(openapiYmlPath))
|
|
21
|
+
openapi = fs.createReadStream(openapiYmlPath, 'utf8');
|
|
22
|
+
if (openapi)
|
|
23
|
+
return streamToBlob(openapi);
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
async function buildServiceJob(qhubService, service, serviceDefinition, silentMode) {
|
|
27
|
+
let buildJob;
|
|
28
|
+
let spin;
|
|
29
|
+
let currentStep;
|
|
30
|
+
try {
|
|
31
|
+
await waitUntil(async () => {
|
|
32
|
+
buildJob = await qhubService.getBuildJob(service, serviceDefinition);
|
|
33
|
+
if (!silentMode) {
|
|
34
|
+
if (buildJob.step !== currentStep) {
|
|
35
|
+
if (buildJob.step === BuildJobDtoStepEnum.BuildImage) {
|
|
36
|
+
if (!spin)
|
|
37
|
+
spin = spinner('Building Image (1/2)');
|
|
38
|
+
}
|
|
39
|
+
else if (buildJob.step === BuildJobDtoStepEnum.PushImage) {
|
|
40
|
+
if (spin) {
|
|
41
|
+
spin.succeed();
|
|
42
|
+
spin = undefined;
|
|
43
|
+
}
|
|
44
|
+
spin = spinner('Pushing Image (2/2)');
|
|
45
|
+
}
|
|
46
|
+
currentStep = buildJob.step;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return buildJob.status === BuildJobDtoStatusEnum.Success || buildJob.status === BuildJobDtoStatusEnum.Failure;
|
|
50
|
+
}, {
|
|
51
|
+
intervalBetweenAttempts: 5000,
|
|
52
|
+
timeout: silentMode ? 60 * 60 * 1000 : 20 * 60 * 1000,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
spin?.fail();
|
|
57
|
+
throw new Error('Error while waiting for the build job to finish: ' + err);
|
|
58
|
+
}
|
|
59
|
+
if (spin) {
|
|
60
|
+
if (buildJob?.status === BuildJobDtoStatusEnum.Success)
|
|
61
|
+
spin.succeed();
|
|
62
|
+
else
|
|
63
|
+
spin.fail();
|
|
64
|
+
spin = undefined;
|
|
65
|
+
}
|
|
66
|
+
return buildJob;
|
|
67
|
+
}
|
|
68
|
+
async function createService(qhubService, serviceConfig, files, silentMode, noSaveId = false, customName) {
|
|
69
|
+
const spin = silentMode ? undefined : spinner('Creating service');
|
|
70
|
+
const configToUse = { ...serviceConfig };
|
|
71
|
+
if (customName)
|
|
72
|
+
configToUse.name = customName;
|
|
73
|
+
const service = await qhubService.createService(configToUse, files.sourceCode, files.openapi);
|
|
74
|
+
serviceConfig.serviceId = service?.id;
|
|
75
|
+
if (!noSaveId)
|
|
76
|
+
writeServiceConfig(process.cwd(), serviceConfig);
|
|
77
|
+
if (files.descriptionText)
|
|
78
|
+
await qhubService.updateDescription(serviceConfig, files.descriptionText);
|
|
79
|
+
if (files.openapi)
|
|
80
|
+
await qhubService.updateOpenapi(serviceConfig, files.openapi);
|
|
81
|
+
spin?.succeed();
|
|
82
|
+
return service;
|
|
83
|
+
}
|
|
84
|
+
async function updateService(qhubService, serviceConfig, files, silentMode) {
|
|
85
|
+
const spin = silentMode ? undefined : spinner('Updating service');
|
|
86
|
+
const result = await qhubService.updateService(serviceConfig, files.descriptionText, files.sourceCode, files.openapi);
|
|
87
|
+
spin?.succeed();
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
const EXAMPLES = `
|
|
91
|
+
Examples:
|
|
92
|
+
$ qhubctl up
|
|
93
|
+
$ qhubctl up --no-save-id
|
|
94
|
+
$ qhubctl up --name "my-custom-service-name"
|
|
95
|
+
$ qhubctl up --name "test-service" --no-save-id`;
|
|
96
|
+
export const upCommand = new Command('up')
|
|
97
|
+
.description('Creates or updates a service')
|
|
98
|
+
.option('--silent', 'Suppresses all outputs, helpful when executed in a CI/CD pipeline.', false)
|
|
99
|
+
.option('--no-save-id', 'Prevents storing the created service ID in qhub.json file.', false)
|
|
100
|
+
.option('--name <value>', 'Override the service name from qhub.json with a custom name.')
|
|
101
|
+
.addHelpText('after', EXAMPLES)
|
|
102
|
+
.action(async (opts) => {
|
|
103
|
+
const userConfig = await requireAuth();
|
|
104
|
+
const qhubService = new QuantumHubService(userConfig);
|
|
105
|
+
const silentMode = opts.silent;
|
|
106
|
+
// Commander inverts --no-save-id into opts.saveId = false
|
|
107
|
+
const noSaveId = opts.saveId === false;
|
|
108
|
+
const serviceConfig = readServiceConfig(process.cwd());
|
|
109
|
+
if (!('descriptionFile' in serviceConfig)) {
|
|
110
|
+
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');
|
|
111
|
+
}
|
|
112
|
+
const deprecatedOpenapiFile = path.join(process.cwd(), 'openapi-spec.yml');
|
|
113
|
+
if (fs.existsSync(deprecatedOpenapiFile)) {
|
|
114
|
+
warn('You are having the deprecated file "openapi-spec.yml" in your project. Please consider renaming it to "openapi.yaml".');
|
|
115
|
+
}
|
|
116
|
+
let serviceExistsInPlatform = false;
|
|
117
|
+
if (serviceConfig.serviceId) {
|
|
118
|
+
try {
|
|
119
|
+
await qhubService.getService(serviceConfig.serviceId);
|
|
120
|
+
serviceExistsInPlatform = true;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
serviceExistsInPlatform = false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
let createNewService = true;
|
|
127
|
+
if (serviceConfig.serviceId && !serviceExistsInPlatform) {
|
|
128
|
+
stdout(`We could not find a service with id '${serviceConfig.serviceId}' in the current context!`);
|
|
129
|
+
createNewService = await confirm({ message: 'Do you want to create a new service?' });
|
|
130
|
+
if (!createNewService)
|
|
131
|
+
process.exit(0);
|
|
132
|
+
}
|
|
133
|
+
const serviceFiles = {
|
|
134
|
+
openapi: await getOpenapi(),
|
|
135
|
+
descriptionText: await getDescriptionText(process.cwd()),
|
|
136
|
+
sourceCode: await zipProjectFolder('./'),
|
|
137
|
+
};
|
|
138
|
+
const service = serviceExistsInPlatform
|
|
139
|
+
? await updateService(qhubService, serviceConfig, serviceFiles, silentMode)
|
|
140
|
+
: await createService(qhubService, serviceConfig, serviceFiles, silentMode, noSaveId, opts.name);
|
|
141
|
+
const serviceDefinition = service?.serviceDefinitions?.[0];
|
|
142
|
+
if (!serviceDefinition) {
|
|
143
|
+
error('Service definition not found');
|
|
144
|
+
}
|
|
145
|
+
const buildJob = await buildServiceJob(qhubService, service, serviceDefinition, silentMode);
|
|
146
|
+
if (buildJob?.status === BuildJobDtoStatusEnum.Success) {
|
|
147
|
+
const msg = `Service ${serviceExistsInPlatform ? 'updated' : 'created'} \u{1F680}`;
|
|
148
|
+
stdout(msg);
|
|
149
|
+
}
|
|
150
|
+
else if (buildJob?.status === BuildJobDtoStatusEnum.Failure) {
|
|
151
|
+
const { validationResult } = buildJob;
|
|
152
|
+
let reason = 'Failed creating service';
|
|
153
|
+
if (validationResult?.state === ValidationResultStateEnum.Error && validationResult.summary) {
|
|
154
|
+
reason = `${reason}: ${validationResult.summary}`;
|
|
155
|
+
}
|
|
156
|
+
stdout(reason);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
stdout('Still pending, please check the platform UI to determine the status');
|
|
160
|
+
}
|
|
161
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { program } from './program.js';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { program } from './program.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the user-scoped config directory for qhubctl.
|
|
5
|
+
* Equivalent to oclif's `this.config.configDir` (driven by `oclif.dirname = "qhubctl"`).
|
|
6
|
+
* On all platforms this follows XDG convention: ~/.config/qhubctl
|
|
7
|
+
*/
|
|
8
|
+
export const configDir = path.join(os.homedir(), '.config', 'qhubctl');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { warn } from './output.js';
|
|
2
2
|
export class EntrypointResolver {
|
|
3
3
|
/**
|
|
4
4
|
* Resolves the entrypoint string from various flag combinations.
|
|
@@ -50,7 +50,7 @@ export class EntrypointResolver {
|
|
|
50
50
|
this.validateObjectPath(objectPath, entrypoint);
|
|
51
51
|
// Warn if object path starts with underscore (private methods/classes)
|
|
52
52
|
if (objectPath.startsWith('_')) {
|
|
53
|
-
|
|
53
|
+
warn(`Object "${objectPath}" starts with underscore. Make sure this is intended for a private object.`);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Ora } from 'ora';
|
|
2
|
+
export type { Ora };
|
|
3
|
+
/**
|
|
4
|
+
* Output helpers — replaces oclif's `ux.*` surface.
|
|
5
|
+
*
|
|
6
|
+
* stdout → ux.stdout()
|
|
7
|
+
* warn → ux.warn()
|
|
8
|
+
* error → ux.error() / this.error()
|
|
9
|
+
* spinner → ux.action.start() / ux.action.stop()
|
|
10
|
+
*/
|
|
11
|
+
export declare function stdout(msg?: string): void;
|
|
12
|
+
export declare function warn(msg: string): void;
|
|
13
|
+
export declare function error(msg: string, exitCode?: number): never;
|
|
14
|
+
export declare function spinner(msg: string): Ora;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
/**
|
|
3
|
+
* Output helpers — replaces oclif's `ux.*` surface.
|
|
4
|
+
*
|
|
5
|
+
* stdout → ux.stdout()
|
|
6
|
+
* warn → ux.warn()
|
|
7
|
+
* error → ux.error() / this.error()
|
|
8
|
+
* spinner → ux.action.start() / ux.action.stop()
|
|
9
|
+
*/
|
|
10
|
+
export function stdout(msg = '') {
|
|
11
|
+
process.stdout.write(msg + '\n');
|
|
12
|
+
}
|
|
13
|
+
export function warn(msg) {
|
|
14
|
+
process.stderr.write(`Warning: ${msg}\n`);
|
|
15
|
+
}
|
|
16
|
+
export function error(msg, exitCode = 1) {
|
|
17
|
+
process.stderr.write(`Error: ${msg}\n`);
|
|
18
|
+
process.exit(exitCode);
|
|
19
|
+
}
|
|
20
|
+
export function spinner(msg) {
|
|
21
|
+
return ora(msg).start();
|
|
22
|
+
}
|
package/dist/main.d.ts
ADDED
package/dist/main.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Suppress Node.js experimental/deprecation warnings
|
|
3
|
+
process.removeAllListeners('warning');
|
|
4
|
+
// Disable SSL/TLS certificate verification
|
|
5
|
+
// (required for some on-premise Quantum Hub deployments)
|
|
6
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
7
|
+
import { program } from './program.js';
|
|
8
|
+
await program.parseAsync(process.argv);
|
package/dist/model/command.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Config } from '@oclif/core/config';
|
|
1
|
+
import { configDir } from '../lib/config-dir.js';
|
|
3
2
|
import UserConfig from './user-config.js';
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
export { configDir };
|
|
4
|
+
export declare function getUserConfig(): UserConfig;
|
|
5
|
+
export declare function getContextDisplayString(userConfig: UserConfig): string;
|
|
6
|
+
export declare function showCustomBasePathWarning(): void;
|
|
7
|
+
/**
|
|
8
|
+
* Validates that the user is authenticated and returns the current UserConfig.
|
|
9
|
+
* Replaces AuthenticatedCommand.init().
|
|
10
|
+
*
|
|
11
|
+
* @param opts.printContext - Print "Current context: ..." line (default: true)
|
|
12
|
+
*/
|
|
13
|
+
export declare function requireAuth(opts?: {
|
|
14
|
+
printContext?: boolean;
|
|
15
|
+
}): Promise<UserConfig>;
|
package/dist/model/command.js
CHANGED
|
@@ -1,47 +1,51 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { configDir } from '../lib/config-dir.js';
|
|
2
|
+
import { stdout, warn } from '../lib/output.js';
|
|
2
3
|
import AuthService from '../service/auth-service.js';
|
|
3
4
|
import { readUserConfig, writeUserConfig } from '../service/user-config-service.js';
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
ux.stdout('');
|
|
5
|
+
export { configDir };
|
|
6
|
+
export function getUserConfig() {
|
|
7
|
+
return readUserConfig(configDir);
|
|
8
|
+
}
|
|
9
|
+
export function getContextDisplayString(userConfig) {
|
|
10
|
+
if (userConfig?.context) {
|
|
11
|
+
const type = userConfig.context.isOrganization ? 'Organization' : 'Personal';
|
|
12
|
+
return `${userConfig.context.displayName} (${type})`;
|
|
13
13
|
}
|
|
14
|
+
return 'No context set. Use "qhubctl set-context" to set a context.';
|
|
15
|
+
}
|
|
16
|
+
export function showCustomBasePathWarning() {
|
|
17
|
+
warn('Using custom base path. This is intended for internal development use only.');
|
|
18
|
+
stdout();
|
|
14
19
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Validates that the user is authenticated and returns the current UserConfig.
|
|
22
|
+
* Replaces AuthenticatedCommand.init().
|
|
23
|
+
*
|
|
24
|
+
* @param opts.printContext - Print "Current context: ..." line (default: true)
|
|
25
|
+
*/
|
|
26
|
+
export async function requireAuth(opts = {}) {
|
|
27
|
+
const { printContext = true } = opts;
|
|
28
|
+
const userConfig = getUserConfig();
|
|
29
|
+
if (!userConfig.auth) {
|
|
30
|
+
throw new Error('No credentials provided. Use the "login" command to log in.');
|
|
31
|
+
}
|
|
32
|
+
if (userConfig.endpoint?.basePath) {
|
|
33
|
+
showCustomBasePathWarning();
|
|
34
|
+
}
|
|
35
|
+
const auth = new AuthService(userConfig);
|
|
36
|
+
try {
|
|
37
|
+
await auth.authenticate(userConfig.auth.value);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
writeUserConfig(configDir, {
|
|
41
|
+
...userConfig,
|
|
42
|
+
auth: undefined,
|
|
43
|
+
context: undefined,
|
|
44
|
+
});
|
|
45
|
+
throw new Error('Invalid credentials provided. Use the "login" command to log in.');
|
|
22
46
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (!this.userConfig.auth) {
|
|
26
|
-
throw new Error('No credentials provided. Use the "login" command to log-in.');
|
|
27
|
-
}
|
|
28
|
-
if (this.userConfig.endpoint?.basePath) {
|
|
29
|
-
this.showCustomBasePathWarning();
|
|
30
|
-
}
|
|
31
|
-
const auth = new AuthService(this.userConfig);
|
|
32
|
-
try {
|
|
33
|
-
await auth.authenticate(this.userConfig.auth.value);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
writeUserConfig(this.config.configDir, {
|
|
37
|
-
...this.userConfig,
|
|
38
|
-
auth: undefined,
|
|
39
|
-
context: undefined,
|
|
40
|
-
});
|
|
41
|
-
throw new Error('Invalid credentials provided. Use the "login" command to log-in.');
|
|
42
|
-
}
|
|
43
|
-
if (printContext) {
|
|
44
|
-
ux.stdout('Current context: ' + await this.getContextOutputString(this.userConfig));
|
|
45
|
-
}
|
|
47
|
+
if (printContext) {
|
|
48
|
+
stdout('Current context: ' + getContextDisplayString(userConfig));
|
|
46
49
|
}
|
|
50
|
+
return userConfig;
|
|
47
51
|
}
|
package/dist/program.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import updateNotifier from 'update-notifier';
|
|
4
|
+
import { compressCommand } from './commands/compress.js';
|
|
5
|
+
import { datapoolUploadCommand } from './commands/datapool-upload.js';
|
|
6
|
+
import { getContextCommand } from './commands/get-context.js';
|
|
7
|
+
import { initCommand } from './commands/init.js';
|
|
8
|
+
import { listContextsCommand } from './commands/list-contexts.js';
|
|
9
|
+
import { loginCommand } from './commands/login.js';
|
|
10
|
+
import { logoutCommand } from './commands/logout.js';
|
|
11
|
+
import { openapiCommand } from './commands/openapi.js';
|
|
12
|
+
import { runCommand } from './commands/run.js';
|
|
13
|
+
import { serveCommand } from './commands/serve.js';
|
|
14
|
+
import { servicesCommand } from './commands/services.js';
|
|
15
|
+
import { setContextCommand } from './commands/set-context.js';
|
|
16
|
+
import { upCommand } from './commands/up.js';
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
const pkg = require('../package.json');
|
|
19
|
+
// Check for updates in the background (non-blocking).
|
|
20
|
+
updateNotifier({ pkg, updateCheckInterval: 24 * 60 * 60 * 1000 }).notify();
|
|
21
|
+
export const program = new Command()
|
|
22
|
+
.name('qhubctl')
|
|
23
|
+
.description(pkg.description)
|
|
24
|
+
.version(pkg.version, '-v, --version');
|
|
25
|
+
// Top-level commands
|
|
26
|
+
program.addCommand(compressCommand);
|
|
27
|
+
program.addCommand(getContextCommand);
|
|
28
|
+
program.addCommand(initCommand);
|
|
29
|
+
program.addCommand(listContextsCommand);
|
|
30
|
+
program.addCommand(loginCommand);
|
|
31
|
+
program.addCommand(logoutCommand);
|
|
32
|
+
program.addCommand(openapiCommand);
|
|
33
|
+
program.addCommand(runCommand);
|
|
34
|
+
program.addCommand(serveCommand);
|
|
35
|
+
program.addCommand(servicesCommand);
|
|
36
|
+
program.addCommand(setContextCommand);
|
|
37
|
+
program.addCommand(upCommand);
|
|
38
|
+
// Nested: datapool <subcommand>
|
|
39
|
+
const datapoolCommand = new Command('datapool').description('Manage data pools');
|
|
40
|
+
datapoolCommand.addCommand(datapoolUploadCommand);
|
|
41
|
+
program.addCommand(datapoolCommand);
|
|
42
|
+
// Surface a clear error for unknown commands instead of silently doing nothing
|
|
43
|
+
program.on('command:*', (operands) => {
|
|
44
|
+
process.stderr.write(`\n error: unknown command '${operands[0]}'\n\n`);
|
|
45
|
+
process.stderr.write(` Run 'qhubctl --help' to see available commands.\n\n`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
});
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
2
|
-
import { Config } from '@oclif/core/config';
|
|
3
1
|
import UserConfig from '../model/user-config.js';
|
|
4
2
|
export declare class CommandService {
|
|
5
|
-
cmd: Command;
|
|
6
|
-
config: Config;
|
|
7
3
|
userConfig: UserConfig;
|
|
8
|
-
constructor(
|
|
4
|
+
constructor(userConfig: UserConfig);
|
|
9
5
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
2
|
-
import { Config } from '@oclif/core/config';
|
|
3
1
|
import { HubPlatformClient } from "@quantum-hub/qhub-api/platform";
|
|
4
2
|
import { BuildJobDto, ServiceDefinitionDto, ServiceDto, ServiceOverviewDto, ServicePlatformServicesApi } from '../client/kqh/index.js';
|
|
5
3
|
import Account from '../model/account.js';
|
|
@@ -10,7 +8,7 @@ import { HubPlatform } from "@quantum-hub/qhub-api/platform";
|
|
|
10
8
|
export default class QuantumHubService extends CommandService {
|
|
11
9
|
serviceApi: ServicePlatformServicesApi;
|
|
12
10
|
apiClient: HubPlatformClient;
|
|
13
|
-
constructor(
|
|
11
|
+
constructor(userConfig: UserConfig);
|
|
14
12
|
createService(serviceConfig: ManagedServiceConfig, sourceCode: Blob, apiDefinition?: Blob): Promise<ServiceDto>;
|
|
15
13
|
getAccounts(): Promise<Account[]>;
|
|
16
14
|
getBuildJob(service: ServiceDto, serviceDefinition: ServiceDefinitionDto): Promise<BuildJobDto>;
|
|
@@ -7,8 +7,8 @@ import { CommandService } from './command-service.js';
|
|
|
7
7
|
export default class QuantumHubService extends CommandService {
|
|
8
8
|
serviceApi;
|
|
9
9
|
apiClient;
|
|
10
|
-
constructor(
|
|
11
|
-
super(
|
|
10
|
+
constructor(userConfig) {
|
|
11
|
+
super(userConfig);
|
|
12
12
|
const basePath = (userConfig.endpoint?.basePath || defaultBasePath) + '/qc-catalog';
|
|
13
13
|
const defaultHeaders = userConfig.endpoint?.defaultHeaders || {};
|
|
14
14
|
const apiKey = userConfig.auth?.value;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quantum-hub/qhubctl",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Quantum Hub CLI",
|
|
5
5
|
"author": "Kipu Quantum GmbH",
|
|
6
6
|
"contributors": [
|
|
@@ -18,82 +18,51 @@
|
|
|
18
18
|
"kqh"
|
|
19
19
|
],
|
|
20
20
|
"bin": {
|
|
21
|
-
"qhubctl": "./
|
|
21
|
+
"qhubctl": "./dist/main.js"
|
|
22
22
|
},
|
|
23
23
|
"main": "dist/index.js",
|
|
24
24
|
"files": [
|
|
25
|
-
"/
|
|
26
|
-
"/dist",
|
|
27
|
-
"/oclif.manifest.json"
|
|
25
|
+
"/dist"
|
|
28
26
|
],
|
|
29
27
|
"dependencies": {
|
|
30
|
-
"@
|
|
31
|
-
"@
|
|
32
|
-
"@oclif/plugin-help": "^6.2.37",
|
|
33
|
-
"@oclif/plugin-not-found": "^3.2.74",
|
|
34
|
-
"@oclif/plugin-version": "^2.2.36",
|
|
35
|
-
"@oclif/plugin-warn-if-update-available": "^3.1.55",
|
|
36
|
-
"@quantum-hub/qhub-api": "^1.0.24",
|
|
28
|
+
"@inquirer/prompts": "^8",
|
|
29
|
+
"@quantum-hub/qhub-api": "^1",
|
|
37
30
|
"adm-zip": "^0.5.16",
|
|
38
|
-
"async-wait-until": "^2
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"yaml": "^2
|
|
31
|
+
"async-wait-until": "^2",
|
|
32
|
+
"commander": "^14",
|
|
33
|
+
"fs-extra": "^11",
|
|
34
|
+
"ignore": "^7",
|
|
35
|
+
"ora": "^9",
|
|
36
|
+
"tty-table": "^5",
|
|
37
|
+
"update-notifier": "^7",
|
|
38
|
+
"yaml": "^2"
|
|
46
39
|
},
|
|
47
40
|
"devDependencies": {
|
|
48
41
|
"@eslint/js": "^9",
|
|
49
|
-
"@oclif/prettier-config": "^0.2.1",
|
|
50
|
-
"@oclif/test": "^4.1.16",
|
|
51
42
|
"@types/adm-zip": "^0.5.7",
|
|
52
|
-
"@types/chai": "^5
|
|
53
|
-
"@types/fs-extra": "^11
|
|
54
|
-
"@types/
|
|
55
|
-
"@types/
|
|
56
|
-
"@types/
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"nyc": "^17.1.0",
|
|
62
|
-
"oclif": "^4.22.81",
|
|
43
|
+
"@types/chai": "^5",
|
|
44
|
+
"@types/fs-extra": "^11",
|
|
45
|
+
"@types/mocha": "^10",
|
|
46
|
+
"@types/node": "^24",
|
|
47
|
+
"@types/update-notifier": "^6",
|
|
48
|
+
"chai": "^5",
|
|
49
|
+
"eslint": "^9",
|
|
50
|
+
"mocha": "^11",
|
|
51
|
+
"nyc": "^17",
|
|
63
52
|
"shx": "^0.4.0",
|
|
64
|
-
"ts-node": "^10
|
|
65
|
-
"tsx": "^4
|
|
66
|
-
"typescript": "^5
|
|
67
|
-
"typescript-eslint": "^8
|
|
68
|
-
},
|
|
69
|
-
"oclif": {
|
|
70
|
-
"bin": "qhubctl",
|
|
71
|
-
"dirname": "qhubctl",
|
|
72
|
-
"commands": "./dist/commands",
|
|
73
|
-
"plugins": [
|
|
74
|
-
"@oclif/plugin-autocomplete",
|
|
75
|
-
"@oclif/plugin-help",
|
|
76
|
-
"@oclif/plugin-not-found",
|
|
77
|
-
"@oclif/plugin-version",
|
|
78
|
-
"@oclif/plugin-warn-if-update-available"
|
|
79
|
-
],
|
|
80
|
-
"topicSeparator": " ",
|
|
81
|
-
"topics": {},
|
|
82
|
-
"warn-if-update-available": {
|
|
83
|
-
"timeoutInDays": 1,
|
|
84
|
-
"frequency": 1,
|
|
85
|
-
"message": "Update available from <%= chalk.greenBright(config.version) %> to <%= chalk.greenBright(latest) %>. Use 'npm install -g <%= config.name %>' to update."
|
|
86
|
-
}
|
|
53
|
+
"ts-node": "^10",
|
|
54
|
+
"tsx": "^4",
|
|
55
|
+
"typescript": "^5",
|
|
56
|
+
"typescript-eslint": "^8"
|
|
87
57
|
},
|
|
88
58
|
"scripts": {
|
|
89
|
-
"build": "shx rm -rf dist && tsc -b",
|
|
59
|
+
"build": "shx rm -rf dist && tsc -b && shx chmod +x dist/main.js",
|
|
60
|
+
"dev": "tsc -b --watch",
|
|
61
|
+
"docs:generate": "node scripts/generate-docs.mjs --out docs/cli-reference.md",
|
|
90
62
|
"lint": "eslint",
|
|
91
|
-
"postpack": "shx rm -f oclif.manifest.json",
|
|
92
63
|
"posttest": "npm run lint",
|
|
93
|
-
"prepack": "oclif manifest && oclif readme",
|
|
94
64
|
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
|
|
95
|
-
"test
|
|
96
|
-
"version": "oclif readme && git add README.md"
|
|
65
|
+
"test:coverage": "nyc --reporter=lcov --reporter=text-lcov mocha --forbid-only \"test/**/*.test.ts\""
|
|
97
66
|
},
|
|
98
67
|
"engines": {
|
|
99
68
|
"node": ">=18.0.0"
|
package/bin/dev.cmd
DELETED
package/bin/dev.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// disable warnings
|
|
4
|
-
process.removeAllListeners('warning');
|
|
5
|
-
|
|
6
|
-
// disable SSL/TLS cert verification
|
|
7
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
8
|
-
|
|
9
|
-
// always perform version update check
|
|
10
|
-
process.env.QHUBCTL_FORCE_VERSION_CACHE_UPDATE = 'true';
|
|
11
|
-
|
|
12
|
-
(async () => {
|
|
13
|
-
const {settings} = await import('@oclif/core')
|
|
14
|
-
settings.enableAutoTranspile = false
|
|
15
|
-
const oclif = await import('@oclif/core')
|
|
16
|
-
await oclif.execute({ development: true, dir: import.meta.url })
|
|
17
|
-
})()
|
package/bin/run.cmd
DELETED
package/bin/run.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// disable warnings
|
|
4
|
-
process.removeAllListeners('warning');
|
|
5
|
-
|
|
6
|
-
// disable SSL/TLS cert verification
|
|
7
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
8
|
-
|
|
9
|
-
(async () => {
|
|
10
|
-
const oclif = await import('@oclif/core')
|
|
11
|
-
await oclif.execute({ dir: import.meta.url })
|
|
12
|
-
})()
|