Skip to content

feat(no-response): reopen from sweep also#7

Merged
tcely merged 25 commits intomainfrom
tcely-reopen-from-sweep
Mar 27, 2026
Merged

feat(no-response): reopen from sweep also#7
tcely merged 25 commits intomainfrom
tcely-reopen-from-sweep

Conversation

@tcely
Copy link
Copy Markdown
Owner

@tcely tcely commented Mar 17, 2026

PR Type

Enhancement, Bug fix


Description

  • Refactored codebase with new modular architecture for GitHub API interactions

  • Added author assignment on label application and reopen logic with 15-minute grace period

  • Implemented resilient batch processing with error handling for sweep operations

  • Enhanced configuration validation with safe numeric parsing and readonly properties


Diagram Walkthrough

flowchart LR
  Config["Config<br/>readonly properties<br/>safe parsing"]
  GitHubApiClient["GitHubApiClient<br/>REST API wrapper"]
  RepoMetadataCache["RepoMetadataCache<br/>label & repo caching"]
  IssueCache["IssueCache<br/>issue details caching"]
  LogicHelpers["Logic Helpers<br/>business logic"]
  NoResponse["NoResponse<br/>orchestrator"]
  
  Config --> NoResponse
  GitHubApiClient --> RepoMetadataCache
  GitHubApiClient --> IssueCache
  RepoMetadataCache --> NoResponse
  IssueCache --> NoResponse
  LogicHelpers --> NoResponse
  
  NoResponse -- "sweep: reopen + close" --> GitHubApiClient
  NoResponse -- "handleLabeled: assign author" --> GitHubApiClient
  NoResponse -- "handleAuthorCommented: reopen + adjust labels" --> GitHubApiClient
  NoResponse -- "handleClosedIssue: clear labels" --> GitHubApiClient
Loading

File Walkthrough

Relevant files
Enhancement
9 files
config.ts
Add readonly properties and safe numeric parsing                 
+13/-11 
gh-api-client.ts
New modular GitHub API client wrapper class                           
+258/-0 
gh-api-helpers.ts
Helper functions for API response mapping                               
+89/-0   
issue-cache.ts
New issue details caching layer with timeline support       
+121/-0 
logic-helpers.ts
Business logic utilities for issue state checks                   
+47/-0   
repo-metadata-cache.ts
Repository metadata and label caching system                         
+121/-0 
types.ts
New TypeScript interfaces for domain models                           
+65/-0   
main.ts
Refactored event routing with improved logging                     
+21/-3   
no-response.ts
Complete rewrite with author assignment and grace period 
+355/-265
Documentation
2 files
README.md
Comprehensive documentation of new features                           
+118/-39
TODO.md
Project roadmap and improvement tracking                                 
+76/-0   
Configuration changes
2 files
action.yml
Add cleanup step for temporary hash files                               
+5/-0     
package.json
Add TypeScript type checking to CI pipeline                           
+4/-3     

@tcely tcely self-assigned this Mar 17, 2026
@tcely tcely changed the title chore: remove an unused function feat: reopen from sweep also Mar 17, 2026
@tcely tcely changed the title feat: reopen from sweep also feat(no-response): reopen from sweep also Mar 17, 2026
@tcely tcely marked this pull request as ready for review March 17, 2026 10:37
Comment thread src/no-response.ts Outdated
Comment thread src/no-response.ts Outdated
Repository owner deleted a comment from qodo-code-review Bot Mar 19, 2026
Repository owner deleted a comment from qodo-code-review Bot Mar 19, 2026
Comment thread src/gh-api-helpers.ts
Comment thread src/no-response.ts
Comment thread src/no-response.ts
@tcely

This comment was marked as outdated.

@qodo-code-review

This comment was marked as resolved.

@tcely

This comment was marked as outdated.

@qodo-code-review

This comment was marked as resolved.

@tcely

This comment was marked as outdated.

@qodo-code-review

This comment was marked as resolved.

Comment thread src/no-response.ts
Comment thread src/issue-cache.ts
Comment thread src/no-response.ts Outdated
@tcely

This comment was marked as outdated.

Comment thread src/no-response.ts
Comment thread src/no-response.ts
Comment thread src/config.ts Outdated
Repository owner deleted a comment from qodo-code-review Bot Mar 20, 2026
Repository owner deleted a comment from qodo-code-review Bot Mar 20, 2026
Repository owner deleted a comment from qodo-code-review Bot Mar 20, 2026
Comment thread src/no-response.ts
Comment thread src/no-response.ts
Repository owner deleted a comment from qodo-code-review Bot Mar 20, 2026
Repository owner deleted a comment from qodo-code-review Bot Mar 20, 2026
@tcely

This comment was marked as outdated.

@qodo-code-review

This comment was marked as resolved.

@tcely

This comment was marked as outdated.

@qodo-code-review

This comment was marked as resolved.

@tcely

This comment was marked as outdated.

@qodo-code-review

This comment was marked as resolved.

Repository owner deleted a comment from qodo-code-review Bot Mar 21, 2026
@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Mar 21, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. Sweep may crash pre-batch🐞 Bug ⛯ Reliability
Description
getReopenableIssues() uses raw.user!.login while building Issue objects from search results; if
raw.user is missing, the sweep throws before runWriteBatch() is reached and the entire scheduled
run aborts. This defeats the intended resilience and prevents both reopen and close passes from
running.
Code

src/no-response.ts[R241-246]

+      const issue: Issue = {
+        number: raw.number,
+        repo: this.repository,
+        state: raw.state as 'open' | 'closed',
+        user: { login: raw.user!.login }
+      }
Evidence
The sweep computes toReopen by fully executing getReopenableIssues() before entering the
resilient runWriteBatch() loops; any exception inside that pre-pass aborts the run.
getReopenableIssues() currently dereferences raw.user with a non-null assertion, while the
repo’s own REST mappers explicitly treat raw.user as optional (fallbacking to 'unknown'),
indicating the codebase expects missing user data to be possible and should be handled safely.

src/no-response.ts[65-104]
src/no-response.ts[232-261]
src/gh-api-helpers.ts[47-60]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`src/no-response.ts#getReopenableIssues()` constructs an `Issue` using `raw.user!.login`. If `raw.user` is `null/undefined` (e.g., deleted user or incomplete search result), the non-null assertion throws, and because this happens before `runWriteBatch()` starts, the entire `sweep()` aborts.
### Issue Context
`sweep()` calls `getReopenableIssues()` *before* any resilient batching. The project already treats `raw.user` as optional in `mapRestIssue()` by using `raw.user?.login || &amp;#x27;unknown&amp;#x27;`, so the reopen pre-pass should not assume presence.
### Fix Focus Areas
- src/no-response.ts[232-261]
### What to change
- Replace `raw.user!.login` with safe access:
- Prefer: `const login = raw.user?.login; if (!login) { core.warning(...); continue; }`
- Or: build with a placeholder login and then immediately skip if `issueDetails.user.login === &amp;#x27;unknown&amp;#x27;` after fetching details.
- Ensure `getReopenableIssues()` never throws on missing user metadata so `sweep()` can continue to the close phase.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Writes use 'unknown' login🐞 Bug ⛯ Reliability
Description
mapRestIssue() substitutes a missing author login with the literal 'unknown', and
handleLabeled() passes issueDetails.user.login directly into addAssignees(). If an issue
author is missing (e.g., deleted user), this becomes an invalid write request and can fail the
labeled-event run.
Code

src/no-response.ts[R135-139]

+    core.info(
+      `Target label matched. Assigning #${issueDetails.number} to author: ${issueDetails.user.login}`
+    )
+    await this.client.addAssignees(issueDetails, [issueDetails.user.login])
+  }
Evidence
The REST issue mapper hard-codes user.login to 'unknown' when raw.user is absent.
handleLabeled() then uses that value as an assignee login without validation, so the sentinel
value can escape into API writes.

src/gh-api-helpers.ts[47-55]
src/no-response.ts[127-139]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`mapRestIssue()` uses `&amp;#x27;unknown&amp;#x27;` as a fallback author login, but `handleLabeled()` uses `issueDetails.user.login` as an assignee value without validating that it is a real GitHub username. This can turn “missing author” into a failing API write.
### Issue Context
The codebase already uses sentinel `&amp;#x27;unknown&amp;#x27;` values (user login and actor login). Those sentinels are useful for logging, but they must not be used in write endpoints like `issues.addAssignees`/`issues.removeAssignees`.
### Fix Focus Areas
- src/no-response.ts[127-139]
- src/gh-api-helpers.ts[47-55]
### What to change
- In `handleLabeled()`, guard before calling `addAssignees()`:
- If `issueDetails.user.login` is falsy or equals `&amp;#x27;unknown&amp;#x27;`, log a warning and return.
- Optionally apply the same guard in `unassignAuthor()` to avoid attempting `removeAssignees()` with the sentinel login.
- (Optional, bigger change) Consider representing missing users as `user?: {login: string}` instead of coercing to `&amp;#x27;unknown&amp;#x27;`, and update call sites accordingly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Repository owner deleted a comment from qodo-code-review Bot Mar 21, 2026
Repository owner deleted a comment from qodo-code-review Bot Mar 21, 2026
Comment thread src/no-response.ts Outdated
@tcely

This comment was marked as outdated.

@qodo-code-review

This comment was marked as resolved.

Repository owner deleted a comment from qodo-code-review Bot Mar 27, 2026
@tcely tcely merged commit 8f69f0a into main Mar 27, 2026
1 check passed
@tcely tcely deleted the tcely-reopen-from-sweep branch March 27, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant