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
13 changes: 1 addition & 12 deletions api/team-directory.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
import { get } from './lmdb-store.ts'

// Matches the `Person` shape from tickets.ts (issue 1, a separate branch as
// of this issue) — duplicated rather than imported since this issue has no
// dependency on it.
export type Person = {
id: string
name: string
emails: string[]
githubLogin?: string
discordId?: string
jiraAccountId?: string
}
import type { Person } from './tickets.ts'

export type PersonLink = {
githubLogin?: string
Expand Down
76 changes: 76 additions & 0 deletions api/tickets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,41 @@ describe('deriveStatus', () => {
it('defaults to todo with no recognizable signal', () => {
assertEquals(deriveStatus([]), 'todo')
})

it('is in_progress while any PR is open, even next to a merged one', () => {
assertEquals(
deriveStatus([
jiraItem({ status: 'Done' }),
githubItem({ status: 'merged' }),
githubItem({ externalId: 'gh-2', status: 'open' }),
]),
'in_progress',
)
})

it('is done when a PR is merged after another was closed unmerged', () => {
assertEquals(
deriveStatus([
jiraItem({ status: 'In Progress' }),
githubItem({ status: 'closed' }),
githubItem({ externalId: 'gh-2', status: 'merged' }),
]),
'done',
)
})

it('does not count an open github issue as work in progress', () => {
assertEquals(
deriveStatus([
jiraItem({ status: 'To Do' }),
githubItem({
externalUrl: 'https://github.com/01edu/license-hub/issues/2',
status: 'open',
}),
]),
'todo',
)
})
})

describe('resolvePerson', () => {
Expand Down Expand Up @@ -173,6 +208,47 @@ describe('groupIntoTickets', () => {
assertEquals(tickets[0].assignees.map((p) => p.id), ['p1'])
})

it('merges the items of all three providers sharing a key', () => {
const tickets = groupIntoTickets(
[jiraItem(), githubItem({ status: 'open' }), discordItem()],
directory,
)

assertEquals(tickets.length, 1)
assertEquals(tickets[0].items.map((item) => item.source), [
'jira',
'github',
'discord',
])
})

const statusCases: [string, string, string][] = [
['To Do', 'open', 'in_progress'],
['In Progress', 'open', 'in_progress'],
['In Progress', 'merged', 'done'],
]
for (const [jiraStatus, prStatus, expected] of statusCases) {
it(`deduces ${expected} from jira ${jiraStatus} + PR ${prStatus}`, () => {
const [ticket] = groupIntoTickets(
[jiraItem({ status: jiraStatus }), githubItem({ status: prStatus })],
directory,
)
assertEquals(ticket.status, expected)
})
}

it('resolves reviewers to deduped people and drops unknown refs', () => {
const tickets = groupIntoTickets(
[
githubItem({ reviewerRefs: [{ login: 'ada' }, { login: 'stranger' }] }),
githubItem({ externalId: 'gh-2', reviewerRefs: [{ login: 'ada' }] }),
],
directory,
)

assertEquals(tickets[0].reviewers, [directory[0]])
})

it('keeps an unkeyed item as its own single-item ticket', () => {
const unkeyed = githubItem({ title: 'Fix login bug' })
const tickets = groupIntoTickets([unkeyed], [])
Expand Down
15 changes: 12 additions & 3 deletions api/tickets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,19 @@ const JIRA_STATUS_MAP: Record<string, TicketStatus> = {
const mapJiraStatus = (status?: string): TicketStatus | undefined =>
status ? JIRA_STATUS_MAP[status.toLowerCase()] : undefined

// a github issue is only a placeholder, a PR is the evidence of real work
const isPullRequest = (item: WorkItem): boolean =>
item.source === 'github' && item.externalUrl.includes('/pull/')

const isOpen = (item: WorkItem): boolean => item.status === 'open'
const isMerged = (item: WorkItem): boolean => item.status === 'merged'

export const deriveStatus = (items: WorkItem[]): TicketStatus => {
const pr = items.find((item) => item.source === 'github')
if (pr?.status === 'merged') return 'done'
if (pr?.status === 'open') return 'in_progress'
// one key can carry several PRs (a follow-up, an abandoned first try):
// any still open means work is ongoing, otherwise any merged one is done
const prs = items.filter(isPullRequest)
if (prs.some(isOpen)) return 'in_progress'
if (prs.some(isMerged)) return 'done'
const jira = items.find((item) => item.source === 'jira')
return mapJiraStatus(jira?.status) ?? 'todo'
}
Expand Down
Loading