Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions eng/pipelines/templates/jobs/apireview-hub-job-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Python job wrapper for API Review Hub requests. This file owns Python-specific
# setup and delegates shared job boilerplate to the base API Review Hub job.
# The caller supplies the create/update orchestration steps.
parameters:
- name: poolName
type: string
default: 'azsdk-pool'
- name: imageOverride
type: string
default: 'ubuntu-24.04'
- name: repositoryOwner
type: string
default: 'Azure'
- name: toolRef
type: string
default: 'main'
- name: pythonVersion
type: string
default: '3.12'
- name: steps
type: stepList
default: []

jobs:
- template: /eng/common/pipelines/templates/jobs/apireview-hub-job-base.yml
parameters:
jobName: CreatePythonApiReviewArtifacts
displayName: 'Create Python API review artifacts'
poolName: ${{ parameters.poolName }}
imageOverride: ${{ parameters.imageOverride }}
sourceRepositoryFullName: ${{ format('{0}/azure-sdk-for-python', parameters.repositoryOwner) }}
sourceCheckoutDir: $(Pipeline.Workspace)/apireview/source
setupSteps:
- task: UsePythonVersion@0
displayName: 'Use Python ${{ parameters.pythonVersion }}'
inputs:
versionSpec: ${{ parameters.pythonVersion }}

# Install Python API review tooling once for the job. The base and target
# generation steps reuse this prepared environment.
- bash: |
set -Eeuo pipefail

source_repo="$(ApiReviewSourceDir)"
tooling_dir="$(ApiReviewToolingDir)"
requirements_file="$source_repo/eng/apiview_reqs.txt"
azpysdk_package="$source_repo/eng/tools/azure-sdk-tools[build]"

echo "Checking out Python API review tooling requirements from ${{ parameters.toolRef }}"
git -C "$source_repo" fetch --depth=1 origin "${{ parameters.toolRef }}"
git -C "$source_repo" checkout --force FETCH_HEAD
git -C "$source_repo" clean -ffd

if [ ! -f "$requirements_file" ]; then
echo "Expected Python API review requirements file was not found at $requirements_file" >&2
exit 1
fi

mkdir -p "$tooling_dir/eng/common/scripts" "$tooling_dir/eng/scripts"
cp "$source_repo/eng/common/scripts/Export-APIViewMarkdown.ps1" "$tooling_dir/eng/common/scripts/Export-APIViewMarkdown.ps1"
cp "$source_repo/eng/scripts/Extract-APIViewMetadata-Python.ps1" "$tooling_dir/eng/scripts/Extract-APIViewMetadata-Python.ps1"

python -m pip install --upgrade pip
python -m pip install virtualenv

echo "Installing Python API review requirements from $requirements_file"
python -m pip install -r "$requirements_file" --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/"

echo "Installing azpysdk tooling from ${{ parameters.toolRef }}"
python -m pip install "$azpysdk_package"

echo "Installing setuptools runtime dependency for Python SDK common_tasks.py"
python -m pip install "setuptools<81"
PYTHONPATH="$source_repo/scripts/devops_tasks${PYTHONPATH:+:$PYTHONPATH}" python -c "import common_tasks; import pkg_resources; import azpysdk.main"
displayName: 'Install Python API review tooling'
steps: ${{ parameters.steps }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Generate one Python API review artifact bundle for one ref. This template
# supplies Python-specific generation and delegates shared artifact validation
# and metadata writing to the base API Review Hub artifact template.
parameters:
- name: requestMode
type: string
- name: operationId
type: string
- name: packageName
type: string
- name: ref
type: string
- name: kind
type: string
- name: outputDir
type: string
- name: workingDir
type: string
steps:
- template: /eng/common/pipelines/templates/steps/create-apireview-hub-artifacts-base.yml
parameters:
requestMode: ${{ parameters.requestMode }}
operationId: ${{ parameters.operationId }}
packageName: ${{ parameters.packageName }}
ref: ${{ parameters.ref }}
kind: ${{ parameters.kind }}
outputDir: ${{ parameters.outputDir }}
workingDir: ${{ parameters.workingDir }}
sourceDir: $(ApiReviewSourceDir)
language: python
repositoryFullName: $(ApiReviewRepositoryFullName)
generationSteps:
- bash: |
set -Eeuo pipefail

source_repo="$(ApiReviewSourceDir)"
tooling_dir="$(ApiReviewToolingDir)"
output_dir="${{ parameters.outputDir }}"
state_dir="${{ parameters.workingDir }}/state"

mkdir -p "$source_repo" "$output_dir" "$state_dir"

find_package_dir() {
local repo="$1"
local package_name="$2"
local matches

matches=$(find "$repo/sdk" -mindepth 2 -maxdepth 2 -type d -name "$package_name" | sort)
if [ -z "$matches" ]; then
echo "Package '$package_name' was not found under sdk/*/." >&2
return 1
fi

if [ "$(printf '%s\n' "$matches" | wc -l)" -ne 1 ]; then
echo "Package '$package_name' matched multiple directories:" >&2
printf '%s\n' "$matches" >&2
return 1
fi

printf '%s' "$matches"
}

package_dir=$(find_package_dir "$source_repo" "${{ parameters.packageName }}")
package_relative_path=$(realpath --relative-to="$source_repo" "$package_dir")

echo "Generating ${{ parameters.kind }} API review artifact from ${{ parameters.ref }}"
Comment on lines +63 to +66
common_tasks_dir="$source_repo/scripts/devops_tasks"
if [ ! -f "$common_tasks_dir/common_tasks.py" ]; then
echo "Expected Python SDK common_tasks.py was not found at $common_tasks_dir/common_tasks.py" >&2
exit 1
fi
install -D "$tooling_dir/eng/common/scripts/Export-APIViewMarkdown.ps1" "$source_repo/eng/common/scripts/Export-APIViewMarkdown.ps1"
install -D "$tooling_dir/eng/scripts/Extract-APIViewMetadata-Python.ps1" "$source_repo/eng/scripts/Extract-APIViewMetadata-Python.ps1"
(cd "$source_repo" && PYTHONPATH="$common_tasks_dir${PYTHONPATH:+:$PYTHONPATH}" python -m azpysdk.main apistub --dest-dir "$package_dir" "${{ parameters.packageName }}")

if [ ! -f "$package_dir/api.md" ]; then
echo "Expected api.md was not generated at $package_dir/api.md" >&2
exit 1
fi
if [ ! -f "$package_dir/api.metadata.yml" ]; then
echo "Expected api.metadata.yml was not generated at $package_dir/api.metadata.yml" >&2
exit 1
fi

cp "$package_dir/api.md" "$output_dir/api.md"
cp "$package_dir/api.metadata.yml" "$output_dir/api.metadata.yml"

version=$(python -c 'import pathlib, re, sys; package_dir = pathlib.Path(sys.argv[1]); pattern = re.compile(r"^\s*VERSION\s*[:=]\s*[\"'"'"']([^\"'"'"']+)[\"'"'"']", re.MULTILINE); candidates = sorted(package_dir.rglob("*_version.py")) + sorted(package_dir.rglob("version.py")); match = next((pattern.search(candidate.read_text(encoding="utf-8")) for candidate in candidates if "_generated" not in candidate.parts and pattern.search(candidate.read_text(encoding="utf-8"))), None); print(match.group(1) if match else "")' "$package_dir")
printf '%s' "$package_relative_path" > "$state_dir/package-relative-path.txt"
printf '%s' "$version" > "$state_dir/version.txt"
displayName: 'Generate ${{ parameters.kind }} Python API review bundle'
Loading