@laioutr/cli 0.3.2 → 0.4.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/CHANGELOG.md +17 -0
- package/README.md +168 -25
- package/dist/api/deploy.d.ts +66 -0
- package/dist/api/deploy.js +34 -0
- package/dist/api/fetchRc.d.ts +1 -0
- package/dist/api/fetchRc.js +12 -28
- package/dist/api/http.d.ts +30 -0
- package/dist/api/http.js +93 -0
- package/dist/api/releaseAppVersion.d.ts +1 -0
- package/dist/api/releaseAppVersion.js +9 -20
- package/dist/commands/app/release.d.ts +2 -1
- package/dist/commands/app/release.js +2 -1
- package/dist/commands/deploy/list.d.ts +32 -0
- package/dist/commands/deploy/list.js +55 -0
- package/dist/commands/deploy/logs.d.ts +23 -0
- package/dist/commands/deploy/logs.js +54 -0
- package/dist/commands/deploy/status.d.ts +31 -0
- package/dist/commands/deploy/status.js +41 -0
- package/dist/commands/deploy/trigger.d.ts +24 -0
- package/dist/commands/deploy/trigger.js +130 -0
- package/dist/commands/rc/fetch.d.ts +4 -3
- package/dist/commands/rc/fetch.js +24 -3
- package/dist/commands/rc/update.d.ts +2 -1
- package/dist/commands/rc/update.js +2 -1
- package/dist/deploy/attribution.d.ts +12 -0
- package/dist/deploy/attribution.js +16 -0
- package/dist/deploy/log-renderer.d.ts +13 -0
- package/dist/deploy/log-renderer.js +21 -0
- package/dist/deploy/polling.d.ts +4 -0
- package/dist/deploy/polling.js +12 -0
- package/dist/deploy/validation.d.ts +81 -0
- package/dist/deploy/validation.js +47 -0
- package/dist/deploy-base-command.d.ts +12 -0
- package/dist/deploy-base-command.js +27 -0
- package/dist/format/color.d.ts +5 -0
- package/dist/format/color.js +10 -0
- package/dist/format/detail.d.ts +19 -0
- package/dist/format/detail.js +18 -0
- package/dist/laioutr-base-command.d.ts +9 -1
- package/dist/laioutr-base-command.js +21 -3
- package/dist/project.d.ts +14 -0
- package/dist/project.js +16 -0
- package/oclif.manifest.json +443 -22
- package/package.json +4 -2
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
export const deployTriggerResponseSchema = z.object({
|
|
3
|
+
deploymentId: z.string(),
|
|
4
|
+
status: z.string(),
|
|
5
|
+
environment: z.string(),
|
|
6
|
+
previewName: z.string().nullable(),
|
|
7
|
+
});
|
|
8
|
+
export const attributionSchema = z.object({
|
|
9
|
+
principalType: z.enum(['user', 'api-key', 'system']),
|
|
10
|
+
displayName: z.string(),
|
|
11
|
+
email: z.string().nullable(),
|
|
12
|
+
agentName: z.string().nullable(),
|
|
13
|
+
redacted: z.boolean(),
|
|
14
|
+
});
|
|
15
|
+
export const deploymentStatusResponseSchema = z.object({
|
|
16
|
+
deploymentId: z.string(),
|
|
17
|
+
status: z.string(),
|
|
18
|
+
environment: z.string(),
|
|
19
|
+
previewName: z.string().nullable(),
|
|
20
|
+
url: z.string().nullable(),
|
|
21
|
+
lastError: z.string().nullable(),
|
|
22
|
+
createdAt: z.string(),
|
|
23
|
+
stoppedAt: z.string().nullable(),
|
|
24
|
+
attribution: attributionSchema.nullable(),
|
|
25
|
+
});
|
|
26
|
+
export const deploymentsListResponseSchema = z.object({
|
|
27
|
+
deployments: z.array(z.object({
|
|
28
|
+
deploymentId: z.string(),
|
|
29
|
+
status: z.string(),
|
|
30
|
+
environment: z.string(),
|
|
31
|
+
previewName: z.string().nullable(),
|
|
32
|
+
url: z.string().nullable(),
|
|
33
|
+
createdAt: z.string(),
|
|
34
|
+
stoppedAt: z.string().nullable(),
|
|
35
|
+
attribution: attributionSchema.nullable(),
|
|
36
|
+
})),
|
|
37
|
+
});
|
|
38
|
+
export const buildLogLineSchema = z.object({
|
|
39
|
+
text: z.string(),
|
|
40
|
+
level: z.enum(['error', 'warning']).nullable().optional(),
|
|
41
|
+
timestamp: z.number().nullable().optional(),
|
|
42
|
+
});
|
|
43
|
+
export const deploymentLogsResponseSchema = z.object({
|
|
44
|
+
lines: z.array(buildLogLineSchema).nullable(),
|
|
45
|
+
supported: z.boolean(),
|
|
46
|
+
deploymentStatus: z.string(),
|
|
47
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import LaioutrBaseCommand from './laioutr-base-command.js';
|
|
2
|
+
import type { ProjectSlugs } from './project.js';
|
|
3
|
+
export default abstract class DeployBaseCommand extends LaioutrBaseCommand {
|
|
4
|
+
static flags: {
|
|
5
|
+
project: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
key: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'no-color': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
'cockpit-api-host': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
cwd: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
protected parseProject(project: string): ProjectSlugs;
|
|
12
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import LaioutrBaseCommand from './laioutr-base-command.js';
|
|
3
|
+
import { parseProjectSlug } from './project.js';
|
|
4
|
+
export default class DeployBaseCommand extends LaioutrBaseCommand {
|
|
5
|
+
static flags = {
|
|
6
|
+
...LaioutrBaseCommand.flags,
|
|
7
|
+
project: Flags.string({
|
|
8
|
+
char: 'p',
|
|
9
|
+
description: 'Project identifier in org/project format',
|
|
10
|
+
env: 'PROJECT',
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
key: Flags.string({
|
|
14
|
+
char: 'k',
|
|
15
|
+
description: 'Organization API key with project:deploy scope',
|
|
16
|
+
env: 'LAIOUTR_API_KEY',
|
|
17
|
+
required: true,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
parseProject(project) {
|
|
21
|
+
const parsed = parseProjectSlug(project);
|
|
22
|
+
if (!parsed) {
|
|
23
|
+
this.error('--project must be in org/project format');
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { stripVTControlCharacters } from 'node:util';
|
|
2
|
+
function hasNoColorFlag(argv) {
|
|
3
|
+
const flagIndex = argv.indexOf('--no-color');
|
|
4
|
+
const separatorIndex = argv.indexOf('--');
|
|
5
|
+
return flagIndex !== -1 && (separatorIndex === -1 || flagIndex < separatorIndex);
|
|
6
|
+
}
|
|
7
|
+
export function stripColorsIfDisabled(text, output = process.stdout) {
|
|
8
|
+
const colorsDisabled = !output.isTTY || Boolean(process.env.NO_COLOR) || process.env.TERM === 'dumb' || hasNoColorFlag(process.argv);
|
|
9
|
+
return colorsDisabled ? stripVTControlCharacters(text) : text;
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type DetailField = [label: string, value: string | null | undefined];
|
|
2
|
+
export interface FormatDetailOptions {
|
|
3
|
+
/** Optional heading printed above the aligned fields. */
|
|
4
|
+
title?: string;
|
|
5
|
+
/** Leading indent for each field line. Defaults to two spaces. */
|
|
6
|
+
indent?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Formats an object's fields as an aligned `label: value` detail block:
|
|
10
|
+
*
|
|
11
|
+
* Deployment dep_abc123
|
|
12
|
+
* Status: success
|
|
13
|
+
* Environment: production
|
|
14
|
+
*
|
|
15
|
+
* Labels are padded so every value starts in the same column. Fields whose
|
|
16
|
+
* value is `null`, `undefined`, or empty are omitted, so a caller can list
|
|
17
|
+
* every possible field inline without pre-filtering the absent ones.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatDetail(fields: DetailField[], options?: FormatDetailOptions): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats an object's fields as an aligned `label: value` detail block:
|
|
3
|
+
*
|
|
4
|
+
* Deployment dep_abc123
|
|
5
|
+
* Status: success
|
|
6
|
+
* Environment: production
|
|
7
|
+
*
|
|
8
|
+
* Labels are padded so every value starts in the same column. Fields whose
|
|
9
|
+
* value is `null`, `undefined`, or empty are omitted, so a caller can list
|
|
10
|
+
* every possible field inline without pre-filtering the absent ones.
|
|
11
|
+
*/
|
|
12
|
+
export function formatDetail(fields, options = {}) {
|
|
13
|
+
const indent = options.indent ?? ' ';
|
|
14
|
+
const present = fields.filter((field) => Boolean(field[1]));
|
|
15
|
+
const labelWidth = Math.max(0, ...present.map(([label]) => label.length));
|
|
16
|
+
const lines = present.map(([label, value]) => `${indent}${`${label}:`.padEnd(labelWidth + 2)}${value}`);
|
|
17
|
+
return options.title ? [options.title, ...lines].join('\n') : lines.join('\n');
|
|
18
|
+
}
|
|
@@ -2,7 +2,15 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
export default abstract class LaioutrBaseCommand extends Command {
|
|
3
3
|
static args: {};
|
|
4
4
|
static flags: {
|
|
5
|
-
|
|
5
|
+
'no-color': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
|
+
'cockpit-api-host': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
7
|
cwd: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
8
|
};
|
|
9
|
+
protected toErrorJson(error: unknown): {
|
|
10
|
+
error: {
|
|
11
|
+
status?: number | undefined;
|
|
12
|
+
code: string;
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
8
16
|
}
|
|
@@ -2,17 +2,35 @@ import { Command, Flags } from '@oclif/core';
|
|
|
2
2
|
export default class LaioutrBaseCommand extends Command {
|
|
3
3
|
static args = {};
|
|
4
4
|
static flags = {
|
|
5
|
-
|
|
5
|
+
'no-color': Flags.boolean({
|
|
6
|
+
description: 'Disable color in output',
|
|
7
|
+
}),
|
|
8
|
+
'cockpit-api-host': Flags.string({
|
|
9
|
+
aliases: ['cockpitApiHost'],
|
|
6
10
|
default: 'https://cockpit.laioutr.cloud',
|
|
7
|
-
|
|
11
|
+
deprecateAliases: true,
|
|
12
|
+
description: 'Cockpit API host',
|
|
8
13
|
env: 'COCKPIT_API_HOST',
|
|
9
14
|
required: true,
|
|
10
15
|
}),
|
|
11
16
|
cwd: Flags.string({
|
|
12
17
|
default: process.cwd(),
|
|
13
|
-
description: '
|
|
18
|
+
description: 'Current working directory',
|
|
14
19
|
env: 'CWD',
|
|
15
20
|
required: true,
|
|
16
21
|
}),
|
|
17
22
|
};
|
|
23
|
+
toErrorJson(error) {
|
|
24
|
+
if (!(error instanceof Error)) {
|
|
25
|
+
return { error: { code: 'CLI_ERROR', message: 'An unexpected error occurred.' } };
|
|
26
|
+
}
|
|
27
|
+
const details = error;
|
|
28
|
+
return {
|
|
29
|
+
error: {
|
|
30
|
+
code: typeof details.code === 'string' ? details.code : 'CLI_ERROR',
|
|
31
|
+
message: details.message || 'An unexpected error occurred.',
|
|
32
|
+
...(typeof details.status === 'number' ? { status: details.status } : {}),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
18
36
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ProjectSlugs {
|
|
2
|
+
organizationSlug: string;
|
|
3
|
+
projectSlug: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Parses an `org/project` project identifier into its organization and project
|
|
7
|
+
* slugs.
|
|
8
|
+
*
|
|
9
|
+
* Tolerates a `/p/` path segment (e.g. a pasted `org/p/project` URL) by
|
|
10
|
+
* normalising it to a plain separator. Returns `null` when the input is not
|
|
11
|
+
* exactly two non-empty slash-separated parts, so callers decide how to report
|
|
12
|
+
* the error.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseProjectSlug(project: string): ProjectSlugs | null;
|
package/dist/project.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses an `org/project` project identifier into its organization and project
|
|
3
|
+
* slugs.
|
|
4
|
+
*
|
|
5
|
+
* Tolerates a `/p/` path segment (e.g. a pasted `org/p/project` URL) by
|
|
6
|
+
* normalising it to a plain separator. Returns `null` when the input is not
|
|
7
|
+
* exactly two non-empty slash-separated parts, so callers decide how to report
|
|
8
|
+
* the error.
|
|
9
|
+
*/
|
|
10
|
+
export function parseProjectSlug(project) {
|
|
11
|
+
const parts = project.replace('/p/', '/').split('/');
|
|
12
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return { organizationSlug: parts[0], projectSlug: parts[1] };
|
|
16
|
+
}
|