verification
use it
# add to stunt.yaml
services:
azure-devops:
adapter: embedded:azure-devops-style
# then
$ stunt upThe embedded: source extracts this adapter from the binary — no git clone, fully offline.
how to mock the Azure DevOps REST API locally
Install stunt, paste the service block above into stunt.yaml, run stunt up — then point your client at localhost instead of Azure DevOps REST API. It works offline, keeps state across requests and restarts, and every response is synthetic: the route shapes, status codes, pagination, and webhook delivery follow the real Azure DevOps REST API 7.1 surface — the data is fake, the behavior is real.
backing stores
projectsreposworkitems
api surface (17)
generated from the adapter manifest — exactly what boots, nothing more · covers 5% of the real API's 305 routes (derived from spec vsts-rest-api-specs core 7.2 + pipelines/git/wit/hooks/work 7.1 @ 7.2-preview, 7.1, 7.1, 7.1, 7.1, 7.1)
17 routes
GET/{org}/_apis/projects
GET/{org}/{project}/_apis/pipelines
GET/{org}/{project}/_apis/pipelines/{pipelineId}
GET/{org}/{project}/_apis/pipelines/{pipelineId}/runs
POST/{org}/{project}/_apis/pipelines/{pipelineId}/runs
GET/{org}/{project}/_apis/pipelines/{pipelineId}/runs/{runId}
GET/{org}/{project}/_apis/git/repositories
GET/{org}/{project}/_apis/git/repositories/{repoId}/items
GET/{org}/{project}/_apis/git/repositories/{repoId}/commits
POST/{org}/{project}/_apis/git/repositories/{repoId}/pushes
GET/{org}/{project}/_apis/work/teamsettings/iterations
GET/{org}/{project}/_apis/wit/workitems
GET/{org}/{project}/_apis/wit/workitems/{id}
PATCH/{org}/{project}/_apis/wit/workitems/{id}
POST/{org}/{project}/_apis/wit/workitems/{type}
POST/{org}/{project}/_apis/wit/wiql
POST/{org}/_apis/hooks/subscriptions
VM-verified behaviors (23)
- ✓a missing, unknown, or non-PAT credential gets the UnauthorizedRequestException 401 envelope
- ✓both PAT wire forms — Basic base64(PAT:) and Bearer — authenticate
- ✓the projects list returns the two seeded projects in the Azure DevOps shape
- ✓$top/$skip walk pages each project exactly once via continuationToken, and a bad token 400s
- ✓creating on the typed route applies the patch document and defaults area/iteration
- ✓the fully-qualified $type route normalizes to the bare type
- ✓read-back returns the integer id; an unknown id is the WIT 404 envelope
- ✓a patch bumps rev, applies field ops, and refreshes audit fields
- ✓relations are added at - and removed by numeric index only
- ✓malformed patches answer the PatchOperationFailed / Argument envelopes
- ✓ids= returns the asked work items and fields= projects to those columns
- ✓WIQL ANDs string and numeric predicates and matches CONTAINS
- ✓ORDER BY sorts by the field and $top caps the result
- ✓OR and non-WorkItems FROM targets answer the 400 envelope
- ✓the repos list is scoped to the project
- ✓a push stores content that items serves at the branch and at a pinned commit
- ✓the commits list walks newest-first along the parent chain and filters by refName
- ✓git faults: unknown repo, missing path, unknown path, malformed versionDescriptor
- ✓pipelines list and get round-trip, and unknown ids answer 404
- ✓a queued run derives inProgress then completed from the clock, once each
- ✓simulate_fail drives the completed result to failed
- ✓a registered subscription receives the service-hook envelope when a work item is created
- ✓iterations list the two sprints and page under $top
Not implemented (8)
- No WIQL OR predicates, @Me/@Project macros, or non-WorkItems FROM targets
- No work-item comments, links/attachments, or revisions endpoints
- No project CRUD — projects are list-only
- No pipeline create/update or run artifacts/logs/approvals endpoints
- No repo create, refs/branch ops, pull requests, or tags
- No team-settings writes — iterations are list-only, no boards/columns
- No service-hook list/update/delete or publisher/consumer discovery
- No project-create and no pull-request routes (repos/pushes/commits/items only)
Differs from the real API (6)
- Run state derives from clock — inProgress at +1s, completed/succeeded at +3s
- simulate_fail run parameter (templateParameters or top-level) forces result failed
- Run-state webhooks may double-emit when list/bulk reads race single-run polls
- A non-JSON versionDescriptor is silently ignored (falls back to the default branch); real ADO 400s
- Items always returns the JSON envelope with inline content; real ADO serves raw bytes for single items
- A no-op replace patch skips the rev bump and audit fields
want more of the Azure DevOps REST API surface? adapters are YAML + Starlark — the authoring guide covers adding routes, fixtures, and state machines. Open an issue for anything big first, or just file a PR — merged routes ship in the next release.