Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions actions/setup/js/create_pull_request.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2089,10 +2089,11 @@ ${patchPreview}`;
// Return success with PR details
return {
success: true,
pull_request_number: pullRequest.number,
pull_request_url: pullRequest.html_url,
number: pullRequest.number,
url: pullRequest.html_url,
managedBody: body,
branch_name: branchName,
temporary_id: temporaryId,
temporaryId: temporaryId,
repo: itemRepo,
};
} catch (prError) {
Expand Down
2 changes: 1 addition & 1 deletion actions/setup/js/create_pull_request.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -3048,7 +3048,7 @@ describe("create_pull_request - rate-limit retry", () => {
const result = await resultPromise;

expect(result.success).toBe(true);
expect(result.pull_request_number).toBe(42);
expect(result.number).toBe(42);
// 1 initial (rate-limited) + 1 retry (succeeds) = 2 calls total
expect(global.github.rest.pulls.create).toHaveBeenCalledTimes(2);
expect(global.core.warning).toHaveBeenCalledWith(expect.stringContaining("create pull request"));
Expand Down
30 changes: 30 additions & 0 deletions actions/setup/js/safe_output_handler_manager.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,8 @@ function getContentToCheck(messageType, message, result) {
return message.body || "";
case "comment_memory":
return result?.managedBody || message.body || "";
case "create_pull_request":
return result?.managedBody || message.body || "";
default:
return null;
}
Expand Down Expand Up @@ -1061,6 +1063,30 @@ async function updateIssueBody(github, context, repo, issueNumber, updatedBody,
core.info(`✓ Updated issue ${repo}#${issueNumber}`);
}

/**
* Update the body of a pull request with resolved temporary IDs
* @param {any} github - GitHub API client
* @param {any} context - GitHub Actions context
* @param {string} repo - Repository in "owner/repo" format
* @param {number} prNumber - Pull request number to update
* @param {string} updatedBody - Updated body content with resolved temp IDs
* @returns {Promise<void>}
*/
async function updatePullRequestBody(github, context, repo, prNumber, updatedBody, allowedMentionAliases = []) {
const [owner, repoName] = repo.split("/");

core.info(`Updating pull request ${repo}#${prNumber} body with resolved temporary IDs`);

await github.rest.pulls.update({
owner,
repo: repoName,
pull_number: prNumber,
body: sanitizeContent(updatedBody, { allowedAliases: allowedMentionAliases }),
});

core.info(`✓ Updated pull request ${repo}#${prNumber}`);
}

/**
* Update the body of a discussion with resolved temporary IDs
* @param {any} github - GitHub API client
Expand Down Expand Up @@ -1228,6 +1254,10 @@ async function processSyntheticUpdates(github, context, trackedOutputs, temporar
core.debug(`Skipping synthetic update for comment_memory - comment ID not tracked`);
}
break;
case "create_pull_request":
await updatePullRequestBody(github, context, tracked.result.repo, tracked.result.number, updatedContent, allowedMentionAliases);
updateCount++;
break;
default:
core.debug(`Unknown output type: ${tracked.type}`);
}
Expand Down
96 changes: 94 additions & 2 deletions actions/setup/js/safe_output_handler_manager.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,98 @@ describe("Safe Output Handler Manager", () => {
expect(parentTracked.type).toBe("create_issue");
});

it("should register temporary ID from create_pull_request result", async () => {
const messages = [{ type: "create_pull_request", temporary_id: "aw_pr1", title: "My PR", body: "PR body" }];

const prHandler = vi.fn().mockResolvedValue({
success: true,
number: 42,
url: "https://github.com/owner/repo/pull/42",
temporaryId: "aw_pr1",
repo: "owner/repo",
});

const handlers = new Map([["create_pull_request", prHandler]]);

const result = await processMessages(handlers, messages);

expect(result.success).toBe(true);
expect(result.temporaryIdMap["aw_pr1"]).toBeDefined();
expect(result.temporaryIdMap["aw_pr1"].number).toBe(42);
expect(result.temporaryIdMap["aw_pr1"].repo).toBe("owner/repo");
});

it("should resolve #aw_prN in later messages after create_pull_request registers its temp ID", async () => {
const messages = [
{ type: "create_pull_request", temporary_id: "aw_pr1", title: "My PR", body: "PR body" },
{ type: "create_issue", title: "Summary", body: "See #aw_pr1 for the changes" },
];

const prHandler = vi.fn().mockResolvedValue({
success: true,
number: 42,
url: "https://github.com/owner/repo/pull/42",
temporaryId: "aw_pr1",
repo: "owner/repo",
});

let capturedResolvedIds;
const issueHandler = vi.fn().mockImplementation((message, resolvedTemporaryIds) => {
capturedResolvedIds = resolvedTemporaryIds;
return Promise.resolve({ success: true, number: 100, repo: "owner/repo", temporaryId: undefined });
});

const handlers = new Map([
["create_pull_request", prHandler],
["create_issue", issueHandler],
]);

const result = await processMessages(handlers, messages);

expect(result.success).toBe(true);
// aw_pr1 should be in the resolvedTemporaryIds snapshot passed to the second handler
expect(capturedResolvedIds).toBeDefined();
expect(capturedResolvedIds["aw_pr1"]).toBeDefined();
expect(capturedResolvedIds["aw_pr1"].number).toBe(42);
});

it("should track create_pull_request with forward temp ID refs for synthetic update", async () => {
const messages = [
{ type: "create_pull_request", temporary_id: "aw_pr1", title: "My PR", body: "Closes #aw_issue1" },
{ type: "create_issue", temporary_id: "aw_issue1", title: "Issue", body: "Issue body" },
];

const prHandler = vi.fn().mockResolvedValue({
success: true,
number: 10,
url: "https://github.com/owner/repo/pull/10",
managedBody: "Managed: Closes #aw_issue1\n\n<!-- footer -->",
temporaryId: "aw_pr1",
repo: "owner/repo",
});

const issueHandler = vi.fn().mockResolvedValue({
success: true,
number: 99,
repo: "owner/repo",
temporaryId: "aw_issue1",
});

const handlers = new Map([
["create_pull_request", prHandler],
["create_issue", issueHandler],
]);

const result = await processMessages(handlers, messages);

expect(result.success).toBe(true);
// PR was created with an unresolved forward ref (#aw_issue1 not yet registered)
expect(result.outputsWithUnresolvedIds.length).toBeGreaterThan(0);
const trackedPR = result.outputsWithUnresolvedIds.find(o => o.type === "create_pull_request");
expect(trackedPR).toBeDefined();
expect(trackedPR.result.number).toBe(10);
});

it("should collect missing_tool and missing_data messages and include in result", async () => {
const messages = [
{
Expand Down Expand Up @@ -1497,8 +1589,8 @@ describe("Safe Output Handler Manager", () => {

const prHandler = vi.fn().mockResolvedValue({
success: true,
pull_request_number: 5,
pull_request_url: "https://github.com/owner/repo/pull/5",
number: 5,
url: "https://github.com/owner/repo/pull/5",
repo: "owner/repo",
});
const commentHandler = vi.fn().mockResolvedValue([{ _tracking: null }]);
Expand Down
12 changes: 6 additions & 6 deletions actions/setup/js/safe_outputs_action_outputs.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ function emitSafeOutputActionOutputs(processingResult) {
const firstPRResult = successfulResults.find(r => r.type === "create_pull_request");
if (firstPRResult?.result && !Array.isArray(firstPRResult.result)) {
const r = firstPRResult.result;
if (r.pull_request_number != null) {
core.setOutput("created_pr_number", String(r.pull_request_number));
core.info(`Exported created_pr_number: ${r.pull_request_number}`);
if (r.number != null) {
core.setOutput("created_pr_number", String(r.number));
core.info(`Exported created_pr_number: ${r.number}`);
}
if (r.pull_request_url) {
core.setOutput("created_pr_url", r.pull_request_url);
core.info(`Exported created_pr_url: ${r.pull_request_url}`);
if (r.url) {
core.setOutput("created_pr_url", r.url);
core.info(`Exported created_pr_url: ${r.url}`);
}
}

Expand Down
2 changes: 1 addition & 1 deletion actions/setup/js/safe_outputs_action_outputs.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe("emitSafeOutputActionOutputs", () => {

it("emits created_pr_number and created_pr_url for create_pull_request result", () => {
emitSafeOutputActionOutputs({
results: [{ success: true, type: "create_pull_request", result: { pull_request_number: 7, pull_request_url: "https://github.com/owner/repo/pull/7" } }],
results: [{ success: true, type: "create_pull_request", result: { number: 7, url: "https://github.com/owner/repo/pull/7" } }],
});

expect(outputs["created_pr_number"]).toBe("7");
Expand Down
Loading