* Builds a work item document. Work items are returned inline (not deferred) * because the batch fetch already includes all field content. The contentHash * uses the work item revision, which increments on every change. HTML-bearing * fields (description, repro steps, acceptance criteria) are str
( organization: string, project: string, raw: RawWorkItem )
| 443 | * fields (description, repro steps, acceptance criteria) are stripped to text. |
| 444 | */ |
| 445 | function workItemToDocument( |
| 446 | organization: string, |
| 447 | project: string, |
| 448 | raw: RawWorkItem |
| 449 | ): ExternalDocument { |
| 450 | const fields = raw.fields ?? {} |
| 451 | const title = (fields['System.Title'] as string | undefined) ?? `Work Item ${raw.id}` |
| 452 | const workItemType = (fields['System.WorkItemType'] as string | undefined) ?? '' |
| 453 | const state = (fields['System.State'] as string | undefined) ?? '' |
| 454 | const rev = resolveWorkItemRev(raw, fields) |
| 455 | const changedDate = (fields['System.ChangedDate'] as string | undefined) ?? '' |
| 456 | const areaPath = (fields['System.AreaPath'] as string | undefined) ?? '' |
| 457 | const iterationPath = (fields['System.IterationPath'] as string | undefined) ?? '' |
| 458 | const rawTags = (fields['System.Tags'] as string | undefined) ?? '' |
| 459 | const tags = rawTags |
| 460 | .split(';') |
| 461 | .map((t) => t.trim()) |
| 462 | .filter(Boolean) |
| 463 | const description = htmlToPlainText((fields['System.Description'] as string | undefined) ?? '') |
| 464 | const reproSteps = htmlToPlainText( |
| 465 | (fields['Microsoft.VSTS.TCM.ReproSteps'] as string | undefined) ?? '' |
| 466 | ) |
| 467 | const acceptanceCriteria = htmlToPlainText( |
| 468 | (fields['Microsoft.VSTS.Common.AcceptanceCriteria'] as string | undefined) ?? '' |
| 469 | ) |
| 470 | |
| 471 | const contentParts: string[] = [`Title: ${title}`, `Type: ${workItemType}`, `State: ${state}`] |
| 472 | if (tags.length > 0) contentParts.push(`Tags: ${tags.join(', ')}`) |
| 473 | if (description) contentParts.push('', 'Description:', description) |
| 474 | if (reproSteps) contentParts.push('', 'Repro Steps:', reproSteps) |
| 475 | if (acceptanceCriteria) contentParts.push('', 'Acceptance Criteria:', acceptanceCriteria) |
| 476 | |
| 477 | return { |
| 478 | externalId: workItemExternalId(raw.id), |
| 479 | title: `#${raw.id}: ${title}`, |
| 480 | content: contentParts.join('\n'), |
| 481 | contentDeferred: false, |
| 482 | mimeType: 'text/plain', |
| 483 | sourceUrl: `${ADO_BASE_URL}/${encodeURIComponent(organization)}/${encodeURIComponent(project)}/_workitems/edit/${raw.id}`, |
| 484 | contentHash: `ado:wi:${raw.id}:${rev}`, |
| 485 | metadata: { |
| 486 | kind: 'workitem', |
| 487 | organization, |
| 488 | project, |
| 489 | workItemId: raw.id, |
| 490 | workItemType, |
| 491 | state, |
| 492 | areaPath, |
| 493 | iterationPath, |
| 494 | tags, |
| 495 | changedDate, |
| 496 | rev, |
| 497 | }, |
| 498 | } |
| 499 | } |
| 500 | |
| 501 | /** |
| 502 | * Reads the work-item filter configuration from sourceConfig. |
no test coverage detected