* Runs a WIQL query for work items in the project and returns their IDs. * WIQL itself is not paginated and returns at most 20,000 ids; pagination * happens over the resulting ID list via the workitemsbatch endpoint.
( accessToken: string, organization: string, project: string, wiql: string, top: number = WIQL_MAX_RESULTS )
| 570 | * happens over the resulting ID list via the workitemsbatch endpoint. |
| 571 | */ |
| 572 | async function queryWorkItemIds( |
| 573 | accessToken: string, |
| 574 | organization: string, |
| 575 | project: string, |
| 576 | wiql: string, |
| 577 | top: number = WIQL_MAX_RESULTS |
| 578 | ): Promise<number[]> { |
| 579 | const url = `${ADO_BASE_URL}/${encodeURIComponent(organization)}/${encodeURIComponent(project)}/_apis/wit/wiql?$top=${top}&api-version=${WIQL_API_VERSION}` |
| 580 | const response = await fetchWithRetry(url, { |
| 581 | method: 'POST', |
| 582 | headers: { |
| 583 | Accept: 'application/json', |
| 584 | 'Content-Type': 'application/json', |
| 585 | Authorization: patAuthHeader(accessToken), |
| 586 | }, |
| 587 | body: JSON.stringify({ query: wiql }), |
| 588 | }) |
| 589 | if (!response.ok) { |
| 590 | const errorText = await response.text().catch(() => '') |
| 591 | logger.error('Failed to query Azure DevOps work items', { |
| 592 | status: response.status, |
| 593 | error: errorText, |
| 594 | }) |
| 595 | throw new Error(`Failed to query work items: ${response.status}`) |
| 596 | } |
| 597 | const data = await response.json() |
| 598 | const refs = (data.workItems as WorkItemRef[] | undefined) ?? [] |
| 599 | if (refs.length >= WIQL_MAX_RESULTS) { |
| 600 | logger.warn('WIQL result hit the 20,000-item cap; narrow work-item filters to sync all items', { |
| 601 | organization, |
| 602 | project, |
| 603 | }) |
| 604 | } |
| 605 | return refs.map((ref) => ref.id) |
| 606 | } |
| 607 | |
| 608 | /** |
| 609 | * Fetches full field details for a batch of work item IDs (max 200 per call). |
no test coverage detected