Skip to content

Commit 89e7d62

Browse files
authored
feat(targets): allow hyphens in target names (#2577)
1 parent 609ae00 commit 89e7d62

5 files changed

Lines changed: 49 additions & 17 deletions

File tree

‎src/handlers/project/add/gateway/index.test.ts‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { afterEach, describe, expect, test } from "bun:test";
2+
import { writeFile } from "node:fs/promises";
3+
import { join } from "node:path";
24
import { expectError } from "../../../../testing";
35
import { createGatewayProjectTestHarness } from "../gateway-test-support";
46
import { InputValidationError, ResourceNotFoundError } from "../../../../errors";
@@ -152,6 +154,21 @@ describe("project add gateway", () => {
152154
});
153155
});
154156

157+
test("keeps a hyphenated target as is in the hyphen-separated deployed name", async () => {
158+
const projectRoot = await inProject();
159+
await writeFile(
160+
join(projectRoot, "agentcore", "aws-targets.json"),
161+
JSON.stringify([{ name: "prod-us1", account: "111122223333", region: "us-east-1" }]),
162+
);
163+
const name = `g${"x".repeat(80)}`;
164+
165+
await expectError(
166+
run(["add", "gateway", "--name", name]),
167+
`Gateway deployed name 'TestProject-prod-us1-${name}' is 102 characters. The maximum is 100.`,
168+
InputValidationError,
169+
);
170+
});
171+
155172
test.each<
156173
[label: string, args: string[], message: string, errorType?: Parameters<typeof expectError>[2]]
157174
>([

‎src/handlers/project/add/policy-engine/index.test.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,19 @@ describe("project add policy-engine", () => {
7575
);
7676
});
7777

78+
test("writes a hyphenated target with underscores in the deployed name", async () => {
79+
const projectRoot = await inProject();
80+
await writeFile(
81+
join(projectRoot, "agentcore", "aws-targets.json"),
82+
JSON.stringify([{ name: "prod-us1", account: "111122223333", region: "us-east-1" }]),
83+
);
84+
const name = `E${"x".repeat(28)}`;
85+
86+
await expect(run(["add", "policy-engine", "--name", name])).rejects.toThrow(
87+
`Policy Engine deployed name 'TestProject_prod_us1_${name}' is 50 characters. The maximum is 48.`,
88+
);
89+
});
90+
7891
test.each([
7992
["defaults to enforce", [], "ENFORCE"],
8093
["honors --attach-mode log-only", ["--attach-mode", "log-only"], "LOG_ONLY"],

‎src/handlers/project/add/shared.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type AddProjectResourceResultOptions = {
3737
};
3838

3939
/**
40-
The L3 deploys `<project><sep><target><sep><name>` and fails at synth past the service cap. This fails at add time using the longest declared target, or "default" when none is declared yet.
40+
The L3 deploys `<project><sep><target><sep><name>` and fails at synth past the service cap. This fails at add time using the longest declared target, or "default" when none is declared yet. With the `_` separator the L3 writes the target's hyphens as underscores, which keeps the length.
4141
**/
4242
export function requireDeployedNameFits(
4343
kind: string,
@@ -50,7 +50,8 @@ export function requireDeployedNameFits(
5050
const longest = [DEFAULT_TARGET_NAME, ...targets.map((target) => target.name)].reduce((a, b) =>
5151
b.length > a.length ? b : a,
5252
);
53-
const deployed = [projectName, longest, name].join(separator);
53+
const target = separator === "_" ? longest.replaceAll("-", "_") : longest;
54+
const deployed = [projectName, target, name].join(separator);
5455
if (deployed.length <= maxLength) return;
5556
throw new InputValidationError(
5657
`${kind} deployed name '${deployed}' is ${deployed.length} characters. The maximum is ${maxLength}. The deployed name is <project>${separator}<target>${separator}<name>, checked with the longest declared target '${longest}'. Shorten the ${kind.toLowerCase()} name.`,

‎src/projectSchemas/aws-targets.test.ts‎

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,19 @@ describe("AWS deployment targets", () => {
2929
expect(AwsAccountIdSchema.safeParse(account).success).toBe(false);
3030
});
3131

32-
test.each([
33-
"",
34-
"1default",
35-
"-default",
36-
"_default",
37-
"has_underscore",
38-
"has-hyphen",
39-
"has spaces",
40-
"has.dots",
41-
])("rejects invalid target name %j", (name) => {
42-
expect(DeploymentTargetNameSchema.safeParse(name).success).toBe(false);
43-
});
32+
test.each(["", "1default", "-default", "_default", "has_underscore", "has spaces", "has.dots"])(
33+
"rejects invalid target name %j",
34+
(name) => {
35+
expect(DeploymentTargetNameSchema.safeParse(name).success).toBe(false);
36+
},
37+
);
38+
39+
test.each(["prod-us", "a-b-c", "us-east-1", "trailing-"])(
40+
"accepts hyphenated target name %j, as the v0 CLI did",
41+
(name) => {
42+
expect(DeploymentTargetNameSchema.safeParse(name).success).toBe(true);
43+
},
44+
);
4445

4546
test("enforces target name and description lengths", () => {
4647
expect(DeploymentTargetNameSchema.safeParse("a".repeat(64)).success).toBe(true);

‎src/projectSchemas/aws-targets.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ export const DeploymentTargetNameSchema = z
4242
.min(1)
4343
.max(64)
4444
/**
45-
Letters and digits only: the target is the middle segment of every deployed resource name, so a separator inside it would make two targets compose the same name.
45+
The v0 CLI's rule, so v0 targets such as `prod-us` keep working. The target is the middle segment of deployed resource names (`<project><sep><target><sep><name>`). Where the separator is `_` because the service disallows `-` (Runtime, Memory, Harness, ...), the CDK library writes the target's hyphens as underscores; `-` and `/` separated names (Gateway, ECR, Lambda, ...) and the `AgentCore-<project>-<target>` stack name keep them.
4646
**/
4747
.regex(
48-
/^[a-zA-Z][a-zA-Z0-9]*$/,
49-
"Name must start with a letter and contain only letters and digits",
48+
/^[a-zA-Z][a-zA-Z0-9-]*$/,
49+
"Name must start with a letter and contain only letters, digits, and hyphens",
5050
)
5151
.describe("Unique identifier for the deployment target");
5252

0 commit comments

Comments
 (0)