Sync from dev @ 497baf0
Source: main (497baf0) Excluded: live tenant exports, generated artifacts, and dev-only tooling.
This commit is contained in:
86
scripts/trigger_backup_pipeline.py
Normal file
86
scripts/trigger_backup_pipeline.py
Normal file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Trigger an Azure DevOps pipeline run via REST API.
|
||||
|
||||
Intended to be invoked from the queue-consumer Azure Function or locally for testing.
|
||||
|
||||
Usage:
|
||||
python3 scripts/trigger_backup_pipeline.py \
|
||||
--organization "my-org" \
|
||||
--project "my-project" \
|
||||
--pipeline-id 123 \
|
||||
--token "$ADO_PAT" \
|
||||
--branch "main" \
|
||||
--parameters '{"forceFullRun": false}'
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
from scripts.common import request_json
|
||||
except ImportError:
|
||||
from common import request_json # type: ignore[no-redef]
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--organization", required=True)
|
||||
parser.add_argument("--project", required=True)
|
||||
parser.add_argument("--pipeline-id", type=int, required=True)
|
||||
parser.add_argument("--token", required=True, help="Azure DevOps PAT or OAuth token.")
|
||||
parser.add_argument("--branch", default="main", help="Git ref to run against.")
|
||||
parser.add_argument(
|
||||
"--parameters",
|
||||
default="{}",
|
||||
help='JSON object of pipeline template parameters (e.g. \'{"forceFullRun": true}\').',
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
|
||||
base_url = (
|
||||
f"https://dev.azure.com/{args.organization}/{args.project}"
|
||||
f"/_apis/pipelines/{args.pipeline_id}/runs?api-version=7.1"
|
||||
)
|
||||
|
||||
body: dict[str, Any] = {
|
||||
"resources": {
|
||||
"repositories": {
|
||||
"self": {"refName": f"refs/heads/{args.branch.lstrip('refs/heads/')}"}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
params = json.loads(args.parameters)
|
||||
if isinstance(params, dict) and params:
|
||||
body["templateParameters"] = params
|
||||
|
||||
# ADO REST API accepts Basic auth with an empty username and the PAT as password.
|
||||
import base64
|
||||
encoded = base64.b64encode(f":{args.token}".encode("utf-8")).decode("utf-8")
|
||||
auth_header = f"Basic {encoded}"
|
||||
|
||||
print(f"Triggering pipeline {args.pipeline_id} on branch {args.branch} ...")
|
||||
response = request_json(
|
||||
base_url,
|
||||
method="POST",
|
||||
body=body,
|
||||
headers={"Authorization": auth_header},
|
||||
timeout=30,
|
||||
max_retries=2,
|
||||
)
|
||||
|
||||
run_id = response.get("id")
|
||||
run_url = response.get("url")
|
||||
print(f"Queued run id={run_id} url={run_url}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user