@geekmidas/cli 10.0.0-alpha.113 → 10.0.0-alpha.114

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.
@@ -97,6 +97,19 @@ function awsSecretsRegion(workspace) {
97
97
  return "";
98
98
  }
99
99
  /**
100
+ * The host a workflow logs in to for `deploy.registry`, as Docker reads an
101
+ * image name: the first part when it names a host (a dot, a port, or
102
+ * `localhost`), Docker Hub's `docker.io` for a bare namespace, and `''` when
103
+ * no registry is set. Read at run time, so a workflow follows the config
104
+ * rather than what it said when the workflow was written.
105
+ */
106
+ function registryHost(workspace) {
107
+ const registry = workspace.deploy?.registry?.trim();
108
+ if (!registry) return "";
109
+ const first = registry.split("/")[0];
110
+ return first.includes(".") || first.includes(":") || first === "localhost" ? first : "docker.io";
111
+ }
112
+ /**
100
113
  * Every output the stages action sets, each a string `fromJSON()` reads, for
101
114
  * one workflow run.
102
115
  */
@@ -111,7 +124,8 @@ function githubOutputs(workspace, input) {
111
124
  deploy: JSON.stringify(plan.deploy),
112
125
  "has-build": String(plan.build.length > 0),
113
126
  "has-deploy": String(plan.deploy.length > 0),
114
- "aws-region": awsSecretsRegion(workspace)
127
+ "aws-region": awsSecretsRegion(workspace),
128
+ registry: registryHost(workspace)
115
129
  };
116
130
  }
117
131
  /** `name=value` lines, as `$GITHUB_OUTPUT` takes single-line values. */
@@ -173,4 +187,4 @@ var GithubEventNotSet = class extends GkmError {
173
187
  //#endregion
174
188
  export { stagesCommand };
175
189
 
176
- //# sourceMappingURL=stages-DJrOYLZ-.mjs.map
190
+ //# sourceMappingURL=stages-Cb9rqRbN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stages-Cb9rqRbN.mjs","names":[],"sources":["../src/stages/plan.ts","../src/stages/index.ts"],"sourcesContent":["/**\n * Which stages a workflow run builds and deploys, from the event that started\n * it and the project's `stages`.\n *\n * The rules live here, in tested code, rather than in a workflow's YAML or in\n * the action that runs `gkm stages --github-output`: a project's deploy\n * workflow names no stage, and what it does for each event is decided by the\n * CLI the project installed.\n *\n * | event | build | deploy |\n * | ------------------- | ------------------ | ------------------------------- |\n * | `push` | every deployed | deployed, less the protected |\n * | `release` | none | the protected |\n * | `workflow_dispatch` | none | the one stage named |\n * | anything else | none | none |\n *\n * A push builds every deployed stage, protected ones included, so a release\n * deploys images built from the very commit its tag names; a release and a\n * manual run deploy what a push already built.\n */\n\nimport { GkmError } from '../errors';\nimport { UndeclaredStage } from '../workspace/stages.js';\nimport type { StagesConfig } from '../workspace/types.js';\n\nexport interface StagePlan {\n\t/** The stages whose images this run builds and pushes. */\n\tbuild: string[];\n\t/** The stages this run deploys. */\n\tdeploy: string[];\n}\n\nexport interface PlanInput {\n\t/** The GitHub event name: `push`, `release`, `workflow_dispatch`, … */\n\tevent: string;\n\t/** The stage a `workflow_dispatch` names. */\n\tstage?: string;\n}\n\nexport function planStages(stages: StagesConfig, input: PlanInput): StagePlan {\n\tconst kept = stages.protected ?? [];\n\n\tswitch (input.event) {\n\t\tcase 'push':\n\t\t\treturn {\n\t\t\t\tbuild: [...stages.deployed],\n\t\t\t\tdeploy: stages.deployed.filter((stage) => !kept.includes(stage)),\n\t\t\t};\n\t\tcase 'release':\n\t\t\treturn { build: [], deploy: [...kept] };\n\t\tcase 'workflow_dispatch': {\n\t\t\tconst stage = input.stage?.trim();\n\t\t\tif (!stage) throw new DispatchNamesNoStage(stages.deployed);\n\t\t\tif (!stages.deployed.includes(stage)) {\n\t\t\t\tthrow new UndeclaredStage(stage, stages.deployed);\n\t\t\t}\n\t\t\treturn { build: [], deploy: [stage] };\n\t\t}\n\t\tdefault:\n\t\t\treturn { build: [], deploy: [] };\n\t}\n}\n\n/**\n * A manual run with no stage. Refused rather than read as \"nothing to do\", so\n * a run started with the field left empty fails where it can be seen.\n */\nexport class DispatchNamesNoStage extends GkmError {\n\tconstructor(readonly deployed: readonly string[]) {\n\t\tsuper(\n\t\t\t`A manual run deploys one stage, and none was given. Run the workflow again with stage set to one of: ${deployed.join(', ') || 'nothing yet — gkm.config.ts deploys to no stage'}.`,\n\t\t);\n\t\tthis.name = 'DispatchNamesNoStage';\n\t}\n}\n","/**\n * `gkm stages` — the workspace's stages, as gkm.config.ts declares them.\n *\n * ```bash\n * gkm stages # a table\n * gkm stages --json # {\"local\":\"dev\",\"deployed\":[\"prod\"],\"protected\":[\"prod\"]}\n * gkm stages --github-output # a workflow run's build and deploy matrices\n * ```\n *\n * The config is read by the normal loader (and sandbox), so a workflow never\n * parses TypeScript to learn which stages exist. `--github-output` is what the\n * `geekmidas/toolbox/actions/stages` action runs: it writes the stages, and\n * which of them this run builds and deploys, to `$GITHUB_OUTPUT`.\n */\n\nimport { appendFile } from 'node:fs/promises';\nimport { loadWorkspaceSettings } from '../config.js';\nimport { GkmError } from '../errors';\nimport { s3SecretsLocation } from '../secrets/providers.js';\nimport type { NormalizedWorkspace, StagesConfig } from '../workspace/types.js';\nimport { planStages } from './plan.js';\n\nexport { DispatchNamesNoStage, type PlanInput, planStages } from './plan.js';\n\nexport interface StagesOptions {\n\t/** Print the stages as JSON. */\n\tjson?: boolean;\n\t/** Write the outputs a deploy workflow reads to `$GITHUB_OUTPUT`. */\n\tgithubOutput?: boolean;\n\t/** The event to plan for; defaults to `GITHUB_EVENT_NAME`. */\n\tevent?: string;\n\t/** The stage a `workflow_dispatch` names. */\n\tstage?: string;\n}\n\nexport interface StagesDeps {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\t/** Where lines go; stdout by default. */\n\tlog?: (line: string) => void;\n}\n\n/** The stages, as `gkm stages --json` prints them. */\nexport interface StagesJson {\n\tlocal: string;\n\tdeployed: string[];\n\tprotected: string[];\n}\n\nexport function stagesJson(stages: StagesConfig): StagesJson {\n\treturn {\n\t\tlocal: stages.local,\n\t\tdeployed: [...stages.deployed],\n\t\tprotected: [...(stages.protected ?? [])],\n\t};\n}\n\n/**\n * The region of the workspace's AWS secrets store — `s3`, `ssm` or\n * `secrets-manager` — or `''` when its deployed stages keep their secrets\n * anywhere else. A job assumes the stage's AWS role only when this is set.\n */\nexport function awsSecretsRegion(workspace: NormalizedWorkspace): string {\n\tconst store = workspace.secrets?.store;\n\tif (typeof store !== 'object' || store === null) return '';\n\tif (store.provider === 's3') {\n\t\treturn s3SecretsLocation(store, workspace.state).region;\n\t}\n\tif (store.provider === 'ssm' || store.provider === 'secrets-manager') {\n\t\treturn store.region;\n\t}\n\treturn '';\n}\n\n/**\n * The host a workflow logs in to for `deploy.registry`, as Docker reads an\n * image name: the first part when it names a host (a dot, a port, or\n * `localhost`), Docker Hub's `docker.io` for a bare namespace, and `''` when\n * no registry is set. Read at run time, so a workflow follows the config\n * rather than what it said when the workflow was written.\n */\nexport function registryHost(workspace: NormalizedWorkspace): string {\n\tconst registry = workspace.deploy?.registry?.trim();\n\tif (!registry) return '';\n\tconst first = registry.split('/')[0]!;\n\treturn first.includes('.') || first.includes(':') || first === 'localhost'\n\t\t? first\n\t\t: 'docker.io';\n}\n\n/**\n * Every output the stages action sets, each a string `fromJSON()` reads, for\n * one workflow run.\n */\nexport function githubOutputs(\n\tworkspace: NormalizedWorkspace,\n\tinput: { event: string; stage?: string },\n): Record<string, string> {\n\tconst stages = stagesJson(workspace.stages);\n\tconst plan = planStages(workspace.stages, input);\n\n\treturn {\n\t\tlocal: JSON.stringify(stages.local),\n\t\tdeployed: JSON.stringify(stages.deployed),\n\t\tprotected: JSON.stringify(stages.protected),\n\t\tbuild: JSON.stringify(plan.build),\n\t\tdeploy: JSON.stringify(plan.deploy),\n\t\t// A matrix over an empty list is an error on GitHub, so a job over one\n\t\t// is skipped on these instead.\n\t\t'has-build': String(plan.build.length > 0),\n\t\t'has-deploy': String(plan.deploy.length > 0),\n\t\t'aws-region': awsSecretsRegion(workspace),\n\t\tregistry: registryHost(workspace),\n\t};\n}\n\n/** `name=value` lines, as `$GITHUB_OUTPUT` takes single-line values. */\nexport function formatGithubOutputs(outputs: Record<string, string>): string {\n\treturn Object.entries(outputs)\n\t\t.map(([name, value]) => `${name}=${value}\\n`)\n\t\t.join('');\n}\n\n/** A message as a workflow command's data: GitHub reads `%`, CR and LF escaped. */\nfunction workflowCommandData(message: string): string {\n\treturn message\n\t\t.replaceAll('%', '%25')\n\t\t.replaceAll('\\r', '%0D')\n\t\t.replaceAll('\\n', '%0A');\n}\n\nfunction table(stages: StagesJson): string {\n\tconst rows: [string, string][] = [\n\t\t['STAGE', 'KIND'],\n\t\t[stages.local, 'local'],\n\t\t...stages.deployed.map((name): [string, string] => [\n\t\t\tname,\n\t\t\tstages.protected.includes(name) ? 'deployed, protected' : 'deployed',\n\t\t]),\n\t];\n\tconst width = Math.max(...rows.map(([name]) => name.length));\n\treturn rows\n\t\t.map(([name, kind]) => `${name.padEnd(width)} ${kind}`)\n\t\t.join('\\n');\n}\n\nexport async function stagesCommand(\n\toptions: StagesOptions,\n\tdeps: StagesDeps = {},\n): Promise<void> {\n\tconst env = deps.env ?? process.env;\n\tconst log = deps.log ?? ((line: string) => console.log(line));\n\n\tif (!options.githubOutput) {\n\t\tconst workspace = await loadWorkspaceSettings(deps.cwd);\n\t\tconst stages = stagesJson(workspace.stages);\n\t\tlog(options.json ? JSON.stringify(stages) : table(stages));\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst file = env.GITHUB_OUTPUT;\n\t\tif (!file) throw new GithubOutputNotSet();\n\n\t\tconst workspace = await loadWorkspaceSettings(deps.cwd);\n\t\tconst event = options.event || env.GITHUB_EVENT_NAME;\n\t\tif (!event) throw new GithubEventNotSet();\n\n\t\tconst outputs = githubOutputs(workspace, {\n\t\t\tevent,\n\t\t\t...(options.stage ? { stage: options.stage } : {}),\n\t\t});\n\t\tawait appendFile(file, formatGithubOutputs(outputs));\n\n\t\tlog(`${event}: build ${outputs.build}, deploy ${outputs.deploy}`);\n\t} catch (error) {\n\t\t// Annotated on the run, where whoever started it looks first.\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tlog(`::error title=gkm stages::${workflowCommandData(message)}`);\n\t\tthrow error;\n\t}\n}\n\n/** `--github-output` outside a GitHub Actions step, which sets the file. */\nexport class GithubOutputNotSet extends GkmError {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'gkm stages --github-output writes to the file GITHUB_OUTPUT names, and it is not set. Run it in a GitHub Actions step, or set GITHUB_OUTPUT to a file to write to.',\n\t\t);\n\t\tthis.name = 'GithubOutputNotSet';\n\t}\n}\n\n/** No `--event`, and no `GITHUB_EVENT_NAME` to take it from. */\nexport class GithubEventNotSet extends GkmError {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'gkm stages --github-output plans for an event, and none was given. Pass --event (push, release, workflow_dispatch), or run it in a GitHub Actions step, which sets GITHUB_EVENT_NAME.',\n\t\t);\n\t\tthis.name = 'GithubEventNotSet';\n\t}\n}\n"],"mappings":"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"}
@@ -97,6 +97,19 @@ function awsSecretsRegion(workspace) {
97
97
  return "";
98
98
  }
99
99
  /**
100
+ * The host a workflow logs in to for `deploy.registry`, as Docker reads an
101
+ * image name: the first part when it names a host (a dot, a port, or
102
+ * `localhost`), Docker Hub's `docker.io` for a bare namespace, and `''` when
103
+ * no registry is set. Read at run time, so a workflow follows the config
104
+ * rather than what it said when the workflow was written.
105
+ */
106
+ function registryHost(workspace) {
107
+ const registry = workspace.deploy?.registry?.trim();
108
+ if (!registry) return "";
109
+ const first = registry.split("/")[0];
110
+ return first.includes(".") || first.includes(":") || first === "localhost" ? first : "docker.io";
111
+ }
112
+ /**
100
113
  * Every output the stages action sets, each a string `fromJSON()` reads, for
101
114
  * one workflow run.
102
115
  */
@@ -111,7 +124,8 @@ function githubOutputs(workspace, input) {
111
124
  deploy: JSON.stringify(plan.deploy),
112
125
  "has-build": String(plan.build.length > 0),
113
126
  "has-deploy": String(plan.deploy.length > 0),
114
- "aws-region": awsSecretsRegion(workspace)
127
+ "aws-region": awsSecretsRegion(workspace),
128
+ registry: registryHost(workspace)
115
129
  };
116
130
  }
117
131
  /** `name=value` lines, as `$GITHUB_OUTPUT` takes single-line values. */
@@ -173,4 +187,4 @@ var GithubEventNotSet = class extends require_errors.GkmError {
173
187
  //#endregion
174
188
  exports.stagesCommand = stagesCommand;
175
189
 
176
- //# sourceMappingURL=stages-_3RVNG83.cjs.map
190
+ //# sourceMappingURL=stages-D4SnG5yl.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stages-D4SnG5yl.cjs","names":["UndeclaredStage","GkmError","s3SecretsLocation","loadWorkspaceSettings","appendFile","GkmError"],"sources":["../src/stages/plan.ts","../src/stages/index.ts"],"sourcesContent":["/**\n * Which stages a workflow run builds and deploys, from the event that started\n * it and the project's `stages`.\n *\n * The rules live here, in tested code, rather than in a workflow's YAML or in\n * the action that runs `gkm stages --github-output`: a project's deploy\n * workflow names no stage, and what it does for each event is decided by the\n * CLI the project installed.\n *\n * | event | build | deploy |\n * | ------------------- | ------------------ | ------------------------------- |\n * | `push` | every deployed | deployed, less the protected |\n * | `release` | none | the protected |\n * | `workflow_dispatch` | none | the one stage named |\n * | anything else | none | none |\n *\n * A push builds every deployed stage, protected ones included, so a release\n * deploys images built from the very commit its tag names; a release and a\n * manual run deploy what a push already built.\n */\n\nimport { GkmError } from '../errors';\nimport { UndeclaredStage } from '../workspace/stages.js';\nimport type { StagesConfig } from '../workspace/types.js';\n\nexport interface StagePlan {\n\t/** The stages whose images this run builds and pushes. */\n\tbuild: string[];\n\t/** The stages this run deploys. */\n\tdeploy: string[];\n}\n\nexport interface PlanInput {\n\t/** The GitHub event name: `push`, `release`, `workflow_dispatch`, … */\n\tevent: string;\n\t/** The stage a `workflow_dispatch` names. */\n\tstage?: string;\n}\n\nexport function planStages(stages: StagesConfig, input: PlanInput): StagePlan {\n\tconst kept = stages.protected ?? [];\n\n\tswitch (input.event) {\n\t\tcase 'push':\n\t\t\treturn {\n\t\t\t\tbuild: [...stages.deployed],\n\t\t\t\tdeploy: stages.deployed.filter((stage) => !kept.includes(stage)),\n\t\t\t};\n\t\tcase 'release':\n\t\t\treturn { build: [], deploy: [...kept] };\n\t\tcase 'workflow_dispatch': {\n\t\t\tconst stage = input.stage?.trim();\n\t\t\tif (!stage) throw new DispatchNamesNoStage(stages.deployed);\n\t\t\tif (!stages.deployed.includes(stage)) {\n\t\t\t\tthrow new UndeclaredStage(stage, stages.deployed);\n\t\t\t}\n\t\t\treturn { build: [], deploy: [stage] };\n\t\t}\n\t\tdefault:\n\t\t\treturn { build: [], deploy: [] };\n\t}\n}\n\n/**\n * A manual run with no stage. Refused rather than read as \"nothing to do\", so\n * a run started with the field left empty fails where it can be seen.\n */\nexport class DispatchNamesNoStage extends GkmError {\n\tconstructor(readonly deployed: readonly string[]) {\n\t\tsuper(\n\t\t\t`A manual run deploys one stage, and none was given. Run the workflow again with stage set to one of: ${deployed.join(', ') || 'nothing yet — gkm.config.ts deploys to no stage'}.`,\n\t\t);\n\t\tthis.name = 'DispatchNamesNoStage';\n\t}\n}\n","/**\n * `gkm stages` — the workspace's stages, as gkm.config.ts declares them.\n *\n * ```bash\n * gkm stages # a table\n * gkm stages --json # {\"local\":\"dev\",\"deployed\":[\"prod\"],\"protected\":[\"prod\"]}\n * gkm stages --github-output # a workflow run's build and deploy matrices\n * ```\n *\n * The config is read by the normal loader (and sandbox), so a workflow never\n * parses TypeScript to learn which stages exist. `--github-output` is what the\n * `geekmidas/toolbox/actions/stages` action runs: it writes the stages, and\n * which of them this run builds and deploys, to `$GITHUB_OUTPUT`.\n */\n\nimport { appendFile } from 'node:fs/promises';\nimport { loadWorkspaceSettings } from '../config.js';\nimport { GkmError } from '../errors';\nimport { s3SecretsLocation } from '../secrets/providers.js';\nimport type { NormalizedWorkspace, StagesConfig } from '../workspace/types.js';\nimport { planStages } from './plan.js';\n\nexport { DispatchNamesNoStage, type PlanInput, planStages } from './plan.js';\n\nexport interface StagesOptions {\n\t/** Print the stages as JSON. */\n\tjson?: boolean;\n\t/** Write the outputs a deploy workflow reads to `$GITHUB_OUTPUT`. */\n\tgithubOutput?: boolean;\n\t/** The event to plan for; defaults to `GITHUB_EVENT_NAME`. */\n\tevent?: string;\n\t/** The stage a `workflow_dispatch` names. */\n\tstage?: string;\n}\n\nexport interface StagesDeps {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\t/** Where lines go; stdout by default. */\n\tlog?: (line: string) => void;\n}\n\n/** The stages, as `gkm stages --json` prints them. */\nexport interface StagesJson {\n\tlocal: string;\n\tdeployed: string[];\n\tprotected: string[];\n}\n\nexport function stagesJson(stages: StagesConfig): StagesJson {\n\treturn {\n\t\tlocal: stages.local,\n\t\tdeployed: [...stages.deployed],\n\t\tprotected: [...(stages.protected ?? [])],\n\t};\n}\n\n/**\n * The region of the workspace's AWS secrets store — `s3`, `ssm` or\n * `secrets-manager` — or `''` when its deployed stages keep their secrets\n * anywhere else. A job assumes the stage's AWS role only when this is set.\n */\nexport function awsSecretsRegion(workspace: NormalizedWorkspace): string {\n\tconst store = workspace.secrets?.store;\n\tif (typeof store !== 'object' || store === null) return '';\n\tif (store.provider === 's3') {\n\t\treturn s3SecretsLocation(store, workspace.state).region;\n\t}\n\tif (store.provider === 'ssm' || store.provider === 'secrets-manager') {\n\t\treturn store.region;\n\t}\n\treturn '';\n}\n\n/**\n * The host a workflow logs in to for `deploy.registry`, as Docker reads an\n * image name: the first part when it names a host (a dot, a port, or\n * `localhost`), Docker Hub's `docker.io` for a bare namespace, and `''` when\n * no registry is set. Read at run time, so a workflow follows the config\n * rather than what it said when the workflow was written.\n */\nexport function registryHost(workspace: NormalizedWorkspace): string {\n\tconst registry = workspace.deploy?.registry?.trim();\n\tif (!registry) return '';\n\tconst first = registry.split('/')[0]!;\n\treturn first.includes('.') || first.includes(':') || first === 'localhost'\n\t\t? first\n\t\t: 'docker.io';\n}\n\n/**\n * Every output the stages action sets, each a string `fromJSON()` reads, for\n * one workflow run.\n */\nexport function githubOutputs(\n\tworkspace: NormalizedWorkspace,\n\tinput: { event: string; stage?: string },\n): Record<string, string> {\n\tconst stages = stagesJson(workspace.stages);\n\tconst plan = planStages(workspace.stages, input);\n\n\treturn {\n\t\tlocal: JSON.stringify(stages.local),\n\t\tdeployed: JSON.stringify(stages.deployed),\n\t\tprotected: JSON.stringify(stages.protected),\n\t\tbuild: JSON.stringify(plan.build),\n\t\tdeploy: JSON.stringify(plan.deploy),\n\t\t// A matrix over an empty list is an error on GitHub, so a job over one\n\t\t// is skipped on these instead.\n\t\t'has-build': String(plan.build.length > 0),\n\t\t'has-deploy': String(plan.deploy.length > 0),\n\t\t'aws-region': awsSecretsRegion(workspace),\n\t\tregistry: registryHost(workspace),\n\t};\n}\n\n/** `name=value` lines, as `$GITHUB_OUTPUT` takes single-line values. */\nexport function formatGithubOutputs(outputs: Record<string, string>): string {\n\treturn Object.entries(outputs)\n\t\t.map(([name, value]) => `${name}=${value}\\n`)\n\t\t.join('');\n}\n\n/** A message as a workflow command's data: GitHub reads `%`, CR and LF escaped. */\nfunction workflowCommandData(message: string): string {\n\treturn message\n\t\t.replaceAll('%', '%25')\n\t\t.replaceAll('\\r', '%0D')\n\t\t.replaceAll('\\n', '%0A');\n}\n\nfunction table(stages: StagesJson): string {\n\tconst rows: [string, string][] = [\n\t\t['STAGE', 'KIND'],\n\t\t[stages.local, 'local'],\n\t\t...stages.deployed.map((name): [string, string] => [\n\t\t\tname,\n\t\t\tstages.protected.includes(name) ? 'deployed, protected' : 'deployed',\n\t\t]),\n\t];\n\tconst width = Math.max(...rows.map(([name]) => name.length));\n\treturn rows\n\t\t.map(([name, kind]) => `${name.padEnd(width)} ${kind}`)\n\t\t.join('\\n');\n}\n\nexport async function stagesCommand(\n\toptions: StagesOptions,\n\tdeps: StagesDeps = {},\n): Promise<void> {\n\tconst env = deps.env ?? process.env;\n\tconst log = deps.log ?? ((line: string) => console.log(line));\n\n\tif (!options.githubOutput) {\n\t\tconst workspace = await loadWorkspaceSettings(deps.cwd);\n\t\tconst stages = stagesJson(workspace.stages);\n\t\tlog(options.json ? JSON.stringify(stages) : table(stages));\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst file = env.GITHUB_OUTPUT;\n\t\tif (!file) throw new GithubOutputNotSet();\n\n\t\tconst workspace = await loadWorkspaceSettings(deps.cwd);\n\t\tconst event = options.event || env.GITHUB_EVENT_NAME;\n\t\tif (!event) throw new GithubEventNotSet();\n\n\t\tconst outputs = githubOutputs(workspace, {\n\t\t\tevent,\n\t\t\t...(options.stage ? { stage: options.stage } : {}),\n\t\t});\n\t\tawait appendFile(file, formatGithubOutputs(outputs));\n\n\t\tlog(`${event}: build ${outputs.build}, deploy ${outputs.deploy}`);\n\t} catch (error) {\n\t\t// Annotated on the run, where whoever started it looks first.\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tlog(`::error title=gkm stages::${workflowCommandData(message)}`);\n\t\tthrow error;\n\t}\n}\n\n/** `--github-output` outside a GitHub Actions step, which sets the file. */\nexport class GithubOutputNotSet extends GkmError {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'gkm stages --github-output writes to the file GITHUB_OUTPUT names, and it is not set. Run it in a GitHub Actions step, or set GITHUB_OUTPUT to a file to write to.',\n\t\t);\n\t\tthis.name = 'GithubOutputNotSet';\n\t}\n}\n\n/** No `--event`, and no `GITHUB_EVENT_NAME` to take it from. */\nexport class GithubEventNotSet extends GkmError {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'gkm stages --github-output plans for an event, and none was given. Pass --event (push, release, workflow_dispatch), or run it in a GitHub Actions step, which sets GITHUB_EVENT_NAME.',\n\t\t);\n\t\tthis.name = 'GithubEventNotSet';\n\t}\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/cli",
3
- "version": "10.0.0-alpha.113",
3
+ "version": "10.0.0-alpha.114",
4
4
  "description": "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs",
5
5
  "private": false,
6
6
  "type": "module",
@@ -120,16 +120,16 @@
120
120
  "prompts": "~2.4.2",
121
121
  "tsx": "~4.23.15",
122
122
  "yaml": "~2.9.1",
123
- "@geekmidas/cache": "10.0.0-alpha.113",
124
- "@geekmidas/constructs": "~10.0.0-alpha.113",
125
- "@geekmidas/db": "10.0.0-alpha.113",
126
- "@geekmidas/envkit": "~10.0.0-alpha.113",
127
- "@geekmidas/errors": "~10.0.0-alpha.113",
128
- "@geekmidas/logger": "~10.0.0-alpha.113",
129
- "@geekmidas/manifest": "10.0.0-alpha.113",
130
- "@geekmidas/schema": "~10.0.0-alpha.113",
131
- "@geekmidas/services": "~10.0.0-alpha.113",
132
- "@geekmidas/storage": "~10.0.0-alpha.113"
123
+ "@geekmidas/cache": "10.0.0-alpha.114",
124
+ "@geekmidas/constructs": "~10.0.0-alpha.114",
125
+ "@geekmidas/db": "10.0.0-alpha.114",
126
+ "@geekmidas/envkit": "~10.0.0-alpha.114",
127
+ "@geekmidas/errors": "~10.0.0-alpha.114",
128
+ "@geekmidas/logger": "~10.0.0-alpha.114",
129
+ "@geekmidas/manifest": "10.0.0-alpha.114",
130
+ "@geekmidas/schema": "~10.0.0-alpha.114",
131
+ "@geekmidas/services": "~10.0.0-alpha.114",
132
+ "@geekmidas/storage": "~10.0.0-alpha.114"
133
133
  },
134
134
  "devDependencies": {
135
135
  "@hono/node-server": "~1.19.5",
@@ -144,12 +144,12 @@
144
144
  "typescript": "~7.0.2",
145
145
  "vitest": "~5.0.2",
146
146
  "zod": "~4.6.5",
147
- "@geekmidas/emailkit": "~10.0.0-alpha.113",
148
- "@geekmidas/events": "~10.0.0-alpha.113",
149
- "@geekmidas/testkit": "10.0.0-alpha.113"
147
+ "@geekmidas/emailkit": "~10.0.0-alpha.114",
148
+ "@geekmidas/events": "~10.0.0-alpha.114",
149
+ "@geekmidas/testkit": "10.0.0-alpha.114"
150
150
  },
151
151
  "peerDependencies": {
152
- "@geekmidas/telescope": "~10.0.0-alpha.113"
152
+ "@geekmidas/telescope": "~10.0.0-alpha.114"
153
153
  },
154
154
  "peerDependenciesMeta": {
155
155
  "@geekmidas/telescope": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"stages-DJrOYLZ-.mjs","names":[],"sources":["../src/stages/plan.ts","../src/stages/index.ts"],"sourcesContent":["/**\n * Which stages a workflow run builds and deploys, from the event that started\n * it and the project's `stages`.\n *\n * The rules live here, in tested code, rather than in a workflow's YAML or in\n * the action that runs `gkm stages --github-output`: a project's deploy\n * workflow names no stage, and what it does for each event is decided by the\n * CLI the project installed.\n *\n * | event | build | deploy |\n * | ------------------- | ------------------ | ------------------------------- |\n * | `push` | every deployed | deployed, less the protected |\n * | `release` | none | the protected |\n * | `workflow_dispatch` | none | the one stage named |\n * | anything else | none | none |\n *\n * A push builds every deployed stage, protected ones included, so a release\n * deploys images built from the very commit its tag names; a release and a\n * manual run deploy what a push already built.\n */\n\nimport { GkmError } from '../errors';\nimport { UndeclaredStage } from '../workspace/stages.js';\nimport type { StagesConfig } from '../workspace/types.js';\n\nexport interface StagePlan {\n\t/** The stages whose images this run builds and pushes. */\n\tbuild: string[];\n\t/** The stages this run deploys. */\n\tdeploy: string[];\n}\n\nexport interface PlanInput {\n\t/** The GitHub event name: `push`, `release`, `workflow_dispatch`, … */\n\tevent: string;\n\t/** The stage a `workflow_dispatch` names. */\n\tstage?: string;\n}\n\nexport function planStages(stages: StagesConfig, input: PlanInput): StagePlan {\n\tconst kept = stages.protected ?? [];\n\n\tswitch (input.event) {\n\t\tcase 'push':\n\t\t\treturn {\n\t\t\t\tbuild: [...stages.deployed],\n\t\t\t\tdeploy: stages.deployed.filter((stage) => !kept.includes(stage)),\n\t\t\t};\n\t\tcase 'release':\n\t\t\treturn { build: [], deploy: [...kept] };\n\t\tcase 'workflow_dispatch': {\n\t\t\tconst stage = input.stage?.trim();\n\t\t\tif (!stage) throw new DispatchNamesNoStage(stages.deployed);\n\t\t\tif (!stages.deployed.includes(stage)) {\n\t\t\t\tthrow new UndeclaredStage(stage, stages.deployed);\n\t\t\t}\n\t\t\treturn { build: [], deploy: [stage] };\n\t\t}\n\t\tdefault:\n\t\t\treturn { build: [], deploy: [] };\n\t}\n}\n\n/**\n * A manual run with no stage. Refused rather than read as \"nothing to do\", so\n * a run started with the field left empty fails where it can be seen.\n */\nexport class DispatchNamesNoStage extends GkmError {\n\tconstructor(readonly deployed: readonly string[]) {\n\t\tsuper(\n\t\t\t`A manual run deploys one stage, and none was given. Run the workflow again with stage set to one of: ${deployed.join(', ') || 'nothing yet — gkm.config.ts deploys to no stage'}.`,\n\t\t);\n\t\tthis.name = 'DispatchNamesNoStage';\n\t}\n}\n","/**\n * `gkm stages` — the workspace's stages, as gkm.config.ts declares them.\n *\n * ```bash\n * gkm stages # a table\n * gkm stages --json # {\"local\":\"dev\",\"deployed\":[\"prod\"],\"protected\":[\"prod\"]}\n * gkm stages --github-output # a workflow run's build and deploy matrices\n * ```\n *\n * The config is read by the normal loader (and sandbox), so a workflow never\n * parses TypeScript to learn which stages exist. `--github-output` is what the\n * `geekmidas/toolbox/actions/stages` action runs: it writes the stages, and\n * which of them this run builds and deploys, to `$GITHUB_OUTPUT`.\n */\n\nimport { appendFile } from 'node:fs/promises';\nimport { loadWorkspaceSettings } from '../config.js';\nimport { GkmError } from '../errors';\nimport { s3SecretsLocation } from '../secrets/providers.js';\nimport type { NormalizedWorkspace, StagesConfig } from '../workspace/types.js';\nimport { planStages } from './plan.js';\n\nexport { DispatchNamesNoStage, type PlanInput, planStages } from './plan.js';\n\nexport interface StagesOptions {\n\t/** Print the stages as JSON. */\n\tjson?: boolean;\n\t/** Write the outputs a deploy workflow reads to `$GITHUB_OUTPUT`. */\n\tgithubOutput?: boolean;\n\t/** The event to plan for; defaults to `GITHUB_EVENT_NAME`. */\n\tevent?: string;\n\t/** The stage a `workflow_dispatch` names. */\n\tstage?: string;\n}\n\nexport interface StagesDeps {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\t/** Where lines go; stdout by default. */\n\tlog?: (line: string) => void;\n}\n\n/** The stages, as `gkm stages --json` prints them. */\nexport interface StagesJson {\n\tlocal: string;\n\tdeployed: string[];\n\tprotected: string[];\n}\n\nexport function stagesJson(stages: StagesConfig): StagesJson {\n\treturn {\n\t\tlocal: stages.local,\n\t\tdeployed: [...stages.deployed],\n\t\tprotected: [...(stages.protected ?? [])],\n\t};\n}\n\n/**\n * The region of the workspace's AWS secrets store — `s3`, `ssm` or\n * `secrets-manager` — or `''` when its deployed stages keep their secrets\n * anywhere else. A job assumes the stage's AWS role only when this is set.\n */\nexport function awsSecretsRegion(workspace: NormalizedWorkspace): string {\n\tconst store = workspace.secrets?.store;\n\tif (typeof store !== 'object' || store === null) return '';\n\tif (store.provider === 's3') {\n\t\treturn s3SecretsLocation(store, workspace.state).region;\n\t}\n\tif (store.provider === 'ssm' || store.provider === 'secrets-manager') {\n\t\treturn store.region;\n\t}\n\treturn '';\n}\n\n/**\n * Every output the stages action sets, each a string `fromJSON()` reads, for\n * one workflow run.\n */\nexport function githubOutputs(\n\tworkspace: NormalizedWorkspace,\n\tinput: { event: string; stage?: string },\n): Record<string, string> {\n\tconst stages = stagesJson(workspace.stages);\n\tconst plan = planStages(workspace.stages, input);\n\n\treturn {\n\t\tlocal: JSON.stringify(stages.local),\n\t\tdeployed: JSON.stringify(stages.deployed),\n\t\tprotected: JSON.stringify(stages.protected),\n\t\tbuild: JSON.stringify(plan.build),\n\t\tdeploy: JSON.stringify(plan.deploy),\n\t\t// A matrix over an empty list is an error on GitHub, so a job over one\n\t\t// is skipped on these instead.\n\t\t'has-build': String(plan.build.length > 0),\n\t\t'has-deploy': String(plan.deploy.length > 0),\n\t\t'aws-region': awsSecretsRegion(workspace),\n\t};\n}\n\n/** `name=value` lines, as `$GITHUB_OUTPUT` takes single-line values. */\nexport function formatGithubOutputs(outputs: Record<string, string>): string {\n\treturn Object.entries(outputs)\n\t\t.map(([name, value]) => `${name}=${value}\\n`)\n\t\t.join('');\n}\n\n/** A message as a workflow command's data: GitHub reads `%`, CR and LF escaped. */\nfunction workflowCommandData(message: string): string {\n\treturn message\n\t\t.replaceAll('%', '%25')\n\t\t.replaceAll('\\r', '%0D')\n\t\t.replaceAll('\\n', '%0A');\n}\n\nfunction table(stages: StagesJson): string {\n\tconst rows: [string, string][] = [\n\t\t['STAGE', 'KIND'],\n\t\t[stages.local, 'local'],\n\t\t...stages.deployed.map((name): [string, string] => [\n\t\t\tname,\n\t\t\tstages.protected.includes(name) ? 'deployed, protected' : 'deployed',\n\t\t]),\n\t];\n\tconst width = Math.max(...rows.map(([name]) => name.length));\n\treturn rows\n\t\t.map(([name, kind]) => `${name.padEnd(width)} ${kind}`)\n\t\t.join('\\n');\n}\n\nexport async function stagesCommand(\n\toptions: StagesOptions,\n\tdeps: StagesDeps = {},\n): Promise<void> {\n\tconst env = deps.env ?? process.env;\n\tconst log = deps.log ?? ((line: string) => console.log(line));\n\n\tif (!options.githubOutput) {\n\t\tconst workspace = await loadWorkspaceSettings(deps.cwd);\n\t\tconst stages = stagesJson(workspace.stages);\n\t\tlog(options.json ? JSON.stringify(stages) : table(stages));\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst file = env.GITHUB_OUTPUT;\n\t\tif (!file) throw new GithubOutputNotSet();\n\n\t\tconst workspace = await loadWorkspaceSettings(deps.cwd);\n\t\tconst event = options.event || env.GITHUB_EVENT_NAME;\n\t\tif (!event) throw new GithubEventNotSet();\n\n\t\tconst outputs = githubOutputs(workspace, {\n\t\t\tevent,\n\t\t\t...(options.stage ? { stage: options.stage } : {}),\n\t\t});\n\t\tawait appendFile(file, formatGithubOutputs(outputs));\n\n\t\tlog(`${event}: build ${outputs.build}, deploy ${outputs.deploy}`);\n\t} catch (error) {\n\t\t// Annotated on the run, where whoever started it looks first.\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tlog(`::error title=gkm stages::${workflowCommandData(message)}`);\n\t\tthrow error;\n\t}\n}\n\n/** `--github-output` outside a GitHub Actions step, which sets the file. */\nexport class GithubOutputNotSet extends GkmError {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'gkm stages --github-output writes to the file GITHUB_OUTPUT names, and it is not set. Run it in a GitHub Actions step, or set GITHUB_OUTPUT to a file to write to.',\n\t\t);\n\t\tthis.name = 'GithubOutputNotSet';\n\t}\n}\n\n/** No `--event`, and no `GITHUB_EVENT_NAME` to take it from. */\nexport class GithubEventNotSet extends GkmError {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'gkm stages --github-output plans for an event, and none was given. Pass --event (push, release, workflow_dispatch), or run it in a GitHub Actions step, which sets GITHUB_EVENT_NAME.',\n\t\t);\n\t\tthis.name = 'GithubEventNotSet';\n\t}\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"stages-_3RVNG83.cjs","names":["UndeclaredStage","GkmError","s3SecretsLocation","loadWorkspaceSettings","appendFile","GkmError"],"sources":["../src/stages/plan.ts","../src/stages/index.ts"],"sourcesContent":["/**\n * Which stages a workflow run builds and deploys, from the event that started\n * it and the project's `stages`.\n *\n * The rules live here, in tested code, rather than in a workflow's YAML or in\n * the action that runs `gkm stages --github-output`: a project's deploy\n * workflow names no stage, and what it does for each event is decided by the\n * CLI the project installed.\n *\n * | event | build | deploy |\n * | ------------------- | ------------------ | ------------------------------- |\n * | `push` | every deployed | deployed, less the protected |\n * | `release` | none | the protected |\n * | `workflow_dispatch` | none | the one stage named |\n * | anything else | none | none |\n *\n * A push builds every deployed stage, protected ones included, so a release\n * deploys images built from the very commit its tag names; a release and a\n * manual run deploy what a push already built.\n */\n\nimport { GkmError } from '../errors';\nimport { UndeclaredStage } from '../workspace/stages.js';\nimport type { StagesConfig } from '../workspace/types.js';\n\nexport interface StagePlan {\n\t/** The stages whose images this run builds and pushes. */\n\tbuild: string[];\n\t/** The stages this run deploys. */\n\tdeploy: string[];\n}\n\nexport interface PlanInput {\n\t/** The GitHub event name: `push`, `release`, `workflow_dispatch`, … */\n\tevent: string;\n\t/** The stage a `workflow_dispatch` names. */\n\tstage?: string;\n}\n\nexport function planStages(stages: StagesConfig, input: PlanInput): StagePlan {\n\tconst kept = stages.protected ?? [];\n\n\tswitch (input.event) {\n\t\tcase 'push':\n\t\t\treturn {\n\t\t\t\tbuild: [...stages.deployed],\n\t\t\t\tdeploy: stages.deployed.filter((stage) => !kept.includes(stage)),\n\t\t\t};\n\t\tcase 'release':\n\t\t\treturn { build: [], deploy: [...kept] };\n\t\tcase 'workflow_dispatch': {\n\t\t\tconst stage = input.stage?.trim();\n\t\t\tif (!stage) throw new DispatchNamesNoStage(stages.deployed);\n\t\t\tif (!stages.deployed.includes(stage)) {\n\t\t\t\tthrow new UndeclaredStage(stage, stages.deployed);\n\t\t\t}\n\t\t\treturn { build: [], deploy: [stage] };\n\t\t}\n\t\tdefault:\n\t\t\treturn { build: [], deploy: [] };\n\t}\n}\n\n/**\n * A manual run with no stage. Refused rather than read as \"nothing to do\", so\n * a run started with the field left empty fails where it can be seen.\n */\nexport class DispatchNamesNoStage extends GkmError {\n\tconstructor(readonly deployed: readonly string[]) {\n\t\tsuper(\n\t\t\t`A manual run deploys one stage, and none was given. Run the workflow again with stage set to one of: ${deployed.join(', ') || 'nothing yet — gkm.config.ts deploys to no stage'}.`,\n\t\t);\n\t\tthis.name = 'DispatchNamesNoStage';\n\t}\n}\n","/**\n * `gkm stages` — the workspace's stages, as gkm.config.ts declares them.\n *\n * ```bash\n * gkm stages # a table\n * gkm stages --json # {\"local\":\"dev\",\"deployed\":[\"prod\"],\"protected\":[\"prod\"]}\n * gkm stages --github-output # a workflow run's build and deploy matrices\n * ```\n *\n * The config is read by the normal loader (and sandbox), so a workflow never\n * parses TypeScript to learn which stages exist. `--github-output` is what the\n * `geekmidas/toolbox/actions/stages` action runs: it writes the stages, and\n * which of them this run builds and deploys, to `$GITHUB_OUTPUT`.\n */\n\nimport { appendFile } from 'node:fs/promises';\nimport { loadWorkspaceSettings } from '../config.js';\nimport { GkmError } from '../errors';\nimport { s3SecretsLocation } from '../secrets/providers.js';\nimport type { NormalizedWorkspace, StagesConfig } from '../workspace/types.js';\nimport { planStages } from './plan.js';\n\nexport { DispatchNamesNoStage, type PlanInput, planStages } from './plan.js';\n\nexport interface StagesOptions {\n\t/** Print the stages as JSON. */\n\tjson?: boolean;\n\t/** Write the outputs a deploy workflow reads to `$GITHUB_OUTPUT`. */\n\tgithubOutput?: boolean;\n\t/** The event to plan for; defaults to `GITHUB_EVENT_NAME`. */\n\tevent?: string;\n\t/** The stage a `workflow_dispatch` names. */\n\tstage?: string;\n}\n\nexport interface StagesDeps {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\t/** Where lines go; stdout by default. */\n\tlog?: (line: string) => void;\n}\n\n/** The stages, as `gkm stages --json` prints them. */\nexport interface StagesJson {\n\tlocal: string;\n\tdeployed: string[];\n\tprotected: string[];\n}\n\nexport function stagesJson(stages: StagesConfig): StagesJson {\n\treturn {\n\t\tlocal: stages.local,\n\t\tdeployed: [...stages.deployed],\n\t\tprotected: [...(stages.protected ?? [])],\n\t};\n}\n\n/**\n * The region of the workspace's AWS secrets store — `s3`, `ssm` or\n * `secrets-manager` — or `''` when its deployed stages keep their secrets\n * anywhere else. A job assumes the stage's AWS role only when this is set.\n */\nexport function awsSecretsRegion(workspace: NormalizedWorkspace): string {\n\tconst store = workspace.secrets?.store;\n\tif (typeof store !== 'object' || store === null) return '';\n\tif (store.provider === 's3') {\n\t\treturn s3SecretsLocation(store, workspace.state).region;\n\t}\n\tif (store.provider === 'ssm' || store.provider === 'secrets-manager') {\n\t\treturn store.region;\n\t}\n\treturn '';\n}\n\n/**\n * Every output the stages action sets, each a string `fromJSON()` reads, for\n * one workflow run.\n */\nexport function githubOutputs(\n\tworkspace: NormalizedWorkspace,\n\tinput: { event: string; stage?: string },\n): Record<string, string> {\n\tconst stages = stagesJson(workspace.stages);\n\tconst plan = planStages(workspace.stages, input);\n\n\treturn {\n\t\tlocal: JSON.stringify(stages.local),\n\t\tdeployed: JSON.stringify(stages.deployed),\n\t\tprotected: JSON.stringify(stages.protected),\n\t\tbuild: JSON.stringify(plan.build),\n\t\tdeploy: JSON.stringify(plan.deploy),\n\t\t// A matrix over an empty list is an error on GitHub, so a job over one\n\t\t// is skipped on these instead.\n\t\t'has-build': String(plan.build.length > 0),\n\t\t'has-deploy': String(plan.deploy.length > 0),\n\t\t'aws-region': awsSecretsRegion(workspace),\n\t};\n}\n\n/** `name=value` lines, as `$GITHUB_OUTPUT` takes single-line values. */\nexport function formatGithubOutputs(outputs: Record<string, string>): string {\n\treturn Object.entries(outputs)\n\t\t.map(([name, value]) => `${name}=${value}\\n`)\n\t\t.join('');\n}\n\n/** A message as a workflow command's data: GitHub reads `%`, CR and LF escaped. */\nfunction workflowCommandData(message: string): string {\n\treturn message\n\t\t.replaceAll('%', '%25')\n\t\t.replaceAll('\\r', '%0D')\n\t\t.replaceAll('\\n', '%0A');\n}\n\nfunction table(stages: StagesJson): string {\n\tconst rows: [string, string][] = [\n\t\t['STAGE', 'KIND'],\n\t\t[stages.local, 'local'],\n\t\t...stages.deployed.map((name): [string, string] => [\n\t\t\tname,\n\t\t\tstages.protected.includes(name) ? 'deployed, protected' : 'deployed',\n\t\t]),\n\t];\n\tconst width = Math.max(...rows.map(([name]) => name.length));\n\treturn rows\n\t\t.map(([name, kind]) => `${name.padEnd(width)} ${kind}`)\n\t\t.join('\\n');\n}\n\nexport async function stagesCommand(\n\toptions: StagesOptions,\n\tdeps: StagesDeps = {},\n): Promise<void> {\n\tconst env = deps.env ?? process.env;\n\tconst log = deps.log ?? ((line: string) => console.log(line));\n\n\tif (!options.githubOutput) {\n\t\tconst workspace = await loadWorkspaceSettings(deps.cwd);\n\t\tconst stages = stagesJson(workspace.stages);\n\t\tlog(options.json ? JSON.stringify(stages) : table(stages));\n\t\treturn;\n\t}\n\n\ttry {\n\t\tconst file = env.GITHUB_OUTPUT;\n\t\tif (!file) throw new GithubOutputNotSet();\n\n\t\tconst workspace = await loadWorkspaceSettings(deps.cwd);\n\t\tconst event = options.event || env.GITHUB_EVENT_NAME;\n\t\tif (!event) throw new GithubEventNotSet();\n\n\t\tconst outputs = githubOutputs(workspace, {\n\t\t\tevent,\n\t\t\t...(options.stage ? { stage: options.stage } : {}),\n\t\t});\n\t\tawait appendFile(file, formatGithubOutputs(outputs));\n\n\t\tlog(`${event}: build ${outputs.build}, deploy ${outputs.deploy}`);\n\t} catch (error) {\n\t\t// Annotated on the run, where whoever started it looks first.\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tlog(`::error title=gkm stages::${workflowCommandData(message)}`);\n\t\tthrow error;\n\t}\n}\n\n/** `--github-output` outside a GitHub Actions step, which sets the file. */\nexport class GithubOutputNotSet extends GkmError {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'gkm stages --github-output writes to the file GITHUB_OUTPUT names, and it is not set. Run it in a GitHub Actions step, or set GITHUB_OUTPUT to a file to write to.',\n\t\t);\n\t\tthis.name = 'GithubOutputNotSet';\n\t}\n}\n\n/** No `--event`, and no `GITHUB_EVENT_NAME` to take it from. */\nexport class GithubEventNotSet extends GkmError {\n\tconstructor() {\n\t\tsuper(\n\t\t\t'gkm stages --github-output plans for an event, and none was given. Pass --event (push, release, workflow_dispatch), or run it in a GitHub Actions step, which sets GITHUB_EVENT_NAME.',\n\t\t);\n\t\tthis.name = 'GithubEventNotSet';\n\t}\n}\n"],"mappings":"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"}