Guide for Azure DevOps automation using az CLI with azure-devops extension. Covers Azure Pipelines, Azure Repos, Azure Boards, work items, pull requests, artifacts, service connections, variable groups, and DevOps automation. Use when working with ADO, az devops commands, YAML pipelines, or Azure DevOps REST API.
Comprehensive guide for automating Azure DevOps operations using the az CLI with the azure-devops extension. Covers common patterns, best practices, and examples for working with Azure Pipelines, Repos, Boards, and Artifacts.
Activates when you mention:
# Ubuntu/WSL
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Verify installation
az --version
az extension add --name azure-devops
az extension update --name azure-devops # Update to latest
az login
# Or use Personal Access Token (PAT)
export AZURE_DEVOPS_EXT_PAT=<your-pat-token>
# Set defaults to avoid repeating on every command
az devops configure --defaults organization=https://dev.azure.com/YourOrg project=YourProject
# View current defaults
az devops configure --list
az login
# Opens browser for authentication
# Set as environment variable
export AZURE_DEVOPS_EXT_PAT=<your-pat-token>
# Or use --org and --detect flags
az devops project list --org https://dev.azure.com/YourOrg
az login --service-principal \
--username <app-id> \
--password <password-or-cert> \
--tenant <tenant-id>
# List organizations (requires authentication)
az devops project list --org https://dev.azure.com/YourOrg
# Show project details
az devops project show --project MyProject
# Create new project
az devops project create --name MyNewProject --visibility private
# List teams in project
az devops team list --project MyProject
# List repositories
az repos list --project MyProject
# Create repository
az repos create --name MyNewRepo --project MyProject
# Show repo details
az repos show --repository MyRepo --project MyProject
# Import repository
az repos import create \
--git-source-url https://github.com/user/repo \
--repository MyRepo
# List branches
az repos ref list --repository MyRepo
# Create branch
az repos ref create \
--name refs/heads/feature/new-feature \
--object-id <commit-sha> \
--repository MyRepo
# Delete branch
az repos ref delete \
--name refs/heads/old-branch \
--object-id <commit-sha> \
--repository MyRepo
# List pull requests
az repos pr list --repository MyRepo --status active
# Create pull request
az repos pr create \
--repository MyRepo \
--source-branch feature/my-feature \
--target-branch main \
--title "My Feature" \
--description "Description here"
# Show PR details
az repos pr show --id 123
# Update PR
az repos pr update --id 123 --title "Updated Title"
# Add reviewers
az repos pr reviewer add --id 123 --reviewers user@domain.com
# Complete/merge PR
az repos pr set-vote --id 123 --vote approve
az repos pr update --id 123 --status completed
# Abandon PR
az repos pr update --id 123 --status abandoned
# List PR work items
az repos pr work-item list --id 123
# List pipelines
az pipelines list --project MyProject
# Show pipeline details
az pipelines show --name MyPipeline
# Create pipeline from YAML
az pipelines create \
--name MyPipeline \
--repository MyRepo \
--branch main \
--yml-path azure-pipelines.yml
# Run pipeline
az pipelines run --name MyPipeline
# Run with parameters
az pipelines run --name MyPipeline \
--parameters param1=value1 param2=value2
# List pipeline runs
az pipelines runs list --pipeline-ids 123
# Show run details
az pipelines runs show --id 456
# List pipeline artifacts
az pipelines runs artifact list --run-id 456
# Download artifact
az pipelines runs artifact download \
--run-id 456 \
--artifact-name drop \
--path ./artifacts
# List work items
az boards work-item query --wiql "SELECT [System.Id], [System.Title] FROM WorkItems WHERE [System.State] = 'Active'"
# Show work item
az boards work-item show --id 1234
# Create work item
az boards work-item create \
--type "User Story" \
--title "My User Story" \
--description "Story description" \
--assigned-to user@domain.com
# Update work item
az boards work-item update --id 1234 --state "In Progress"
# Add comment to work item
az boards work-item relation add \
--id 1234 \
--relation-type Comment \
--target-id <comment-text>
# Link work items
az boards work-item relation add \
--id 1234 \
--relation-type Related \
--target-id 5678
# List variable groups
az pipelines variable-group list
# Create variable group
az pipelines variable-group create \
--name MyVariableGroup \
--variables key1=value1 key2=value2
# Show variable group
az pipelines variable-group show --group-id 123
# Update variable
az pipelines variable-group variable create \
--group-id 123 \
--name newKey \
--value newValue
# Delete variable
az pipelines variable-group variable delete \
--group-id 123 \
--name oldKey
# List service connections
az devops service-endpoint list --project MyProject
# Create Azure RM service connection
az devops service-endpoint azurerm create \
--name MyAzureConnection \
--azure-rm-service-principal-id <sp-id> \
--azure-rm-subscription-id <subscription-id> \
--azure-rm-subscription-name "My Subscription" \
--azure-rm-tenant-id <tenant-id>
# Show service connection
az devops service-endpoint show --id <connection-id>
#!/bin/bash
PR_ID=$1
# Wait for PR build to complete
while true; do
STATUS=$(az repos pr show --id $PR_ID --query "mergeStatus" -o tsv)
if [ "$STATUS" == "succeeded" ]; then
echo "Build passed, approving PR..."
az repos pr set-vote --id $PR_ID --vote approve
az repos pr update --id $PR_ID --status completed --delete-source-branch true
break
elif [ "$STATUS" == "failed" ]; then
echo "Build failed, not approving PR"
break
fi
sleep 30
done
#!/bin/bash
# work-items.txt format: Type|Title|Description
while IFS='|' read -r type title description; do
az boards work-item create \
--type "$type" \
--title "$title" \
--description "$description"
done < work-items.txt
#!/bin/bash
ORG="https://dev.azure.com/YourOrg"
PROJECT="YourProject"
az repos list --project $PROJECT --query "[].name" -o tsv | while read repo; do
echo "Cloning $repo..."
git clone "$ORG/$PROJECT/_git/$repo"
done
#!/bin/bash
PIPELINE_NAME="MyPipeline"
# Start pipeline run
RUN_ID=$(az pipelines run --name $PIPELINE_NAME --query "id" -o tsv)
echo "Started run $RUN_ID"
# Poll for completion
while true; do
STATUS=$(az pipelines runs show --id $RUN_ID --query "status" -o tsv)
RESULT=$(az pipelines runs show --id $RUN_ID --query "result" -o tsv)
if [ "$STATUS" == "completed" ]; then
echo "Run completed with result: $RESULT"
[ "$RESULT" == "succeeded" ] && exit 0 || exit 1
fi
sleep 10
done
Set defaults to avoid repeating org/project on every command:
az devops configure --defaults \
organization=https://dev.azure.com/YourOrg \
project=YourProject
# Table format (human-readable)
az repos list -o table
# JSON for scripting
az repos list -o json
# TSV for parsing
az repos list --query "[].name" -o tsv
# Get specific fields
az repos list --query "[].{Name:name, Id:id}" -o table
# Filter results
az repos pr list --query "[?status=='active'].id" -o tsv
# Never hardcode PAT in scripts
# Use environment variables or Azure Key Vault
export AZURE_DEVOPS_EXT_PAT=$(az keyvault secret show --name ado-pat --vault-name myvault --query value -o tsv)
set -e # Exit on error
set -o pipefail # Exit on pipe failure
if ! az repos show --repository MyRepo 2>/dev/null; then
echo "Repository does not exist"
exit 1
fi
Never use personal accounts for automated pipelines - use service principals with minimal required permissions.
# Build .NET project
dotnet build MyProject.csproj
# If build succeeds, trigger Azure Pipeline
if [ $? -eq 0 ]; then
az pipelines run --name DeployPipeline
fi
# In Azure Pipeline YAML
- script: |
if [ $(Agent.JobStatus) == "Failed" ]; then
az boards work-item create \
--type Bug \
--title "Build $(Build.BuildNumber) failed" \
--description "Build failed: $(Build.BuildUri)"
fi
condition: failed()
displayName: 'Create work item on failure'
DATE_7_DAYS_AGO=$(date -d '7 days ago' +%Y-%m-%d)
az repos pr list --status active --query \
"[?creationDate<'$DATE_7_DAYS_AGO'].{ID:pullRequestId, Title:title, Created:creationDate}" \
-o table
az pipelines runs list \
--query "[?finishTime>='$(date -d '1 day ago' --iso-8601=seconds)' && result=='failed'].{ID:id, Pipeline:definition.name, Result:result}" \
-o table
MY_EMAIL="user@domain.com"
az boards work-item query --wiql \
"SELECT [System.Id], [System.Title], [System.State] FROM WorkItems WHERE [System.AssignedTo] = '$MY_EMAIL' AND [System.State] <> 'Closed'"
Solution: Ensure you're authenticated:
az login
# Or set PAT
export AZURE_DEVOPS_EXT_PAT=<your-token>
Solution: Install Azure CLI and add to PATH
Solution: Install azure-devops extension:
az extension add --name azure-devops
Solution: Check PAT scopes - ensure it has required permissions:
# Setup
az extension add --name azure-devops
az login
az devops configure --defaults organization=<org> project=<project>
# Repos
az repos list
az repos pr list --status active
# Pipelines
az pipelines list
az pipelines run --name <pipeline>
# Work Items
az boards work-item show --id <id>
# Output formats
-o json # JSON output
-o table # Table format
-o tsv # Tab-separated values
--query # JMESPath query
Related Documentation:
Skill Type: Domain Enforcement: Suggest Line Count: ~450 lines ✅
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer