From e9e31d9e733711f9b6b2ac2c4b0e2138206e95f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Mar 2026 11:47:37 +0000 Subject: [PATCH 1/6] Initial plan From 372783f2050dabdbff31b2dbd3c0f3af77385a01 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Mar 2026 11:59:05 +0000 Subject: [PATCH 2/6] fix: warn about malformed #aw_* references in body text Add malformed-ref detection to replaceTemporaryIdReferences() so that body text containing #aw_ prefixed sequences that fail the valid temp ID format (3-8 alphanumeric chars) emit a core.warning() instead of silently passing through as literal text. Fixes # Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/temporary_id.cjs | 12 +++++++ actions/setup/js/temporary_id.test.cjs | 46 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/actions/setup/js/temporary_id.cjs b/actions/setup/js/temporary_id.cjs index 20c260b7fae..4301eaa1a87 100644 --- a/actions/setup/js/temporary_id.cjs +++ b/actions/setup/js/temporary_id.cjs @@ -80,6 +80,18 @@ function normalizeTemporaryId(tempId) { * @returns {string} Text with temporary IDs replaced with issue numbers */ function replaceTemporaryIdReferences(text, tempIdMap, currentRepo) { + // Detect and warn about malformed #aw_ references that won't be resolved + if (typeof core !== "undefined") { + const candidatePattern = /#aw_([A-Za-z0-9]+)/gi; + let candidate; + while ((candidate = candidatePattern.exec(text)) !== null) { + const tempId = `aw_${candidate[1]}`; + if (!isTemporaryId(tempId)) { + core.warning(`Malformed temporary ID reference '${candidate[0]}' found in body text. Temporary IDs must be in format '#aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9). Example: '#aw_abc' or '#aw_Test123'`); + } + } + } + return text.replace(TEMPORARY_ID_PATTERN, (match, tempId) => { const resolved = tempIdMap.get(normalizeTemporaryId(tempId)); if (resolved !== undefined) { diff --git a/actions/setup/js/temporary_id.test.cjs b/actions/setup/js/temporary_id.test.cjs index 7af37ce41db..632d086697c 100644 --- a/actions/setup/js/temporary_id.test.cjs +++ b/actions/setup/js/temporary_id.test.cjs @@ -123,6 +123,52 @@ describe("temporary_id.cjs", () => { const text = "Check #aw_ab and #temp:abc123 for details"; expect(replaceTemporaryIdReferences(text, map, "owner/repo")).toBe("Check #aw_ab and #temp:abc123 for details"); }); + + it("should warn about malformed temporary ID reference that is too short", async () => { + const { replaceTemporaryIdReferences } = await import("./temporary_id.cjs"); + const map = new Map(); + const text = "Check #aw_ab for details"; + const result = replaceTemporaryIdReferences(text, map, "owner/repo"); + expect(result).toBe("Check #aw_ab for details"); + expect(mockCore.warning).toHaveBeenCalledOnce(); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("#aw_ab")); + }); + + it("should warn about malformed temporary ID reference that is too long", async () => { + const { replaceTemporaryIdReferences } = await import("./temporary_id.cjs"); + const map = new Map(); + const text = "Check #aw_toolongname123 for details"; + const result = replaceTemporaryIdReferences(text, map, "owner/repo"); + expect(result).toBe("Check #aw_toolongname123 for details"); + expect(mockCore.warning).toHaveBeenCalledOnce(); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("#aw_toolongname123")); + }); + + it("should not warn for valid temporary ID references", async () => { + const { replaceTemporaryIdReferences } = await import("./temporary_id.cjs"); + const map = new Map([["aw_abc123", { repo: "owner/repo", number: 100 }]]); + const text = "Check #aw_abc123 for details"; + replaceTemporaryIdReferences(text, map, "owner/repo"); + expect(mockCore.warning).not.toHaveBeenCalled(); + }); + + it("should not warn for valid unresolved temporary ID references", async () => { + const { replaceTemporaryIdReferences } = await import("./temporary_id.cjs"); + const map = new Map(); + const text = "Check #aw_abc123 for details"; + replaceTemporaryIdReferences(text, map, "owner/repo"); + expect(mockCore.warning).not.toHaveBeenCalled(); + }); + + it("should warn once per malformed reference when multiple are present", async () => { + const { replaceTemporaryIdReferences } = await import("./temporary_id.cjs"); + const map = new Map(); + const text = "See #aw_ab and #aw_toolongname123 here"; + replaceTemporaryIdReferences(text, map, "owner/repo"); + expect(mockCore.warning).toHaveBeenCalledTimes(2); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("#aw_ab")); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("#aw_toolongname123")); + }); }); describe("replaceTemporaryIdReferencesLegacy", () => { From 8cfae30111863dea35ac2566eb30000097be755c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:16:04 +0000 Subject: [PATCH 3/6] fix: centralize candidate pattern, remove core guard, add word boundaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract TEMPORARY_ID_CANDIDATE_PATTERN as a module-level constant next to TEMPORARY_ID_PATTERN (with word boundary \b at end) - Remove typeof core guard — core is always defined via shim.cjs - Reset lastIndex before using the global regex in replaceTemporaryIdReferences Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/temporary_id.cjs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/actions/setup/js/temporary_id.cjs b/actions/setup/js/temporary_id.cjs index 4301eaa1a87..ed5ad9bfd35 100644 --- a/actions/setup/js/temporary_id.cjs +++ b/actions/setup/js/temporary_id.cjs @@ -29,6 +29,12 @@ const crypto = require("crypto"); */ const TEMPORARY_ID_PATTERN = /#(aw_[A-Za-z0-9]{3,8})/gi; +/** + * Regex pattern for detecting candidate #aw_ references (any length, word-boundary delimited) + * Used to identify malformed temporary ID references that don't match TEMPORARY_ID_PATTERN + */ +const TEMPORARY_ID_CANDIDATE_PATTERN = /#aw_([A-Za-z0-9]+)\b/gi; + /** * @typedef {Object} RepoIssuePair * @property {string} repo - Repository slug in "owner/repo" format @@ -81,14 +87,12 @@ function normalizeTemporaryId(tempId) { */ function replaceTemporaryIdReferences(text, tempIdMap, currentRepo) { // Detect and warn about malformed #aw_ references that won't be resolved - if (typeof core !== "undefined") { - const candidatePattern = /#aw_([A-Za-z0-9]+)/gi; - let candidate; - while ((candidate = candidatePattern.exec(text)) !== null) { - const tempId = `aw_${candidate[1]}`; - if (!isTemporaryId(tempId)) { - core.warning(`Malformed temporary ID reference '${candidate[0]}' found in body text. Temporary IDs must be in format '#aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9). Example: '#aw_abc' or '#aw_Test123'`); - } + let candidate; + TEMPORARY_ID_CANDIDATE_PATTERN.lastIndex = 0; + while ((candidate = TEMPORARY_ID_CANDIDATE_PATTERN.exec(text)) !== null) { + const tempId = `aw_${candidate[1]}`; + if (!isTemporaryId(tempId)) { + core.warning(`Malformed temporary ID reference '${candidate[0]}' found in body text. Temporary IDs must be in format '#aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9). Example: '#aw_abc' or '#aw_Test123'`); } } @@ -539,6 +543,7 @@ function getCreatedTemporaryId(message) { module.exports = { TEMPORARY_ID_PATTERN, + TEMPORARY_ID_CANDIDATE_PATTERN, generateTemporaryId, isTemporaryId, normalizeTemporaryId, From 89d3deb589a915c0b439f37bd9be9769d9049d77 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:39:08 +0000 Subject: [PATCH 4/6] fix: extend TEMPORARY_ID_PATTERN and isTemporaryId to 12 chars, add word boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TEMPORARY_ID_PATTERN: {3,8} → {3,12} and add \b word boundary - isTemporaryId(): /^aw_[A-Za-z0-9]{3,8}$/ → /^aw_[A-Za-z0-9]{3,12}$/ - Update JSDoc comments to reflect new 3-12 char range - Tests: 9-char IDs now valid; update "too long" cases to use 13+ chars Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/temporary_id.cjs | 8 ++++---- actions/setup/js/temporary_id.test.cjs | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/actions/setup/js/temporary_id.cjs b/actions/setup/js/temporary_id.cjs index ed5ad9bfd35..bc142bfbbd6 100644 --- a/actions/setup/js/temporary_id.cjs +++ b/actions/setup/js/temporary_id.cjs @@ -25,9 +25,9 @@ const crypto = require("crypto"); /** * Regex pattern for matching temporary ID references in text - * Format: #aw_XXX to #aw_XXXXXXXX (aw_ prefix + 3 to 8 alphanumeric characters) + * Format: #aw_XXX to #aw_XXXXXXXXXXXX (aw_ prefix + 3 to 12 alphanumeric characters) */ -const TEMPORARY_ID_PATTERN = /#(aw_[A-Za-z0-9]{3,8})/gi; +const TEMPORARY_ID_PATTERN = /#(aw_[A-Za-z0-9]{3,12})\b/gi; /** * Regex pattern for detecting candidate #aw_ references (any length, word-boundary delimited) @@ -57,13 +57,13 @@ function generateTemporaryId() { } /** - * Check if a value is a valid temporary ID (aw_ prefix + 3 to 8 alphanumeric characters) + * Check if a value is a valid temporary ID (aw_ prefix + 3 to 12 alphanumeric characters) * @param {any} value - The value to check * @returns {boolean} True if the value is a valid temporary ID */ function isTemporaryId(value) { if (typeof value === "string") { - return /^aw_[A-Za-z0-9]{3,8}$/i.test(value); + return /^aw_[A-Za-z0-9]{3,12}$/i.test(value); } return false; } diff --git a/actions/setup/js/temporary_id.test.cjs b/actions/setup/js/temporary_id.test.cjs index 632d086697c..c23031763af 100644 --- a/actions/setup/js/temporary_id.test.cjs +++ b/actions/setup/js/temporary_id.test.cjs @@ -38,7 +38,7 @@ describe("temporary_id.cjs", () => { }); describe("isTemporaryId", () => { - it("should return true for valid aw_ prefixed 3-8 char alphanumeric strings", async () => { + it("should return true for valid aw_ prefixed 3-12 char alphanumeric strings", async () => { const { isTemporaryId } = await import("./temporary_id.cjs"); expect(isTemporaryId("aw_abc")).toBe(true); expect(isTemporaryId("aw_abc1")).toBe(true); @@ -48,13 +48,15 @@ describe("temporary_id.cjs", () => { expect(isTemporaryId("aw_ABCD")).toBe(true); expect(isTemporaryId("aw_xyz9")).toBe(true); expect(isTemporaryId("aw_xyz")).toBe(true); + expect(isTemporaryId("aw_123456789")).toBe(true); // 9 chars - valid with extended limit + expect(isTemporaryId("aw_123456789abc")).toBe(true); // 12 chars - at the limit }); it("should return false for invalid strings", async () => { const { isTemporaryId } = await import("./temporary_id.cjs"); expect(isTemporaryId("abc123def456")).toBe(false); // Missing aw_ prefix expect(isTemporaryId("aw_ab")).toBe(false); // Too short (2 chars) - expect(isTemporaryId("aw_123456789")).toBe(false); // Too long (9 chars) + expect(isTemporaryId("aw_1234567890abc")).toBe(false); // Too long (13 chars) expect(isTemporaryId("aw_test-id")).toBe(false); // Contains hyphen expect(isTemporaryId("aw_id_123")).toBe(false); // Contains underscore expect(isTemporaryId("")).toBe(false); @@ -337,11 +339,11 @@ describe("temporary_id.cjs", () => { it("should return specific error for malformed temporary ID (too long)", async () => { const { resolveIssueNumber } = await import("./temporary_id.cjs"); const map = new Map(); - const result = resolveIssueNumber("aw_abc123456789", map); + const result = resolveIssueNumber("aw_abc1234567890", map); // 13 chars - too long expect(result.resolved).toBe(null); expect(result.wasTemporaryId).toBe(false); expect(result.errorMessage).toContain("Invalid temporary ID format"); - expect(result.errorMessage).toContain("aw_abc123456789"); + expect(result.errorMessage).toContain("aw_abc1234567890"); }); it("should handle temporary ID with # prefix", async () => { From 53bcf7638e9464bea96af1369e4b870db4acb072 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Mar 2026 12:55:34 +0000 Subject: [PATCH 5/6] fix: update all error messages and tests from 3-to-8 to 3-to-12 char limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update "3 to 8" → "3 to 12" in error messages across: temporary_id.cjs, create_issue.cjs, create_pull_request.cjs, safe_output_unified_handler_manager.cjs, update_project.cjs - Update test assertions in temporary_id.test.cjs and update_project.test.cjs - Use 13-char "aw_toolong123456" in update_project.test.cjs "too long" test case (previous "aw_toolong123" was 10 chars, now valid under 12-char limit) Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/create_issue.cjs | 2 +- actions/setup/js/create_pull_request.cjs | 4 ++-- actions/setup/js/safe_output_unified_handler_manager.cjs | 2 +- actions/setup/js/temporary_id.cjs | 8 ++++---- actions/setup/js/temporary_id.test.cjs | 2 +- actions/setup/js/update_project.cjs | 6 +++--- actions/setup/js/update_project.test.cjs | 6 +++--- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/actions/setup/js/create_issue.cjs b/actions/setup/js/create_issue.cjs index ffae1f4ec31..7efe70c1629 100644 --- a/actions/setup/js/create_issue.cjs +++ b/actions/setup/js/create_issue.cjs @@ -340,7 +340,7 @@ async function main(config = {}) { } else { // Check if it looks like a malformed temporary ID if (parentWithoutHash.startsWith("aw_")) { - core.warning(`Invalid temporary ID format for parent: '${message.parent}'. Temporary IDs must be in format 'aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_Test123'`); + core.warning(`Invalid temporary ID format for parent: '${message.parent}'. Temporary IDs must be in format 'aw_' followed by 3 to 12 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_Test123'`); } else { // It's a real issue number const parsed = parseInt(parentWithoutHash, 10); diff --git a/actions/setup/js/create_pull_request.cjs b/actions/setup/js/create_pull_request.cjs index 4ac8dc389c8..e17736c9112 100644 --- a/actions/setup/js/create_pull_request.cjs +++ b/actions/setup/js/create_pull_request.cjs @@ -211,11 +211,11 @@ async function main(config = {}) { if (!isTemporaryId(normalized)) { core.warning( - `Skipping create_pull_request: Invalid temporary_id format: '${pullRequestItem.temporary_id}'. Temporary IDs must be in format 'aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_Test123'` + `Skipping create_pull_request: Invalid temporary_id format: '${pullRequestItem.temporary_id}'. Temporary IDs must be in format 'aw_' followed by 3 to 12 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_Test123'` ); return { success: false, - error: `Invalid temporary_id format: '${pullRequestItem.temporary_id}'. Temporary IDs must be in format 'aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_Test123'`, + error: `Invalid temporary_id format: '${pullRequestItem.temporary_id}'. Temporary IDs must be in format 'aw_' followed by 3 to 12 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_Test123'`, }; } diff --git a/actions/setup/js/safe_output_unified_handler_manager.cjs b/actions/setup/js/safe_output_unified_handler_manager.cjs index 67992685397..ad42acbb01b 100644 --- a/actions/setup/js/safe_output_unified_handler_manager.cjs +++ b/actions/setup/js/safe_output_unified_handler_manager.cjs @@ -759,7 +759,7 @@ function normalizeAndValidateTemporaryId(message, messageType, messageIndex) { const withoutHash = trimmed.startsWith("#") ? trimmed.substring(1).trim() : trimmed; if (!isTemporaryId(withoutHash)) { - throw new Error(`${ERR_VALIDATION}: Message ${messageIndex + 1} (${messageType}): invalid temporary_id '${raw}'. Temporary IDs must be 'aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9), e.g. 'aw_abc' or 'aw_Test123'`); + throw new Error(`${ERR_VALIDATION}: Message ${messageIndex + 1} (${messageType}): invalid temporary_id '${raw}'. Temporary IDs must be 'aw_' followed by 3 to 12 alphanumeric characters (A-Za-z0-9), e.g. 'aw_abc' or 'aw_Test123'`); } // Normalize to the strict bare ID to keep lookups consistent. diff --git a/actions/setup/js/temporary_id.cjs b/actions/setup/js/temporary_id.cjs index bc142bfbbd6..7d1fc201a2c 100644 --- a/actions/setup/js/temporary_id.cjs +++ b/actions/setup/js/temporary_id.cjs @@ -92,7 +92,7 @@ function replaceTemporaryIdReferences(text, tempIdMap, currentRepo) { while ((candidate = TEMPORARY_ID_CANDIDATE_PATTERN.exec(text)) !== null) { const tempId = `aw_${candidate[1]}`; if (!isTemporaryId(tempId)) { - core.warning(`Malformed temporary ID reference '${candidate[0]}' found in body text. Temporary IDs must be in format '#aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9). Example: '#aw_abc' or '#aw_Test123'`); + core.warning(`Malformed temporary ID reference '${candidate[0]}' found in body text. Temporary IDs must be in format '#aw_' followed by 3 to 12 alphanumeric characters (A-Za-z0-9). Example: '#aw_abc' or '#aw_Test123'`); } } @@ -162,7 +162,7 @@ function getOrGenerateTemporaryId(message, entityType = "item") { if (!isTemporaryId(normalized)) { return { temporaryId: null, - error: `Invalid temporary_id format: '${message.temporary_id}'. Temporary IDs must be in format 'aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_Test123'`, + error: `Invalid temporary_id format: '${message.temporary_id}'. Temporary IDs must be in format 'aw_' followed by 3 to 12 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_Test123'`, }; } @@ -298,14 +298,14 @@ function resolveIssueNumber(value, temporaryIdMap) { return { resolved: null, wasTemporaryId: false, - errorMessage: `Invalid temporary ID format: '${valueStr}'. Temporary IDs must be in format 'aw_' followed by 3 to 8 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_abc12345'`, + errorMessage: `Invalid temporary ID format: '${valueStr}'. Temporary IDs must be in format 'aw_' followed by 3 to 12 alphanumeric characters (A-Za-z0-9). Example: 'aw_abc' or 'aw_abc12345'`, }; } // It's a real issue number - use context repo as default const issueNumber = typeof value === "number" ? value : parseInt(valueWithoutHash, 10); if (isNaN(issueNumber) || issueNumber <= 0) { - return { resolved: null, wasTemporaryId: false, errorMessage: `Invalid issue number: ${value}. Expected either a valid temporary ID (format: aw_ followed by 3-8 alphanumeric characters) or a numeric issue number.` }; + return { resolved: null, wasTemporaryId: false, errorMessage: `Invalid issue number: ${value}. Expected either a valid temporary ID (format: aw_ followed by 3-12 alphanumeric characters) or a numeric issue number.` }; } const contextRepo = typeof context !== "undefined" ? `${context.repo.owner}/${context.repo.repo}` : ""; diff --git a/actions/setup/js/temporary_id.test.cjs b/actions/setup/js/temporary_id.test.cjs index c23031763af..3e1c757ef04 100644 --- a/actions/setup/js/temporary_id.test.cjs +++ b/actions/setup/js/temporary_id.test.cjs @@ -323,7 +323,7 @@ describe("temporary_id.cjs", () => { expect(result.wasTemporaryId).toBe(false); expect(result.errorMessage).toContain("Invalid temporary ID format"); expect(result.errorMessage).toContain("aw_test-id"); - expect(result.errorMessage).toContain("3 to 8 alphanumeric characters"); + expect(result.errorMessage).toContain("3 to 12 alphanumeric characters"); }); it("should return specific error for malformed temporary ID (too short)", async () => { diff --git a/actions/setup/js/update_project.cjs b/actions/setup/js/update_project.cjs index b176d9e17f6..bd185e9704e 100644 --- a/actions/setup/js/update_project.cjs +++ b/actions/setup/js/update_project.cjs @@ -703,11 +703,11 @@ async function updateProject(output, temporaryIdMap = new Map(), githubClient = // Validate IDs used for draft chaining. // Draft issue chaining must use strict temporary IDs to match the unified handler manager. if (temporaryId && !isTemporaryId(temporaryId)) { - throw new Error(`${ERR_VALIDATION}: Invalid temporary_id format: "${temporaryId}". Expected format: aw_ followed by 3 to 8 alphanumeric characters (e.g., "aw_abc", "aw_Test123").`); + throw new Error(`${ERR_VALIDATION}: Invalid temporary_id format: "${temporaryId}". Expected format: aw_ followed by 3 to 12 alphanumeric characters (e.g., "aw_abc", "aw_Test123").`); } if (draftIssueId && !isTemporaryId(draftIssueId)) { - throw new Error(`${ERR_VALIDATION}: Invalid draft_issue_id format: "${draftIssueId}". Expected format: aw_ followed by 3 to 8 alphanumeric characters (e.g., "aw_abc", "aw_Test123").`); + throw new Error(`${ERR_VALIDATION}: Invalid draft_issue_id format: "${draftIssueId}". Expected format: aw_ followed by 3 to 12 alphanumeric characters (e.g., "aw_abc", "aw_Test123").`); } const draftTitle = typeof output.draft_title === "string" ? output.draft_title.trim() : ""; @@ -939,7 +939,7 @@ async function updateProject(output, temporaryIdMap = new Map(), githubClient = } else { // Not a temporary ID - validate as numeric if (!/^\d+$/.test(sanitizedContentNumber)) { - throw new Error(`${ERR_VALIDATION}: Invalid content number "${rawContentNumber}". Provide a positive integer or a valid temporary ID (format: aw_ followed by 3-8 alphanumeric characters).`); + throw new Error(`${ERR_VALIDATION}: Invalid content number "${rawContentNumber}". Provide a positive integer or a valid temporary ID (format: aw_ followed by 3-12 alphanumeric characters).`); } contentNumber = Number.parseInt(sanitizedContentNumber, 10); } diff --git a/actions/setup/js/update_project.test.cjs b/actions/setup/js/update_project.test.cjs index 52b071eda7c..db1bb9af467 100644 --- a/actions/setup/js/update_project.test.cjs +++ b/actions/setup/js/update_project.test.cjs @@ -884,12 +884,12 @@ describe("updateProject", () => { project: projectUrl, content_type: "draft_issue", draft_title: "Test Draft", - temporary_id: "aw_toolong123", + temporary_id: "aw_toolong123456", }; queueResponses([repoResponse(), viewerResponse(), orgProjectV2Response(projectUrl, 60, "project-draft")]); - await expect(updateProject(output)).rejects.toThrow(/Invalid temporary_id format.*aw_ followed by 3 to 8 alphanumeric characters/); + await expect(updateProject(output)).rejects.toThrow(/Invalid temporary_id format.*aw_ followed by 3 to 12 alphanumeric characters/); }); it("rejects malformed auto-generated draft_issue_id with aw_ prefix", async () => { @@ -904,7 +904,7 @@ describe("updateProject", () => { queueResponses([repoResponse(), viewerResponse(), orgProjectV2Response(projectUrl, 60, "project-draft")]); - await expect(updateProject(output, temporaryIdMap)).rejects.toThrow(/Invalid draft_issue_id format.*aw_ followed by 3 to 8 alphanumeric characters/); + await expect(updateProject(output, temporaryIdMap)).rejects.toThrow(/Invalid draft_issue_id format.*aw_ followed by 3 to 12 alphanumeric characters/); }); it("rejects draft_issue without title when creating (no draft_issue_id)", async () => { From b31a26bc40101f9b42c2350068e450a60492e0a2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Mar 2026 13:09:33 +0000 Subject: [PATCH 6/6] fix: use alphanumeric-only IDs in topological sort large graph test IDs like 'aw_lv1_0000000' contain underscores which are not matched by TEMPORARY_ID_PATTERN ([A-Za-z0-9]{3,12}), making the test unable to resolve dependencies. Replace underscore separators with 'n' to produce valid alphanumeric IDs: 'aw_lv1n0000000' and 'aw_lv2n0n0001'. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/safe_output_topological_sort.test.cjs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/actions/setup/js/safe_output_topological_sort.test.cjs b/actions/setup/js/safe_output_topological_sort.test.cjs index cd70013c762..adcf637b981 100644 --- a/actions/setup/js/safe_output_topological_sort.test.cjs +++ b/actions/setup/js/safe_output_topological_sort.test.cjs @@ -483,7 +483,7 @@ describe("safe_output_topological_sort.cjs", () => { messages.push({ type: "create_issue", temporary_id: rootId, title: "Root" }); for (let i = 0; i < 10; i++) { - const level1Id = `aw_lv1_${i.toString().padStart(7, "0")}`; + const level1Id = `aw_lv1n${i.toString().padStart(7, "0")}`; messages.push({ type: "create_issue", temporary_id: level1Id, @@ -491,7 +491,7 @@ describe("safe_output_topological_sort.cjs", () => { }); for (let j = 0; j < 5; j++) { - const level2Id = `aw_lv2_${i}_${j.toString().padStart(4, "0")}`; + const level2Id = `aw_lv2n${i}n${j.toString().padStart(4, "0")}`; messages.push({ type: "create_issue", temporary_id: level2Id, @@ -507,11 +507,11 @@ describe("safe_output_topological_sort.cjs", () => { // Verify each level-1 item comes before its level-2 children for (let i = 0; i < 10; i++) { - const level1Id = `aw_lv1_${i.toString().padStart(7, "0")}`; + const level1Id = `aw_lv1n${i.toString().padStart(7, "0")}`; const level1Index = sorted.findIndex(m => m.temporary_id === level1Id); for (let j = 0; j < 5; j++) { - const level2Id = `aw_lv2_${i}_${j.toString().padStart(4, "0")}`; + const level2Id = `aw_lv2n${i}n${j.toString().padStart(4, "0")}`; const level2Index = sorted.findIndex(m => m.temporary_id === level2Id); expect(level1Index).toBeLessThan(level2Index); } @@ -520,7 +520,7 @@ describe("safe_output_topological_sort.cjs", () => { // Verify root comes before all level-1 items const rootIndex = sorted.findIndex(m => m.temporary_id === rootId); for (let i = 0; i < 10; i++) { - const level1Id = `aw_lv1_${i.toString().padStart(7, "0")}`; + const level1Id = `aw_lv1n${i.toString().padStart(7, "0")}`; const level1Index = sorted.findIndex(m => m.temporary_id === level1Id); expect(rootIndex).toBeLessThan(level1Index); }