--- name: azure-devops-pipelines description: Manage Azure DevOps build pipelines, release pipelines, pipeline runs, deployments, and pull requests via Azure CLI. Trigger builds, create releases, approve/vote on PRs, merge PRs, manage reviewers, monitor status, and manage artifacts. --- # Azure DevOps Pipelines ## Prerequisites ```bash # Install Azure CLI extension az extension add --name azure-devops az extension update --name azure-devops # Auth: interactive login az login # Auth: PAT-based login az devops login --organization https://dev.azure.com/ORG # Then paste your PAT when prompted # Set defaults (avoids passing --org and --project every time) az devops configure --defaults organization=https://dev.azure.com/ORG project=PROJECT ``` ## Common Flags Every command below supports these global flags. Omitted from examples for brevity: | Flag | Purpose | |------|---------| | `--org URL` | Override default organization | | `--project NAME` | Override default project | | `--detect false` | Disable auto-detection from git remote (recommended in scripts) | | `--output table` | Human-readable output | | `--output json` | Machine-readable output | | `--query JMESPATH` | Filter JSON output | --- ## 1. YAML Pipelines (Modern) ### Run a pipeline ```bash # By name az pipelines run --name "MyPipeline" # By ID az pipelines run --id 42 # With branch az pipelines run --name "MyPipeline" --branch refs/heads/feature/xyz # With variables az pipelines run --name "MyPipeline" --variables "env=staging" "debug=true" # With parameters (template parameters) az pipelines run --name "MyPipeline" --parameters "image=ubuntu-latest" "pool=MyPool" # With commit az pipelines run --name "MyPipeline" --commit-id abc123def # Open in browser after queuing az pipelines run --name "MyPipeline" --open ``` ### List pipelines ```bash # All pipelines az pipelines list --output table # Filter by name (supports wildcards) az pipelines list --name "Deploy*" --output table # Filter by folder az pipelines list --folder-path "production" --top 20 # Get pipeline IDs only az pipelines list --query "[].{ID:id, Name:name}" --output table ``` ### Show pipeline details ```bash az pipelines show --id 42 az pipelines show --name "MyPipeline" --open ``` ### Create / Update / Delete pipeline ```bash # Create from YAML in Azure Repos az pipelines create --name "NewPipeline" \ --repository RepoName --branch master \ --repository-type tfsgit \ --yaml-path azure-pipelines.yml # Create from GitHub az pipelines create --name "NewPipeline" \ --repository Owner/Repo --branch main \ --repository-type github \ --service-connection SERVICE_CONN_ID \ --yaml-path .azure/pipelines.yml # Skip first run on create az pipelines create --name "NewPipeline" \ --repository RepoName --branch main \ --repository-type tfsgit \ --yaml-path azure-pipelines.yml \ --skip-first-run true # Update pipeline az pipelines update --id 42 --new-name "RenamedPipeline" az pipelines update --id 42 --yaml-path new-pipeline.yml --branch main az pipelines update --id 42 --new-folder-path "team/production" # Delete pipeline az pipelines delete --id 42 --yes ``` --- ## 2. Classic Builds ### Queue a build ```bash # By definition ID az pipelines build queue --definition-id 10 # By definition name az pipelines build queue --definition-name "LegacyBuild" # With branch and variables az pipelines build queue --definition-id 10 \ --branch refs/heads/release/1.0 \ --variables "config=Release" "deploy=true" # Open results in browser az pipelines build queue --definition-id 10 --open ``` ### List builds ```bash # Recent builds az pipelines build list --top 10 --output table # Filter by definition az pipelines build list --definition-ids 10 20 --top 5 # Filter by status az pipelines build list --status inProgress --output table az pipelines build list --status completed --result failed --top 10 # Filter by branch az pipelines build list --branch refs/heads/main --top 5 # Filter by reason az pipelines build list --reason pullRequest --top 10 # Useful JMESPath queries az pipelines build list --top 5 \ --query "[].{ID:id, Status:status, Result:result, Pipeline:definition.name}" \ --output table ``` ### Show build details ```bash az pipelines build show --id 1234 az pipelines build show --id 1234 --open ``` ### Cancel a build ```bash az pipelines build cancel --build-id 1234 ``` ### Build definitions ```bash # List all build definitions az pipelines build definition list --output table az pipelines build definition list --query "[].{ID:id, Name:name, Path:path}" --output table # Show definition details az pipelines build definition show --id 10 az pipelines build definition show --name "MyBuildDef" --open ``` ### Build tags ```bash # Add tags az pipelines build tag add --build-id 1234 --tags "production" "v1.0" # List tags az pipelines build tag list --build-id 1234 # Delete a tag az pipelines build tag delete --build-id 1234 --tag "v1.0" ``` --- ## 3. Release Pipelines ### Create a release ```bash # By definition ID az pipelines release create --definition-id 5 # By definition name az pipelines release create --definition-name "MyRelease" # With description az pipelines release create --definition-id 5 \ --description "Release v1.2.3 - hotfix for login bug" # With artifact version az pipelines release create --definition-id 5 \ --artifact-metadata-list "alias1=version_id1" "alias2=version_id2" # Open in browser az pipelines release create --definition-id 5 --open ``` ### List releases ```bash # Recent releases az pipelines release list --top 10 --output table # Filter by definition az pipelines release list --definition-id 5 --top 10 # Filter by status az pipelines release list --status active --top 10 # Filter by branch az pipelines release list --source-branch refs/heads/main # Filter by time range az pipelines release list --min-created-time "2025-01-01" --max-created-time "2025-02-01" # Useful JMESPath queries az pipelines release list --top 5 \ --query "[].{ID:id, Name:name, Status:status, CreatedOn:createdOn}" \ --output table ``` ### Show release details ```bash az pipelines release show --id 100 az pipelines release show --id 100 --open ``` ### Release definitions ```bash # List all release definitions az pipelines release definition list --output table az pipelines release definition list --name "Deploy*" --top 10 # Filter by artifact type az pipelines release definition list --artifact-type build # Show definition details az pipelines release definition show --id 5 az pipelines release definition show --name "MyRelease" --open # Get environments from a release definition az pipelines release definition show --id 5 \ --query "environments[].{ID:id, Name:name, Rank:rank}" ``` --- ## 4. Pipeline Runs ### List runs ```bash # Recent runs az pipelines runs list --top 10 --output table # Filter by pipeline az pipelines runs list --pipeline-ids 42 --top 5 # Multiple pipelines az pipelines runs list --pipeline-ids 42 43 44 --top 10 # Filter by status and result az pipelines runs list --status completed --result succeeded --top 10 az pipelines runs list --status inProgress --output table # Order by time az pipelines runs list --query-order FinishTimeDesc --top 10 # Useful JMESPath az pipelines runs list --top 5 \ --query "[].{ID:id, Pipeline:pipeline.name, Status:status, Result:result}" \ --output table ``` ### Show run details ```bash az pipelines runs show --id 5678 az pipelines runs show --id 5678 --open ``` ### Run artifacts ```bash # List artifacts for a run az pipelines runs artifact list --run-id 5678 # Download an artifact az pipelines runs artifact download --run-id 5678 \ --artifact-name "drop" --path ./artifacts # Upload an artifact az pipelines runs artifact upload --run-id 5678 \ --artifact-name "test-results" --path ./test-output ``` ### Run tags ```bash az pipelines runs tag add --run-id 5678 --tags "deployed" "v2.0" az pipelines runs tag list --run-id 5678 az pipelines runs tag delete --run-id 5678 --tag "deployed" ``` --- ## 5. Variables & Variable Groups ### Pipeline variables ```bash # List variables for a pipeline az pipelines variable list --pipeline-id 42 --output table # Create a variable az pipelines variable create --pipeline-id 42 \ --name "MY_VAR" --value "my_value" # Create a secret variable az pipelines variable create --pipeline-id 42 \ --name "MY_SECRET" --value "s3cret" --is-secret true # Update a variable az pipelines variable update --pipeline-id 42 \ --name "MY_VAR" --new-value "updated_value" # Delete a variable az pipelines variable delete --pipeline-id 42 --name "MY_VAR" --yes ``` ### Variable groups ```bash # List variable groups az pipelines variable-group list --output table # Create a variable group az pipelines variable-group create --name "MyVarGroup" \ --variables "key1=val1" "key2=val2" # Show variable group az pipelines variable-group show --id 1 az pipelines variable-group show --group-name "MyVarGroup" # Update variable group az pipelines variable-group update --id 1 --name "RenamedGroup" # Delete variable group az pipelines variable-group delete --id 1 --yes # Manage variables within a group az pipelines variable-group variable list --group-id 1 --output table az pipelines variable-group variable create --group-id 1 --name "NEW_VAR" --value "val" az pipelines variable-group variable update --group-id 1 --name "NEW_VAR" --new-value "val2" az pipelines variable-group variable delete --group-id 1 --name "NEW_VAR" --yes ``` --- ## 6. Agent Pools & Queues ```bash # List agent pools az pipelines pool list --output table az pipelines pool show --id 1 # List agents in a pool az pipelines agent list --pool-id 1 --output table az pipelines agent show --pool-id 1 --agent-id 5 # List agent queues az pipelines queue list --output table az pipelines queue show --id 1 ``` --- ## 7. Pipeline Folders ```bash # List folders az pipelines folder list --output table # Create a folder az pipelines folder create --path "team/production" # Update folder az pipelines folder update --path "team/production" --new-path "team/prod" # Delete folder az pipelines folder delete --path "team/prod" --yes ``` --- ## 8. Advanced: REST API via az devops invoke For operations not directly supported by the CLI, use `az devops invoke`. ### Approve a release deployment ```bash # Step 1: Get pending approvals az devops invoke --area release --resource approvals \ --route-parameters project=PROJECT \ --query-parameters releaseId=RELEASE_ID \ --api-version 7.1 --http-method GET # Step 2: Approve (PATCH) az devops invoke --area release --resource approvals \ --route-parameters project=PROJECT approvalId=APPROVAL_ID \ --api-version 7.1 --http-method PATCH \ --in-file approval-body.json ``` Where `approval-body.json`: ```json { "status": "approved", "comments": "Approved via CLI" } ``` ### Deploy to a specific environment ```bash # Trigger deployment of a release to an environment az devops invoke --area release --resource releases \ --route-parameters project=PROJECT releaseId=RELEASE_ID \ --resource-sub-type environments --resource-id ENV_ID \ --api-version 7.1 --http-method PATCH \ --in-file deploy-body.json ``` Where `deploy-body.json`: ```json { "status": "inProgress", "comment": "Deploying via CLI" } ``` ### Get build timeline / logs ```bash # Get build timeline (stages, jobs, tasks) az devops invoke --area build --resource timeline \ --route-parameters project=PROJECT buildId=BUILD_ID \ --api-version 7.1 --http-method GET # Get build logs az devops invoke --area build --resource logs \ --route-parameters project=PROJECT buildId=BUILD_ID \ --api-version 7.1 --http-method GET ``` ### Check run approvals (YAML pipeline environments) ```bash # List checks for a pipeline run az devops invoke --area pipelines --resource runs \ --route-parameters project=PROJECT pipelineId=PIPELINE_ID runId=RUN_ID \ --api-version 7.1 --http-method GET ``` --- ## 9. Composite Workflows ### Build then release ```bash # 1. Queue a build and capture the build ID BUILD_JSON=$(az pipelines build queue --definition-id 10 --output json) BUILD_ID=$(echo "$BUILD_JSON" | jq -r '.id') echo "Build queued: $BUILD_ID" # 2. Poll until complete while true; do STATUS=$(az pipelines build show --id "$BUILD_ID" \ --query "status" --output tsv) RESULT=$(az pipelines build show --id "$BUILD_ID" \ --query "result" --output tsv) echo "Build $BUILD_ID: status=$STATUS result=$RESULT" if [ "$STATUS" = "completed" ]; then break; fi sleep 30 done # 3. Check result if [ "$RESULT" != "succeeded" ]; then echo "Build failed with result: $RESULT" exit 1 fi # 4. Create release az pipelines release create --definition-id 5 \ --description "Auto-release from build $BUILD_ID" ``` ### Run YAML pipeline and wait ```bash # 1. Run pipeline and capture run ID RUN_JSON=$(az pipelines run --id 42 --branch refs/heads/main --output json) RUN_ID=$(echo "$RUN_JSON" | jq -r '.id') echo "Pipeline run queued: $RUN_ID" # 2. Poll until complete while true; do STATE=$(az pipelines runs show --id "$RUN_ID" \ --query "state" --output tsv) RESULT=$(az pipelines runs show --id "$RUN_ID" \ --query "result" --output tsv) echo "Run $RUN_ID: state=$STATE result=$RESULT" if [ "$STATE" = "completed" ]; then break; fi sleep 30 done # 3. Download artifacts on success if [ "$RESULT" = "succeeded" ]; then az pipelines runs artifact download --run-id "$RUN_ID" \ --artifact-name "drop" --path ./artifacts fi ``` ### List failed builds across multiple pipelines ```bash az pipelines build list \ --definition-ids 10 20 30 \ --result failed \ --top 20 \ --query "[].{ID:id, Pipeline:definition.name, Branch:sourceBranch, Time:finishTime}" \ --output table ``` ### Find latest successful build for a branch ```bash az pipelines build list \ --definition-ids 10 \ --branch refs/heads/main \ --result succeeded \ --top 1 \ --query "[0].{ID:id, BuildNumber:buildNumber, Time:finishTime}" \ --output table ``` ### Release status dashboard ```bash # Show recent releases with environment statuses az pipelines release list --definition-id 5 --top 5 \ --query "[].{ID:id, Name:name, Status:status, Envs:environments[].{Name:name,Status:status}}" \ --output json | jq '.' ``` --- ## 10. Pull Request Management PR 操作用 `az repos pr` 命令,完全原生支持,无需 REST API。 ### Approve / Vote on a PR ```bash # Approve az repos pr set-vote --id 123 --vote approve # Approve with suggestions az repos pr set-vote --id 123 --vote approve-with-suggestions # Reject az repos pr set-vote --id 123 --vote reject # Wait for author az repos pr set-vote --id 123 --vote wait-for-author # Reset vote az repos pr set-vote --id 123 --vote reset ``` ### Create a PR ```bash # Basic az repos pr create --title "feat: add login page" \ --source-branch feature/login --target-branch main # With description and reviewers az repos pr create \ --title "feat: add login page" \ --description "Implements OAuth2 login flow" "See JIRA-123" \ --source-branch feature/login \ --target-branch main \ --required-reviewers "user@company.com" "team@company.com" \ --reviewers "optional@company.com" # With auto-complete and squash merge az repos pr create \ --title "feat: add login page" \ --source-branch feature/login \ --target-branch main \ --auto-complete true \ --squash true \ --delete-source-branch true # Create as draft az repos pr create --title "WIP: new feature" \ --source-branch feature/xyz --draft true # Open in browser after creation az repos pr create --title "My PR" \ --source-branch feature/xyz --open ``` ### List PRs ```bash # All active PRs az repos pr list --status active --output table # PRs targeting main az repos pr list --target-branch main --output table # PRs created by me az repos pr list --creator "me@company.com" --output table # PRs where I'm a reviewer az repos pr list --reviewer "me@company.com" --output table # From a specific branch az repos pr list --source-branch feature/login # Completed/merged PRs az repos pr list --status completed --top 10 --output table # All PRs (active + completed + abandoned) az repos pr list --status all --top 20 \ --query "[].{ID:pullRequestId, Title:title, Status:status, Author:createdBy.displayName}" \ --output table ``` ### Show PR details ```bash az repos pr show --id 123 az repos pr show --id 123 --open ``` ### Update a PR ```bash # Merge/complete a PR az repos pr update --id 123 --status completed # Abandon a PR az repos pr update --id 123 --status abandoned # Reactivate an abandoned PR az repos pr update --id 123 --status active # Rename title az repos pr update --id 123 --title "fix: corrected login flow" # Update description az repos pr update --id 123 --description "Updated description" "Second line" # Enable auto-complete az repos pr update --id 123 --auto-complete true # Publish draft PR az repos pr update --id 123 --draft false # Convert to draft az repos pr update --id 123 --draft true # Bypass policies and force complete (use with caution) az repos pr update --id 123 --status completed \ --bypass-policy true --bypass-policy-reason "Emergency hotfix" ``` ### Manage reviewers ```bash # Add reviewers az repos pr reviewer add --id 123 --reviewers "user1@company.com" "user2@company.com" # List reviewers az repos pr reviewer list --id 123 --output table # Remove a reviewer az repos pr reviewer remove --id 123 --reviewers "user1@company.com" ``` ### Manage policies ```bash # List policies on a PR az repos pr policy list --id 123 --output table # Re-queue a failed policy check az repos pr policy queue --id 123 --evaluation-id EVAL_ID ``` ### Work items ```bash # Link work items to a PR az repos pr work-item add --id 123 --work-items 456 789 # List linked work items az repos pr work-item list --id 123 --output table # Unlink work items az repos pr work-item remove --id 123 --work-items 456 ``` ### Checkout PR branch locally ```bash az repos pr checkout --id 123 ``` ### Composite: Create PR and wait for approval ```bash # 1. Create PR PR_JSON=$(az repos pr create \ --title "feat: new feature" \ --source-branch feature/xyz \ --target-branch main \ --output json) PR_ID=$(echo "$PR_JSON" | jq -r '.pullRequestId') echo "PR created: $PR_ID" # 2. Poll until completed or abandoned while true; do STATUS=$(az repos pr show --id "$PR_ID" --query "status" --output tsv) echo "PR $PR_ID status: $STATUS" if [ "$STATUS" = "completed" ] || [ "$STATUS" = "abandoned" ]; then break fi sleep 60 done ``` --- ## 11. Useful JMESPath Patterns ```bash # Get only IDs --query "[].id" --output tsv # ID + Name table --query "[].{ID:id, Name:name}" --output table # Filter in query (e.g., only inProgress) --query "[?status=='inProgress'].{ID:id, Name:name}" --output table # Nested: release environments --query "environments[].{Env:name, Status:status}" --output table # First item only --query "[0].id" --output tsv # Sort by field --query "sort_by([],&finishTime)" --output json ```