はじめに
-
目的
- Azure DevOps の Pull Request(PR)から 差分ファイル一覧 を取得
-
test
を含むファイルを除外し、CSV にエクスポート - CI/CD やリリースノート作成の自動化に便利
フォルダ構成
PR-tool/
├─ get_PR_filename.py # 差分取得スクリプト(本記事で解説)
└─ run_get_PR_filename.bat # Windows 1クリック実行用
前提条件
項目 | バージョン・備考 |
---|---|
Python | 3.8 以上 |
追加ライブラリ | requests |
Azure DevOps | PAT (Personal Access Token) 発行済み レポジトリの Read 権限 があれば OK |
PAT の発行手順
1.Azure DevOps → User Settings → Personal access tokens
2.New Token を押下
3.Scopes で “Code (Read)” を有効
4.“Create” → トークンが表示されるのでコピー
5.絶対に Git 等へコミットしないこと!
get_PR_filename.py(サンプル)
import sys
import os
import csv
import requests
from datetime import datetime
from requests.auth import HTTPBasicAuth
def getLatestIterationId(org, project, repo, pr_id, headers, auth):
url = (
f"https://dev.azure.com/{org}/{project}"
f"/_apis/git/repositories/{repo}/pullRequests/{pr_id}/iterations?api-version=7.0"
)
response = requests.get(url, headers=headers, auth=auth)
response.raise_for_status()
iterations = response.json().get("value", [])
if not iterations:
raise Exception(f"No iterations found for PR#{pr_id}")
return max(i["id"] for i in iterations)
def getPullRequestChanges(org, project, repo, pr_id, iteration_id, headers, auth):
url = (
f"https://dev.azure.com/{org}/{project}"
f"/_apis/git/repositories/{repo}/pullRequests/{pr_id}/iterations/{iteration_id}/changes"
"?$top=1000&api-version=7.0"
)
response = requests.get(url, headers=headers, auth=auth)
response.raise_for_status()
return response.json().get("changes", []) # 正しいキーは "changes"
def is_excluded(path):
lower_path = path.lower()
return (
"test" in lower_path
or "/stub" in lower_path
or (path.endswith(".yml") and (
path.count("/") == 1 or path.startswith("/azure-pipelines/")
))
)
def write_csv(pr_id, changes, output_folder):
filtered_changes = [
c for c in changes if c.get("item", {}).get("path") and not is_excluded(c["item"]["path"])
]
if not filtered_changes:
print("[NO_CHANGES]")
return None
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
output_path = os.path.join(output_folder, f"PR_{pr_id}_{timestamp}.csv")
try:
with open(output_path, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["FolderPath", "FileName", "ChangeType"])
for change in filtered_changes:
path = change["item"]["path"]
folder, filename = os.path.split(path)
writer.writerow([folder, filename, change.get("changeType", "")])
except IOError as e:
print(f"File write error: {e}")
return None
print(f"CSV saved to: {output_path}")
return output_path
def main():
if len(sys.argv) < 6:
print("Usage: script.py <ORG> <PROJECT> <REPO> <PR_ID> <PAT>")
sys.exit(1)
org = sys.argv[1]
project = sys.argv[2]
repo = sys.argv[3]
pr_id = sys.argv[4]
pat = sys.argv[5]
script_path = sys.argv[0]
base_dir = os.path.dirname(os.path.abspath(script_path))
output_dir = os.path.join(base_dir, "csv")
os.makedirs(output_dir, exist_ok=True)
headers = {"Content-Type": "application/json"}
auth = HTTPBasicAuth("", pat)
try:
iteration_id = getLatestIterationId(org, project, repo, pr_id, headers, auth)
changes = getPullRequestChanges(org, project, repo, pr_id, iteration_id, headers, auth)
csv_path = write_csv(pr_id, changes, output_dir)
if csv_path:
print(f"[CSV_PATH]{csv_path}")
except requests.HTTPError as e:
print(f"HTTP error: {e.response.status_code} {e.response.text}")
sys.exit(1)
except Exception as e:
print(f"Unhandled exception: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
run_get_PR_filename.bat
@echo off
REM === Azure DevOps PR 差分取得ツール ===
REM --- 環境変数 AZURE_PAT から PAT を取得 ---
set PAT=%AZURE_PAT%
REM --- その他引数 ---
set ORG=my-org
set PROJECT=my-project
set REPO=my-repo
set PR_ID=12345
REM --- 環境変数 PAT が設定されているか確認 ---
if "%PAT%"=="" (
echo Error: AZURE_PAT environment variable is not set.
pause
exit /b 1
)
REM --- スクリプト実行(PATは環境変数から取得)---
python get_PR_filename.py %ORG% %PROJECT% %REPO% %PR_ID% %PAT%
pause
使い方
1.リポジトリ複製
git clone https://github.com/your-name/PR-tool.git
cd PR-tool
2.依存ライブラリのインストール
pip install requests
# または: pip install -r requirements.txt
3.スクリプト実行
Windows: run_get_PR_filename.bat をダブルクリック
CLI: python get_PR_filename.py
4.生成物確認
ルートに PR_files_YYYYMMDDhhmmss.csv が出力
カラム: FolderPath, FileName, ChangeType
😲 ハマりどころメモ
🔒 401 Unauthorized
- 原因
- PAT の権限不足
- または有効期限切れ
- 対策
- Azure DevOps で新しい PAT を発行し、スクリプトの環境変数に設定し直す
📂 404 Not Found
- 原因
- project / repository / pull_request_id のいずれかが間違っている
- 対策
- Azure DevOps の URL を確認し、正しい値を設定
📦 取得件数が 0
- 原因
- PR の source と target ブランチが正しく指定されていない
- 対策
- sourceRefName と targetRefName を API レスポンスから確認
🚨 デフォルトで 100 件しか取得できない
- 原因
- Azure DevOps API の diffs/commits はデフォルトで最大 100 件までしか返さない
- 対策
- パラメータに ?$top=1000 を指定する
- 1,000 件を超える場合は x-ms-continuationtoken を使い、ページネーション処理で繰り返し取得する(このスクリプトは対応済み)
おわりに
- PAT は ハードコードしない / Git に上げない
- 差分一覧を活用し、リリースノート生成や CI の品質チェックを自動化
- 気づきや改善点があればコメントでぜひ共有してください 🙌