From 6176916bede5e51fe04c085fdae2dd5370507711 Mon Sep 17 00:00:00 2001 From: Shoujian Zheng Date: Fri, 20 Oct 2023 14:22:12 +0800 Subject: [PATCH] enhance: add arch ref confirmation --- apps/cli/package.json | 3 +- apps/cli/src/commands/deploy.ts | 67 ++++++++++++++++++++++- apps/cli/template/src/index.ts | 3 +- components/deducers/static/src/deducer.ts | 2 +- pnpm-lock.yaml | 60 ++++++++++---------- 5 files changed, 100 insertions(+), 35 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index c8ccf1ce..f32358fe 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -37,7 +37,8 @@ "@pluto/static-generator": "workspace:^", "chalk": "^4.1.2", "commander": "^11.0.0", - "js-yaml": "^4.1.0" + "js-yaml": "^4.1.0", + "table": "^6.8.1" }, "devDependencies": { "@pluto/pluto": "workspace:^", diff --git a/apps/cli/src/commands/deploy.ts b/apps/cli/src/commands/deploy.ts index 263dca56..987901f9 100644 --- a/apps/cli/src/commands/deploy.ts +++ b/apps/cli/src/commands/deploy.ts @@ -1,5 +1,7 @@ import path from "path"; -import { project } from "@pluto/base"; +import { table, TableUserConfig } from "table"; +import { confirm } from "@inquirer/prompts"; +import { arch, project } from "@pluto/base"; import { BuildAdapterByEngine } from "@pluto/adapters"; import logger from "../log"; import { loadConfig } from "../utils"; @@ -35,11 +37,17 @@ export async function deploy(files: string[], opts: DeployOptions) { } // construct the arch ref from user code - logger.info("Deducing..."); + logger.info("Generating reference architecture..."); const archRef = await loadAndDeduce(opts.deducer, files); + const confirmed = await confirmArch(archRef); + if (!confirmed) { + logger.info("You can modify your code and try again."); + process.exit(1); + } + // generate the IR code based on the arch ref - logger.info("Generating..."); + logger.info("Generating the IaC Code and computing modules..."); const outdir = path.join(".pluto", sta.name); const entrypointFile = await loadAndGenerate(opts.generator, archRef, outdir); if (process.env.DEBUG) { @@ -69,3 +77,56 @@ export async function deploy(files: string[], opts: DeployOptions) { logger.info(`${key}: ${applyResult.outputs[key]}`); } } + +async function confirmArch(archRef: arch.Architecture): Promise { + // Create the resource table for printing. + const resData = [["Name", "Type", "Location"]]; + for (let resName in archRef.resources) { + const resource = archRef.resources[resName]; + if (resource.type == "Root") continue; + + let position = ""; + if (resource.locations.length > 0) { + const loc = resource.locations[0]; + position = path.basename(loc.file) + `:${loc.linenum.start},${loc.linenum.end}`; + } + resData.push([resName, resource.type, position]); + } + + // To display the resource table, which includes the resources in the arch ref + const resConfig: TableUserConfig = { + drawHorizontalLine: (lineIndex: number, rowCount: number) => { + return lineIndex === 0 || lineIndex === 2 || lineIndex === 1 || lineIndex === rowCount; + }, + header: { + content: "Resource in Architecture Reference", + }, + }; + console.log(table(resData, resConfig)); + + // Create the relationship table for printing. + const relatData = [["From", "To", "Type", "Operation"]]; + for (let relat of archRef.relationships) { + if (relat.from.type == "Root") continue; + + const typ = relat.type == "access" ? "Access" : "Create"; + relatData.push([relat.from.name, relat.to.name, typ, relat.operation]); + } + + // To display the relationship table, which includes the relationships among resources in the arch ref. + const relatConfig: TableUserConfig = { + drawHorizontalLine: (lineIndex: number, rowCount: number) => { + return lineIndex === 0 || lineIndex === 2 || lineIndex === 1 || lineIndex === rowCount; + }, + header: { + content: "Relationship between Resources", + }, + }; + console.log(table(relatData, relatConfig)); + + const result = await confirm({ + message: "Does this reference architecture satisfy the design of your application?", + default: true, + }); + return result; +} diff --git a/apps/cli/template/src/index.ts b/apps/cli/template/src/index.ts index 74cdee7e..de70dc3c 100644 --- a/apps/cli/template/src/index.ts +++ b/apps/cli/template/src/index.ts @@ -1,5 +1,4 @@ -import { Router, Queue, KVStore, CloudEvent, HttpRequest } from "@pluto/pluto"; -import { HttpResponse } from "@pluto/pluto/dist/router"; +import { Router, Queue, KVStore, CloudEvent, HttpRequest, HttpResponse } from "@pluto/pluto"; const kvstore = new KVStore("kvstore"); const queue = new Queue("queue"); diff --git a/components/deducers/static/src/deducer.ts b/components/deducers/static/src/deducer.ts index 02b1d810..f76dc0e7 100644 --- a/components/deducers/static/src/deducer.ts +++ b/components/deducers/static/src/deducer.ts @@ -73,7 +73,7 @@ async function compilePluto( const startPos = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)); const endPos = sourceFile.getLineAndCharacterOfPosition(node.getEnd()); const loc: arch.Location = { - file: "main.ts", + file: fileNames[0], linenum: { start: `${startPos.line}-${startPos.character}`, end: `${endPos.line}-${endPos.character}`, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7b1970c..97660ac7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,6 +47,9 @@ importers: js-yaml: specifier: ^4.1.0 version: 4.1.0 + table: + specifier: ^6.8.1 + version: 6.8.1 devDependencies: '@pluto/pluto': specifier: workspace:^ @@ -137,25 +140,6 @@ importers: specifier: ^5.2.2 version: 5.2.2 - examples/hello-pluto: - dependencies: - '@pluto/pluto': - specifier: workspace:^ - version: link:../../packages/pluto - devDependencies: - '@pluto/base': - specifier: workspace:^ - version: link:../../packages/base - '@pluto/pluto-infra': - specifier: workspace:^ - version: link:../../packages/pluto-infra - '@types/node': - specifier: ^16 - version: 16.0.0 - typescript: - specifier: ^5.2.2 - version: 5.2.2 - packages/base: dependencies: js-yaml: @@ -1968,10 +1952,6 @@ packages: form-data: 4.0.0 dev: false - /@types/node@16.0.0: - resolution: {integrity: sha512-TmCW5HoZ2o2/z2EYi109jLqIaPIi9y/lc2LmDCWzuCi35bcaQ+OtUh6nwBiFK7SOu25FAU5+YKdqFZUwtqGSdg==} - dev: true - /@types/node@20.8.4: resolution: {integrity: sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A==} dependencies: @@ -2056,7 +2036,6 @@ packages: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 uri-js: 4.4.1 - dev: true /ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} @@ -2128,6 +2107,11 @@ packages: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} dev: false + /astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + dev: false + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: false @@ -2710,7 +2694,6 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -3205,7 +3188,6 @@ packages: /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -3241,6 +3223,10 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + dev: false + /long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} dev: false @@ -3585,7 +3571,6 @@ packages: /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} - dev: true /qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} @@ -3845,6 +3830,15 @@ packages: engines: {node: '>=14'} dev: false + /slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: false + /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: @@ -3953,6 +3947,17 @@ packages: engines: {node: '>= 0.4'} dev: false + /table@6.8.1: + resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} + engines: {node: '>=10.0.0'} + dependencies: + ajv: 8.12.0 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -4161,7 +4166,6 @@ packages: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.0 - dev: true /url@0.10.3: resolution: {integrity: sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==}