Metadata-Version: 2.4
Name: ado-source-core
Version: 0.3.0
Summary: Read-only Azure DevOps API client and Pydantic models. OSS library shared by ado-scanner and Shyftport engines.
Project-URL: Homepage, https://github.com/n8group-oss/ado-source-core
Project-URL: Repository, https://github.com/n8group-oss/ado-source-core
Project-URL: Issues, https://github.com/n8group-oss/ado-source-core/issues
Author-email: n8group-oss <hello@n8group.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Requires-Python: >=3.11
Requires-Dist: httpx<1.0,>=0.27
Requires-Dist: pydantic-settings<3,>=2
Requires-Dist: pydantic<3.0,>=2.7
Requires-Dist: structlog<26,>=24
Provides-Extra: dev
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# ado-source-core

Read-only Azure DevOps API client and Pydantic models. OSS library (MIT-licensed) shared by:

- [`ado-scanner`](https://github.com/n8group-oss/ado-scanner) — standalone discovery CLI
- Shyftport engines that need to read from Azure DevOps

This library is **read-only**. It does not perform any writes against Azure DevOps. Migration-side writes live in proprietary code outside this package.

## Install

```bash
pip install ado-source-core
```

## Quickstart

```python
import asyncio
from ado_source_core import ADOClient, PATAuth

async def main():
    auth = PATAuth(token="your-pat")
    async with ADOClient(organization="myorg", auth=auth) as client:
        async for repo in client.list_repositories(project="MyProject"):
            print(repo.name, repo.default_branch)

asyncio.run(main())
```

## Cloud vs Server

`ado-source-core` ships two adapters:

- `AzureDevOpsCloudAdapter` — for Azure DevOps Services (`dev.azure.com/{org}`).
  REST API pinned to 7.1.
- `AzureDevOpsServerAdapter` — for self-hosted Azure DevOps Server (the
  on-prem product, formerly TFS). The REST api-version is auto-discovered
  when the client connects (`await client.connect()` or implicitly via
  `async with ADOServerClient(...)`) by probing `/_apis/connectionData`
  with candidate iteration as a fallback. Construction itself performs
  no network I/O.

### Supported Server versions

| Server release            | REST api-version |
| ------------------------- | ---------------- |
| Azure DevOps Server 2022  | 7.0              |
| Azure DevOps Server 2020  | 6.0              |
| Azure DevOps Server 2019 Update 1+ | 5.1     |
| Azure DevOps Server 2019 RTW | 5.0           |

TFS 2018 (REST 4.x) and earlier are out of scope for v0.3.0. Server
deployments with PATs disabled at the org-policy level (or NTLM-only
deployments behind enterprise SSO) are not supported — PAT support is
a hard prerequisite. NTLM/Negotiate auth is a v0.4.0 candidate.

### Server quickstart

```python
import asyncio
from ado_source_core import (
    ADOServerClient, AzureDevOpsServerAdapter, PATAuth,
    UnsupportedOnAzureDevOpsServerError,
)

async def main():
    auth = PATAuth(token="your-server-pat")
    async with ADOServerClient(
        base_url="https://devops.example.com:8080/tfs",
        collection="DefaultCollection",
        auth=auth,
    ) as client:
        adapter = AzureDevOpsServerAdapter(client=client)
        caps = await adapter.get_capabilities()
        print(f"Resolved api-version: {caps.api_version}")
        print(f"Notes: {caps.notes}")

        # Always-available calls work the same as on cloud:
        for project in await adapter.list_projects():
            print(project["name"])

        # Optional calls gate on capability flags:
        if caps.supports_graph_api:
            for user in await adapter.list_users():
                print(user.username)
        else:
            print("Graph extension not installed; user listing unavailable.")

        # Capabilities that don't exist on Server raise:
        try:
            await adapter.list_user_entitlements()
        except UnsupportedOnAzureDevOpsServerError as exc:
            print(f"Skipped {exc.capability}: {exc.remediation}")

asyncio.run(main())
```

### Capability matrix

Comprehensive flag-by-flag state across both adapters:

| Capability                      | Cloud | Server                                          | Notes                                                                  |
| ------------------------------- | ----- | ----------------------------------------------- | ---------------------------------------------------------------------- |
| `supports_collections`          | False | True                                            | Server is collection-scoped; cloud is org-scoped.                       |
| `supports_pipelines`            | True  | True                                            | Build defs + classic release defs both available.                       |
| `supports_pull_request_threads` | True  | True                                            | Available on Server 2019+.                                              |
| `supports_user_entitlements`    | True  | **False (hard)**                                | vsaex Member Entitlements API is cloud-only.                            |
| `supports_graph_api`            | True  | **Probed**                                      | Requires the Graph extension on Server.                                 |
| `supports_analytics_odata`      | True  | **Probed**                                      | Auto-installed on Server 2020+; manual install on Server 2019.          |
| `supports_artifact_feeds`       | True  | **Probed**                                      | Requires the Package Management extension on Server.                    |
| `compatibility_mode`            | False | True iff api-version is `5.0` or `5.1`          | Server 2019 (RTW or Update 1+) — adapter behavior unchanged; flag is informational. |

When a probe-resolvable capability is `False`, the corresponding adapter
methods raise `UnsupportedOnAzureDevOpsServerError` with `capability`,
`api_version`, and `remediation` fields populated for downstream
discovery reports.

## Status

Alpha. Stable enough for `ado-scanner` consumption; API may change before v1.0.

## License

MIT.
