Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/linear.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,9 @@ export async function fetchIssues(
return issues;
}
const team = { team: { key: { eq: config.linear_team_key } } };
// parent lets the Slack stale digest list only top-level issues.
export const openIssues = cache(() =>
fetchIssues({ ...team, state: { type: { in: openTypes } } }, true, "open"),
fetchIssues({ ...team, state: { type: { in: openTypes } } }, true, "open", `${fields} parent { id }`),
);
const completedFilter = (after: string, before: string) => ({
...team,
Expand Down
2 changes: 2 additions & 0 deletions lib/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,10 @@ export async function staleMessage() {
personMetrics(slug, report.completed, report.prs, report.projects, report.window),
])) : {};
const reviews = reviewReminders(queue, Date.now(), metrics);
// Sub-issues roll up to their parent, so the digest lists only top-level issues.
const issues = open.filter(
(i) =>
!i.parent &&
daysSince(i.updatedAt) > 21 &&
engineers.includes(
slugFor(i.assignee?.name, i.assignee?.displayName) || "",
Expand Down
2 changes: 1 addition & 1 deletion lib/reports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const openWork = cache(async () => {
);
}
return unstable_cache(async () => compactOpenIssues(await openIssues()),
["open-work-v4", process.env.VERCEL_URL || "local"], { revalidate: 60 })();
["open-work-v5", process.env.VERCEL_URL || "local"], { revalidate: 60 })();
});
export function sortedTeam(rows: TeamRow[], search: Search) {
const everyone = param(search, "everyone") === "1";
Expand Down
1 change: 1 addition & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type Issue = {
slaStartedAt?: string;
assignee: Identity | null;
project: { id: string; name: string } | null;
parent?: { id: string } | null;
state: IssueState;
labels: { nodes: { name: string }[] };
attachments?: {
Expand Down
8 changes: 5 additions & 3 deletions tests/notifications.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ test("Slack digests preserve complete lines and claim delivery per part", async
assert.deepEqual(await notify("stale", "short"), { status: "already-claimed" });
assert.equal(posts.length, 1);
});
await t.test("stale issues include projects without changing age or assignee gates", async () => {
await t.test("stale issues include projects, skip sub-issues, and keep age or assignee gates", async () => {
const project = { id: "project", name: "Backlog cleanup" };
issues = [
issue(2, "Standalone stale"),
Expand All @@ -147,13 +147,15 @@ test("Slack digests preserve complete lines and claim delivery per part", async
{ ...issue(6, "Project recent"), project, updatedAt: new Date(Date.now() - 21 * 86_400_000).toISOString() },
{ ...issue(7, "Project unassigned"), project, assignee: null },
{ ...issue(8, "Project outside engineering"), project, assignee: { name: "vincent", displayName: "vincent" } },
{ ...issue(10, "Stale sub-issue"), parent: { id: "2" } },
{ ...issue(11, "Top-level null parent"), parent: null },
];
const message = (await staleMessage())!;
assert.match(message, /\*Stale Open Issues\*/);
assert.match(message, /<@U0BLNNPAB> \(avg completion: n\/a, last 30d\):/);
for (const title of ["Standalone stale", "Project stale", "Project merged", "Project parked"])
for (const title of ["Standalone stale", "Project stale", "Project merged", "Project parked", "Top-level null parent"])
assert.ok(message.includes(`|${title}>`), title);
for (const title of ["Project recent", "Project unassigned", "Project outside engineering"])
for (const title of ["Project recent", "Project unassigned", "Project outside engineering", "Stale sub-issue"])
assert.ok(!message.includes(title), title);
});
await t.test("person headings reuse the metrics snapshot for both 30-day averages", async () => {
Expand Down
Loading