repomatic.github.issue module

GitHub issue lifecycle management.

Lists, creates, updates, closes and reopens the issues CI jobs maintain, used by repomatic.broken_links and the setup guide. The writes that issues share with pull requests (labels, locks) live in threads.

The life-cycle of issues created in CI jobs is managed here by hand because the create-issue-from-file action blindly creates issues ad-nauseam.

See: - https://github.com/peter-evans/create-issue-from-file/issues/298 - https://github.com/lycheeverse/lychee-action/issues/74#issuecomment-1587089689

repomatic.github.issue.ISSUE_LIST_LIMIT = 100

Issues list_issues() reads at most.

gh issue list stops at 30 unless told otherwise. A title search matches a handful of issues, since a recurring condition reopens its one issue instead of filing a new one, so this bound is never reached in practice.

class repomatic.github.issue.Triage(keep, keep_state, close)[source]

Bases: NamedTuple

What triage_issues() decided for the issues sharing one title.

Create new instance of Triage(keep, keep_state, close)

keep: int | None

The issue to update, or None when no issue is needed or none exists.

keep_state: str | None

The state of the kept issue, OPEN or CLOSED.

close: set[int]

The open issues to close as duplicates or as resolved.

repomatic.github.issue.list_issues(title='', *, repository=None)[source]

List all issues (open and closed), optionally filtered by title.

Note

No --author filter is applied. When REPOMATIC_PAT is configured, gh authenticates as the token owner (not github-actions[bot]), so issues may be authored by either identity. Filtering by author would miss issues created under the other identity, breaking deduplication.

Parameters:
  • title (str) – If provided, only return issues whose title matches exactly.

  • repository (str | None) – Repository in owner/name form, or None to let gh resolve it.

Return type:

list[dict[str, Any]]

Returns:

List of issue dicts with number, title, createdAt, and state.

repomatic.github.issue.close_issue(number, comment, *, repository=None)[source]

Close an issue with a comment.

Parameters:
  • number (int) – The issue number to close.

  • comment (str) – The comment to add when closing.

  • repository (str | None) – Repository in owner/name form, or None to let gh resolve it.

Return type:

None

repomatic.github.issue.reopen_issue(number, comment='', *, repository=None)[source]

Reopen a previously closed issue.

A closed issue old enough to reopen is old enough to have been autolocked, so the write goes through run_unlocking().

Parameters:
  • number (int) – The issue number to reopen.

  • comment (str) – Optional comment to add when reopening.

  • repository (str | None) – Repository in owner/name form, or None to let gh resolve it.

Return type:

None

repomatic.github.issue.create_issue(body_file, labels, title, *, repository=None, assignees=())[source]

Create a new issue.

Parameters:
  • body_file (Path) – Path to the file containing the issue body, already trimmed to GitHub’s size limit (see fit_github_body()).

  • labels (Sequence[str]) – Labels to apply.

  • title (str) – Issue title.

  • repository (str | None) – Repository in owner/name form, or None to let gh resolve it.

  • assignees (Sequence[str]) – Logins to assign the issue to.

Return type:

int

Returns:

The created issue number.

Raises:

RuntimeError – When the output carries no parsable issue URL.

repomatic.github.issue.update_issue(number, body_file, *, repository=None)[source]

Update an existing issue body.

Parameters:
  • number (int) – The issue number to update.

  • body_file (Path) – Path to the file containing the new issue body, already trimmed to GitHub’s size limit (see fit_github_body()).

  • repository (str | None) – Repository in owner/name form, or None to let gh resolve it.

Return type:

None

repomatic.github.issue.triage_issues(issues, needed)[source]

Triage the issues sharing one title, for deduplication.

If needed, the most recent issue is kept (with its state) and every older open one is closed. If not, every open issue is closed. An issue already closed is never closed again.

Parameters:
  • issues (Sequence[dict[str, Any]]) – Issue dicts from gh issue list –json number,title,createdAt,state, already filtered to one title (see list_issues()).

  • needed (bool) – Whether an issue with this title should exist.

Return type:

Triage

Returns:

The issue to keep, its state, and the issues to close.

repomatic.github.issue.manage_issue_lifecycle(has_issues, body, labels, title, no_issues_comment='No more issues.', *, repository=None, assignees=())[source]

Manage the full issue lifecycle: list, triage, close, create/update.

This function handles:

  1. Listing all issues (open and closed) via gh issue list.

  2. Triaging matching issues (keep newest if needed, close duplicates).

  3. Closing duplicate open issues via gh issue close.

  4. Creating, updating, or reopening the main issue via gh issue create, gh issue edit, or gh issue reopen.

When has_issues is True and the most recent matching issue is closed, it is reopened and updated rather than creating a duplicate. A conversation lock standing in the way of that reopen is cleared first, so a recurring issue survives the autolock workflow that closes over it; see run_unlocking().

Parameters:
  • has_issues (bool) – Whether issues were found that warrant an open issue.

  • body (str) – The rendered markdown issue body. Written to a temporary file only when a create or update actually happens, since a run that just closes issues never needs one.

  • labels (Sequence[str]) – Labels to apply when creating a new issue.

  • title (str) – Issue title to match and create.

  • no_issues_comment (str) – Comment to add when closing issues because the condition no longer applies.

  • repository (str | None) – Repository in owner/name form, or None to let gh resolve it.

  • assignees (Sequence[str]) – Logins to assign a newly created issue to. An issue that already exists keeps its assignees.

Return type:

int | None

Returns:

The number of the issue created, updated or reopened, or None when has_issues is false.