11// @ts -check
22/// <reference types="@actions/github-script" />
33
4- const { getWorkflowIdMarkerContent, generateWorkflowIdMarker, generateWorkflowCallIdMarker, generateCloseKeyMarker, getCloseKeyMarkerContent } = require ( "./generate_footer.cjs" ) ;
54const { sanitizeContent } = require ( "./sanitize_content.cjs" ) ;
65const { closeOlderEntities, MAX_CLOSE_COUNT : SHARED_MAX_CLOSE_COUNT } = require ( "./close_older_entities.cjs" ) ;
6+ const { buildMarkerSearchQuery, filterByMarker, logFilterSummary } = require ( "./close_older_search_helpers.cjs" ) ;
77
88/**
99 * Maximum number of older issues to close
@@ -41,26 +41,14 @@ async function searchOlderIssues(github, owner, repo, workflowId, excludeNumber,
4141 return [ ] ;
4242 }
4343
44- // Build REST API search query.
45- // When a close-older-key is provided it becomes the primary search term; otherwise
46- // fall back to the workflow-id marker.
47- let searchQuery ;
48- let exactMarker ;
49- if ( closeOlderKey ) {
50- const closeKeyMarkerContent = getCloseKeyMarkerContent ( closeOlderKey ) ;
51- const escapedMarker = closeKeyMarkerContent . replace ( / " / g, '\\"' ) ;
52- searchQuery = `repo:${ owner } /${ repo } is:issue is:open "${ escapedMarker } " in:body` ;
53- exactMarker = generateCloseKeyMarker ( closeOlderKey ) ;
54- core . info ( ` Using close-older-key for search: "${ escapedMarker } " in:body` ) ;
55- } else {
56- // Search for open issues with the workflow-id marker in the body
57- const workflowIdMarker = getWorkflowIdMarkerContent ( workflowId ) ;
58- // Escape quotes in workflow ID to prevent query injection
59- const escapedMarker = workflowIdMarker . replace ( / " / g, '\\"' ) ;
60- searchQuery = `repo:${ owner } /${ repo } is:issue is:open "${ escapedMarker } " in:body` ;
61- exactMarker = callerWorkflowId ? generateWorkflowCallIdMarker ( callerWorkflowId ) : generateWorkflowIdMarker ( workflowId ) ;
62- core . info ( ` Added workflow-id marker filter to query: "${ escapedMarker } " in:body` ) ;
63- }
44+ const { searchQuery, exactMarker } = buildMarkerSearchQuery ( {
45+ owner,
46+ repo,
47+ workflowId,
48+ callerWorkflowId,
49+ closeOlderKey,
50+ entityQualifier : "is:issue" ,
51+ } ) ;
6452 core . info ( `Executing GitHub search with query: ${ searchQuery } ` ) ;
6553
6654 const result = await github . rest . search . issuesAndPullRequests ( {
@@ -75,60 +63,35 @@ async function searchOlderIssues(github, owner, repo, workflowId, excludeNumber,
7563 return [ ] ;
7664 }
7765
78- // Filter results:
79- // 1. Must not be the excluded issue (newly created one)
80- // 2. Must not be a pull request
81- // 3. Body must contain the exact marker. When closeOlderKey is set the close-key marker
82- // is used. Otherwise, when callerWorkflowId is set, match `gh-aw-workflow-call-id` so
83- // that callers sharing the same reusable workflow do not close each other's issues.
84- // Fall back to `gh-aw-workflow-id` for backward compat with older issues.
8566 core . info ( "Filtering search results..." ) ;
86- let filteredCount = 0 ;
87- let pullRequestCount = 0 ;
88- let excludedCount = 0 ;
89- let markerMismatchCount = 0 ;
9067
91- const filtered = result . data . items
92- . filter ( item => {
93- // Exclude pull requests
68+ const { filtered : filteredItems , counters } = filterByMarker ( {
69+ items : result . data . items ,
70+ excludeNumber,
71+ exactMarker,
72+ entityType : "issue" ,
73+ additionalFilter : ( item , extra ) => {
9474 if ( item . pull_request ) {
95- pullRequestCount ++ ;
96- return false ;
97- }
98-
99- // Exclude the newly created issue
100- if ( item . number === excludeNumber ) {
101- excludedCount ++ ;
102- core . info ( ` Excluding issue #${ item . number } (the newly created issue)` ) ;
103- return false ;
104- }
105-
106- // Exact-match the marker in the issue body to prevent GitHub search
107- // substring tokenization from matching related workflow IDs
108- // (e.g. "foo" would otherwise match issues from "foo-bar")
109- if ( ! item . body ?. includes ( exactMarker ) ) {
110- markerMismatchCount ++ ;
111- core . info ( ` Excluding issue #${ item . number } (body does not contain exact marker)` ) ;
75+ extra . pullRequestCount = ( extra . pullRequestCount || 0 ) + 1 ;
11276 return false ;
11377 }
114-
115- filteredCount ++ ;
116- core . info ( ` ✓ Issue #${ item . number } matches criteria: ${ item . title } ` ) ;
11778 return true ;
118- } )
119- . map ( item => ( {
120- number : item . number ,
121- title : item . title ,
122- html_url : item . html_url ,
123- labels : item . labels || [ ] ,
124- created_at : item . created_at ,
125- } ) ) ;
79+ } ,
80+ } ) ;
12681
127- core . info ( `Filtering complete:` ) ;
128- core . info ( ` - Matched issues: ${ filteredCount } ` ) ;
129- core . info ( ` - Excluded pull requests: ${ pullRequestCount } ` ) ;
130- core . info ( ` - Excluded new issue: ${ excludedCount } ` ) ;
131- core . info ( ` - Excluded marker mismatch: ${ markerMismatchCount } ` ) ;
82+ const filtered = filteredItems . map ( item => ( {
83+ number : item . number ,
84+ title : item . title ,
85+ html_url : item . html_url ,
86+ labels : item . labels || [ ] ,
87+ created_at : item . created_at ,
88+ } ) ) ;
89+
90+ logFilterSummary ( {
91+ entityTypePlural : "issues" ,
92+ counters,
93+ extraLabels : [ [ "pullRequestCount" , "Excluded pull requests" ] ] ,
94+ } ) ;
13295
13396 return filtered ;
13497}
0 commit comments