Skip to content

Duplicate Code: closeOlder* issue/discussion cleanup flow #15861

@github-actions

Description

@github-actions

🔍 Duplicate Code Detected: Close Older Entities Flow

Analysis of commit 56e1ce9

Assignee: @copilot

Summary

The closeOlderIssues and closeOlderDiscussions functions implement nearly identical control flow for searching older entities, logging results, rate-limiting, and iterating to close items. The bodies are structurally the same with only entity-specific naming and API calls changed.

Duplication Details

Pattern: Close older entities with shared flow

  • Severity: Medium
  • Occurrences: 2
  • Locations:
    • actions/setup/js/close_older_issues.cjs:195
    • actions/setup/js/close_older_discussions.cjs:199
  • Code Sample:
async function closeOlderIssues(github, owner, repo, workflowId, newIssue, workflowName, runUrl) {
  core.info("=".repeat(70));
  core.info("Starting closeOlderIssues operation");
  core.info("=".repeat(70));
  ...
  const olderIssues = await searchOlderIssues(...);
  if (olderIssues.length === 0) {
    core.info("✓ No older issues found to close - operation complete");
    core.info("=".repeat(70));
    return [];
  }
  ...
  for (let i = 0; i < issuesToClose.length; i++) {
    const issue = issuesToClose[i];
    ...
    await addIssueComment(...);
    await closeIssueAsNotPlanned(...);
    ...
    if (i < issuesToClose.length - 1) {
      core.info(`Waiting \$\{API_DELAY_MS}ms before processing next issue to avoid rate limiting...`);
      await delay(API_DELAY_MS);
    }
  }
  ...
}
async function closeOlderDiscussions(github, owner, repo, workflowId, categoryId, newDiscussion, workflowName, runUrl) {
  core.info("=".repeat(70));
  core.info("Starting closeOlderDiscussions operation");
  core.info("=".repeat(70));
  ...
  const olderDiscussions = await searchOlderDiscussions(...);
  if (olderDiscussions.length === 0) {
    core.info("✓ No older discussions found to close - operation complete");
    core.info("=".repeat(70));
    return [];
  }
  ...
  for (let i = 0; i < discussionsToClose.length; i++) {
    const discussion = discussionsToClose[i];
    ...
    await addDiscussionComment(...);
    await closeDiscussionAsOutdated(...);
    ...
    if (i < discussionsToClose.length - 1) {
      core.info(`Waiting \$\{GRAPHQL_DELAY_MS}ms before processing next discussion to avoid rate limiting...`);
      await delay(GRAPHQL_DELAY_MS);
    }
  }
  ...
}

Impact Analysis

  • Maintainability: Changes to logging, rate limit handling, or summary output must be duplicated and kept in sync.
  • Bug Risk: Divergence risk if one flow receives a fix or enhancement but the other does not.
  • Code Bloat: Large, repetitive bodies across two files.

Refactoring Recommendations

  1. Extract shared flow to a helper

    • Extract to: actions/setup/js/expired_entity_main_flow.cjs or a new actions/setup/js/close_older_entities.cjs
    • Estimated effort: Medium (2-4 hours)
    • Benefits: Single flow for search/limit/log/close logic with entity-specific callbacks
  2. Parameterize entity-specific actions

    • Accept callbacks for search, comment, close, and delay duration
    • Benefits: Reduce duplication while preserving behavioral differences

Implementation Checklist

  • Review duplication findings
  • Prioritize refactoring tasks
  • Create refactoring plan
  • Implement changes
  • Update tests
  • Verify no functionality broken

Analysis Metadata

  • Analyzed Files: 2
  • Detection Method: Serena semantic code analysis
  • Commit: 56e1ce9
  • Analysis Date: 2026-02-15

Generated by Duplicate Code Detector

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions