diff --git a/src/commands/openclawcode.test.ts b/src/commands/openclawcode.test.ts index 618044fe3128..22674b391e3f 100644 --- a/src/commands/openclawcode.test.ts +++ b/src/commands/openclawcode.test.ts @@ -1306,6 +1306,50 @@ describe("openclawCodeRunCommand", () => { expect(payload.publishedPullRequestOpenedAt).toBe("2026-01-01T00:00:00.000Z"); }); + it("treats an empty published pull request url list as absent", async () => { + mocks.runIssueWorkflow.mockResolvedValue( + createRun({ + draftPullRequest: { + ...createRun().draftPullRequest!, + number: undefined, + url: [] as unknown as WorkflowRun["draftPullRequest"]["url"], + }, + }), + ); + + await openclawCodeRunCommand({ issue: "2", repoRoot: "/repo", json: true }, runtime); + + const payload = JSON.parse(runtime.log.mock.calls[0]?.[0] ?? "null"); + expect(payload.pullRequestPublished).toBe(false); + expect(payload.publishedPullRequestHasNumber).toBe(false); + expect(payload.publishedPullRequestHasUrl).toBe(false); + expect(payload.publishedPullRequestUrl).toEqual([]); + }); + + it("treats a populated published pull request url list as present", async () => { + mocks.runIssueWorkflow.mockResolvedValue( + createRun({ + draftPullRequest: { + ...createRun().draftPullRequest!, + number: undefined, + url: [ + "https://github.com/openclaw/openclaw/pull/42", + ] as unknown as WorkflowRun["draftPullRequest"]["url"], + }, + }), + ); + + await openclawCodeRunCommand({ issue: "2", repoRoot: "/repo", json: true }, runtime); + + const payload = JSON.parse(runtime.log.mock.calls[0]?.[0] ?? "null"); + expect(payload.pullRequestPublished).toBe(true); + expect(payload.publishedPullRequestHasNumber).toBe(false); + expect(payload.publishedPullRequestHasUrl).toBe(true); + expect(payload.publishedPullRequestUrl).toEqual([ + "https://github.com/openclaw/openclaw/pull/42", + ]); + }); + it("treats blank published pull request bodies as absent in convenience signals", async () => { mocks.runIssueWorkflow.mockResolvedValue( createRun({ diff --git a/src/commands/openclawcode.ts b/src/commands/openclawcode.ts index 70999dfed20a..42c4fd0ed55c 100644 --- a/src/commands/openclawcode.ts +++ b/src/commands/openclawcode.ts @@ -1494,14 +1494,20 @@ function resolvePublishedPullRequest(run: WorkflowRun): { publishedPullRequestUrl: string | null; publishedPullRequestOpenedAt: string | null; } { + const publishedPullRequestUrl = run.draftPullRequest?.url; + const publishedPullRequestHasUrl = + publishedPullRequestUrl === true || + (typeof publishedPullRequestUrl === "string" && publishedPullRequestUrl.length > 0) || + (Array.isArray(publishedPullRequestUrl) && publishedPullRequestUrl.length > 0); + // Workflow runs only persist one PR object. Once GitHub assigns a number or URL, // that same draft metadata becomes the published PR source of truth. - const published = run.draftPullRequest?.number != null || run.draftPullRequest?.url != null; + const published = run.draftPullRequest?.number != null || publishedPullRequestHasUrl; return { pullRequestPublished: published, publishedPullRequestNumber: published ? (run.draftPullRequest?.number ?? null) : null, publishedPullRequestHasNumber: published && run.draftPullRequest?.number != null, - publishedPullRequestHasUrl: published && run.draftPullRequest?.url != null, + publishedPullRequestHasUrl, publishedPullRequestHasOpenedAt: published && run.draftPullRequest?.openedAt != null, publishedPullRequestHasTitle: published && (run.draftPullRequest?.title?.trim().length ?? 0) > 0,