diff --git a/actions/setup/js/close_older_adapter.cjs b/actions/setup/js/close_older_adapter.cjs
new file mode 100644
index 00000000000..02ec09d433a
--- /dev/null
+++ b/actions/setup/js/close_older_adapter.cjs
@@ -0,0 +1,52 @@
+// @ts-check
+///
+
+const { closeOlderEntities } = require("./close_older_entities.cjs");
+
+/**
+ * Close older issues/PRs using shared adapter wiring.
+ * @param {object} params
+ * @param {any} params.github
+ * @param {string} params.owner
+ * @param {string} params.repo
+ * @param {string} params.workflowId
+ * @param {{number: number, html_url: string}} params.newEntity
+ * @param {string} params.workflowName
+ * @param {string} params.runUrl
+ * @param {string | undefined} params.callerWorkflowId
+ * @param {string | undefined} params.closeOlderKey
+ * @param {string} params.entityType
+ * @param {string} params.entityTypePlural
+ * @param {(github: any, owner: string, repo: string, workflowId: string, excludeNumber: number, callerWorkflowId?: string, closeOlderKey?: string) => Promise>} params.searchOlderEntities
+ * @param {(params: any) => string} params.getCloseMessage
+ * @param {(github: any, owner: string, repo: string, entityId: number, message: string) => Promise} params.addComment
+ * @param {(github: any, owner: string, repo: string, entityId: number) => Promise} params.closeEntity
+ * @param {number} params.delayMs
+ * @param {(params: {newEntityUrl: string, newEntityNumber: number, workflowName: string, runUrl: string}) => any} params.messageParams
+ * @returns {Promise>}
+ */
+async function closeOlderWithAdapter(params) {
+ const result = await closeOlderEntities(params.github, params.owner, params.repo, params.workflowId, params.newEntity, params.workflowName, params.runUrl, {
+ entityType: params.entityType,
+ entityTypePlural: params.entityTypePlural,
+ // Use a closure so callerWorkflowId and closeOlderKey are forwarded to searchOlderEntities
+ // without going through the closeOlderEntities extraArgs mechanism (which appends
+ // excludeNumber last)
+ searchOlderEntities: (gh, o, r, wid, excludeNumber) => params.searchOlderEntities(gh, o, r, wid, excludeNumber, params.callerWorkflowId, params.closeOlderKey),
+ getCloseMessage: closeParams => params.getCloseMessage(params.messageParams(closeParams)),
+ addComment: params.addComment,
+ closeEntity: params.closeEntity,
+ delayMs: params.delayMs,
+ getEntityId: entity => entity.number,
+ getEntityUrl: entity => entity.html_url,
+ });
+
+ return result.map(item => ({
+ number: item.number,
+ html_url: item.html_url || "",
+ }));
+}
+
+module.exports = {
+ closeOlderWithAdapter,
+};
diff --git a/actions/setup/js/close_older_adapter.test.cjs b/actions/setup/js/close_older_adapter.test.cjs
new file mode 100644
index 00000000000..23f1dde99b7
--- /dev/null
+++ b/actions/setup/js/close_older_adapter.test.cjs
@@ -0,0 +1,107 @@
+// @ts-check
+
+import { describe, it, expect, beforeEach, vi } from "vitest";
+import { closeOlderWithAdapter } from "./close_older_adapter.cjs";
+
+describe("close_older_adapter", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ global.core = {
+ info: vi.fn(),
+ warning: vi.fn(),
+ error: vi.fn(),
+ };
+ });
+
+ it("forwards callerWorkflowId and closeOlderKey to searchOlderEntities", async () => {
+ const github = {};
+ const searchOlderEntities = vi.fn().mockResolvedValue([
+ {
+ number: 12,
+ title: "Older issue",
+ html_url: "https://example/12",
+ },
+ ]);
+ const getCloseMessage = vi.fn().mockReturnValue("close message");
+ const addComment = vi.fn().mockResolvedValue({ id: 1 });
+ const closeEntity = vi.fn().mockResolvedValue({ number: 12, html_url: "https://example/12" });
+
+ const result = await closeOlderWithAdapter({
+ github,
+ owner: "owner",
+ repo: "repo",
+ workflowId: "workflow",
+ newEntity: { number: 55, html_url: "https://example/new" },
+ workflowName: "Workflow",
+ runUrl: "https://example/run",
+ callerWorkflowId: "caller-id",
+ closeOlderKey: "close-key",
+ entityType: "issue",
+ entityTypePlural: "issues",
+ searchOlderEntities,
+ getCloseMessage,
+ addComment,
+ closeEntity,
+ delayMs: 1,
+ messageParams: params => ({ transformedEntityUrl: params.newEntityUrl, transformedEntityNumber: params.newEntityNumber }),
+ });
+
+ expect(searchOlderEntities).toHaveBeenCalledWith(github, "owner", "repo", "workflow", 55, "caller-id", "close-key");
+ expect(result).toEqual([{ number: 12, html_url: "https://example/12" }]);
+ });
+
+ it("applies messageParams transformation before getCloseMessage", async () => {
+ const github = {};
+ const getCloseMessage = vi.fn().mockReturnValue("close message");
+ const addComment = vi.fn().mockResolvedValue({ id: 1 });
+ const closeEntity = vi.fn().mockResolvedValue({ number: 12, html_url: "https://example/12" });
+
+ await closeOlderWithAdapter({
+ github,
+ owner: "owner",
+ repo: "repo",
+ workflowId: "workflow",
+ newEntity: { number: 55, html_url: "https://example/new" },
+ workflowName: "Workflow",
+ runUrl: "https://example/run",
+ callerWorkflowId: "caller-id",
+ closeOlderKey: "close-key",
+ entityType: "issue",
+ entityTypePlural: "issues",
+ searchOlderEntities: vi.fn().mockResolvedValue([{ number: 12, title: "Older issue", html_url: "https://example/12" }]),
+ getCloseMessage,
+ addComment,
+ closeEntity,
+ delayMs: 1,
+ messageParams: params => ({ transformedEntityUrl: params.newEntityUrl, transformedEntityNumber: params.newEntityNumber }),
+ });
+
+ expect(getCloseMessage).toHaveBeenCalledWith({ transformedEntityUrl: "https://example/new", transformedEntityNumber: 55 });
+ expect(addComment).toHaveBeenCalledWith(github, "owner", "repo", 12, "close message");
+ expect(closeEntity).toHaveBeenCalledWith(github, "owner", "repo", 12);
+ });
+
+ it("normalizes missing html_url in mapped result", async () => {
+ const result = await closeOlderWithAdapter({
+ github: {},
+ owner: "owner",
+ repo: "repo",
+ workflowId: "workflow",
+ newEntity: { number: 10, html_url: "https://example/new" },
+ workflowName: "Workflow",
+ runUrl: "https://example/run",
+ callerWorkflowId: undefined,
+ closeOlderKey: undefined,
+ entityType: "issue",
+ entityTypePlural: "issues",
+ searchOlderEntities: vi.fn().mockResolvedValue([{ number: 22, title: "Older issue" }]),
+ getCloseMessage: vi.fn().mockReturnValue("close message"),
+ addComment: vi.fn().mockResolvedValue({ id: 1 }),
+ closeEntity: vi.fn().mockResolvedValue({ number: 22 }),
+ delayMs: 1,
+ messageParams: params => params,
+ });
+
+ expect(result).toEqual([{ number: 22, html_url: "" }]);
+ });
+});
diff --git a/actions/setup/js/close_older_issues.cjs b/actions/setup/js/close_older_issues.cjs
index e7b51be8d98..957262f70ea 100644
--- a/actions/setup/js/close_older_issues.cjs
+++ b/actions/setup/js/close_older_issues.cjs
@@ -2,7 +2,8 @@
///
const { sanitizeContent } = require("./sanitize_content.cjs");
-const { closeOlderEntities, MAX_CLOSE_COUNT: SHARED_MAX_CLOSE_COUNT } = require("./close_older_entities.cjs");
+const { MAX_CLOSE_COUNT: SHARED_MAX_CLOSE_COUNT } = require("./close_older_entities.cjs");
+const { closeOlderWithAdapter } = require("./close_older_adapter.cjs");
const { buildMarkerSearchQuery, filterByMarker, logFilterSummary } = require("./close_older_search_helpers.cjs");
/**
@@ -186,32 +187,30 @@ function getCloseOlderIssueMessage({ newIssueUrl, newIssueNumber, workflowName,
* @returns {Promise>} List of closed issues
*/
async function closeOlderIssues(github, owner, repo, workflowId, newIssue, workflowName, runUrl, callerWorkflowId, closeOlderKey) {
- const result = await closeOlderEntities(github, owner, repo, workflowId, newIssue, workflowName, runUrl, {
+ return closeOlderWithAdapter({
+ github,
+ owner,
+ repo,
+ workflowId,
+ newEntity: newIssue,
+ workflowName,
+ runUrl,
+ callerWorkflowId,
+ closeOlderKey,
entityType: "issue",
entityTypePlural: "issues",
- // Use a closure so callerWorkflowId and closeOlderKey are forwarded to searchOlderIssues
- // without going through the closeOlderEntities extraArgs mechanism (which appends
- // excludeNumber last)
- searchOlderEntities: (gh, o, r, wid, excludeNumber) => searchOlderIssues(gh, o, r, wid, excludeNumber, callerWorkflowId, closeOlderKey),
- getCloseMessage: params =>
- getCloseOlderIssueMessage({
- newIssueUrl: params.newEntityUrl,
- newIssueNumber: params.newEntityNumber,
- workflowName: params.workflowName,
- runUrl: params.runUrl,
- }),
+ searchOlderEntities: searchOlderIssues,
+ getCloseMessage: getCloseOlderIssueMessage,
+ messageParams: params => ({
+ newIssueUrl: params.newEntityUrl,
+ newIssueNumber: params.newEntityNumber,
+ workflowName: params.workflowName,
+ runUrl: params.runUrl,
+ }),
addComment: addIssueComment,
closeEntity: closeIssueAsNotPlanned,
delayMs: API_DELAY_MS,
- getEntityId: entity => entity.number,
- getEntityUrl: entity => entity.html_url,
});
-
- // Map to issue-specific return type
- return result.map(item => ({
- number: item.number,
- html_url: item.html_url || "",
- }));
}
module.exports = {
diff --git a/actions/setup/js/close_older_pull_requests.cjs b/actions/setup/js/close_older_pull_requests.cjs
index 6293d12805a..a66eb406c84 100644
--- a/actions/setup/js/close_older_pull_requests.cjs
+++ b/actions/setup/js/close_older_pull_requests.cjs
@@ -2,7 +2,8 @@
///
const { sanitizeContent } = require("./sanitize_content.cjs");
-const { closeOlderEntities, MAX_CLOSE_COUNT: SHARED_MAX_CLOSE_COUNT } = require("./close_older_entities.cjs");
+const { MAX_CLOSE_COUNT: SHARED_MAX_CLOSE_COUNT } = require("./close_older_entities.cjs");
+const { closeOlderWithAdapter } = require("./close_older_adapter.cjs");
const { buildMarkerSearchQuery, filterByMarker, logFilterSummary } = require("./close_older_search_helpers.cjs");
/**
@@ -185,32 +186,30 @@ function getCloseOlderPullRequestMessage({ newPullRequestUrl, newPullRequestNumb
* @returns {Promise>} List of closed pull requests
*/
async function closeOlderPullRequests(github, owner, repo, workflowId, newPullRequest, workflowName, runUrl, callerWorkflowId, closeOlderKey) {
- const result = await closeOlderEntities(github, owner, repo, workflowId, newPullRequest, workflowName, runUrl, {
+ return closeOlderWithAdapter({
+ github,
+ owner,
+ repo,
+ workflowId,
+ newEntity: newPullRequest,
+ workflowName,
+ runUrl,
+ callerWorkflowId,
+ closeOlderKey,
entityType: "pull request",
entityTypePlural: "pull requests",
- // Use a closure so callerWorkflowId and closeOlderKey are forwarded to searchOlderPullRequests
- // without going through the closeOlderEntities extraArgs mechanism (which appends
- // excludeNumber last)
- searchOlderEntities: (gh, o, r, wid, excludeNumber) => searchOlderPullRequests(gh, o, r, wid, excludeNumber, callerWorkflowId, closeOlderKey),
- getCloseMessage: params =>
- getCloseOlderPullRequestMessage({
- newPullRequestUrl: params.newEntityUrl,
- newPullRequestNumber: params.newEntityNumber,
- workflowName: params.workflowName,
- runUrl: params.runUrl,
- }),
+ searchOlderEntities: searchOlderPullRequests,
+ getCloseMessage: getCloseOlderPullRequestMessage,
+ messageParams: params => ({
+ newPullRequestUrl: params.newEntityUrl,
+ newPullRequestNumber: params.newEntityNumber,
+ workflowName: params.workflowName,
+ runUrl: params.runUrl,
+ }),
addComment: addPullRequestComment,
closeEntity: closePullRequest,
delayMs: API_DELAY_MS,
- getEntityId: entity => entity.number,
- getEntityUrl: entity => entity.html_url,
});
-
- // Map to pull-request-specific return type
- return result.map(item => ({
- number: item.number,
- html_url: item.html_url || "",
- }));
}
module.exports = {