-
Notifications
You must be signed in to change notification settings - Fork 311
Description
Overview
The latest commit (ede35d6767817737063d25a155df2c81f8386a07) includes significant structural duplication in expired-entity cleanup handlers under actions/setup/js/.
The close-and-comment orchestration logic is implemented separately for issues, pull requests, and discussions with only entity-specific API differences. This exceeds the reporting threshold (>10 duplicated lines and 3+ similar occurrences).
Critical Information
- Severity: Medium
- Pattern type: Structural duplication / copy-variant handlers
- Occurrences: 3
- Primary impact: Maintenance overhead and drift risk in expiration behavior
Duplication Details
Pattern: Expired entity close flow duplicated per entity type
actions/setup/js/close_expired_issues.cjs:49actions/setup/js/close_expired_pull_requests.cjs:48actions/setup/js/close_expired_discussions.cjs:92
All three files independently implement the same high-level workflow:
- Resolve repo/workflow metadata
- Invoke
executeExpiredEntityCleanup(...)with entity metadata - Build closing message from expiration date + footer
- Add comment
- Close entity
- Return normalized
{ status, record }
Representative duplicated block (issue vs PR handlers)
const { workflowName, workflowId, runUrl } = getWorkflowMetadata(owner, repo);
await executeExpiredEntityCleanup(github, owner, repo, {
entityType: "...",
graphqlField: "...",
resultKey: "...",
entityLabel: "...",
summaryHeading: "...",
processEntity: async entity => {
const closingMessage = `This ... was automatically closed because it expired on \$\{entity.expirationDate.toISOString()}.` + generateExpiredEntityFooter(workflowName, runUrl, workflowId);
await add...Comment(github, owner, repo, entity.number, closingMessage);
await close...(github, owner, repo, entity.number);
return { status: "closed", record: { number: entity.number, url: entity.url, title: entity.title } };
},
});Notes on discussion variant
close_expired_discussions.cjs adds duplicate-avoidance checks (hasExpirationComment, closed-state handling), but still duplicates the same metadata acquisition, cleanup invocation structure, message generation, comment/close sequencing, and normalized result mapping.
Impact Analysis
- Maintainability: Policy changes (message/footer format, status mapping, logging style) must be updated in 3 places.
- Bug Risk: One handler can diverge silently from others (e.g., footer composition, closing semantics, dedupe behavior).
- Code Bloat: Repeated orchestration obscures the true entity-specific differences.
Refactoring Recommendations
- Extract a shared expired-entity adapter factory
- Add a helper like
buildExpiredEntityProcessor(config)inactions/setup/js/expired_entity_main_flow.cjs(or a newexpired_entity_adapters.cjs). - Keep only API-specific operations (comment/close/checkExisting) in per-entity files.
- Estimated effort: Medium (3-5 hours).
- Move message generation and record shaping to shared utilities
- Centralize closing message and
{status, record}shaping. - Keep discussions-specific dedupe hook as optional callback.
- Estimated effort: Low-Medium (2-3 hours).
Implementation Checklist
- Define shared processor/adapters interface for expired entities
- Refactor issue and PR handlers to use shared adapter
- Refactor discussion handler to use shared adapter + dedupe hooks
- Add/adjust tests for consistent behavior across entity types
- Verify no behavior regression for comments, closure, and summary output
Analysis Metadata
- Analyzed files (changed, non-test): 601
.gofiles inpkg/, 238.cjsfiles inactions/setup/js/ - Detection method: Serena semantic analysis for Go hotspots + structural comparison in changed
.cjshandlers - Commit:
ede35d6767817737063d25a155df2c81f8386a07 - Workflow run: §23420898530
- Analysis date: 2026-03-23 UTC
Warning
**⚠️ Firewall blocked 1 domain**
The following domain was blocked by the firewall during workflow execution:
ab.chatgpt.com
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "ab.chatgpt.com"See Network Configuration for more information.
Generated by Duplicate Code Detector · ◷