@zuplo/cli 6.69.5 → 6.69.8
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/dist/__tests__/integration/confirm-production-deploy.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.js +184 -0
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.js.map +1 -0
- package/dist/__tests__/integration/custom-domain.integration.test.js +4 -4
- package/dist/__tests__/integration/custom-domain.integration.test.js.map +1 -1
- package/dist/__tests__/integration/deploy.integration.test.js +1 -0
- package/dist/__tests__/integration/deploy.integration.test.js.map +1 -1
- package/dist/__tests__/integration/jest-mocks-setup.js +4 -0
- package/dist/__tests__/integration/jest-mocks-setup.js.map +1 -1
- package/dist/__tests__/integration/list.integration.test.js +2 -2
- package/dist/__tests__/integration/list.integration.test.js.map +1 -1
- package/dist/__tests__/integration/tunnel.integration.test.js +14 -14
- package/dist/__tests__/integration/tunnel.integration.test.js.map +1 -1
- package/dist/__tests__/integration/variable.integration.test.js +4 -4
- package/dist/__tests__/integration/variable.integration.test.js.map +1 -1
- package/dist/__tests__/integration/whoami.integration.test.js +29 -5
- package/dist/__tests__/integration/whoami.integration.test.js.map +1 -1
- package/dist/bucket/list/handler.d.ts +8 -0
- package/dist/bucket/list/handler.d.ts.map +1 -0
- package/dist/bucket/list/handler.js +54 -0
- package/dist/bucket/list/handler.js.map +1 -0
- package/dist/bucket/models.d.ts +23 -0
- package/dist/bucket/models.d.ts.map +1 -0
- package/dist/bucket/models.js +2 -0
- package/dist/bucket/models.js.map +1 -0
- package/dist/cli.js +16 -6
- package/dist/cli.js.map +1 -1
- package/dist/cmds/bucket/index.d.ts +4 -0
- package/dist/cmds/bucket/index.d.ts.map +1 -0
- package/dist/cmds/bucket/index.js +9 -0
- package/dist/cmds/bucket/index.js.map +1 -0
- package/dist/cmds/bucket/list.d.ts +9 -0
- package/dist/cmds/bucket/list.d.ts.map +1 -0
- package/dist/cmds/bucket/list.js +60 -0
- package/dist/cmds/bucket/list.js.map +1 -0
- package/dist/cmds/deploy.d.ts.map +1 -1
- package/dist/cmds/deploy.js +4 -1
- package/dist/cmds/deploy.js.map +1 -1
- package/dist/cmds/logout.d.ts +9 -0
- package/dist/cmds/logout.d.ts.map +1 -0
- package/dist/cmds/logout.js +23 -0
- package/dist/cmds/logout.js.map +1 -0
- package/dist/cmds/whoami.d.ts.map +1 -1
- package/dist/cmds/whoami.js +1 -2
- package/dist/cmds/whoami.js.map +1 -1
- package/dist/common/api/client.d.ts +40 -0
- package/dist/common/api/client.d.ts.map +1 -0
- package/dist/common/api/client.js +92 -0
- package/dist/common/api/client.js.map +1 -0
- package/dist/common/middleware/confirm-production-deploy.d.ts +4 -0
- package/dist/common/middleware/confirm-production-deploy.d.ts.map +1 -0
- package/dist/common/middleware/confirm-production-deploy.js +49 -0
- package/dist/common/middleware/confirm-production-deploy.js.map +1 -0
- package/dist/common/middleware/get-environment-param.d.ts +6 -0
- package/dist/common/middleware/get-environment-param.d.ts.map +1 -1
- package/dist/common/middleware/get-environment-param.js +15 -0
- package/dist/common/middleware/get-environment-param.js.map +1 -1
- package/dist/common/middleware/get-environment-param.test.d.ts +2 -0
- package/dist/common/middleware/get-environment-param.test.d.ts.map +1 -0
- package/dist/common/middleware/get-environment-param.test.js +33 -0
- package/dist/common/middleware/get-environment-param.test.js.map +1 -0
- package/dist/common/output.d.ts +7 -0
- package/dist/common/output.d.ts.map +1 -1
- package/dist/common/output.js +15 -1
- package/dist/common/output.js.map +1 -1
- package/dist/common/read-linked-config.d.ts +6 -1
- package/dist/common/read-linked-config.d.ts.map +1 -1
- package/dist/common/read-linked-config.js +14 -4
- package/dist/common/read-linked-config.js.map +1 -1
- package/dist/common/read-linked-config.test.js +97 -0
- package/dist/common/read-linked-config.test.js.map +1 -1
- package/dist/custom-domain/create/handler.d.ts.map +1 -1
- package/dist/custom-domain/create/handler.js +12 -27
- package/dist/custom-domain/create/handler.js.map +1 -1
- package/dist/custom-domain/delete/handler.d.ts.map +1 -1
- package/dist/custom-domain/delete/handler.js +25 -54
- package/dist/custom-domain/delete/handler.js.map +1 -1
- package/dist/custom-domain/list/handler.d.ts.map +1 -1
- package/dist/custom-domain/list/handler.js +15 -29
- package/dist/custom-domain/list/handler.js.map +1 -1
- package/dist/custom-domain/update/handler.d.ts.map +1 -1
- package/dist/custom-domain/update/handler.js +12 -27
- package/dist/custom-domain/update/handler.js.map +1 -1
- package/dist/deploy/environments.d.ts +1 -0
- package/dist/deploy/environments.d.ts.map +1 -1
- package/dist/deploy/environments.js +11 -7
- package/dist/deploy/environments.js.map +1 -1
- package/dist/list/handler.d.ts.map +1 -1
- package/dist/list/handler.js +41 -59
- package/dist/list/handler.js.map +1 -1
- package/dist/login/logout.d.ts +5 -0
- package/dist/login/logout.d.ts.map +1 -0
- package/dist/login/logout.js +6 -0
- package/dist/login/logout.js.map +1 -0
- package/dist/login/tokens.d.ts +1 -0
- package/dist/login/tokens.d.ts.map +1 -1
- package/dist/login/tokens.js +16 -1
- package/dist/login/tokens.js.map +1 -1
- package/dist/mtls-certificates/create/handler.d.ts.map +1 -1
- package/dist/mtls-certificates/create/handler.js +9 -23
- package/dist/mtls-certificates/create/handler.js.map +1 -1
- package/dist/mtls-certificates/delete/handler.d.ts.map +1 -1
- package/dist/mtls-certificates/delete/handler.js +8 -20
- package/dist/mtls-certificates/delete/handler.js.map +1 -1
- package/dist/mtls-certificates/describe/handler.d.ts.map +1 -1
- package/dist/mtls-certificates/describe/handler.js +17 -31
- package/dist/mtls-certificates/describe/handler.js.map +1 -1
- package/dist/mtls-certificates/disable/handler.d.ts.map +1 -1
- package/dist/mtls-certificates/disable/handler.js +9 -26
- package/dist/mtls-certificates/disable/handler.js.map +1 -1
- package/dist/mtls-certificates/list/handler.d.ts.map +1 -1
- package/dist/mtls-certificates/list/handler.js +22 -36
- package/dist/mtls-certificates/list/handler.js.map +1 -1
- package/dist/mtls-certificates/update/handler.d.ts.map +1 -1
- package/dist/mtls-certificates/update/handler.js +14 -29
- package/dist/mtls-certificates/update/handler.js.map +1 -1
- package/dist/proxies/create/handler.d.ts.map +1 -1
- package/dist/proxies/create/handler.js +9 -22
- package/dist/proxies/create/handler.js.map +1 -1
- package/dist/proxies/delete/handler.d.ts.map +1 -1
- package/dist/proxies/delete/handler.js +8 -21
- package/dist/proxies/delete/handler.js.map +1 -1
- package/dist/proxies/describe/handler.d.ts.map +1 -1
- package/dist/proxies/describe/handler.js +7 -22
- package/dist/proxies/describe/handler.js.map +1 -1
- package/dist/proxies/update/handler.d.ts.map +1 -1
- package/dist/proxies/update/handler.js +9 -22
- package/dist/proxies/update/handler.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tunnel/create/handler.d.ts.map +1 -1
- package/dist/tunnel/create/handler.js +8 -22
- package/dist/tunnel/create/handler.js.map +1 -1
- package/dist/tunnel/delete/handler.d.ts.map +1 -1
- package/dist/tunnel/delete/handler.js +16 -30
- package/dist/tunnel/delete/handler.js.map +1 -1
- package/dist/tunnel/describe/handler.d.ts.map +1 -1
- package/dist/tunnel/describe/handler.js +7 -21
- package/dist/tunnel/describe/handler.js.map +1 -1
- package/dist/tunnel/list/handler.d.ts.map +1 -1
- package/dist/tunnel/list/handler.js +13 -28
- package/dist/tunnel/list/handler.js.map +1 -1
- package/dist/tunnel/rotate-token/handler.d.ts.map +1 -1
- package/dist/tunnel/rotate-token/handler.js +7 -21
- package/dist/tunnel/rotate-token/handler.js.map +1 -1
- package/dist/tunnel/services/describe/handler.d.ts.map +1 -1
- package/dist/tunnel/services/describe/handler.js +7 -21
- package/dist/tunnel/services/describe/handler.js.map +1 -1
- package/dist/tunnel/services/update/handler.d.ts.map +1 -1
- package/dist/tunnel/services/update/handler.js +18 -32
- package/dist/tunnel/services/update/handler.js.map +1 -1
- package/dist/variable/create/handler.d.ts.map +1 -1
- package/dist/variable/create/handler.js +9 -24
- package/dist/variable/create/handler.js.map +1 -1
- package/dist/variable/update/handler.d.ts.map +1 -1
- package/dist/variable/update/handler.js +9 -24
- package/dist/variable/update/handler.js.map +1 -1
- package/dist/whoami/handler.d.ts +1 -1
- package/dist/whoami/handler.d.ts.map +1 -1
- package/dist/whoami/handler.js +12 -17
- package/dist/whoami/handler.js.map +1 -1
- package/node_modules/@zuplo/core/customer.cli.minified.js +225 -211
- package/node_modules/@zuplo/core/index.minified.js +237 -223
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/editor/node_modules/find-my-way/.github/workflows/node.js.yml +1 -1
- package/node_modules/@zuplo/editor/node_modules/find-my-way/README.md +10 -0
- package/node_modules/@zuplo/editor/node_modules/find-my-way/index.d.ts +6 -0
- package/node_modules/@zuplo/editor/node_modules/find-my-way/index.js +37 -4
- package/node_modules/@zuplo/editor/node_modules/find-my-way/lib/handler-storage.js +2 -2
- package/node_modules/@zuplo/editor/node_modules/find-my-way/package.json +3 -3
- package/node_modules/@zuplo/editor/node_modules/find-my-way/test/repro-issue-414.test.js +57 -0
- package/node_modules/@zuplo/editor/node_modules/find-my-way/test/types/router.test-d.ts +1 -0
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +1 -1
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/node_modules/graphql/index.d.ts +1 -0
- package/node_modules/graphql/language/ast.d.ts +10 -1
- package/node_modules/graphql/language/ast.js +8 -1
- package/node_modules/graphql/language/ast.mjs +8 -1
- package/node_modules/graphql/language/directiveLocation.d.ts +1 -0
- package/node_modules/graphql/language/directiveLocation.js +1 -0
- package/node_modules/graphql/language/directiveLocation.mjs +1 -0
- package/node_modules/graphql/language/index.d.ts +1 -0
- package/node_modules/graphql/language/kinds.d.ts +1 -0
- package/node_modules/graphql/language/kinds.js +1 -0
- package/node_modules/graphql/language/kinds.mjs +1 -0
- package/node_modules/graphql/language/parser.d.ts +14 -0
- package/node_modules/graphql/language/parser.js +33 -0
- package/node_modules/graphql/language/parser.mjs +33 -0
- package/node_modules/graphql/language/predicates.js +3 -1
- package/node_modules/graphql/language/predicates.mjs +5 -1
- package/node_modules/graphql/language/printer.js +13 -1
- package/node_modules/graphql/language/printer.mjs +13 -1
- package/node_modules/graphql/package.json +1 -1
- package/node_modules/graphql/type/directives.d.ts +9 -1
- package/node_modules/graphql/type/directives.js +10 -1
- package/node_modules/graphql/type/directives.mjs +10 -1
- package/node_modules/graphql/type/introspection.js +24 -1
- package/node_modules/graphql/type/introspection.mjs +24 -1
- package/node_modules/graphql/utilities/buildASTSchema.js +4 -0
- package/node_modules/graphql/utilities/buildASTSchema.mjs +4 -0
- package/node_modules/graphql/utilities/buildClientSchema.js +1 -0
- package/node_modules/graphql/utilities/buildClientSchema.mjs +1 -0
- package/node_modules/graphql/utilities/extendSchema.js +58 -3
- package/node_modules/graphql/utilities/extendSchema.mjs +58 -3
- package/node_modules/graphql/utilities/getIntrospectionQuery.d.ts +16 -0
- package/node_modules/graphql/utilities/getIntrospectionQuery.js +31 -38
- package/node_modules/graphql/utilities/getIntrospectionQuery.mjs +31 -38
- package/node_modules/graphql/utilities/introspectionFromSchema.js +1 -0
- package/node_modules/graphql/utilities/introspectionFromSchema.mjs +1 -0
- package/node_modules/graphql/utilities/printSchema.js +1 -0
- package/node_modules/graphql/utilities/printSchema.mjs +1 -0
- package/node_modules/graphql/utilities/valueFromAST.js +12 -2
- package/node_modules/graphql/utilities/valueFromAST.mjs +12 -2
- package/node_modules/graphql/validation/rules/KnownDirectivesRule.js +4 -0
- package/node_modules/graphql/validation/rules/KnownDirectivesRule.mjs +4 -0
- package/node_modules/graphql/validation/rules/UniqueDirectivesPerLocationRule.js +12 -0
- package/node_modules/graphql/validation/rules/UniqueDirectivesPerLocationRule.mjs +12 -0
- package/node_modules/graphql/version.js +3 -3
- package/node_modules/graphql/version.mjs +3 -3
- package/package.json +6 -6
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
export declare const ENVIRONMENT_EXPLICIT_KEY = "environmentExplicit";
|
|
2
|
+
export declare const FETCHED_ENVIRONMENTS_KEY = "fetchedEnvironments";
|
|
3
|
+
export declare function recordEnvironmentExplicit(argv: {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}): void;
|
|
6
|
+
export declare function hasEnvironmentFlag(args: readonly string[]): boolean;
|
|
1
7
|
export declare function fetchEnvironment(argv: {
|
|
2
8
|
[key: string]: unknown;
|
|
3
9
|
}): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-environment-param.d.ts","sourceRoot":"","sources":["../../../src/common/middleware/get-environment-param.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"get-environment-param.d.ts","sourceRoot":"","sources":["../../../src/common/middleware/get-environment-param.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAC9D,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAmB9D,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,QAEzE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CASnE;AAMD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,iBA4LtE"}
|
|
@@ -5,6 +5,20 @@ import { printCriticalFailureToConsoleAndExit, textOrJson } from "../output.js";
|
|
|
5
5
|
import settings from "../settings.js";
|
|
6
6
|
import { isInteractiveTerminal } from "../terminal.js";
|
|
7
7
|
import { buildEnvironmentPromptChoices } from "../utils/build-environment-prompt-choices.js";
|
|
8
|
+
export const ENVIRONMENT_EXPLICIT_KEY = "environmentExplicit";
|
|
9
|
+
export const FETCHED_ENVIRONMENTS_KEY = "fetchedEnvironments";
|
|
10
|
+
export function recordEnvironmentExplicit(argv) {
|
|
11
|
+
argv[ENVIRONMENT_EXPLICIT_KEY] = hasEnvironmentFlag(process.argv);
|
|
12
|
+
}
|
|
13
|
+
export function hasEnvironmentFlag(args) {
|
|
14
|
+
for (let i = 2; i < args.length; i++) {
|
|
15
|
+
const arg = args[i];
|
|
16
|
+
if (arg === "--environment" || arg.startsWith("--environment=")) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
8
22
|
export async function fetchEnvironment(argv) {
|
|
9
23
|
if (argv.environment && typeof argv.environment === "string") {
|
|
10
24
|
return;
|
|
@@ -69,6 +83,7 @@ export async function fetchEnvironment(argv) {
|
|
|
69
83
|
if (environmentJsonFromDeveloperAPI.data.length === 0) {
|
|
70
84
|
await printCriticalFailureToConsoleAndExit("Error: You don't have any environments for this project to link against. First, deploy this project using zuplo deploy and then link against that.");
|
|
71
85
|
}
|
|
86
|
+
argv[FETCHED_ENVIRONMENTS_KEY] = environmentJsonFromDeveloperAPI.data;
|
|
72
87
|
try {
|
|
73
88
|
argv.environment = await select({
|
|
74
89
|
message: "Select the environment",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-environment-param.js","sourceRoot":"","sources":["../../../src/common/middleware/get-environment-param.ts"],"names":[],"mappings":"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","sourcesContent":["import { select } from \"@inquirer/prompts\";\nimport { simpleGit } from \"simple-git\";\nimport { Environment } from \"../api/lib.js\";\nimport { logger } from \"../logger.js\";\nimport { printCriticalFailureToConsoleAndExit, textOrJson } from \"../output.js\";\nimport settings from \"../settings.js\";\nimport { isInteractiveTerminal } from \"../terminal.js\";\nimport { buildEnvironmentPromptChoices } from \"../utils/build-environment-prompt-choices.js\";\n\n/**\n * Middleware that ensures a environment is provided in argv. If not, prompts the user.\n * Note: must be called after get account param and get project param.\n */\nexport async function fetchEnvironment(argv: { [key: string]: unknown }) {\n if (argv.environment && typeof argv.environment === \"string\") {\n return;\n }\n\n if (!argv.account || typeof argv.account !== \"string\") {\n throw new Error(\"Invalid state: account is not set.\");\n }\n if (!argv.project || typeof argv.project !== \"string\") {\n throw new Error(\"Invalid state: project is not set.\");\n }\n\n // 1. Check if the dir argument is set and if we are in a git repository\n // If we are, get the current branch and use that as the environment name.\n const branch = await getGitBranch(argv);\n\n if (branch && !argv[\"fetch-environments\"]) {\n // If the branch is set, use that as the environment name\n argv.environment = branch;\n } else {\n // In non-interactive environments, --environment must be passed explicitly.\n // We check here, before the API calls, to avoid unnecessary network round-trips.\n if (!isInteractiveTerminal()) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: --environment is required in non-interactive environments (e.g. CI/CD).\\nUse the --environment flag to specify an environment name.\"\n );\n return;\n }\n\n const baseUrl = `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments`;\n\n const queryParams: Record<string, string> = {\n // This is safe because of the previous middleware where we set the account and project.\n accountName: argv.account!,\n projectName: argv.project!,\n };\n\n // Create the query string using URLSearchParams\n const url = new URL(baseUrl);\n url.search = new URLSearchParams(queryParams).toString();\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n // biome-ignore lint/style/useNamingConvention: External API property\n Authorization: `Bearer ${argv.authToken}`,\n },\n });\n\n if (response.ok) {\n const environmentJsonFromDeveloperAPI = (await response.json()) as {\n data: Environment[];\n };\n\n // Also fetch working-copy deployments, which are not returned by the\n // /v1/environments endpoint (it only returns self-managed and deployer-owned environments).\n const deploymentsUrl = new URL(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/accounts/${argv.account}/projects/${argv.project}/deployments`\n );\n const deploymentsResponse = await fetch(deploymentsUrl, {\n method: \"GET\",\n headers: {\n // biome-ignore lint/style/useNamingConvention: External API property\n Authorization: `Bearer ${argv.authToken}`,\n },\n });\n\n if (deploymentsResponse.ok) {\n const { data: deployments } = (await deploymentsResponse.json()) as {\n data: Array<{\n name: string;\n accountName: string;\n projectName: string;\n branchName: string;\n environmentType: string;\n createdOn: string;\n }>;\n };\n\n const workingCopies: Environment[] = deployments\n .filter((d) => d.environmentType === \"WORKING_COPY\")\n .map((d) => ({\n name: d.name,\n accountName: d.accountName,\n projectName: d.projectName,\n branchName: d.branchName,\n environmentType: \"working_copy\",\n createdOn: new Date(d.createdOn),\n }));\n\n environmentJsonFromDeveloperAPI.data.push(...workingCopies);\n } else {\n logger.debug(\n {\n status: deploymentsResponse.status,\n statusText: deploymentsResponse.statusText,\n },\n \"Failed to fetch working-copy deployments for project\"\n );\n }\n\n if (environmentJsonFromDeveloperAPI.data.length === 0) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: You don't have any environments for this project to link against. First, deploy this project using zuplo deploy and then link against that.\"\n );\n }\n\n // TODO: This logic doesn't work for working copies anymore due to\n // https://github.com/zuplo/core/blob/main/apps/tenant-api/prisma/migrations/v2_20250711155424_add-working-copy-main-check/migration.sql\n // and https://github.com/zuplo/core/blob/6595268b9d2e5edfb3a20cbb086ccd363cf115f9/apps/tenant-api/src/routes/managed-dedicated/environments.ts#L96-L102\n // Leaving this logic commented out for now since we may want to bring it back.\n // let numDevelopmentEnvironments =\n // environmentJsonFromDeveloperAPI.data.filter((env) => {\n // return env.environmentType === \"development\";\n // }).length;\n\n // if (numDevelopmentEnvironments <= 0) {\n // // Create one on-the-fly\n // const createDevelopmenEnvironmentResponse = await fetch(`${baseUrl}`, {\n // method: \"POST\",\n // headers: {\n // authorization: `Bearer ${argv.authToken}`,\n // \"Content-Type\": \"application/json\",\n // },\n // body: JSON.stringify({\n // accountName: argv.account,\n // projectName: argv.project,\n // environmentType: \"development\",\n // }),\n // });\n\n // if (!createDevelopmenEnvironmentResponse.ok) {\n // console.log(await createDevelopmenEnvironmentResponse.json());\n // logger.debug(\n // {\n // status: createDevelopmenEnvironmentResponse.status,\n // statusText: createDevelopmenEnvironmentResponse.statusText,\n // },\n // \"Failed to create a new instance of development environment\"\n // );\n // await printCriticalFailureToConsoleAndExit(\n // \"Failed to create a new development environment. Please try again later.\"\n // );\n // }\n\n // numDevelopmentEnvironments++;\n\n // // Re-fetch\n // const updatedResponse = await fetch(url, {\n // headers: {\n // authorization: `Bearer ${argv.authToken}`,\n // },\n // });\n\n // environmentJsonFromDeveloperAPI = (await updatedResponse.json()) as {\n // data: Environment[];\n // };\n // }\n\n try {\n argv.environment = await select({\n message: \"Select the environment\",\n choices: buildEnvironmentPromptChoices(\n environmentJsonFromDeveloperAPI.data\n ),\n });\n } catch (error) {\n if (error.isTtyError || error.name === \"ExitPromptError\") {\n process.exit(1);\n }\n logger.trace(\"Failed to select environment\", error);\n process.exit(1);\n }\n } else {\n logger.trace(\n {\n status: response.status,\n statusText: response.statusText,\n response: textOrJson(await response.text()),\n },\n \"Failed to request environments for project\"\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to request environments for the project.\"\n );\n }\n }\n}\nasync function getGitBranch(argv: { [key: string]: unknown }) {\n let branch: string | undefined;\n const dir = argv.dir;\n if (dir && typeof dir === \"string\") {\n const git = simpleGit({ baseDir: dir });\n const isGitRepo = await git.checkIsRepo();\n if (isGitRepo) {\n // Get the current branch from Git\n const status = await git.status();\n if (!status.current) {\n throw new Error(\"Invalid state: Directory is in detached head state.\");\n }\n branch = status.current.trim();\n\n // @NOTE - gitlab returns HEAD as the current branch when running git.status()\n // https://forum.gitlab.com/t/why-i-cant-get-the-branch-name/72462/6\n if (branch === \"HEAD\") {\n // Fetch remote branches to ensure the latest information\n await git.fetch([\"--all\"]);\n\n const branchCommit = await git.branch([\"-a\"]);\n const branchRef = await git.branch([\n \"-r\",\n \"--contains\",\n branchCommit.current,\n ]);\n if (branchRef?.all?.[0]) {\n const originBranch = branchRef.all[0];\n const cleanOriginBranch = originBranch.replace(/^origin\\//, \"\");\n if (!cleanOriginBranch) {\n throw new Error(\n \"Invalid state: Directory is in detached head state.\"\n );\n }\n branch = cleanOriginBranch.trim();\n }\n }\n }\n }\n return branch;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"get-environment-param.js","sourceRoot":"","sources":["../../../src/common/middleware/get-environment-param.ts"],"names":[],"mappings":"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","sourcesContent":["import { select } from \"@inquirer/prompts\";\nimport { simpleGit } from \"simple-git\";\nimport { Environment } from \"../api/lib.js\";\nimport { logger } from \"../logger.js\";\nimport { printCriticalFailureToConsoleAndExit, textOrJson } from \"../output.js\";\nimport settings from \"../settings.js\";\nimport { isInteractiveTerminal } from \"../terminal.js\";\nimport { buildEnvironmentPromptChoices } from \"../utils/build-environment-prompt-choices.js\";\n\nexport const ENVIRONMENT_EXPLICIT_KEY = \"environmentExplicit\";\nexport const FETCHED_ENVIRONMENTS_KEY = \"fetchedEnvironments\";\n\n/**\n * Records whether `--environment` was passed on the command line. Must run\n * before `fetchEnvironment`, which mutates `argv.environment` to the\n * inferred branch and erases the distinction. Downstream middlewares (e.g.\n * the production deploy confirmation) treat an explicit flag as the user's\n * opt-in to deploy to whatever environment they named.\n *\n * We deliberately read `process.argv` rather than `argv.environment` so\n * that `ZUPLO_ENVIRONMENT=...` (picked up by yargs `.env(\"ZUPLO\")`) does\n * NOT count as explicit. A sticky shell export shouldn't silently bypass\n * the production-deploy confirmation; the flag should.\n *\n * Only the long form `--environment` is detected because `cmds/deploy.ts`\n * doesn't declare a short alias. Adding a `-e` check here without a yargs\n * alias would let `-e foo` bypass the prompt while not actually setting\n * the environment — accepting the bypass without the side effect.\n */\nexport function recordEnvironmentExplicit(argv: { [key: string]: unknown }) {\n argv[ENVIRONMENT_EXPLICIT_KEY] = hasEnvironmentFlag(process.argv);\n}\n\nexport function hasEnvironmentFlag(args: readonly string[]): boolean {\n // Skip node + script path; flags only appear after.\n for (let i = 2; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"--environment\" || arg.startsWith(\"--environment=\")) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Middleware that ensures a environment is provided in argv. If not, prompts the user.\n * Note: must be called after get account param and get project param.\n */\nexport async function fetchEnvironment(argv: { [key: string]: unknown }) {\n if (argv.environment && typeof argv.environment === \"string\") {\n return;\n }\n\n if (!argv.account || typeof argv.account !== \"string\") {\n throw new Error(\"Invalid state: account is not set.\");\n }\n if (!argv.project || typeof argv.project !== \"string\") {\n throw new Error(\"Invalid state: project is not set.\");\n }\n\n // 1. Check if the dir argument is set and if we are in a git repository\n // If we are, get the current branch and use that as the environment name.\n const branch = await getGitBranch(argv);\n\n if (branch && !argv[\"fetch-environments\"]) {\n // If the branch is set, use that as the environment name\n argv.environment = branch;\n } else {\n // In non-interactive environments, --environment must be passed explicitly.\n // We check here, before the API calls, to avoid unnecessary network round-trips.\n if (!isInteractiveTerminal()) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: --environment is required in non-interactive environments (e.g. CI/CD).\\nUse the --environment flag to specify an environment name.\"\n );\n return;\n }\n\n const baseUrl = `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments`;\n\n const queryParams: Record<string, string> = {\n // This is safe because of the previous middleware where we set the account and project.\n accountName: argv.account!,\n projectName: argv.project!,\n };\n\n // Create the query string using URLSearchParams\n const url = new URL(baseUrl);\n url.search = new URLSearchParams(queryParams).toString();\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n // biome-ignore lint/style/useNamingConvention: External API property\n Authorization: `Bearer ${argv.authToken}`,\n },\n });\n\n if (response.ok) {\n const environmentJsonFromDeveloperAPI = (await response.json()) as {\n data: Environment[];\n };\n\n // Also fetch working-copy deployments, which are not returned by the\n // /v1/environments endpoint (it only returns self-managed and deployer-owned environments).\n const deploymentsUrl = new URL(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/accounts/${argv.account}/projects/${argv.project}/deployments`\n );\n const deploymentsResponse = await fetch(deploymentsUrl, {\n method: \"GET\",\n headers: {\n // biome-ignore lint/style/useNamingConvention: External API property\n Authorization: `Bearer ${argv.authToken}`,\n },\n });\n\n if (deploymentsResponse.ok) {\n const { data: deployments } = (await deploymentsResponse.json()) as {\n data: Array<{\n name: string;\n accountName: string;\n projectName: string;\n branchName: string;\n environmentType: string;\n createdOn: string;\n }>;\n };\n\n const workingCopies: Environment[] = deployments\n .filter((d) => d.environmentType === \"WORKING_COPY\")\n .map((d) => ({\n name: d.name,\n accountName: d.accountName,\n projectName: d.projectName,\n branchName: d.branchName,\n environmentType: \"working_copy\",\n createdOn: new Date(d.createdOn),\n }));\n\n environmentJsonFromDeveloperAPI.data.push(...workingCopies);\n } else {\n logger.debug(\n {\n status: deploymentsResponse.status,\n statusText: deploymentsResponse.statusText,\n },\n \"Failed to fetch working-copy deployments for project\"\n );\n }\n\n if (environmentJsonFromDeveloperAPI.data.length === 0) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: You don't have any environments for this project to link against. First, deploy this project using zuplo deploy and then link against that.\"\n );\n }\n\n argv[FETCHED_ENVIRONMENTS_KEY] = environmentJsonFromDeveloperAPI.data;\n\n // TODO: This logic doesn't work for working copies anymore due to\n // https://github.com/zuplo/core/blob/main/apps/tenant-api/prisma/migrations/v2_20250711155424_add-working-copy-main-check/migration.sql\n // and https://github.com/zuplo/core/blob/6595268b9d2e5edfb3a20cbb086ccd363cf115f9/apps/tenant-api/src/routes/managed-dedicated/environments.ts#L96-L102\n // Leaving this logic commented out for now since we may want to bring it back.\n // let numDevelopmentEnvironments =\n // environmentJsonFromDeveloperAPI.data.filter((env) => {\n // return env.environmentType === \"development\";\n // }).length;\n\n // if (numDevelopmentEnvironments <= 0) {\n // // Create one on-the-fly\n // const createDevelopmenEnvironmentResponse = await fetch(`${baseUrl}`, {\n // method: \"POST\",\n // headers: {\n // authorization: `Bearer ${argv.authToken}`,\n // \"Content-Type\": \"application/json\",\n // },\n // body: JSON.stringify({\n // accountName: argv.account,\n // projectName: argv.project,\n // environmentType: \"development\",\n // }),\n // });\n\n // if (!createDevelopmenEnvironmentResponse.ok) {\n // console.log(await createDevelopmenEnvironmentResponse.json());\n // logger.debug(\n // {\n // status: createDevelopmenEnvironmentResponse.status,\n // statusText: createDevelopmenEnvironmentResponse.statusText,\n // },\n // \"Failed to create a new instance of development environment\"\n // );\n // await printCriticalFailureToConsoleAndExit(\n // \"Failed to create a new development environment. Please try again later.\"\n // );\n // }\n\n // numDevelopmentEnvironments++;\n\n // // Re-fetch\n // const updatedResponse = await fetch(url, {\n // headers: {\n // authorization: `Bearer ${argv.authToken}`,\n // },\n // });\n\n // environmentJsonFromDeveloperAPI = (await updatedResponse.json()) as {\n // data: Environment[];\n // };\n // }\n\n try {\n argv.environment = await select({\n message: \"Select the environment\",\n choices: buildEnvironmentPromptChoices(\n environmentJsonFromDeveloperAPI.data\n ),\n });\n } catch (error) {\n if (error.isTtyError || error.name === \"ExitPromptError\") {\n process.exit(1);\n }\n logger.trace(\"Failed to select environment\", error);\n process.exit(1);\n }\n } else {\n logger.trace(\n {\n status: response.status,\n statusText: response.statusText,\n response: textOrJson(await response.text()),\n },\n \"Failed to request environments for project\"\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to request environments for the project.\"\n );\n }\n }\n}\nasync function getGitBranch(argv: { [key: string]: unknown }) {\n let branch: string | undefined;\n const dir = argv.dir;\n if (dir && typeof dir === \"string\") {\n const git = simpleGit({ baseDir: dir });\n const isGitRepo = await git.checkIsRepo();\n if (isGitRepo) {\n // Get the current branch from Git\n const status = await git.status();\n if (!status.current) {\n throw new Error(\"Invalid state: Directory is in detached head state.\");\n }\n branch = status.current.trim();\n\n // @NOTE - gitlab returns HEAD as the current branch when running git.status()\n // https://forum.gitlab.com/t/why-i-cant-get-the-branch-name/72462/6\n if (branch === \"HEAD\") {\n // Fetch remote branches to ensure the latest information\n await git.fetch([\"--all\"]);\n\n const branchCommit = await git.branch([\"-a\"]);\n const branchRef = await git.branch([\n \"-r\",\n \"--contains\",\n branchCommit.current,\n ]);\n if (branchRef?.all?.[0]) {\n const originBranch = branchRef.all[0];\n const cleanOriginBranch = originBranch.replace(/^origin\\//, \"\");\n if (!cleanOriginBranch) {\n throw new Error(\n \"Invalid state: Directory is in detached head state.\"\n );\n }\n branch = cleanOriginBranch.trim();\n }\n }\n }\n }\n return branch;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-environment-param.test.d.ts","sourceRoot":"","sources":["../../../src/common/middleware/get-environment-param.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { hasEnvironmentFlag } from "./get-environment-param.js";
|
|
4
|
+
function argv(...userArgs) {
|
|
5
|
+
return ["node", "/path/to/zup.js", ...userArgs];
|
|
6
|
+
}
|
|
7
|
+
describe("hasEnvironmentFlag", () => {
|
|
8
|
+
it("returns true for `--environment main`", () => {
|
|
9
|
+
assert.strictEqual(hasEnvironmentFlag(argv("deploy", "--environment", "main")), true);
|
|
10
|
+
});
|
|
11
|
+
it("returns true for `--environment=main`", () => {
|
|
12
|
+
assert.strictEqual(hasEnvironmentFlag(argv("deploy", "--environment=main")), true);
|
|
13
|
+
});
|
|
14
|
+
it("returns false for `-e main` because deploy doesn't declare a short alias", () => {
|
|
15
|
+
assert.strictEqual(hasEnvironmentFlag(argv("deploy", "-e", "main")), false);
|
|
16
|
+
});
|
|
17
|
+
it("returns false when no environment flag is present", () => {
|
|
18
|
+
assert.strictEqual(hasEnvironmentFlag(argv("deploy")), false);
|
|
19
|
+
});
|
|
20
|
+
it("returns false when only unrelated flags are present", () => {
|
|
21
|
+
assert.strictEqual(hasEnvironmentFlag(argv("deploy", "--no-prompt", "--account", "foo")), false);
|
|
22
|
+
});
|
|
23
|
+
it("returns false for env-var only (no flag in argv) — this is the case the production prompt must not bypass", () => {
|
|
24
|
+
assert.strictEqual(hasEnvironmentFlag(argv("deploy")), false);
|
|
25
|
+
});
|
|
26
|
+
it("does not match flags that share a prefix (e.g. `--environment-other`)", () => {
|
|
27
|
+
assert.strictEqual(hasEnvironmentFlag(argv("deploy", "--environment-other", "x")), false);
|
|
28
|
+
});
|
|
29
|
+
it("ignores `--environment` if it appears in node/script positions", () => {
|
|
30
|
+
assert.strictEqual(hasEnvironmentFlag(["--environment", "x", "deploy"]), false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=get-environment-param.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-environment-param.test.js","sourceRoot":"","sources":["../../../src/common/middleware/get-environment-param.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGhE,SAAS,IAAI,CAAC,GAAG,QAAkB;IACjC,OAAO,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,WAAW,CAChB,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC,EAC3D,IAAI,CACL,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,WAAW,CAChB,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC,EACxD,IAAI,CACL,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAGlF,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,WAAW,CAChB,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,EACrE,KAAK,CACN,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2GAA2G,EAAE,GAAG,EAAE;QAGnH,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,CAAC,WAAW,CAChB,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC,EAC9D,KAAK,CACN,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QAKxE,MAAM,CAAC,WAAW,CAChB,kBAAkB,CAAC,CAAC,eAAe,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,EACpD,KAAK,CACN,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert\";\nimport { describe, it } from \"node:test\";\nimport { hasEnvironmentFlag } from \"./get-environment-param.js\";\n\n// process.argv layout: [node, script, ...userArgs]. Helper builds that shape.\nfunction argv(...userArgs: string[]): string[] {\n return [\"node\", \"/path/to/zup.js\", ...userArgs];\n}\n\ndescribe(\"hasEnvironmentFlag\", () => {\n it(\"returns true for `--environment main`\", () => {\n assert.strictEqual(\n hasEnvironmentFlag(argv(\"deploy\", \"--environment\", \"main\")),\n true\n );\n });\n\n it(\"returns true for `--environment=main`\", () => {\n assert.strictEqual(\n hasEnvironmentFlag(argv(\"deploy\", \"--environment=main\")),\n true\n );\n });\n\n it(\"returns false for `-e main` because deploy doesn't declare a short alias\", () => {\n // If deploy's yargs option ever adds `alias: \\\"e\\\"`, this test should be\n // updated to expect true and the helper extended to match.\n assert.strictEqual(hasEnvironmentFlag(argv(\"deploy\", \"-e\", \"main\")), false);\n });\n\n it(\"returns false when no environment flag is present\", () => {\n assert.strictEqual(hasEnvironmentFlag(argv(\"deploy\")), false);\n });\n\n it(\"returns false when only unrelated flags are present\", () => {\n assert.strictEqual(\n hasEnvironmentFlag(argv(\"deploy\", \"--no-prompt\", \"--account\", \"foo\")),\n false\n );\n });\n\n it(\"returns false for env-var only (no flag in argv) — this is the case the production prompt must not bypass\", () => {\n // Simulates `ZUPLO_ENVIRONMENT=main npx zuplo deploy`: yargs picks up the\n // env var into argv.environment but the flag is absent from process.argv.\n assert.strictEqual(hasEnvironmentFlag(argv(\"deploy\")), false);\n });\n\n it(\"does not match flags that share a prefix (e.g. `--environment-other`)\", () => {\n assert.strictEqual(\n hasEnvironmentFlag(argv(\"deploy\", \"--environment-other\", \"x\")),\n false\n );\n });\n\n it(\"ignores `--environment` if it appears in node/script positions\", () => {\n // Defensive: the loop intentionally starts at index 2 so an args array\n // that happens to put `--environment` at index 0 or 1 is not treated\n // as an explicit flag. (Not a realistic process.argv shape, but guards\n // the contract.)\n assert.strictEqual(\n hasEnvironmentFlag([\"--environment\", \"x\", \"deploy\"]),\n false\n );\n });\n});\n"]}
|
package/dist/common/output.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ export declare function printDiagnosticsToConsole(
|
|
|
5
5
|
): void;
|
|
6
6
|
export declare function printSpinnerToConsole(message?: string): Ora;
|
|
7
7
|
export declare function printWarningToConsole(message?: any): void;
|
|
8
|
+
export declare function printCriticalFailureToConsole(
|
|
9
|
+
message?: any,
|
|
10
|
+
spinner?: Ora
|
|
11
|
+
): void;
|
|
8
12
|
export declare function printCriticalFailureToConsoleAndExit(
|
|
9
13
|
message?: any,
|
|
10
14
|
spinner?: Ora
|
|
@@ -19,6 +23,9 @@ export declare function printResultToConsoleAndExitGracefully(
|
|
|
19
23
|
export declare function printTableToConsoleAndExitGracefully(
|
|
20
24
|
table: any
|
|
21
25
|
): Promise<void>;
|
|
26
|
+
export declare function printCancellationToConsoleAndExitGracefully(
|
|
27
|
+
message?: any
|
|
28
|
+
): Promise<void>;
|
|
22
29
|
export declare function printJsonToConsoleAndExitGracefully(
|
|
23
30
|
value?: unknown
|
|
24
31
|
): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/common/output.ts"],"names":[],"mappings":"AAIA,OAAY,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAS/B,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,EAAE,GAAG,QAwB1E;AAED,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,OAErD;AAED,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,GAAG,QAElD;AAGD,wBAAsB,oCAAoC,CACxD,OAAO,CAAC,EAAE,GAAG,EACb,OAAO,CAAC,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/common/output.ts"],"names":[],"mappings":"AAIA,OAAY,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAS/B,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,EAAE,GAAG,QAwB1E;AAED,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,OAErD;AAED,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,GAAG,QAElD;AAKD,wBAAgB,6BAA6B,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,QASzE;AAGD,wBAAsB,oCAAoC,CACxD,OAAO,CAAC,EAAE,GAAG,EACb,OAAO,CAAC,EAAE,GAAG,iBAMd;AAID,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,GAAG,QAEjD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE,OAAO,QAEjD;AAID,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,QAE7C;AAED,wBAAsB,qCAAqC,CACzD,OAAO,CAAC,EAAE,GAAG,EACb,OAAO,CAAC,EAAE,GAAG,iBAUd;AAED,wBAAsB,oCAAoC,CAAC,KAAK,EAAE,GAAG,iBAKpE;AAQD,wBAAsB,2CAA2C,CAC/D,OAAO,CAAC,EAAE,GAAG,iBAUd;AAED,wBAAsB,mCAAmC,CAAC,KAAK,CAAC,EAAE,OAAO,iBAKxE;AAaD,MAAM,CAAC,OAAO,UAAU,WAAW,SAalC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,OAMtC;AAED,qBAAa,aAAa;IACxB,KAAK;wBACa,MAAM;wBACN,MAAM;yBACL,MAAM;MACtB;CACJ"}
|
package/dist/common/output.js
CHANGED
|
@@ -24,7 +24,7 @@ export function printSpinnerToConsole(message) {
|
|
|
24
24
|
export function printWarningToConsole(message) {
|
|
25
25
|
console.error(chalk.yellow(message));
|
|
26
26
|
}
|
|
27
|
-
export
|
|
27
|
+
export function printCriticalFailureToConsole(message, spinner) {
|
|
28
28
|
if (spinner) {
|
|
29
29
|
spinner?.fail(message);
|
|
30
30
|
}
|
|
@@ -34,6 +34,9 @@ export async function printCriticalFailureToConsoleAndExit(message, spinner) {
|
|
|
34
34
|
Sentry.captureMessage(message, {
|
|
35
35
|
level: "error",
|
|
36
36
|
});
|
|
37
|
+
}
|
|
38
|
+
export async function printCriticalFailureToConsoleAndExit(message, spinner) {
|
|
39
|
+
printCriticalFailureToConsole(message, spinner);
|
|
37
40
|
await Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {
|
|
38
41
|
process.exit(1);
|
|
39
42
|
});
|
|
@@ -64,6 +67,17 @@ export async function printTableToConsoleAndExitGracefully(table) {
|
|
|
64
67
|
process.exit(0);
|
|
65
68
|
});
|
|
66
69
|
}
|
|
70
|
+
export async function printCancellationToConsoleAndExitGracefully(message) {
|
|
71
|
+
printDiagnosticsToConsole(message);
|
|
72
|
+
try {
|
|
73
|
+
await Sentry.close(MAX_WAIT_PENDING_TIME_MS);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
process.exit(0);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
67
81
|
export async function printJsonToConsoleAndExitGracefully(value) {
|
|
68
82
|
printJsonToConsole(value);
|
|
69
83
|
await Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/common/output.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAY,MAAM,KAAK,CAAC;AAC/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAMzC,MAAM,UAAU,yBAAyB,CAAC,OAAa,EAAE,YAAkB;IACzE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAExC,IACE,YAAY;QACZ,OAAO,YAAY,KAAK,QAAQ;QAChC,QAAQ,IAAI,YAAY;QACxB,OAAO,YAAY,CAAC,MAAM,KAAK,QAAQ,EACvC,CAAC;QAED,OAAO,CAAC,KAAK,CACX,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAC/D,CAAC;IACJ,CAAC;SAAM,IACL,YAAY;QACZ,OAAO,YAAY,KAAK,QAAQ;QAChC,OAAO,IAAI,YAAY;QACvB,OAAO,YAAY,CAAC,KAAK,KAAK,QAAQ,EACtC,CAAC;QAED,OAAO,CAAC,KAAK,CACX,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CACrE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAa;IACjD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,CAAC;
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/common/output.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AACvC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAY,MAAM,KAAK,CAAC;AAC/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAMzC,MAAM,UAAU,yBAAyB,CAAC,OAAa,EAAE,YAAkB;IACzE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAExC,IACE,YAAY;QACZ,OAAO,YAAY,KAAK,QAAQ;QAChC,QAAQ,IAAI,YAAY;QACxB,OAAO,YAAY,CAAC,MAAM,KAAK,QAAQ,EACvC,CAAC;QAED,OAAO,CAAC,KAAK,CACX,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAC/D,CAAC;IACJ,CAAC;SAAM,IACL,YAAY;QACZ,OAAO,YAAY,KAAK,QAAQ;QAChC,OAAO,IAAI,YAAY;QACvB,OAAO,YAAY,CAAC,KAAK,KAAK,QAAQ,EACtC,CAAC;QAED,OAAO,CAAC,KAAK,CACX,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CACrE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAa;IACjD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,CAAC;AAKD,MAAM,UAAU,6BAA6B,CAAC,OAAa,EAAE,OAAa;IACxE,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE;QAC7B,KAAK,EAAE,OAAO;KACf,CAAC,CAAC;AACL,CAAC;AAGD,MAAM,CAAC,KAAK,UAAU,oCAAoC,CACxD,OAAa,EACb,OAAa;IAEb,6BAA6B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAID,MAAM,UAAU,oBAAoB,CAAC,OAAa;IAChD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAe;IAChD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC;AAID,MAAM,UAAU,mBAAmB,CAAC,KAAU;IAC5C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qCAAqC,CACzD,OAAa,EACb,OAAa;IAEb,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oCAAoC,CAAC,KAAU;IACnE,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAC3B,MAAM,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,2CAA2C,CAC/D,OAAa;IAEb,yBAAyB,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;IAET,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mCAAmC,CAAC,KAAe;IACvE,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC1B,MAAM,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAaD,MAAM,CAAC,OAAO,UAAU,WAAW;IAEjC,IAAI,OAAO,OAAO,KAAK,WAAW;QAAE,OAAO;IAC3C,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QACnD,MAAM,MAAM,GAAG,OAAuC,CAAC;QACvD,IACE,MAAM,CAAC,OAAO;YACd,MAAM,CAAC,KAAK;YACZ,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,KAAK,UAAU,EAChD,CAAC;YACD,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,OAAO,aAAa;IACxB,KAAK,GAAG,GAAG,EAAE,CAAC,CAAC;QACb,IAAI,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QAC/C,IAAI,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;QAChD,KAAK,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;KACnD,CAAC,CAAC;CACJ","sourcesContent":["/** biome-ignore-all lint/suspicious/noConsole: CLI output file */\n// biome-ignore-all lint/suspicious/noExplicitAny: Lots of any here\nimport * as Sentry from \"@sentry/node\";\nimport chalk from \"chalk\";\nimport ora, { Ora } from \"ora\";\nimport { MAX_WAIT_PENDING_TIME_MS } from \"./constants.js\";\n\nconst indent = ` ${chalk.gray(\"|\")} `;\n\n// We standardize printing to the terminal with this module\n\n// According to https://unix.stackexchange.com/questions/331611/do-progress-reports-logging-information-belong-on-stderr-or-stdout\n// any diagnostic information should go to stderr, and only the actual output goes to stdout\nexport function printDiagnosticsToConsole(message?: any, maybeProblem?: any) {\n console.error(chalk.bold.blue(message));\n\n if (\n maybeProblem &&\n typeof maybeProblem === \"object\" &&\n \"detail\" in maybeProblem &&\n typeof maybeProblem.detail === \"string\"\n ) {\n // The details are better to log if we have it\n console.error(\n indent + chalk.bold.red(JSON.stringify(maybeProblem, null, 2))\n );\n } else if (\n maybeProblem &&\n typeof maybeProblem === \"object\" &&\n \"title\" in maybeProblem &&\n typeof maybeProblem.title === \"string\"\n ) {\n // If we dont have details then log the title\n console.error(\n indent + chalk.bold.red(JSON.stringify(maybeProblem.title, null, 2))\n );\n }\n}\n\nexport function printSpinnerToConsole(message?: string) {\n return ora(message).start();\n}\n\nexport function printWarningToConsole(message?: any) {\n console.error(chalk.yellow(message));\n}\n\n// Display a critical failure message without terminating the process.\n// Use this when the caller is responsible for exiting (e.g. cli.ts's catch\n// block needs the finally to run analytics shutdown before process.exit).\nexport function printCriticalFailureToConsole(message?: any, spinner?: Ora) {\n if (spinner) {\n spinner?.fail(message);\n } else {\n console.error(chalk.bold.red(message));\n }\n Sentry.captureMessage(message, {\n level: \"error\",\n });\n}\n\n// This information is displayed to the user, so it should be actionable.\nexport async function printCriticalFailureToConsoleAndExit(\n message?: any,\n spinner?: Ora\n) {\n printCriticalFailureToConsole(message, spinner);\n await Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {\n process.exit(1);\n });\n}\n\n// Only use this to output the actual result of a command\n// This outputs to STDOUT, which is reserved for the actual result of a command\nexport function printResultToConsole(message?: any) {\n console.log(chalk.bold.green(message));\n}\n\nexport function printJsonToConsole(value?: unknown) {\n console.log(JSON.stringify(value, null, 2));\n}\n\n// Only use this to output the actual result of a command\n// This outputs to STDOUT, which is reserved for the actual result of a command\nexport function printTableToConsole(table: any) {\n console.table(table);\n}\n\nexport async function printResultToConsoleAndExitGracefully(\n message?: any,\n spinner?: Ora\n) {\n if (spinner) {\n spinner?.succeed(message);\n } else {\n printResultToConsole(message);\n }\n await Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {\n process.exit(0);\n });\n}\n\nexport async function printTableToConsoleAndExitGracefully(table: any) {\n printTableToConsole(table);\n await Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {\n process.exit(0);\n });\n}\n\n// User-initiated cancellation (not a failure, not a result). Goes to STDERR\n// like other diagnostics, flushes Sentry to avoid losing pending events, then\n// exits with code 0 — the user successfully aborted, not crashed.\n//\n// Wrapped in try/finally so that a Sentry.close rejection does not strand\n// the process: cancellation must always exit.\nexport async function printCancellationToConsoleAndExitGracefully(\n message?: any\n) {\n printDiagnosticsToConsole(message);\n try {\n await Sentry.close(MAX_WAIT_PENDING_TIME_MS);\n } catch {\n // Best-effort flush; we're exiting regardless.\n } finally {\n process.exit(0);\n }\n}\n\nexport async function printJsonToConsoleAndExitGracefully(value?: unknown) {\n printJsonToConsole(value);\n await Sentry.close(MAX_WAIT_PENDING_TIME_MS).then(() => {\n process.exit(0);\n });\n}\n\n// See https://nodejs.org/docs/latest-v18.x/api/process.html#a-note-on-process-io\n// We want to deliberately have STDOUT flush synchronously, so we can pipe the output to another command\n\ninterface WriteStreamWithHandle {\n _handle: {\n // biome-ignore lint/complexity/noBannedTypes: Migrated from ESLint\n setBlocking: Function;\n };\n isTTY: boolean;\n}\n\nexport default function setBlocking() {\n // Deno and browser have no process object:\n if (typeof process === \"undefined\") return;\n [process.stdout, process.stderr].forEach((_stream) => {\n const stream = _stream as any as WriteStreamWithHandle;\n if (\n stream._handle &&\n stream.isTTY &&\n typeof stream._handle.setBlocking === \"function\"\n ) {\n stream._handle.setBlocking(true);\n }\n });\n}\n\nexport function textOrJson(text: string) {\n try {\n return JSON.parse(text);\n } catch (_e) {\n return text;\n }\n}\n\nexport class ConsoleOutput {\n child = () => ({\n info: (message: string) => console.log(message),\n warn: (message: string) => console.warn(message),\n error: (message: string) => console.error(message),\n });\n}\n"]}
|
|
@@ -10,5 +10,10 @@ export declare function readLinkedConfig(argv: {
|
|
|
10
10
|
export declare function ignoreLinkedDetails(argv: {
|
|
11
11
|
[key: string]: unknown;
|
|
12
12
|
}): void;
|
|
13
|
-
export declare function confirmLinkedValue(
|
|
13
|
+
export declare function confirmLinkedValue(
|
|
14
|
+
message: string,
|
|
15
|
+
options?: {
|
|
16
|
+
defaultYes?: boolean;
|
|
17
|
+
}
|
|
18
|
+
): Promise<boolean>;
|
|
14
19
|
//# sourceMappingURL=read-linked-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-linked-config.d.ts","sourceRoot":"","sources":["../../src/common/read-linked-config.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAGD,eAAO,MAAM,kBAAkB,qBAAqB,CAAC;AAOrD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuBxB;AAMD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,IAAI,CAE1E;
|
|
1
|
+
{"version":3,"file":"read-linked-config.d.ts","sourceRoot":"","sources":["../../src/common/read-linked-config.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAGD,eAAO,MAAM,kBAAkB,qBAAqB,CAAC;AAOrD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuBxB;AAMD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,IAAI,CAE1E;AAYD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GACrC,OAAO,CAAC,OAAO,CAAC,CAgClB"}
|
|
@@ -35,9 +35,10 @@ export async function readLinkedConfig(argv) {
|
|
|
35
35
|
export function ignoreLinkedDetails(argv) {
|
|
36
36
|
argv[USE_LINKED_DETAILS] = false;
|
|
37
37
|
}
|
|
38
|
-
export async function confirmLinkedValue(message) {
|
|
38
|
+
export async function confirmLinkedValue(message, options = {}) {
|
|
39
|
+
const defaultYes = options.defaultYes ?? true;
|
|
39
40
|
if (!isInteractiveTerminal()) {
|
|
40
|
-
return
|
|
41
|
+
return defaultYes;
|
|
41
42
|
}
|
|
42
43
|
return new Promise((resolve) => {
|
|
43
44
|
const rl = readline.createInterface({
|
|
@@ -48,10 +49,19 @@ export async function confirmLinkedValue(message) {
|
|
|
48
49
|
rl.close();
|
|
49
50
|
process.exit(1);
|
|
50
51
|
});
|
|
51
|
-
|
|
52
|
+
const hint = defaultYes ? "[Y/n]" : "[y/N]";
|
|
53
|
+
rl.question(`${message} ${hint} `, (answer) => {
|
|
52
54
|
rl.close();
|
|
53
55
|
const normalized = answer.trim().toLowerCase();
|
|
54
|
-
|
|
56
|
+
if (normalized === "y" || normalized === "yes") {
|
|
57
|
+
resolve(true);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (normalized === "n" || normalized === "no") {
|
|
61
|
+
resolve(false);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
resolve(defaultYes);
|
|
55
65
|
});
|
|
56
66
|
});
|
|
57
67
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-linked-config.js","sourceRoot":"","sources":["../../src/common/read-linked-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAQtD,MAAM,uBAAuB,GAAG,cAAc,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAOrD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAEtC;IACC,IAAI,IAAI,CAAC,uBAAuB,CAAC,KAAK,SAAS,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC,uBAAuB,CAAiB,CAAC;IACvD,CAAC;IACD,MAAM,GAAG,GAAI,IAAI,CAAC,GAA0B,IAAI,GAAG,CAAC;IACpD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,oBAAoB,CAAC,CAAC;IAC7D,IAAI,MAAoB,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,GAAG;YACP,WAAW,EAAE,MAAM,CAAC,oBAAoB,CAAC,IAAI,SAAS;YACtD,WAAW,EAAE,MAAM,CAAC,oBAAoB,CAAC,IAAI,SAAS;YACtD,eAAe,EAAE,MAAM,CAAC,wBAAwB,CAAC,IAAI,SAAS;SAC/D,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,8CAA8C,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,GAAG,EAAE,CAAC;IACd,CAAC;IACD,IAAI,CAAC,uBAAuB,CAAC,GAAG,MAAM,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAMD,MAAM,UAAU,mBAAmB,CAAC,IAAgC;IAClE,IAAI,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAC;AACnC,CAAC;
|
|
1
|
+
{"version":3,"file":"read-linked-config.js","sourceRoot":"","sources":["../../src/common/read-linked-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport readline from \"node:readline\";\nimport dotenv from \"dotenv\";\nimport { ZUPLO_SYSTEM_ENV_VAR } from \"./constants.js\";\nimport { logger } from \"./logger.js\";\nimport { isInteractiveTerminal } from \"./terminal.js\";\n\nexport interface LinkedConfig {\n accountName?: string;\n projectName?: string;\n environmentType?: string;\n}\n\nconst LINKED_CONFIG_CACHE_KEY = \"linkedConfig\";\nexport const USE_LINKED_DETAILS = \"useLinkedDetails\";\n\n/**\n * Reads the linked project configuration from `.env.zuplo` if it exists.\n * Caches the result on argv to avoid reading the file multiple times per command.\n * Returns an empty object if the file is missing or cannot be parsed.\n */\nexport async function readLinkedConfig(argv: {\n [key: string]: unknown;\n}): Promise<LinkedConfig> {\n if (argv[LINKED_CONFIG_CACHE_KEY] !== undefined) {\n return argv[LINKED_CONFIG_CACHE_KEY] as LinkedConfig;\n }\n const dir = (argv.dir as string | undefined) ?? \".\";\n const envFilePath = join(resolve(dir), ZUPLO_SYSTEM_ENV_VAR);\n let config: LinkedConfig;\n try {\n const content = await readFile(envFilePath, \"utf-8\");\n const parsed = dotenv.parse(content);\n config = {\n accountName: parsed[\"ZUPLO_ACCOUNT_NAME\"] || undefined,\n projectName: parsed[\"ZUPLO_PROJECT_NAME\"] || undefined,\n environmentType: parsed[\"ZUPLO_ENVIRONMENT_TYPE\"] || undefined,\n };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n logger.trace(error, \"Failed to read linked config from .env.zuplo\");\n }\n config = {};\n }\n argv[LINKED_CONFIG_CACHE_KEY] = config;\n return config;\n}\n\n/**\n * Middleware that prevents downstream middlewares from using linked config values.\n * Used by commands (e.g. link) that always re-prompt from scratch.\n */\nexport function ignoreLinkedDetails(argv: { [key: string]: unknown }): void {\n argv[USE_LINKED_DETAILS] = false;\n}\n\n/**\n * Prompts the user with a Y/n question using plain readline output.\n * Avoids @inquirer/prompts cursor management which conflicts with ora spinners.\n * In non-interactive terminals, resolves to the default answer without\n * prompting. Callers that need different non-interactive behavior should\n * check isInteractiveTerminal() and skip this call entirely.\n *\n * `defaultYes: false` renders the prompt as `[y/N]` so a bare Enter\n * cancels — use it for destructive confirmations like production deploys.\n */\nexport async function confirmLinkedValue(\n message: string,\n options: { defaultYes?: boolean } = {}\n): Promise<boolean> {\n const defaultYes = options.defaultYes ?? true;\n if (!isInteractiveTerminal()) {\n return defaultYes;\n }\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n rl.on(\"SIGINT\", () => {\n rl.close();\n process.exit(1);\n });\n const hint = defaultYes ? \"[Y/n]\" : \"[y/N]\";\n rl.question(`${message} ${hint} `, (answer) => {\n rl.close();\n const normalized = answer.trim().toLowerCase();\n if (normalized === \"y\" || normalized === \"yes\") {\n resolve(true);\n return;\n }\n if (normalized === \"n\" || normalized === \"no\") {\n resolve(false);\n return;\n }\n // Empty or unrecognized input falls back to the configured default.\n // This preserves the long-standing `[Y/n]` behavior where anything\n // other than n/no was treated as Yes.\n resolve(defaultYes);\n });\n });\n}\n"]}
|
|
@@ -206,6 +206,103 @@ describe("confirmLinkedValue", () => {
|
|
|
206
206
|
stubReadlineAnswer("NO");
|
|
207
207
|
assert.strictEqual(await confirmLinkedValue("Use linked account 'foo'?"), false);
|
|
208
208
|
});
|
|
209
|
+
it("falls back to defaultYes when input is unrecognized (preserves [Y/n] tolerance)", async () => {
|
|
210
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
211
|
+
value: true,
|
|
212
|
+
configurable: true,
|
|
213
|
+
});
|
|
214
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
215
|
+
value: true,
|
|
216
|
+
configurable: true,
|
|
217
|
+
});
|
|
218
|
+
stubReadlineAnswer("foo");
|
|
219
|
+
assert.strictEqual(await confirmLinkedValue("Use linked account 'foo'?"), true);
|
|
220
|
+
});
|
|
221
|
+
describe("with { defaultYes: false }", () => {
|
|
222
|
+
it("returns false in non-interactive terminals", async () => {
|
|
223
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
224
|
+
value: false,
|
|
225
|
+
configurable: true,
|
|
226
|
+
});
|
|
227
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
228
|
+
value: false,
|
|
229
|
+
configurable: true,
|
|
230
|
+
});
|
|
231
|
+
const result = await confirmLinkedValue("Deploy to prod?", {
|
|
232
|
+
defaultYes: false,
|
|
233
|
+
});
|
|
234
|
+
assert.strictEqual(result, false);
|
|
235
|
+
});
|
|
236
|
+
it("returns false when user presses Enter (empty input — default no)", async () => {
|
|
237
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
238
|
+
value: true,
|
|
239
|
+
configurable: true,
|
|
240
|
+
});
|
|
241
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
242
|
+
value: true,
|
|
243
|
+
configurable: true,
|
|
244
|
+
});
|
|
245
|
+
stubReadlineAnswer("");
|
|
246
|
+
assert.strictEqual(await confirmLinkedValue("Deploy to prod?", { defaultYes: false }), false);
|
|
247
|
+
});
|
|
248
|
+
it("returns true when user enters 'y'", async () => {
|
|
249
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
250
|
+
value: true,
|
|
251
|
+
configurable: true,
|
|
252
|
+
});
|
|
253
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
254
|
+
value: true,
|
|
255
|
+
configurable: true,
|
|
256
|
+
});
|
|
257
|
+
stubReadlineAnswer("y");
|
|
258
|
+
assert.strictEqual(await confirmLinkedValue("Deploy to prod?", { defaultYes: false }), true);
|
|
259
|
+
});
|
|
260
|
+
it("returns true when user enters 'yes'", async () => {
|
|
261
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
262
|
+
value: true,
|
|
263
|
+
configurable: true,
|
|
264
|
+
});
|
|
265
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
266
|
+
value: true,
|
|
267
|
+
configurable: true,
|
|
268
|
+
});
|
|
269
|
+
stubReadlineAnswer("yes");
|
|
270
|
+
assert.strictEqual(await confirmLinkedValue("Deploy to prod?", { defaultYes: false }), true);
|
|
271
|
+
});
|
|
272
|
+
it("returns false when input is unrecognized (falls back to default)", async () => {
|
|
273
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
274
|
+
value: true,
|
|
275
|
+
configurable: true,
|
|
276
|
+
});
|
|
277
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
278
|
+
value: true,
|
|
279
|
+
configurable: true,
|
|
280
|
+
});
|
|
281
|
+
stubReadlineAnswer("foo");
|
|
282
|
+
assert.strictEqual(await confirmLinkedValue("Deploy to prod?", { defaultYes: false }), false);
|
|
283
|
+
});
|
|
284
|
+
it("renders the prompt with [y/N] hint", async () => {
|
|
285
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
286
|
+
value: true,
|
|
287
|
+
configurable: true,
|
|
288
|
+
});
|
|
289
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
290
|
+
value: true,
|
|
291
|
+
configurable: true,
|
|
292
|
+
});
|
|
293
|
+
let capturedPrompt = "";
|
|
294
|
+
mock.method(readline, "createInterface", () => ({
|
|
295
|
+
on: () => { },
|
|
296
|
+
question: (prompt, callback) => {
|
|
297
|
+
capturedPrompt = prompt;
|
|
298
|
+
callback("");
|
|
299
|
+
},
|
|
300
|
+
close: mock.fn(),
|
|
301
|
+
}));
|
|
302
|
+
await confirmLinkedValue("Deploy to prod?", { defaultYes: false });
|
|
303
|
+
assert.match(capturedPrompt, /\[y\/N\]/);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
209
306
|
it("exits the process when SIGINT is emitted on the readline interface", () => {
|
|
210
307
|
Object.defineProperty(process.stdin, "isTTY", {
|
|
211
308
|
value: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-linked-config.test.js","sourceRoot":"","sources":["../../src/common/read-linked-config.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert\";\nimport { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport readline from \"node:readline\";\nimport { afterEach, beforeEach, describe, it, mock } from \"node:test\";\nimport {\n confirmLinkedValue,\n readLinkedConfig,\n USE_LINKED_DETAILS,\n} from \"./read-linked-config.js\";\n\ndescribe(\"readLinkedConfig\", () => {\n let testDir: string;\n\n beforeEach(async () => {\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-read-linked-config-test-\"));\n });\n\n afterEach(async () => {\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"returns empty object when .env.zuplo does not exist\", async () => {\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {});\n });\n\n it(\"returns both fields when all are present\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n [\"ZUPLO_ACCOUNT_NAME=my-account\", \"ZUPLO_PROJECT_NAME=my-project\"].join(\n \"\\n\"\n ),\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {\n accountName: \"my-account\",\n projectName: \"my-project\",\n environmentType: undefined,\n });\n });\n\n it(\"returns environmentType when ZUPLO_ENVIRONMENT_TYPE is present\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n [\n \"ZUPLO_ACCOUNT_NAME=my-account\",\n \"ZUPLO_PROJECT_NAME=my-project\",\n \"ZUPLO_ENVIRONMENT_TYPE=production\",\n ].join(\"\\n\"),\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {\n accountName: \"my-account\",\n projectName: \"my-project\",\n environmentType: \"production\",\n });\n });\n\n it(\"returns undefined for fields that are missing from the file\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n \"ZUPLO_ACCOUNT_NAME=my-account\\n\",\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.strictEqual(result.accountName, \"my-account\");\n assert.strictEqual(result.projectName, undefined);\n });\n\n it(\"returns undefined for fields set to empty string\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n 'ZUPLO_ACCOUNT_NAME=\\nZUPLO_PROJECT_NAME=\"\"\\n',\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.strictEqual(result.accountName, undefined);\n assert.strictEqual(result.projectName, undefined);\n });\n\n it(\"caches the result on argv so the file is only read once\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n \"ZUPLO_ACCOUNT_NAME=my-account\\n\",\n \"utf-8\"\n );\n const argv: { [key: string]: unknown } = { dir: testDir };\n\n const first = await readLinkedConfig(argv);\n // Delete the file — a second call must return the cached value, not throw\n await rm(join(testDir, \".env.zuplo\"));\n const second = await readLinkedConfig(argv);\n\n assert.strictEqual(first, second); // same object reference\n assert.strictEqual(second.accountName, \"my-account\");\n });\n\n it(\"returns empty object and does not throw on a malformed file\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n \"THIS IS NOT VALID\\x00ENV\\n\",\n \"utf-8\"\n );\n const argv = { dir: testDir };\n // dotenv silently skips lines it cannot parse, so no throw is expected\n const result = await readLinkedConfig(argv);\n assert.ok(typeof result === \"object\");\n });\n\n it(\"defaults dir to '.' when argv.dir is not set\", async () => {\n // Use testDir so the test is not sensitive to whether .env.zuplo exists in the process CWD\n const argv: { [key: string]: unknown } = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {});\n });\n});\n\ndescribe(\"confirmLinkedValue\", () => {\n let originalStdinIsTTY: PropertyDescriptor | undefined;\n let originalStdoutIsTTY: PropertyDescriptor | undefined;\n let originalCI: string | undefined;\n let hadCI: boolean;\n\n beforeEach(() => {\n originalStdinIsTTY = Object.getOwnPropertyDescriptor(\n process.stdin,\n \"isTTY\"\n );\n originalStdoutIsTTY = Object.getOwnPropertyDescriptor(\n process.stdout,\n \"isTTY\"\n );\n hadCI = Object.hasOwn(process.env, \"CI\");\n originalCI = process.env.CI;\n // Clear CI so isInteractiveTerminal() doesn't short-circuit the readline path\n // in CI environments (e.g. GitHub Actions sets CI=true automatically).\n delete process.env.CI;\n });\n\n afterEach(() => {\n mock.restoreAll();\n if (originalStdinIsTTY) {\n Object.defineProperty(process.stdin, \"isTTY\", originalStdinIsTTY);\n } else {\n delete (process.stdin as { isTTY?: boolean }).isTTY;\n }\n if (originalStdoutIsTTY) {\n Object.defineProperty(process.stdout, \"isTTY\", originalStdoutIsTTY);\n } else {\n delete (process.stdout as { isTTY?: boolean }).isTTY;\n }\n if (hadCI) {\n process.env.CI = originalCI;\n } else {\n delete process.env.CI;\n }\n });\n\n it(\"returns true immediately without prompting in non-interactive terminals\", async () => {\n // Make isInteractiveTerminal() return false by setting stdin to non-TTY.\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: false,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: false,\n configurable: true,\n });\n // readline must not be touched — if it were, the test would hang.\n const result = await confirmLinkedValue(\"Use linked account 'foo'?\");\n assert.strictEqual(result, true);\n });\n\n it(\"returns true when user enters 'y'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"y\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n it(\"returns true when user enters 'Y' (case-insensitive)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"Y\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n it(\"returns true when user presses Enter (empty input — default yes)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n it(\"returns false when user enters 'n'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"n\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"returns false when user enters 'N' (case-insensitive)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"N\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"returns false when user enters 'no'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"no\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"returns false when user enters 'NO' (case-insensitive)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"NO\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"exits the process when SIGINT is emitted on the readline interface\", () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n\n const exitStub = mock.method(process, \"exit\", () => {\n throw new Error(\"process.exit called\");\n });\n\n let sigintEmitter: (() => void) | undefined;\n mock.method(readline, \"createInterface\", () => ({\n on: (event: string, handler: () => void) => {\n if (event === \"SIGINT\") sigintEmitter = handler;\n },\n question: () => {\n /* never resolves */\n },\n close: mock.fn(),\n }));\n\n // Start the prompt — it won't resolve (question callback never fires)\n void confirmLinkedValue(\"Use linked account 'foo'?\");\n\n // Emitting SIGINT calls process.exit(1) synchronously; our mock throws to intercept it\n assert.throws(() => sigintEmitter!(), /process\\.exit called/);\n assert.strictEqual(exitStub.mock.calls[0].arguments[0], 1);\n });\n});\n\ndescribe(\"USE_LINKED_DETAILS\", () => {\n let testDir: string;\n\n beforeEach(async () => {\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-use-linked-details-test-\"));\n });\n\n afterEach(async () => {\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"is exported and has the expected value\", () => {\n assert.strictEqual(USE_LINKED_DETAILS, \"useLinkedDetails\");\n });\n\n it(\"setting it to false on argv does not collide with the internal cache key\", async () => {\n // The useLinkedDetails key must not collide with the internal cache key so that\n // readLinkedConfig continues to work even when useLinkedDetails is false.\n const argv: { [key: string]: unknown } = {\n dir: testDir,\n [USE_LINKED_DETAILS]: false,\n };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {});\n });\n});\n\n/**\n * Helper: stub readline.createInterface so that the `question` callback is\n * called synchronously with `answer`, simulating user input.\n */\nfunction stubReadlineAnswer(answer: string) {\n mock.method(readline, \"createInterface\", () => ({\n on: () => {\n /* ignore SIGINT in these tests */\n },\n question: (_prompt: string, callback: (a: string) => void) => {\n callback(answer);\n },\n close: mock.fn(),\n }));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"read-linked-config.test.js","sourceRoot":"","sources":["../../src/common/read-linked-config.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert\";\nimport { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport readline from \"node:readline\";\nimport { afterEach, beforeEach, describe, it, mock } from \"node:test\";\nimport {\n confirmLinkedValue,\n readLinkedConfig,\n USE_LINKED_DETAILS,\n} from \"./read-linked-config.js\";\n\ndescribe(\"readLinkedConfig\", () => {\n let testDir: string;\n\n beforeEach(async () => {\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-read-linked-config-test-\"));\n });\n\n afterEach(async () => {\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"returns empty object when .env.zuplo does not exist\", async () => {\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {});\n });\n\n it(\"returns both fields when all are present\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n [\"ZUPLO_ACCOUNT_NAME=my-account\", \"ZUPLO_PROJECT_NAME=my-project\"].join(\n \"\\n\"\n ),\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {\n accountName: \"my-account\",\n projectName: \"my-project\",\n environmentType: undefined,\n });\n });\n\n it(\"returns environmentType when ZUPLO_ENVIRONMENT_TYPE is present\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n [\n \"ZUPLO_ACCOUNT_NAME=my-account\",\n \"ZUPLO_PROJECT_NAME=my-project\",\n \"ZUPLO_ENVIRONMENT_TYPE=production\",\n ].join(\"\\n\"),\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {\n accountName: \"my-account\",\n projectName: \"my-project\",\n environmentType: \"production\",\n });\n });\n\n it(\"returns undefined for fields that are missing from the file\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n \"ZUPLO_ACCOUNT_NAME=my-account\\n\",\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.strictEqual(result.accountName, \"my-account\");\n assert.strictEqual(result.projectName, undefined);\n });\n\n it(\"returns undefined for fields set to empty string\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n 'ZUPLO_ACCOUNT_NAME=\\nZUPLO_PROJECT_NAME=\"\"\\n',\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.strictEqual(result.accountName, undefined);\n assert.strictEqual(result.projectName, undefined);\n });\n\n it(\"caches the result on argv so the file is only read once\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n \"ZUPLO_ACCOUNT_NAME=my-account\\n\",\n \"utf-8\"\n );\n const argv: { [key: string]: unknown } = { dir: testDir };\n\n const first = await readLinkedConfig(argv);\n // Delete the file — a second call must return the cached value, not throw\n await rm(join(testDir, \".env.zuplo\"));\n const second = await readLinkedConfig(argv);\n\n assert.strictEqual(first, second); // same object reference\n assert.strictEqual(second.accountName, \"my-account\");\n });\n\n it(\"returns empty object and does not throw on a malformed file\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n \"THIS IS NOT VALID\\x00ENV\\n\",\n \"utf-8\"\n );\n const argv = { dir: testDir };\n // dotenv silently skips lines it cannot parse, so no throw is expected\n const result = await readLinkedConfig(argv);\n assert.ok(typeof result === \"object\");\n });\n\n it(\"defaults dir to '.' when argv.dir is not set\", async () => {\n // Use testDir so the test is not sensitive to whether .env.zuplo exists in the process CWD\n const argv: { [key: string]: unknown } = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {});\n });\n});\n\ndescribe(\"confirmLinkedValue\", () => {\n let originalStdinIsTTY: PropertyDescriptor | undefined;\n let originalStdoutIsTTY: PropertyDescriptor | undefined;\n let originalCI: string | undefined;\n let hadCI: boolean;\n\n beforeEach(() => {\n originalStdinIsTTY = Object.getOwnPropertyDescriptor(\n process.stdin,\n \"isTTY\"\n );\n originalStdoutIsTTY = Object.getOwnPropertyDescriptor(\n process.stdout,\n \"isTTY\"\n );\n hadCI = Object.hasOwn(process.env, \"CI\");\n originalCI = process.env.CI;\n // Clear CI so isInteractiveTerminal() doesn't short-circuit the readline path\n // in CI environments (e.g. GitHub Actions sets CI=true automatically).\n delete process.env.CI;\n });\n\n afterEach(() => {\n mock.restoreAll();\n if (originalStdinIsTTY) {\n Object.defineProperty(process.stdin, \"isTTY\", originalStdinIsTTY);\n } else {\n delete (process.stdin as { isTTY?: boolean }).isTTY;\n }\n if (originalStdoutIsTTY) {\n Object.defineProperty(process.stdout, \"isTTY\", originalStdoutIsTTY);\n } else {\n delete (process.stdout as { isTTY?: boolean }).isTTY;\n }\n if (hadCI) {\n process.env.CI = originalCI;\n } else {\n delete process.env.CI;\n }\n });\n\n it(\"returns true immediately without prompting in non-interactive terminals\", async () => {\n // Make isInteractiveTerminal() return false by setting stdin to non-TTY.\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: false,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: false,\n configurable: true,\n });\n // readline must not be touched — if it were, the test would hang.\n const result = await confirmLinkedValue(\"Use linked account 'foo'?\");\n assert.strictEqual(result, true);\n });\n\n it(\"returns true when user enters 'y'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"y\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n it(\"returns true when user enters 'Y' (case-insensitive)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"Y\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n it(\"returns true when user presses Enter (empty input — default yes)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n it(\"returns false when user enters 'n'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"n\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"returns false when user enters 'N' (case-insensitive)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"N\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"returns false when user enters 'no'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"no\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"returns false when user enters 'NO' (case-insensitive)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"NO\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"falls back to defaultYes when input is unrecognized (preserves [Y/n] tolerance)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"foo\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n describe(\"with { defaultYes: false }\", () => {\n it(\"returns false in non-interactive terminals\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: false,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: false,\n configurable: true,\n });\n const result = await confirmLinkedValue(\"Deploy to prod?\", {\n defaultYes: false,\n });\n assert.strictEqual(result, false);\n });\n\n it(\"returns false when user presses Enter (empty input — default no)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"\");\n assert.strictEqual(\n await confirmLinkedValue(\"Deploy to prod?\", { defaultYes: false }),\n false\n );\n });\n\n it(\"returns true when user enters 'y'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"y\");\n assert.strictEqual(\n await confirmLinkedValue(\"Deploy to prod?\", { defaultYes: false }),\n true\n );\n });\n\n it(\"returns true when user enters 'yes'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"yes\");\n assert.strictEqual(\n await confirmLinkedValue(\"Deploy to prod?\", { defaultYes: false }),\n true\n );\n });\n\n it(\"returns false when input is unrecognized (falls back to default)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"foo\");\n assert.strictEqual(\n await confirmLinkedValue(\"Deploy to prod?\", { defaultYes: false }),\n false\n );\n });\n\n it(\"renders the prompt with [y/N] hint\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n let capturedPrompt = \"\";\n mock.method(readline, \"createInterface\", () => ({\n on: () => {},\n question: (prompt: string, callback: (a: string) => void) => {\n capturedPrompt = prompt;\n callback(\"\");\n },\n close: mock.fn(),\n }));\n await confirmLinkedValue(\"Deploy to prod?\", { defaultYes: false });\n assert.match(capturedPrompt, /\\[y\\/N\\]/);\n });\n });\n\n it(\"exits the process when SIGINT is emitted on the readline interface\", () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n\n const exitStub = mock.method(process, \"exit\", () => {\n throw new Error(\"process.exit called\");\n });\n\n let sigintEmitter: (() => void) | undefined;\n mock.method(readline, \"createInterface\", () => ({\n on: (event: string, handler: () => void) => {\n if (event === \"SIGINT\") sigintEmitter = handler;\n },\n question: () => {\n /* never resolves */\n },\n close: mock.fn(),\n }));\n\n // Start the prompt — it won't resolve (question callback never fires)\n void confirmLinkedValue(\"Use linked account 'foo'?\");\n\n // Emitting SIGINT calls process.exit(1) synchronously; our mock throws to intercept it\n assert.throws(() => sigintEmitter!(), /process\\.exit called/);\n assert.strictEqual(exitStub.mock.calls[0].arguments[0], 1);\n });\n});\n\ndescribe(\"USE_LINKED_DETAILS\", () => {\n let testDir: string;\n\n beforeEach(async () => {\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-use-linked-details-test-\"));\n });\n\n afterEach(async () => {\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"is exported and has the expected value\", () => {\n assert.strictEqual(USE_LINKED_DETAILS, \"useLinkedDetails\");\n });\n\n it(\"setting it to false on argv does not collide with the internal cache key\", async () => {\n // The useLinkedDetails key must not collide with the internal cache key so that\n // readLinkedConfig continues to work even when useLinkedDetails is false.\n const argv: { [key: string]: unknown } = {\n dir: testDir,\n [USE_LINKED_DETAILS]: false,\n };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {});\n });\n});\n\n/**\n * Helper: stub readline.createInterface so that the `question` callback is\n * called synchronously with `answer`, simulating user input.\n */\nfunction stubReadlineAnswer(answer: string) {\n mock.method(readline, \"createInterface\", () => ({\n on: () => {\n /* ignore SIGINT in these tests */\n },\n question: (_prompt: string, callback: (a: string) => void) => {\n callback(answer);\n },\n close: mock.fn(),\n }));\n}\n"]}
|