@laioutr/cli 0.3.2 → 0.4.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/CHANGELOG.md +11 -0
- package/README.md +140 -8
- package/dist/api/deploy.d.ts +65 -0
- package/dist/api/deploy.js +34 -0
- package/dist/api/fetchRc.js +12 -28
- package/dist/api/http.d.ts +14 -0
- package/dist/api/http.js +28 -0
- package/dist/api/releaseAppVersion.js +9 -20
- package/dist/commands/deploy/list.d.ts +31 -0
- package/dist/commands/deploy/list.js +54 -0
- package/dist/commands/deploy/logs.d.ts +22 -0
- package/dist/commands/deploy/logs.js +51 -0
- package/dist/commands/deploy/status.d.ts +30 -0
- package/dist/commands/deploy/status.js +38 -0
- package/dist/commands/deploy/trigger.d.ts +23 -0
- package/dist/commands/deploy/trigger.js +129 -0
- 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 +20 -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 +11 -0
- package/dist/deploy-base-command.js +27 -0
- package/dist/format/detail.d.ts +19 -0
- package/dist/format/detail.js +18 -0
- package/dist/project.d.ts +14 -0
- package/dist/project.js +16 -0
- package/oclif.manifest.json +339 -4
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @laioutr/cli
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e5eb46a: Add a `deploy` command group for managing project deployments from the CLI. Every command targets a project as `--project org/project` and authenticates with an organization API key (`--key`, or the `LAIOUTR_API_KEY` env var).
|
|
8
|
+
|
|
9
|
+
- `laioutr deploy trigger` — trigger a production or named-preview deployment (`--preview <name>`). Waits for completion by default (`--no-wait` to return immediately) and can stream build logs with `--logs`.
|
|
10
|
+
- `laioutr deploy status` — show a deployment's status, environment, URL, and who created it.
|
|
11
|
+
- `laioutr deploy list` — list recent deployments for a project (`--limit`, default 20, max 100).
|
|
12
|
+
- `laioutr deploy logs` — fetch and follow a deployment's build logs.
|
|
13
|
+
|
|
3
14
|
## 0.3.1
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ $ npm install -g @laioutr/cli
|
|
|
20
20
|
$ laioutr COMMAND
|
|
21
21
|
running command...
|
|
22
22
|
$ laioutr (--version)
|
|
23
|
-
@laioutr/cli/0.
|
|
23
|
+
@laioutr/cli/0.4.0 linux-x64 node-v24.18.0
|
|
24
24
|
$ laioutr --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ laioutr COMMAND
|
|
@@ -32,6 +32,10 @@ USAGE
|
|
|
32
32
|
|
|
33
33
|
<!-- commands -->
|
|
34
34
|
* [`laioutr app release`](#laioutr-app-release)
|
|
35
|
+
* [`laioutr deploy list`](#laioutr-deploy-list)
|
|
36
|
+
* [`laioutr deploy logs`](#laioutr-deploy-logs)
|
|
37
|
+
* [`laioutr deploy status`](#laioutr-deploy-status)
|
|
38
|
+
* [`laioutr deploy trigger`](#laioutr-deploy-trigger)
|
|
35
39
|
* [`laioutr help [COMMAND]`](#laioutr-help-command)
|
|
36
40
|
* [`laioutr plugins`](#laioutr-plugins)
|
|
37
41
|
* [`laioutr plugins add PLUGIN`](#laioutr-plugins-add-plugin)
|
|
@@ -60,7 +64,8 @@ FLAGS
|
|
|
60
64
|
<options: stable|testing>
|
|
61
65
|
-k, --key=<value> (required) API key for authentication
|
|
62
66
|
--cockpitApiHost=<value> (required) [default: https://cockpit.laioutr.cloud] cockpit api host
|
|
63
|
-
--cwd=<value> (required) [default: /
|
|
67
|
+
--cwd=<value> (required) [default: /home/runner/work/laioutr/laioutr/apps/cli] current working
|
|
68
|
+
directory
|
|
64
69
|
|
|
65
70
|
DESCRIPTION
|
|
66
71
|
Publish an app version to the Laioutr platform.
|
|
@@ -73,7 +78,132 @@ EXAMPLES
|
|
|
73
78
|
LAIOUTR_API_KEY=orgKey_xxx laioutr app release
|
|
74
79
|
```
|
|
75
80
|
|
|
76
|
-
_See code: [src/commands/app/release.ts](https://github.com/laioutr/laioutr/blob/v0.
|
|
81
|
+
_See code: [src/commands/app/release.ts](https://github.com/laioutr/laioutr/blob/v0.4.0/src/commands/app/release.ts)_
|
|
82
|
+
|
|
83
|
+
## `laioutr deploy list`
|
|
84
|
+
|
|
85
|
+
List recent deployments for a project.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
USAGE
|
|
89
|
+
$ laioutr deploy list --cockpitApiHost <value> --cwd <value> -p <value> -k <value> [--json] [--limit <value>]
|
|
90
|
+
|
|
91
|
+
FLAGS
|
|
92
|
+
-k, --key=<value> (required) Organization API key with project:deploy scope
|
|
93
|
+
-p, --project=<value> (required) Project identifier in org/project format
|
|
94
|
+
--cockpitApiHost=<value> (required) [default: https://cockpit.laioutr.cloud] cockpit api host
|
|
95
|
+
--cwd=<value> (required) [default: /home/runner/work/laioutr/laioutr/apps/cli] current working
|
|
96
|
+
directory
|
|
97
|
+
--limit=<value> [default: 20] Maximum number of deployments to list (1-100)
|
|
98
|
+
|
|
99
|
+
GLOBAL FLAGS
|
|
100
|
+
--json Format output as json.
|
|
101
|
+
|
|
102
|
+
DESCRIPTION
|
|
103
|
+
List recent deployments for a project.
|
|
104
|
+
|
|
105
|
+
EXAMPLES
|
|
106
|
+
$ laioutr deploy list --project org/project --key orgKey_xxx
|
|
107
|
+
|
|
108
|
+
$ laioutr deploy list --project org/project --key orgKey_xxx --limit 50
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
_See code: [src/commands/deploy/list.ts](https://github.com/laioutr/laioutr/blob/v0.4.0/src/commands/deploy/list.ts)_
|
|
112
|
+
|
|
113
|
+
## `laioutr deploy logs`
|
|
114
|
+
|
|
115
|
+
Fetch and display build logs for a deployment.
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
USAGE
|
|
119
|
+
$ laioutr deploy logs --cockpitApiHost <value> --cwd <value> -p <value> -k <value> --deploymentId <value>
|
|
120
|
+
[--json]
|
|
121
|
+
|
|
122
|
+
FLAGS
|
|
123
|
+
-k, --key=<value> (required) Organization API key with project:deploy scope
|
|
124
|
+
-p, --project=<value> (required) Project identifier in org/project format
|
|
125
|
+
--cockpitApiHost=<value> (required) [default: https://cockpit.laioutr.cloud] cockpit api host
|
|
126
|
+
--cwd=<value> (required) [default: /home/runner/work/laioutr/laioutr/apps/cli] current working
|
|
127
|
+
directory
|
|
128
|
+
--deploymentId=<value> (required) Deployment ID
|
|
129
|
+
|
|
130
|
+
GLOBAL FLAGS
|
|
131
|
+
--json Format output as json.
|
|
132
|
+
|
|
133
|
+
DESCRIPTION
|
|
134
|
+
Fetch and display build logs for a deployment.
|
|
135
|
+
|
|
136
|
+
EXAMPLES
|
|
137
|
+
$ laioutr deploy logs --project org/project --key orgKey_xxx --deploymentId dep_abc123
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
_See code: [src/commands/deploy/logs.ts](https://github.com/laioutr/laioutr/blob/v0.4.0/src/commands/deploy/logs.ts)_
|
|
141
|
+
|
|
142
|
+
## `laioutr deploy status`
|
|
143
|
+
|
|
144
|
+
Show status of a deployment.
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
USAGE
|
|
148
|
+
$ laioutr deploy status --cockpitApiHost <value> --cwd <value> -p <value> -k <value> --deploymentId <value>
|
|
149
|
+
[--json]
|
|
150
|
+
|
|
151
|
+
FLAGS
|
|
152
|
+
-k, --key=<value> (required) Organization API key with project:deploy scope
|
|
153
|
+
-p, --project=<value> (required) Project identifier in org/project format
|
|
154
|
+
--cockpitApiHost=<value> (required) [default: https://cockpit.laioutr.cloud] cockpit api host
|
|
155
|
+
--cwd=<value> (required) [default: /home/runner/work/laioutr/laioutr/apps/cli] current working
|
|
156
|
+
directory
|
|
157
|
+
--deploymentId=<value> (required) Deployment ID
|
|
158
|
+
|
|
159
|
+
GLOBAL FLAGS
|
|
160
|
+
--json Format output as json.
|
|
161
|
+
|
|
162
|
+
DESCRIPTION
|
|
163
|
+
Show status of a deployment.
|
|
164
|
+
|
|
165
|
+
EXAMPLES
|
|
166
|
+
$ laioutr deploy status --project org/project --key orgKey_xxx --deploymentId dep_abc123
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
_See code: [src/commands/deploy/status.ts](https://github.com/laioutr/laioutr/blob/v0.4.0/src/commands/deploy/status.ts)_
|
|
170
|
+
|
|
171
|
+
## `laioutr deploy trigger`
|
|
172
|
+
|
|
173
|
+
Trigger a project deployment.
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
USAGE
|
|
177
|
+
$ laioutr deploy trigger --cockpitApiHost <value> --cwd <value> -p <value> -k <value> [--json] [--wait] [--logs]
|
|
178
|
+
[--preview <value>]
|
|
179
|
+
|
|
180
|
+
FLAGS
|
|
181
|
+
-k, --key=<value> (required) Organization API key with project:deploy scope
|
|
182
|
+
-p, --project=<value> (required) Project identifier in org/project format
|
|
183
|
+
--cockpitApiHost=<value> (required) [default: https://cockpit.laioutr.cloud] cockpit api host
|
|
184
|
+
--cwd=<value> (required) [default: /home/runner/work/laioutr/laioutr/apps/cli] current working
|
|
185
|
+
directory
|
|
186
|
+
--logs Stream build log output instead of spinner
|
|
187
|
+
--preview=<value> Create a preview deployment with optional name
|
|
188
|
+
--[no-]wait Wait for deployment to complete
|
|
189
|
+
|
|
190
|
+
GLOBAL FLAGS
|
|
191
|
+
--json Format output as json.
|
|
192
|
+
|
|
193
|
+
DESCRIPTION
|
|
194
|
+
Trigger a project deployment.
|
|
195
|
+
|
|
196
|
+
EXAMPLES
|
|
197
|
+
$ laioutr deploy trigger --project org/project --key orgKey_xxx
|
|
198
|
+
|
|
199
|
+
$ laioutr deploy trigger --project org/project --key orgKey_xxx --no-wait
|
|
200
|
+
|
|
201
|
+
$ laioutr deploy trigger --project org/project --key orgKey_xxx --logs
|
|
202
|
+
|
|
203
|
+
$ laioutr deploy trigger --project org/project --key orgKey_xxx --preview my-feature
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
_See code: [src/commands/deploy/trigger.ts](https://github.com/laioutr/laioutr/blob/v0.4.0/src/commands/deploy/trigger.ts)_
|
|
77
207
|
|
|
78
208
|
## `laioutr help [COMMAND]`
|
|
79
209
|
|
|
@@ -398,7 +528,8 @@ FLAGS
|
|
|
398
528
|
-p, --project=<value> (required) <organization slug>/<project slug>
|
|
399
529
|
-s, --projectSecret=<value> (required) project secret
|
|
400
530
|
--cockpitApiHost=<value> (required) [default: https://cockpit.laioutr.cloud] cockpit api host
|
|
401
|
-
--cwd=<value> (required) [default: /
|
|
531
|
+
--cwd=<value> (required) [default: /home/runner/work/laioutr/laioutr/apps/cli] current working
|
|
532
|
+
directory
|
|
402
533
|
|
|
403
534
|
DESCRIPTION
|
|
404
535
|
Fetches the laioutrrc.json of a project from the cockpit api.
|
|
@@ -423,7 +554,8 @@ FLAGS
|
|
|
423
554
|
-p, --project=<value> (required) <organization slug>/<project slug>
|
|
424
555
|
-s, --projectSecret=<value> (required) project secret
|
|
425
556
|
--cockpitApiHost=<value> (required) [default: https://cockpit.laioutr.cloud] cockpit api host
|
|
426
|
-
--cwd=<value> (required) [default: /
|
|
557
|
+
--cwd=<value> (required) [default: /home/runner/work/laioutr/laioutr/apps/cli] current working
|
|
558
|
+
directory
|
|
427
559
|
|
|
428
560
|
DESCRIPTION
|
|
429
561
|
Fetches the laioutrrc.json of a project from the cockpit api.
|
|
@@ -435,7 +567,7 @@ EXAMPLES
|
|
|
435
567
|
$ laioutr rc fetch
|
|
436
568
|
```
|
|
437
569
|
|
|
438
|
-
_See code: [src/commands/rc/fetch.ts](https://github.com/laioutr/laioutr/blob/v0.
|
|
570
|
+
_See code: [src/commands/rc/fetch.ts](https://github.com/laioutr/laioutr/blob/v0.4.0/src/commands/rc/fetch.ts)_
|
|
439
571
|
|
|
440
572
|
## `laioutr rc update [FILENAME]`
|
|
441
573
|
|
|
@@ -447,7 +579,7 @@ USAGE
|
|
|
447
579
|
|
|
448
580
|
FLAGS
|
|
449
581
|
--cockpitApiHost=<value> (required) [default: https://cockpit.laioutr.cloud] cockpit api host
|
|
450
|
-
--cwd=<value> (required) [default: /
|
|
582
|
+
--cwd=<value> (required) [default: /home/runner/work/laioutr/laioutr/apps/cli] current working directory
|
|
451
583
|
|
|
452
584
|
DESCRIPTION
|
|
453
585
|
Updates an existing laioutrrc.json file with the latest from the cockpit api.
|
|
@@ -456,5 +588,5 @@ EXAMPLES
|
|
|
456
588
|
$ laioutr rc update
|
|
457
589
|
```
|
|
458
590
|
|
|
459
|
-
_See code: [src/commands/rc/update.ts](https://github.com/laioutr/laioutr/blob/v0.
|
|
591
|
+
_See code: [src/commands/rc/update.ts](https://github.com/laioutr/laioutr/blob/v0.4.0/src/commands/rc/update.ts)_
|
|
460
592
|
<!-- commandsstop -->
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export interface DeployApiOptions {
|
|
2
|
+
cockpitApiHost: string;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
organizationSlug: string;
|
|
5
|
+
projectSlug: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TriggerOptions extends DeployApiOptions {
|
|
8
|
+
previewName?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function triggerDeployment(options: TriggerOptions): Promise<{
|
|
11
|
+
deploymentId: string;
|
|
12
|
+
status: string;
|
|
13
|
+
environment: string;
|
|
14
|
+
previewName: string | null;
|
|
15
|
+
}>;
|
|
16
|
+
export declare function fetchDeploymentStatus(options: DeployApiOptions & {
|
|
17
|
+
deploymentId: string;
|
|
18
|
+
}): Promise<{
|
|
19
|
+
deploymentId: string;
|
|
20
|
+
status: string;
|
|
21
|
+
environment: string;
|
|
22
|
+
previewName: string | null;
|
|
23
|
+
url: string | null;
|
|
24
|
+
lastError: string | null;
|
|
25
|
+
createdAt: string;
|
|
26
|
+
stoppedAt: string | null;
|
|
27
|
+
attribution: {
|
|
28
|
+
principalType: "user" | "api-key" | "system";
|
|
29
|
+
displayName: string;
|
|
30
|
+
email: string | null;
|
|
31
|
+
agentName: string | null;
|
|
32
|
+
redacted: boolean;
|
|
33
|
+
} | null;
|
|
34
|
+
}>;
|
|
35
|
+
export declare function fetchDeployments(options: DeployApiOptions & {
|
|
36
|
+
limit?: number;
|
|
37
|
+
}): Promise<{
|
|
38
|
+
deployments: {
|
|
39
|
+
deploymentId: string;
|
|
40
|
+
status: string;
|
|
41
|
+
environment: string;
|
|
42
|
+
previewName: string | null;
|
|
43
|
+
url: string | null;
|
|
44
|
+
createdAt: string;
|
|
45
|
+
stoppedAt: string | null;
|
|
46
|
+
attribution: {
|
|
47
|
+
principalType: "user" | "api-key" | "system";
|
|
48
|
+
displayName: string;
|
|
49
|
+
email: string | null;
|
|
50
|
+
agentName: string | null;
|
|
51
|
+
redacted: boolean;
|
|
52
|
+
} | null;
|
|
53
|
+
}[];
|
|
54
|
+
}>;
|
|
55
|
+
export declare function fetchDeploymentLogs(options: DeployApiOptions & {
|
|
56
|
+
deploymentId: string;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
lines: {
|
|
59
|
+
text: string;
|
|
60
|
+
level?: "error" | "warning" | null | undefined;
|
|
61
|
+
timestamp?: number | null | undefined;
|
|
62
|
+
}[] | null;
|
|
63
|
+
supported: boolean;
|
|
64
|
+
deploymentStatus: string;
|
|
65
|
+
}>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { postJson } from './http.js';
|
|
2
|
+
import { deploymentLogsResponseSchema, deploymentsListResponseSchema, deploymentStatusResponseSchema, deployTriggerResponseSchema, } from '../deploy/validation.js';
|
|
3
|
+
export async function triggerDeployment(options) {
|
|
4
|
+
const data = await postJson(`${options.cockpitApiHost}/api/v1/project/deploy`, {
|
|
5
|
+
organizationSlug: options.organizationSlug,
|
|
6
|
+
projectSlug: options.projectSlug,
|
|
7
|
+
previewName: options.previewName,
|
|
8
|
+
}, { apiKey: options.apiKey });
|
|
9
|
+
return deployTriggerResponseSchema.parse(data);
|
|
10
|
+
}
|
|
11
|
+
export async function fetchDeploymentStatus(options) {
|
|
12
|
+
const data = await postJson(`${options.cockpitApiHost}/api/v1/project/deployment-status`, {
|
|
13
|
+
organizationSlug: options.organizationSlug,
|
|
14
|
+
projectSlug: options.projectSlug,
|
|
15
|
+
deploymentId: options.deploymentId,
|
|
16
|
+
}, { apiKey: options.apiKey });
|
|
17
|
+
return deploymentStatusResponseSchema.parse(data);
|
|
18
|
+
}
|
|
19
|
+
export async function fetchDeployments(options) {
|
|
20
|
+
const data = await postJson(`${options.cockpitApiHost}/api/v1/project/deployments`, {
|
|
21
|
+
organizationSlug: options.organizationSlug,
|
|
22
|
+
projectSlug: options.projectSlug,
|
|
23
|
+
limit: options.limit,
|
|
24
|
+
}, { apiKey: options.apiKey });
|
|
25
|
+
return deploymentsListResponseSchema.parse(data);
|
|
26
|
+
}
|
|
27
|
+
export async function fetchDeploymentLogs(options) {
|
|
28
|
+
const data = await postJson(`${options.cockpitApiHost}/api/v1/project/deployment-logs`, {
|
|
29
|
+
organizationSlug: options.organizationSlug,
|
|
30
|
+
projectSlug: options.projectSlug,
|
|
31
|
+
deploymentId: options.deploymentId,
|
|
32
|
+
}, { apiKey: options.apiKey });
|
|
33
|
+
return deploymentLogsResponseSchema.parse(data);
|
|
34
|
+
}
|
package/dist/api/fetchRc.js
CHANGED
|
@@ -1,35 +1,19 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
1
|
import { z } from 'zod/v4';
|
|
2
|
+
import { postJson } from './http.js';
|
|
3
|
+
import { parseProjectSlug } from '../project.js';
|
|
3
4
|
const apiResponseSchema = z.object({
|
|
4
5
|
content: z.string(),
|
|
5
6
|
});
|
|
6
7
|
export const fetchRc = async (flags) => {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
body: JSON.stringify({
|
|
11
|
-
environmentName: flags.environmentName,
|
|
12
|
-
organizationSlug,
|
|
13
|
-
projectSecret: flags.projectSecret,
|
|
14
|
-
projectSlug,
|
|
15
|
-
}),
|
|
16
|
-
headers: {
|
|
17
|
-
'Content-Type': 'application/json',
|
|
18
|
-
},
|
|
19
|
-
method: 'POST',
|
|
20
|
-
});
|
|
21
|
-
const body = await response.text();
|
|
22
|
-
let data = null;
|
|
23
|
-
if (response.status !== 200) {
|
|
24
|
-
throw new Error(`Failed to fetch RC file. Status: ${response.status} ${response.statusText}. Body: ${body}`);
|
|
25
|
-
}
|
|
26
|
-
try {
|
|
27
|
-
data = JSON.parse(body);
|
|
8
|
+
const parsed = parseProjectSlug(flags.project);
|
|
9
|
+
if (!parsed) {
|
|
10
|
+
throw new Error(`Invalid project "${flags.project}" — expected <organization slug>/<project slug>.`);
|
|
28
11
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
12
|
+
const data = await postJson(`${flags.cockpitApiHost}/api/v1/project/fetch-rc`, {
|
|
13
|
+
environmentName: flags.environmentName,
|
|
14
|
+
organizationSlug: parsed.organizationSlug,
|
|
15
|
+
projectSecret: flags.projectSecret,
|
|
16
|
+
projectSlug: parsed.projectSlug,
|
|
17
|
+
});
|
|
18
|
+
return apiResponseSchema.parse(data).content;
|
|
35
19
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface PostJsonOptions {
|
|
2
|
+
/** When set, sent as an `Authorization: Bearer <apiKey>` header. */
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
/** Extra headers, merged over the defaults (`Content-Type` + auth). */
|
|
5
|
+
headers?: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* POSTs a JSON body to `url` and returns the parsed JSON response.
|
|
9
|
+
*
|
|
10
|
+
* Throws if the response status is not 200 (the message carries the status and
|
|
11
|
+
* raw body) or if the body is not valid JSON. Callers validate the returned
|
|
12
|
+
* shape themselves — typically with a zod schema — so this returns `unknown`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function postJson(url: string, body: unknown, options?: PostJsonOptions): Promise<unknown>;
|
package/dist/api/http.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POSTs a JSON body to `url` and returns the parsed JSON response.
|
|
3
|
+
*
|
|
4
|
+
* Throws if the response status is not 200 (the message carries the status and
|
|
5
|
+
* raw body) or if the body is not valid JSON. Callers validate the returned
|
|
6
|
+
* shape themselves — typically with a zod schema — so this returns `unknown`.
|
|
7
|
+
*/
|
|
8
|
+
export async function postJson(url, body, options = {}) {
|
|
9
|
+
const response = await fetch(url, {
|
|
10
|
+
method: 'POST',
|
|
11
|
+
headers: {
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
...(options.apiKey ? { Authorization: `Bearer ${options.apiKey}` } : {}),
|
|
14
|
+
...options.headers,
|
|
15
|
+
},
|
|
16
|
+
body: JSON.stringify(body),
|
|
17
|
+
});
|
|
18
|
+
const text = await response.text();
|
|
19
|
+
if (response.status !== 200) {
|
|
20
|
+
throw new Error(`Request failed (${response.status}): ${text}`);
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(text);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
throw new Error(`Failed to parse JSON response from ${url}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,27 +1,16 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
|
+
import { postJson } from './http.js';
|
|
2
3
|
const releaseResponseSchema = z.object({
|
|
3
4
|
message: z.string(),
|
|
4
5
|
versionId: z.string().optional(),
|
|
5
6
|
});
|
|
6
7
|
export const releaseAppVersion = async (options) => {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
packageName: options.packageName,
|
|
16
|
-
version: options.version,
|
|
17
|
-
configSchema: options.configSchema,
|
|
18
|
-
peerDependencies: options.peerDependencies,
|
|
19
|
-
channel: options.channel,
|
|
20
|
-
}),
|
|
21
|
-
});
|
|
22
|
-
const body = await response.text();
|
|
23
|
-
if (response.status !== 200) {
|
|
24
|
-
throw new Error(`Release failed (${response.status}): ${body}`);
|
|
25
|
-
}
|
|
26
|
-
return releaseResponseSchema.parse(JSON.parse(body));
|
|
8
|
+
const data = await postJson(`${options.cockpitApiHost}/api/v1/app/release`, {
|
|
9
|
+
packageName: options.packageName,
|
|
10
|
+
version: options.version,
|
|
11
|
+
configSchema: options.configSchema,
|
|
12
|
+
peerDependencies: options.peerDependencies,
|
|
13
|
+
channel: options.channel,
|
|
14
|
+
}, { apiKey: options.apiKey });
|
|
15
|
+
return releaseResponseSchema.parse(data);
|
|
27
16
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import DeployBaseCommand from '../../deploy-base-command.js';
|
|
2
|
+
export default class DeployList extends DeployBaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static enableJsonFlag: boolean;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
project: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
key: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
cockpitApiHost: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
cwd: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<{
|
|
14
|
+
deployments: {
|
|
15
|
+
deploymentId: string;
|
|
16
|
+
status: string;
|
|
17
|
+
environment: string;
|
|
18
|
+
previewName: string | null;
|
|
19
|
+
url: string | null;
|
|
20
|
+
createdAt: string;
|
|
21
|
+
stoppedAt: string | null;
|
|
22
|
+
attribution: {
|
|
23
|
+
principalType: "user" | "api-key" | "system";
|
|
24
|
+
displayName: string;
|
|
25
|
+
email: string | null;
|
|
26
|
+
agentName: string | null;
|
|
27
|
+
redacted: boolean;
|
|
28
|
+
} | null;
|
|
29
|
+
}[];
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { makeTable } from '@oclif/table';
|
|
3
|
+
import { fetchDeployments } from '../../api/deploy.js';
|
|
4
|
+
import { formatAttribution } from '../../deploy/attribution.js';
|
|
5
|
+
import DeployBaseCommand from '../../deploy-base-command.js';
|
|
6
|
+
export default class DeployList extends DeployBaseCommand {
|
|
7
|
+
static description = 'List recent deployments for a project.';
|
|
8
|
+
static enableJsonFlag = true;
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> deploy list --project org/project --key orgKey_xxx',
|
|
11
|
+
'<%= config.bin %> deploy list --project org/project --key orgKey_xxx --limit 50',
|
|
12
|
+
];
|
|
13
|
+
static flags = {
|
|
14
|
+
...DeployBaseCommand.flags,
|
|
15
|
+
limit: Flags.integer({
|
|
16
|
+
default: 20,
|
|
17
|
+
description: 'Maximum number of deployments to list (1-100)',
|
|
18
|
+
max: 100,
|
|
19
|
+
min: 1,
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
const { flags } = await this.parse(DeployList);
|
|
24
|
+
const { organizationSlug, projectSlug } = this.parseProject(flags.project);
|
|
25
|
+
const result = await fetchDeployments({
|
|
26
|
+
cockpitApiHost: flags.cockpitApiHost,
|
|
27
|
+
apiKey: flags.key,
|
|
28
|
+
organizationSlug,
|
|
29
|
+
projectSlug,
|
|
30
|
+
limit: flags.limit,
|
|
31
|
+
});
|
|
32
|
+
if (result.deployments.length === 0) {
|
|
33
|
+
this.log('No deployments found.');
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
const rows = result.deployments.map((d) => ({
|
|
37
|
+
ID: d.deploymentId,
|
|
38
|
+
Type: d.environment,
|
|
39
|
+
Preview: d.previewName ?? '—',
|
|
40
|
+
Status: d.status,
|
|
41
|
+
URL: d.url ?? '—',
|
|
42
|
+
'Created by': formatAttribution(d.attribution),
|
|
43
|
+
}));
|
|
44
|
+
this.log(makeTable({
|
|
45
|
+
data: rows,
|
|
46
|
+
// Keep our exact header casing (ID / URL / Created by) instead of the
|
|
47
|
+
// default case-formatter, and truncate the middle of long cells (URLs)
|
|
48
|
+
// so both ends stay visible.
|
|
49
|
+
headerOptions: { formatter: (header) => header },
|
|
50
|
+
overflow: 'truncate-middle',
|
|
51
|
+
}));
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import DeployBaseCommand from '../../deploy-base-command.js';
|
|
2
|
+
export default class DeployLogs extends DeployBaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static enableJsonFlag: boolean;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
deploymentId: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
project: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
key: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
cockpitApiHost: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
cwd: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<{
|
|
14
|
+
lines: {
|
|
15
|
+
text: string;
|
|
16
|
+
level?: "error" | "warning" | null | undefined;
|
|
17
|
+
timestamp?: number | null | undefined;
|
|
18
|
+
}[] | null;
|
|
19
|
+
supported: boolean;
|
|
20
|
+
deploymentStatus: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { fetchDeploymentLogs } from '../../api/deploy.js';
|
|
3
|
+
import { LogRenderer } from '../../deploy/log-renderer.js';
|
|
4
|
+
import { isTerminalStatus, POLL_INTERVAL_MS, sleep } from '../../deploy/polling.js';
|
|
5
|
+
import DeployBaseCommand from '../../deploy-base-command.js';
|
|
6
|
+
export default class DeployLogs extends DeployBaseCommand {
|
|
7
|
+
static description = 'Fetch and display build logs for a deployment.';
|
|
8
|
+
static enableJsonFlag = true;
|
|
9
|
+
static examples = ['<%= config.bin %> deploy logs --project org/project --key orgKey_xxx --deploymentId dep_abc123'];
|
|
10
|
+
static flags = {
|
|
11
|
+
...DeployBaseCommand.flags,
|
|
12
|
+
deploymentId: Flags.string({
|
|
13
|
+
description: 'Deployment ID',
|
|
14
|
+
required: true,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
const { flags } = await this.parse(DeployLogs);
|
|
19
|
+
const { organizationSlug, projectSlug } = this.parseProject(flags.project);
|
|
20
|
+
const apiOptions = {
|
|
21
|
+
cockpitApiHost: flags.cockpitApiHost,
|
|
22
|
+
apiKey: flags.key,
|
|
23
|
+
organizationSlug,
|
|
24
|
+
projectSlug,
|
|
25
|
+
deploymentId: flags.deploymentId,
|
|
26
|
+
};
|
|
27
|
+
// Initial fetch
|
|
28
|
+
const initial = await fetchDeploymentLogs(apiOptions);
|
|
29
|
+
if (!initial.supported) {
|
|
30
|
+
this.log("Build logs are not available for this deployment's hosting provider.");
|
|
31
|
+
return initial;
|
|
32
|
+
}
|
|
33
|
+
const isFollowing = !isTerminalStatus(initial.deploymentStatus);
|
|
34
|
+
this.log(`Build log for deployment ${flags.deploymentId}${isFollowing ? ' (following)' : ''}`);
|
|
35
|
+
this.log('');
|
|
36
|
+
const renderer = new LogRenderer();
|
|
37
|
+
renderer.render(initial.lines, (msg) => this.log(msg));
|
|
38
|
+
if (!isFollowing) {
|
|
39
|
+
return initial;
|
|
40
|
+
}
|
|
41
|
+
// Follow mode — poll until terminal
|
|
42
|
+
while (true) {
|
|
43
|
+
await sleep(POLL_INTERVAL_MS);
|
|
44
|
+
const result = await fetchDeploymentLogs(apiOptions);
|
|
45
|
+
renderer.render(result.lines, (msg) => this.log(msg));
|
|
46
|
+
if (isTerminalStatus(result.deploymentStatus)) {
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import DeployBaseCommand from '../../deploy-base-command.js';
|
|
2
|
+
export default class DeployStatus extends DeployBaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static enableJsonFlag: boolean;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
deploymentId: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
project: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
key: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
cockpitApiHost: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
cwd: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<{
|
|
14
|
+
deploymentId: string;
|
|
15
|
+
status: string;
|
|
16
|
+
environment: string;
|
|
17
|
+
previewName: string | null;
|
|
18
|
+
url: string | null;
|
|
19
|
+
lastError: string | null;
|
|
20
|
+
createdAt: string;
|
|
21
|
+
stoppedAt: string | null;
|
|
22
|
+
attribution: {
|
|
23
|
+
principalType: "user" | "api-key" | "system";
|
|
24
|
+
displayName: string;
|
|
25
|
+
email: string | null;
|
|
26
|
+
agentName: string | null;
|
|
27
|
+
redacted: boolean;
|
|
28
|
+
} | null;
|
|
29
|
+
}>;
|
|
30
|
+
}
|