From 7243c0433f352c609e1b51fc0fa93d8cb18906fc Mon Sep 17 00:00:00 2001 From: Slawomir Koszewski Date: Sat, 1 Nov 2025 18:48:09 +0100 Subject: [PATCH] Add initial implementation of DevOps client and harvester script --- devops.py | 26 ++++++++++++++++++++++++++ harvester.py | 14 ++++++++++++++ requirements.txt | 1 + 3 files changed, 41 insertions(+) create mode 100644 devops.py create mode 100755 harvester.py create mode 100644 requirements.txt diff --git a/devops.py b/devops.py new file mode 100644 index 0000000..9362bf7 --- /dev/null +++ b/devops.py @@ -0,0 +1,26 @@ +import requests +from urllib.parse import urljoin + +DEVOPS_SCOPE = "https://app.vssps.visualstudio.com/.default" +DEVOPS_API_VERSION = "7.1" + +class Client: + def __init__(self, org_url: str, token: str, api_version: str = DEVOPS_API_VERSION): + self._org_url = org_url + self._token = token + self._api_version = api_version + + def get(self, url: str, params: dict = {}): + p = { + "api-version": self._api_version, + **params + } + r = requests.get(url=urljoin(self._org_url, url), params=p, headers={ + "Authorization": f"Bearer {self._token}" + }) + return r + + def get_projects(self): + r = self.get("_apis/projects") + r.raise_for_status() + return r.json() diff --git a/harvester.py b/harvester.py new file mode 100755 index 0000000..cff0627 --- /dev/null +++ b/harvester.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +from devops import Client, DEVOPS_SCOPE +from azure.identity import DefaultAzureCredential +from json import dumps + +def main(): + token = DefaultAzureCredential().get_token(DEVOPS_SCOPE).token + client = Client("https://dev.azure.com/mcovsandbox/", token) + projects = client.get_projects() + print(dumps(projects, indent=2)) + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..43a1acd --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +azure-identity