Skip to content

Conversation

@JoyceZhu
Copy link
Contributor

No description provided.

Copilot AI review requested due to automatic review settings February 12, 2026 18:40
@JoyceZhu JoyceZhu requested a review from a team as a code owner February 12, 2026 18:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new action input to optionally create “tracking” issues that group multiple newly filed issues sharing the same problemShort.

Changes:

  • Introduces a new open_tracking_issues input (default false) on the top-level action and forwards it into the file sub-action.
  • Updates the file action implementation to collect newly-created issues by problemShort and (when enabled) open a tracking issue per group.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
action.yml Adds/forwards the open_tracking_issues input to the file step.
.github/actions/file/action.yml Declares the new open_tracking_issues input for the file action.
.github/actions/file/src/index.ts Implements grouping logic and tracking-issue creation behind the new flag.
Comments suppressed due to low confidence (1)

.github/actions/file/src/index.ts:61

  • trackingIssueUrls is populated later but never read anywhere. Either use it to implement the intended back-linking from newly created issues to the tracking issue, or remove the variable to avoid dead code.
  const newIssuesByProblemShort: Record<string, { url: string; id: number }[]> =
    {};
  const trackingIssueUrls: Record<string, string> = {};


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +78 to +81
newIssuesByProblemShort[problemShort].push({
url: response.data.html_url,
id: response.data.number,
});
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The collected issue object uses { url, id: response.data.number }, but response.data.number is the issue number (not the GitHub issue id). Rename this field to something like issueNumber to avoid confusion with response.data.id (which you later store into filing.issue.id).

Copilot uses AI. Check for mistakes.
import { openIssue } from "./openIssue.js";
import { reopenIssue } from "./reopenIssue.js";
import { updateFilingsWithNewFindings } from "./updateFilingsWithNewFindings.js";
import { OctokitResponse } from "@octokit/types";
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OctokitResponse is only used as a type. Use a type-only import (import type { OctokitResponse } ...) to avoid accidentally generating a runtime import if TS compiler options change (e.g., verbatimModuleSyntax).

Suggested change
import { OctokitResponse } from "@octokit/types";
import type { OctokitResponse } from "@octokit/types";

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +135
// Open tracking issues for each root cause and link back from each newly-created issue
if (shouldOpenTrackingIssues) {
for (const [problemShort, issues] of Object.entries(
newIssuesByProblemShort,
) as [string, { url: string; id: number }[]][]) {
if (issues.length > 1) {
const title: string = `${problemShort} issues`;
const body: string =
`# ${problemShort} issues\n\n` +
issues.map((issue) => `- [ ] ${issue.url}`).join("\n");
try {
const trackingResponse = await octokit.request(
`POST /repos/${repoWithOwner}/issues`,
{
owner: repoWithOwner.split("/")[0],
repo: repoWithOwner.split("/")[1],
title,
body,
},
);
const trackingUrl: string = trackingResponse.data.html_url;
trackingIssueUrls[problemShort] = trackingUrl;
core.info(
`Opened tracking issue for '${problemShort}': ${issues.length} issues.`,
);
} catch (error) {
core.warning(
`Failed to open tracking issue for '${problemShort}': ${error}`,
);
}
}
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New tracking-issue behavior is behind a flag but has no test coverage. Consider adding/adjusting a Vitest test to assert that when open_tracking_issues is enabled and multiple new issues share the same problemShort, exactly one tracking issue is created and includes links to those issues (can be gated behind describe.runIf(!!process.env.GITHUB_TOKEN) like existing GitHub API tests).

Copilot uses AI. Check for mistakes.
core.setOutput("filings", JSON.stringify(filings));
core.debug(`Output: 'filings: ${JSON.stringify(filings)}'`);
core.info("Finished 'file' action");
// Open tracking issues for each root cause and link back from each newly-created issue
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says tracking issues are opened "and link back from each newly-created issue", but the implementation only creates tracking issues and never updates the newly created issues with a backlink. Update the comment or implement the backlinking to avoid misleading future maintainers.

This issue also appears on line 58 of the same file.

Suggested change
// Open tracking issues for each root cause and link back from each newly-created issue
// Open tracking issues for each root cause based on newly-created issues

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +140
// Open tracking issues for each root cause and link back from each newly-created issue
if (shouldOpenTrackingIssues) {
for (const [problemShort, issues] of Object.entries(
newIssuesByProblemShort,
) as [string, { url: string; id: number }[]][]) {
if (issues.length > 1) {
const title: string = `${problemShort} issues`;
const body: string =
`# ${problemShort} issues\n\n` +
issues.map((issue) => `- [ ] ${issue.url}`).join("\n");
try {
const trackingResponse = await octokit.request(
`POST /repos/${repoWithOwner}/issues`,
{
owner: repoWithOwner.split("/")[0],
repo: repoWithOwner.split("/")[1],
title,
body,
},
);
const trackingUrl: string = trackingResponse.data.html_url;
trackingIssueUrls[problemShort] = trackingUrl;
core.info(
`Opened tracking issue for '${problemShort}': ${issues.length} issues.`,
);
} catch (error) {
core.warning(
`Failed to open tracking issue for '${problemShort}': ${error}`,
);
}
}
}

core.setOutput("filings", JSON.stringify(filings));
core.debug(`Output: 'filings: ${JSON.stringify(filings)}'`);
core.info("Finished 'file' action");
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core.setOutput("filings", ...) (and the "Finished 'file' action" log) now run only when shouldOpenTrackingIssues is true. When the flag is false, the action produces no filings output at all, which will break downstream steps that rely on steps.file.outputs.filings (and also changes behavior from before this PR). Move the output/log statements outside the conditional so they always run, and keep the tracking-issue logic inside the flag guard.

Copilot uses AI. Check for mistakes.
description: "Cached filings from previous runs, as stringified JSON. Without this, duplicate issues may be filed."
required: false
open_tracking_issues:
description: "In the 'file' step, also open tracking issues which link to all issues with the same problem"
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core.getBooleanInput("open_tracking_issues") throws if the input is missing or an empty string. Since this action’s action.yml declares the input as optional and has no default, running the file action standalone without specifying open_tracking_issues will fail. Add a default of "false" in .github/actions/file/action.yml (or read it as a string input with a fallback).

Suggested change
description: "In the 'file' step, also open tracking issues which link to all issues with the same problem"
description: "In the 'file' step, also open tracking issues which link to all issues with the same problem"
default: "false"

Copilot uses AI. Check for mistakes.
// Track for grouping
if (shouldOpenTrackingIssues) {
const problemShort: string = filing.findings[0].problemShort;
if (!newIssuesByProblemShort[problemShort])
Copy link

@abdulahmad307 abdulahmad307 Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was originally gonna say: looks like if this if condition is not met, we don't end up pushing anything to the list, but then I realized this line:

newIssuesByProblemShort[problemShort] = [];

is indented more than the rest, and only that line belongs to the condition. For single line conditions like this, my personal preference is either keeping everything on 1 line:

if (x) doY();

or wrapping in brackets

if (x) {
  doY();
}

otherwise it can be easy to miss the intention of the logic.

also, if the problem here was with the length of the line, maybe another approach could help break it up into multiple lines:

const newIssues = newIssuesByProblemShort[problemShort] || [];
newIssues.push({...});
newIssuesByProblemShort[problemShort] = newIssues;

🤷 your call, I'm just thinking out loud mostly

if (shouldOpenTrackingIssues) {
for (const [problemShort, issues] of Object.entries(
newIssuesByProblemShort,
) as [string, { url: string; id: number }[]][]) {
Copy link

@abdulahmad307 abdulahmad307 Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should declare a type for this: { url: string; id: number } - that can make these statements a little easier to read. maybe: type FindingGroupIssue? and then it can be reused on line 58 above too. To take it further, we can also declare a type for the wrapper object: string, { url: string; id: number }[]

type FindingGroupIssue {
  url: string
  id: number
}

type IssuesByProblemShort {
  problemShort: string
  issues: FindingGroupIssue[]
}

again, not a blocker, just a nice to have for readability

body,
},
);
const trackingUrl: string = trackingResponse.data.html_url;
Copy link

@abdulahmad307 abdulahmad307 Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we will want to wrap this in a model in the near future (especially if we start working with other issue types), specifically this part: trackingResponse.data.html_url;. and some of the code around interfacing with octokit (something like this for models, and something like this for a 'client' of some kind - these are just examples, I'm open to other approaches too).

Copy link

@abdulahmad307 abdulahmad307 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The general approach looks good! Left some comments for things to consider.

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.

2 participants