@devkong/cli 0.0.67-alpha.26 → 0.0.67-alpha.27

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/index.js CHANGED
@@ -61109,11 +61109,28 @@ asyncio_mode = "auto"
61109
61109
  asyncio_default_fixture_loop_scope = "function"
61110
61110
  `;
61111
61111
  var TEST_DEPENDENCIES = ["pytest==9.1.1", "pytest-asyncio==1.4.0"];
61112
+ var DEPLOY_STEPS = [
61113
+ "install dependencies",
61114
+ "generate schema",
61115
+ "get publish details",
61116
+ "docker login",
61117
+ "docker build",
61118
+ "docker push",
61119
+ "save publish details"
61120
+ ];
61121
+ function notNullStep(job, name) {
61122
+ const step = job.steps.find((item) => item.name === name);
61123
+ if (!step) {
61124
+ throw new Error(`unknown deployment step ${name}`);
61125
+ }
61126
+ return step;
61127
+ }
61112
61128
  var ConnectCommand = class {
61113
61129
  constructor(profileName, profile) {
61114
61130
  this.profileName = profileName;
61115
61131
  this.profile = profile;
61116
61132
  this.isWin = process.platform === "win32";
61133
+ this.deployments = /* @__PURE__ */ new Map();
61117
61134
  const provider = requestConfigProvider(profile);
61118
61135
  this.registryClient = new RegistryClient(profile.kongBaseUrl, provider);
61119
61136
  this.managementClient = new ManagementClient(profile.kongBaseUrl, provider);
@@ -61155,7 +61172,17 @@ var ConnectCommand = class {
61155
61172
  }
61156
61173
  if (request.method === "POST" && url2.pathname === "/v1/deployments") {
61157
61174
  const body = await this.readBody(request);
61158
- this.json(response, 200, await this.deploy(body));
61175
+ this.json(response, 200, this.startDeployment(body));
61176
+ return;
61177
+ }
61178
+ const statusMatch = url2.pathname.match(/^\/v1\/deployments\/([A-Za-z0-9-]+)$/);
61179
+ if (request.method === "GET" && statusMatch) {
61180
+ const job = this.deployments.get(statusMatch[1]);
61181
+ if (!job) {
61182
+ this.json(response, 404, { error: `unknown deployment ${statusMatch[1]}` });
61183
+ return;
61184
+ }
61185
+ this.json(response, 200, job);
61159
61186
  return;
61160
61187
  }
61161
61188
  this.json(response, 404, { error: `unknown route ${request.method} ${url2.pathname}` });
@@ -61189,38 +61216,80 @@ var ConnectCommand = class {
61189
61216
  import_fs3.default.rmSync(workDir, { recursive: true, force: true });
61190
61217
  }
61191
61218
  }
61219
+ /**
61220
+ * Deployments are asynchronous: the ui polls GET /v1/deployments/{id} and
61221
+ * renders the steps in the same progress dialog as the kong-build path.
61222
+ */
61223
+ startDeployment(request) {
61224
+ const deploymentId = generateShortId();
61225
+ const job = {
61226
+ status: "pending",
61227
+ steps: DEPLOY_STEPS.map((name) => ({ name, status: "idle" })),
61228
+ output: ""
61229
+ };
61230
+ this.deployments.set(deploymentId, job);
61231
+ this.deploy(request, job).catch((ex) => {
61232
+ job.status = "failed";
61233
+ job.error = ex.message;
61234
+ for (const step of job.steps) {
61235
+ if (step.status === "pending") {
61236
+ step.status = "failed";
61237
+ }
61238
+ }
61239
+ });
61240
+ return { deploymentId };
61241
+ }
61192
61242
  /**
61193
61243
  * The client-side twin of the kong-build pipeline: docker build + push from
61194
61244
  * this machine (requirements.txt applied), schema generated locally with
61195
61245
  * `main.py --schema`, then the snapshot registered in kong-management.
61196
61246
  */
61197
- async deploy(request) {
61247
+ async deploy(request, job) {
61248
+ const step = (name) => notNullStep(job, name);
61249
+ const runStep = async (name, action) => {
61250
+ step(name).status = "pending";
61251
+ try {
61252
+ const result = await action();
61253
+ step(name).status = "succeeded";
61254
+ return result;
61255
+ } catch (ex) {
61256
+ step(name).status = "failed";
61257
+ throw ex;
61258
+ }
61259
+ };
61198
61260
  const workDir = this.materialize(request.files);
61199
61261
  try {
61200
61262
  const log = [];
61201
61263
  import_fs3.default.writeFileSync(import_path4.default.join(workDir, "Dockerfile"), DOCKERFILE);
61202
- const prepared = await this.prepareVenv(workDir, log);
61203
- if (prepared.exitCode !== 0) {
61204
- throw new Error(`dependency install failed:
61264
+ await runStep("install dependencies", async () => {
61265
+ const prepared = await this.prepareVenv(workDir, log);
61266
+ job.output = log.join("\n");
61267
+ if (prepared.exitCode !== 0) {
61268
+ throw new Error(`dependency install failed:
61205
61269
  ${log.join("\n")}`);
61206
- }
61207
- const schema = await this.run(
61208
- this.venvPython(workDir),
61209
- [import_path4.default.join("src", "main.py"), "--schema"],
61210
- workDir
61211
- );
61212
- if (schema.exitCode !== 0) {
61213
- throw new Error(`schema generation failed:
61270
+ }
61271
+ });
61272
+ const contract = await runStep("generate schema", async () => {
61273
+ const schema = await this.run(
61274
+ this.venvPython(workDir),
61275
+ [import_path4.default.join("src", "main.py"), "--schema"],
61276
+ workDir
61277
+ );
61278
+ if (schema.exitCode !== 0) {
61279
+ throw new Error(`schema generation failed:
61214
61280
  ${schema.output}`);
61215
- }
61216
- const contract = JSON.parse(schema.output);
61217
- const tenant = parseTenant(this.profile.kongBaseUrl);
61218
- const publishDetails = await this.registryClient.getPublishDetails(
61219
- `${tenant}-k-extension-${request.extensionId}`
61220
- );
61281
+ }
61282
+ return JSON.parse(schema.output);
61283
+ });
61284
+ const publishDetails = await runStep("get publish details", () => {
61285
+ const tenant = parseTenant(this.profile.kongBaseUrl);
61286
+ return this.registryClient.getPublishDetails(
61287
+ `${tenant}-k-extension-${request.extensionId}`
61288
+ );
61289
+ });
61221
61290
  const registryUrl = publishDetails.repoName === "docker-registry:5000" ? "localhost:5000" : publishDetails.repoName;
61222
61291
  const imageName = `${registryUrl}/${publishDetails.imageName}:${publishDetails.imageVersion}`;
61223
- for (const step of [
61292
+ for (const dockerStep of [
61224
61293
  {
61225
61294
  title: "docker login",
61226
61295
  command: "docker",
@@ -61234,21 +61303,34 @@ ${schema.output}`);
61234
61303
  },
61235
61304
  { title: "docker push", command: "docker", args: ["push", imageName] }
61236
61305
  ]) {
61237
- log.push(`> ${step.title}`);
61238
- const result = await this.run(step.command, step.args, workDir, step.stdin);
61239
- log.push(result.output);
61240
- if (result.exitCode !== 0) {
61241
- throw new Error(`${step.title} failed:
61242
- ${log.join("\n")}`);
61243
- }
61306
+ await runStep(dockerStep.title, async () => {
61307
+ log.push(`> ${dockerStep.title}`);
61308
+ const result = await this.run(
61309
+ dockerStep.command,
61310
+ dockerStep.args,
61311
+ workDir,
61312
+ dockerStep.stdin
61313
+ );
61314
+ log.push(result.output);
61315
+ job.output = log.join("\n");
61316
+ if (result.exitCode !== 0) {
61317
+ throw new Error(`${dockerStep.title} failed:
61318
+ ${result.output}`);
61319
+ }
61320
+ });
61244
61321
  }
61245
61322
  const version = Number(publishDetails.imageVersion);
61246
- await this.managementClient.createExtensionSnapshot(
61247
- request.extensionId,
61248
- this.snapshotFor(request, version, contract)
61323
+ await runStep(
61324
+ "save publish details",
61325
+ () => this.managementClient.createExtensionSnapshot(
61326
+ request.extensionId,
61327
+ this.snapshotFor(request, version, contract)
61328
+ )
61249
61329
  );
61250
61330
  log.push(`the version ${version} has been successfully published!`);
61251
- return { version, output: log.join("\n") };
61331
+ job.output = log.join("\n");
61332
+ job.version = version;
61333
+ job.status = "succeeded";
61252
61334
  } finally {
61253
61335
  import_fs3.default.rmSync(workDir, { recursive: true, force: true });
61254
61336
  }
@@ -63860,13 +63942,13 @@ function parseVersionWeightList(list) {
63860
63942
  }
63861
63943
  return uses;
63862
63944
  }
63863
- var DEPLOY_STEPS = [
63945
+ var DEPLOY_STEPS2 = [
63864
63946
  "create deployment",
63865
63947
  "save deployment details",
63866
63948
  "deployment completed"
63867
63949
  ];
63868
63950
  function createDeploySteps() {
63869
- return DEPLOY_STEPS.map((action) => {
63951
+ return DEPLOY_STEPS2.map((action) => {
63870
63952
  const handlers = {
63871
63953
  resolve: () => void 0,
63872
63954
  reject: () => void 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devkong/cli",
3
- "version": "0.0.67-alpha.26",
3
+ "version": "0.0.67-alpha.27",
4
4
  "type": "commonjs",
5
5
  "main": "./index.js",
6
6
  "typings": "./index.d.ts",
@@ -5,12 +5,18 @@ export declare class ConnectCommand {
5
5
  private readonly isWin;
6
6
  private readonly registryClient;
7
7
  private readonly managementClient;
8
+ private readonly deployments;
8
9
  constructor(profileName: ProfileName, profile: Profile);
9
10
  execute(): Promise<void>;
10
11
  private handle;
11
12
  private profileInfo;
12
13
  /** Runs only src/main_test.py in a fresh venv and returns the raw output. */
13
14
  private runTests;
15
+ /**
16
+ * Deployments are asynchronous: the ui polls GET /v1/deployments/{id} and
17
+ * renders the steps in the same progress dialog as the kong-build path.
18
+ */
19
+ private startDeployment;
14
20
  /**
15
21
  * The client-side twin of the kong-build pipeline: docker build + push from
16
22
  * this machine (requirements.txt applied), schema generated locally with
@@ -5,7 +5,7 @@ export { CloudEvent } from "./lib/cloudEvent";
5
5
  export { textToBackground, textToColor, textToMonoGradient } from "./lib/color";
6
6
  export { deepEquals, prepareTextForComparison, sameText, shadowEquals } from "./lib/compare";
7
7
  export { KONG_CONNECT_BASE_URL, KONG_CONNECT_PORT } from "./lib/connect";
8
- export type { KongConnectDeployRequest, KongConnectDeployResult, KongConnectFile, KongConnectProfile, KongConnectTestRequest, KongConnectTestResult, } from "./lib/connect";
8
+ export type { KongConnectDeployRequest, KongConnectDeployStart, KongConnectDeployStatus, KongConnectDeployStep, KongConnectFile, KongConnectProfile, KongConnectStepStatus, KongConnectTestRequest, KongConnectTestResult, } from "./lib/connect";
9
9
  export { cronToText, isCron } from "./lib/cron";
10
10
  export type { Cron } from "./lib/cron";
11
11
  export { DataGuardType } from "./lib/dataGuard";
@@ -25,7 +25,18 @@ export interface KongConnectDeployRequest {
25
25
  files: KongConnectFile[];
26
26
  notes?: string;
27
27
  }
28
- export interface KongConnectDeployResult {
29
- version: number;
28
+ export interface KongConnectDeployStart {
29
+ deploymentId: string;
30
+ }
31
+ export type KongConnectStepStatus = "idle" | "pending" | "succeeded" | "failed";
32
+ export interface KongConnectDeployStep {
33
+ name: string;
34
+ status: KongConnectStepStatus;
35
+ }
36
+ export interface KongConnectDeployStatus {
37
+ status: "pending" | "succeeded" | "failed";
38
+ steps: KongConnectDeployStep[];
30
39
  output: string;
40
+ version?: number;
41
+ error?: string;
31
42
  }