devops_utils.core.azure_devops package

Submodules

Module contents

Azure DevOps REST helpers (cloud + on-prem Server).

Requires the azure extra (httpx); the dependency is deferred-imported so importing devops_utils never pulls it in when unused.

class devops_utils.core.azure_devops.AzureDevOpsClient(org_url: str, token: str, auth_scheme: str = 'bearer', api_version: str = '7.1', transport: Any | None = None)[source]

Bases: object

Thin wrapper over httpx for the Azure DevOps REST API.

Parameters:
  • org_url – Base URL. Cloud https://dev.azure.com/{org} or on-prem https://server/tfs/{collection}. A trailing slash is stripped.

  • token – Bearer token or Personal Access Token (see auth_scheme).

  • auth_scheme – "bearer" sends Authorization: Bearer <token>; "pat" sends Authorization: Basic base64(":" + token) which is how Azure DevOps expects a raw PAT.

  • api_version – REST api-version query value. Lower it for older on-prem servers (e.g. "6.0").

classmethod from_env() → AzureDevOpsClient[source]

Build a client from environment variables.

Reads AZURE_DEVOPS_ORG_URL and AZURE_DEVOPS_TOKEN (both required), and optional AZURE_DEVOPS_AUTH_SCHEME (default bearer) and AZURE_DEVOPS_API_VERSION (default 7.1).

request(method: str, path: str, *, params: dict[str, Any] | None = None, json: Any | None = None, content: bytes | None = None, content_type: str | None = None, api_version: str | None = None, base_url: str | None = None) → Any[source]

Perform a request and return the parsed JSON body (or None).

api-version is injected into the query string unless already present. base_url overrides org_url for APIs served from a different host (e.g. cloud code search on almsearch.dev.azure.com). Raises AzureDevOpsError for any non-2xx response.

exception devops_utils.core.azure_devops.AzureDevOpsError(status_code: int, method: str, url: str, body: str)[source]

Bases: RuntimeError

Raised when the Azure DevOps API returns a non-2xx response.

exception devops_utils.core.azure_devops.PlanError[source]

Bases: ValueError

A plan failed validation; the message lists every problem found.

devops_utils.core.azure_devops.add_attachment(client: AzureDevOpsClient, work_item_id: int, file_path: str, *, comment: str | None = None) → dict[str, Any][source]

Upload a local file and attach it to a work item (2-step).

devops_utils.core.azure_devops.add_build_tags(client: AzureDevOpsClient, project: str, build_id: int, tags: list[str]) → list[str][source]

Add tags to a build and return the build’s resulting tag list.

devops_utils.core.azure_devops.add_comment(client: AzureDevOpsClient, work_item_id: int, text: str) → dict[str, Any][source]

Add a comment to a work item via the System.History field.

Add a reference (relation) to a work item.

Parameters:
  • kind – One of commit, pull_request, branch (all need project + repo), build (value = build id), work_item / parent / child / predecessor / successor (value = target work-item id), or hyperlink (value = raw URL).

  • value – Commit SHA / PR id / branch name / build id / work-item id / URL per kind.

  • project – Team project (required for commit/pull_request/branch).

  • repo – Repository name or id (required for commit/pull_request/branch).

  • comment – Optional note stored on the relation.

devops_utils.core.azure_devops.apply_plan(client: AzureDevOpsClient, plan: dict[str, Any], *, stop_on_error: bool = False) → list[dict[str, Any]][source]

Apply a validated plan sequentially and return per-item results.

Each result is {"ref", "action", "status", "id", "url"} with status one of created/updated/failed (plus "error" when failed). A failed item never stops ref resolution bookkeeping; later items parented to it fail with a clear message instead of mis-parenting.

Parameters:

stop_on_error – When true, stop at the first failed item (already applied items stay applied — there is no rollback).

Search code content via the Search extension API.

Cloud (dev.azure.com) always has the extension; on-prem servers need the Code Search extension installed — without it this raises a clear error, and find_repo_items() / WIQL work-item search are the fallbacks.

Parameters:
  • text – Search text (supports the code-search syntax, e.g. def:Foo).

  • repo – Optional repository name to scope to.

  • branch – Optional branch to scope to.

  • top – Maximum number of results.

Returns:

A list of {path, repo, project, matches} dicts, where matches counts content hits in the file.

devops_utils.core.azure_devops.comment_on_pull_request(client: AzureDevOpsClient, project: str, repo: str, pull_request_id: int, text: str, *, thread_id: int | None = None) → dict[str, Any][source]

Comment on a pull request.

Without thread_id a new (active) comment thread is created; with it the comment is appended to that existing thread as a reply.

Returns a trimmed {thread_id, comment_id, status} dict.

devops_utils.core.azure_devops.create_work_item(client: AzureDevOpsClient, project: str, work_item_type: str, title: str, *, description: str | None = None, tags: list[str] | None = None, area_path: str | None = None, iteration_path: str | None = None, assigned_to: str | None = None, parent: int | None = None, fields: dict[str, Any] | None = None) → dict[str, Any][source]

Create a work item and return the trimmed result.

Parameters:
  • project – Team project name or id.

  • work_item_type – e.g. Bug, Task, User Story.

  • title – Work-item title (System.Title).

  • description – Optional System.Description (HTML).

  • tags – Optional list of tags.

  • iteration_path (area_path /) – Optional classification nodes.

  • assigned_to – Optional identity (email or display name).

  • parent – Optional parent work-item id; links the new item under it.

  • fields – Optional extra/custom fields as {reference_name: value}, e.g. {"Custom.RiskLevel": "High"}. Reference names are process or org specific; use the field’s reference name, not its display label. Applied after the named args above, so a key here overrides e.g. area_path if it targets System.AreaPath.

devops_utils.core.azure_devops.find_repo_items(client: AzureDevOpsClient, project: str, repo: str, *, path_pattern: str = '*', branch: str | None = None, top: int = 100) → list[dict[str, Any]][source]

Find files in a repository by path pattern (no Search extension needed).

Lists the full tree via the Git Items API and matches each path against path_pattern with fnmatch (* also crosses / here because a bare filename pattern like *.yml should match at any depth).

Parameters:
  • path_pattern – Glob matched against the repo-relative path (leading / stripped), e.g. *.yml or src/*/pipeline*.

  • branch – Optional branch to list (defaults to the repo default branch).

  • top – Maximum number of matches to return.

Returns:

A list of {path, size, commit, url} dicts for matching blobs.

devops_utils.core.azure_devops.get_build(client: AzureDevOpsClient, project: str, build_id: int) → dict[str, Any][source]

Fetch a single build by id (trimmed).

devops_utils.core.azure_devops.get_build_log(client: AzureDevOpsClient, project: str, build_id: int, log_id: int, *, start_line: int | None = None, end_line: int | None = None) → str[source]

Fetch a build log’s content as plain text.

Parameters:

end_line (start_line /) – Optional line range. To tail, set start_line to line_count - N (from list_build_logs()).

devops_utils.core.azure_devops.get_build_timeline(client: AzureDevOpsClient, project: str, build_id: int) → list[dict[str, Any]][source]

Fetch a build’s timeline: its stages/phases/jobs/tasks with status.

Each record carries a log_id (when the step produced a log) that can be passed to get_build_log(), and issues with the step’s error and warning messages — the fastest way to locate why a run failed.

Returns:

Timeline records sorted by their order, trimmed to {id, parent_id, type, name, state, result, log_id, start_time, finish_time, issues}.

devops_utils.core.azure_devops.get_work_item(client: AzureDevOpsClient, work_item_id: int, *, relations: bool = False, full: bool = False) → dict[str, Any][source]

Fetch a single work item (trimmed).

Parameters:
  • relations – When true, include the item’s relations (parent/child links, related work items, hyperlinks, attachments, artifact links) as a relations list of {kind, target, ...} dicts.

  • full –

    When true, add the item’s complete raw fields mapping (keyed by field reference name) plus its rev. The trimmed keys stay put; this is the only way to read a description, a scheduling date, or a Custom.* field that _trim() drops, and rev is what a caller needs for a concurrency-safe follow-up patch.

    The whole response body already carries these — no extra request and no REST fields= selector, which matters because fields= and $expand are mutually exclusive server-side (undocumented; it surfaces only as a runtime 400). Reading the default body instead keeps full and relations freely composable.

devops_utils.core.azure_devops.list_build_logs(client: AzureDevOpsClient, project: str, build_id: int) → list[dict[str, Any]][source]

List a build’s logs as {id, line_count} entries.

Use line_count with get_build_log()’s start_line to tail a large log instead of downloading it whole.

devops_utils.core.azure_devops.list_builds(client: AzureDevOpsClient, project: str, *, definitions: list[int] | None = None, branch: str | None = None, statuses: list[str] | None = None, results: list[str] | None = None, top: int = 25) → list[dict[str, Any]][source]

List builds in a project, newest first (API default order).

Parameters:
  • definitions – Optional pipeline definition ids to filter on.

  • branch – Optional source branch (short names get refs/heads/ prefixed).

  • statuses – Optional status filter values (inProgress, completed, notStarted, cancelling, postponed).

  • results – Optional result filter values (succeeded, partiallySucceeded, failed, canceled).

  • top – Maximum number of builds to return.

devops_utils.core.azure_devops.list_definitions(client: AzureDevOpsClient, project: str, *, name: str | None = None, top: int = 25) → list[dict[str, Any]][source]

List build (pipeline) definitions in a project.

Parameters:
  • name – Optional definition name filter; * wildcards are supported by the API (e.g. CI*).

  • top – Maximum number of definitions to return.

devops_utils.core.azure_devops.list_repositories(client: AzureDevOpsClient, project: str | None = None, *, name_filter: str | None = None) → list[dict[str, Any]][source]

List Git repositories, optionally scoped to a single project.

Parameters:

name_filter – Optional case-insensitive substring to filter repo names by.

Returns a trimmed list of {id, name, project, default_branch, web_url}.

devops_utils.core.azure_devops.list_work_items(client: AzureDevOpsClient, project: str, *, states: list[str] | None = None, types: list[str] | None = None, assigned_to: str | None = None, tags: list[str] | None = None, parent: int | None = None, area_path: str | None = None, iteration_path: str | None = None, top: int = 50) → list[dict[str, Any]][source]

List work items in a project, optionally filtered by state/type/assignee/tags.

assigned_to="@Me" uses the WIQL @Me macro, resolving the identity behind the token server-side. Each tag becomes an AND-joined [System.Tags] CONTAINS clause. parent matches direct children of that work item via [System.Parent] (Azure DevOps Services / Server 2019.1+). area_path/iteration_path match the given node and everything under it (Azure Boards area/iteration tree).

devops_utils.core.azure_devops.load_plan(text: str) → dict[str, Any][source]

Parse a YAML (or JSON — a YAML subset) plan document.

devops_utils.core.azure_devops.plan_preview(items: list[dict[str, Any]]) → list[dict[str, Any]][source]

Summarize normalized items for the human review window (no requests).

devops_utils.core.azure_devops.query_wiql(client: AzureDevOpsClient, project: str, wiql: str, top: int = 50) → list[int][source]

Run a WIQL query and return the matching work-item ids.

Remove a reference (relation) from a work item.

Accepts the same kind/value pairs as add_link(). The relation is located by matching its rel type and URL, then removed by index with a guarding test op (the REST API only removes relations by index).

Raises:

ValueError – If no matching relation exists on the work item.

devops_utils.core.azure_devops.resolve_repo(client: AzureDevOpsClient, project: str, repo: str) → dict[str, str][source]

Look up a repository by id or name and return its ids.

Returns {"project_id": ..., "repo_id": ...}. Both GUIDs are needed to build the vstfs:// artifact URIs used for commit/PR/branch links.

devops_utils.core.azure_devops.search_work_items(client: AzureDevOpsClient, project: str, text: str, *, states: list[str] | None = None, types: list[str] | None = None, assigned_to: str | None = None, tags: list[str] | None = None, parent: int | None = None, area_path: str | None = None, iteration_path: str | None = None, top: int = 50) → list[dict[str, Any]][source]

Text-search work items by title/description using WIQL CONTAINS.

Supports the same assigned_to (incl. @Me), tags, parent, area_path, and iteration_path filters as list_work_items().

devops_utils.core.azure_devops.set_tags(client: AzureDevOpsClient, work_item_id: int, tags: list[str], mode: str = 'add') → dict[str, Any][source]

Set work-item tags.

Parameters:
  • tags – Tags to apply.

  • mode – "add" merges with existing tags; "replace" overwrites.

devops_utils.core.azure_devops.update_work_item(client: AzureDevOpsClient, work_item_id: int, *, state: str | None = None, assigned_to: str | None = None, title: str | None = None, description: str | None = None, area_path: str | None = None, iteration_path: str | None = None, fields: dict[str, Any] | None = None) → dict[str, Any][source]

Update mutable fields of an existing work item.

Parameters:
  • state – New System.State (process-template-specific, e.g. Closed, Done, Resolved).

  • assigned_to – New assignee identity (email or display name).

  • title – New System.Title.

  • description – New System.Description (HTML).

  • area_path – New System.AreaPath (e.g. Project\Team), used to move the item between Azure Boards areas.

  • iteration_path – New System.IterationPath (e.g. Project\Sprint 3), used to move the item between sprints.

  • fields – Optional extra/custom fields as {reference_name: value}, e.g. {"Custom.RiskLevel": "High"}. Reference names are process or org specific; use the field’s reference name, not its display label. Applied after the named args above, so a key here overrides e.g. state if it targets System.State.

Raises:

ValueError – If no field to update was given.

devops_utils.core.azure_devops.validate_plan(plan: dict[str, Any]) → tuple[list[dict[str, Any]], list[str]][source]

Normalize and validate a plan.

Merges defaults into every item (item values win; the two fields maps are merged key-wise), resolves the effective project, and checks ordering of ref: references.

Returns:

(items, warnings) — the normalized items in application order and human-readable warnings (unknown keys, …) for the review window.

Raises:

PlanError – With every hard problem found, one per line.