Fix issue create response relation summaries (#8901)
Return blockedBy and blocks relation summaries from issue create paths after blocker relations are synced. Refresh child relation summaries after blockParentUntilDone adds a parent blocker relation. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
ec92728536
commit
2c4c110e90
|
|
@ -3200,6 +3200,114 @@ describeEmbeddedPostgres("issueService blockers and dependency wake readiness",
|
|||
expect(blockedRelations.blockedBy.map((relation) => relation.id)).toEqual([blockerId]);
|
||||
});
|
||||
|
||||
it("returns blocked-by summaries on newly created issues", async () => {
|
||||
const companyId = randomUUID();
|
||||
await db.insert(companies).values({
|
||||
id: companyId,
|
||||
name: "Paperclip",
|
||||
issuePrefix: `T${companyId.replace(/-/g, "").slice(0, 6).toUpperCase()}`,
|
||||
requireBoardApprovalForNewAgents: false,
|
||||
});
|
||||
|
||||
const blockerId = randomUUID();
|
||||
await db.insert(issues).values({
|
||||
id: blockerId,
|
||||
companyId,
|
||||
title: "Blocker",
|
||||
status: "todo",
|
||||
priority: "high",
|
||||
});
|
||||
|
||||
const created = await svc.create(companyId, {
|
||||
title: "Blocked issue",
|
||||
status: "blocked",
|
||||
priority: "medium",
|
||||
blockedByIssueIds: [blockerId],
|
||||
});
|
||||
|
||||
expect(created.blockedBy.map((relation) => relation.id)).toEqual([blockerId]);
|
||||
expect(created.blockedBy[0]).toEqual(expect.objectContaining({
|
||||
title: "Blocker",
|
||||
status: "todo",
|
||||
priority: "high",
|
||||
}));
|
||||
expect(created.blocks).toEqual([]);
|
||||
});
|
||||
|
||||
it("returns blocked-by summaries on newly created child issues", async () => {
|
||||
const companyId = randomUUID();
|
||||
await db.insert(companies).values({
|
||||
id: companyId,
|
||||
name: "Paperclip",
|
||||
issuePrefix: `T${companyId.replace(/-/g, "").slice(0, 6).toUpperCase()}`,
|
||||
requireBoardApprovalForNewAgents: false,
|
||||
});
|
||||
|
||||
const parentId = randomUUID();
|
||||
const blockerId = randomUUID();
|
||||
await db.insert(issues).values([
|
||||
{
|
||||
id: parentId,
|
||||
companyId,
|
||||
title: "Parent",
|
||||
status: "todo",
|
||||
priority: "medium",
|
||||
},
|
||||
{
|
||||
id: blockerId,
|
||||
companyId,
|
||||
title: "Blocker",
|
||||
status: "todo",
|
||||
priority: "high",
|
||||
},
|
||||
]);
|
||||
|
||||
const { issue: child } = await svc.createChild(parentId, {
|
||||
title: "Blocked child issue",
|
||||
status: "blocked",
|
||||
priority: "medium",
|
||||
blockedByIssueIds: [blockerId],
|
||||
});
|
||||
|
||||
expect(child.parentId).toBe(parentId);
|
||||
expect(child.blockedBy.map((relation) => relation.id)).toEqual([blockerId]);
|
||||
expect(child.blocks).toEqual([]);
|
||||
});
|
||||
|
||||
it("returns blocks summaries when child creation blocks the parent", async () => {
|
||||
const companyId = randomUUID();
|
||||
await db.insert(companies).values({
|
||||
id: companyId,
|
||||
name: "Paperclip",
|
||||
issuePrefix: `T${companyId.replace(/-/g, "").slice(0, 6).toUpperCase()}`,
|
||||
requireBoardApprovalForNewAgents: false,
|
||||
});
|
||||
|
||||
const parentId = randomUUID();
|
||||
await db.insert(issues).values({
|
||||
id: parentId,
|
||||
companyId,
|
||||
title: "Parent",
|
||||
status: "todo",
|
||||
priority: "medium",
|
||||
});
|
||||
|
||||
const { issue: child } = await svc.createChild(parentId, {
|
||||
title: "Parent-blocking child",
|
||||
status: "todo",
|
||||
priority: "medium",
|
||||
blockParentUntilDone: true,
|
||||
});
|
||||
|
||||
expect(child.blocks.map((relation) => relation.id)).toEqual([parentId]);
|
||||
expect(child.blocks[0]).toEqual(expect.objectContaining({
|
||||
title: "Parent",
|
||||
status: "todo",
|
||||
priority: "medium",
|
||||
}));
|
||||
expect(child.blockedBy).toEqual([]);
|
||||
});
|
||||
|
||||
it("adds terminal blockers to immediate blocked-by summaries", async () => {
|
||||
const companyId = randomUUID();
|
||||
await db.insert(companies).values({
|
||||
|
|
|
|||
|
|
@ -3991,6 +3991,23 @@ export function issueService(db: Db) {
|
|||
return empty;
|
||||
}
|
||||
|
||||
async function withIssueRelationSummaries<T extends { id: string }>(
|
||||
companyId: string,
|
||||
rows: T[],
|
||||
dbOrTx: DbReader = db,
|
||||
): Promise<Array<T & IssueRelationSummaryMap>> {
|
||||
if (rows.length === 0) return [];
|
||||
const relationMap = await getIssueRelationSummaryMap(
|
||||
companyId,
|
||||
rows.map((row) => row.id),
|
||||
dbOrTx,
|
||||
);
|
||||
return rows.map((row) => ({
|
||||
...row,
|
||||
...(relationMap.get(row.id) ?? { blockedBy: [], blocks: [] }),
|
||||
}));
|
||||
}
|
||||
|
||||
async function assertNoBlockingCycles(
|
||||
companyId: string,
|
||||
issueId: string,
|
||||
|
|
@ -4960,7 +4977,7 @@ export function issueService(db: Db) {
|
|||
actorUserId,
|
||||
...issueData
|
||||
} = data;
|
||||
const child = await issueService(db).create(parent.companyId, {
|
||||
let child = await issueService(db).create(parent.companyId, {
|
||||
...issueData,
|
||||
parentId: parent.id,
|
||||
projectId: issueData.projectId ?? parent.projectId,
|
||||
|
|
@ -4983,6 +5000,7 @@ export function issueService(db: Db) {
|
|||
[...new Set([...existingBlockers.map((row) => row.blockerIssueId), child.id])],
|
||||
{ agentId: actorAgentId ?? null, userId: actorUserId ?? null },
|
||||
);
|
||||
[child] = await withIssueRelationSummaries(parent.companyId, [child], db);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -5484,7 +5502,8 @@ export function issueService(db: Db) {
|
|||
);
|
||||
}
|
||||
const [enriched] = await withIssueLabels(tx, [issue]);
|
||||
return enriched;
|
||||
const [withRelations] = await withIssueRelationSummaries(companyId, [enriched], tx);
|
||||
return withRelations;
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue