如何在VSTS CI/CD流程中通过API提交文件并备份元数据至Git?
Got it, let's break down how to automate committing your metadata files to Git right from your VSTS (now Azure DevOps) CI/CD pipeline. Since you already have the tool to extract metadata, we'll focus on integrating the Git commit step—covering both a simpler CLI approach and the flexible REST API method for advanced scenarios.
Option 1: Use Git CLI (Straightforward & Quick)
If you don't need fine-grained control over each Git operation, the command line is the easiest way to get this done. Here's how to set it up in your pipeline:
Step 1: Add a PowerShell/Bash task to your pipeline
Most hosted agents come with Git pre-installed. Drop in a task with these commands (adjust paths and variables to match your setup):# Navigate to your repository root cd $(Build.SourcesDirectory) # Configure Git identity (required for commits) git config user.name "VSTS Pipeline Bot" git config user.email "pipeline-bot@yourorg.com" # Copy extracted metadata to your repo's dedicated backup folder copy $(Build.ArtifactStagingDirectory)/metadata/app-config-meta.json ./metadata-backups/ # Stage the file for commit git add ./metadata-backups/app-config-meta.json # Commit with context (include release/build details for traceability) git commit -m "Metadata backup: Release $(Release.ReleaseName) | Build $(Build.BuildId)" # Push to target branch (use PAT for authentication) git remote set-url origin https://$(GitPAT)@dev.azure.com/$(System.TeamProjectCollection)/$(System.TeamProject)/_git/$(Build.Repository.Name) git push origin $(Build.SourceBranchName)- Critical Notes:
- Store your Personal Access Token (PAT) as a secret pipeline variable named
GitPAT—grant itCode (Contribute)permissions to allow commits. - To handle potential conflicts (if someone committed to the branch mid-pipeline), add
git pull --rebase origin $(Build.SourceBranchName)before pushing (use cautiously for shared branches). - Use pipeline variables for file paths to keep the script dynamic across environments.
- Store your Personal Access Token (PAT) as a secret pipeline variable named
- Critical Notes:
Option 2: Use VSTS REST API (For Advanced Control)
If you need to validate each step (e.g., blob creation, tree structure) or handle complex workflows, use the Azure DevOps REST API. Here's a complete PowerShell script you can add as a pipeline task:
Prerequisites
- A PAT with
Code (Full)orCode (Contribute)permissions (stored as secret variableGitPAT). - Your repository ID (find it in your repo's settings under "General").
Full Script
# Set up core variables (adjust these to match your environment) $org = $(System.TeamProjectCollection) $proj = $(System.TeamProject) $repoId = "your-repo-guid-here" $targetBranch = "main" $metadataFile = "$(Build.ArtifactStagingDirectory)/metadata/app-config-meta.json" $repoFilePath = "metadata-backups/app-config-meta.json" $commitMsg = "Metadata backup from Release: $(Release.ReleaseName) | Build ID: $(Build.BuildId)" # Encode metadata file to base64 (required for API blob upload) $fileContent = [Convert]::ToBase64String([IO.File]::ReadAllBytes($metadataFile)) # Set auth header for API calls $authHeader = @{ Authorization = "Basic $([Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$(GitPAT)")))" } # Step 1: Get latest commit on target branch $latestCommitUrl = "https://dev.azure.com/$org/$proj/_apis/git/repositories/$repoId/commits?searchCriteria.itemVersion.version=$targetBranch&$top=1&api-version=7.1-preview.1" $latestCommit = Invoke-RestMethod -Uri $latestCommitUrl -Headers $authHeader -Method Get $latestCommitId = $latestCommit.value[0].commitId $latestTreeId = $latestCommit.value[0].treeId # Step 2: Upload metadata as a Git blob $blobUrl = "https://dev.azure.com/$org/$proj/_apis/git/repositories/$repoId/blobs?api-version=7.1-preview.1" $blobBody = @{ content = $fileContent; encoding = "base64" } | ConvertTo-Json $blobResult = Invoke-RestMethod -Uri $blobUrl -Headers $authHeader -Method Post -Body $blobBody -ContentType "application/json" $blobId = $blobResult.objectId # Step 3: Create a new tree with the metadata file $treeUrl = "https://dev.azure.com/$org/$proj/_apis/git/repositories/$repoId/trees?api-version=7.1-preview.1" $treeBody = @{ baseTreeId = $latestTreeId entries = @( @{ path = $repoFilePath objectId = $blobId mode = "100644" # Regular file mode } ) } | ConvertTo-Json $treeResult = Invoke-RestMethod -Uri $treeUrl -Headers $authHeader -Method Post -Body $treeBody -ContentType "application/json" $newTreeId = $treeResult.objectId # Step 4: Create a new commit $commitUrl = "https://dev.azure.com/$org/$proj/_apis/git/repositories/$repoId/commits?api-version=7.1-preview.1" $commitBody = @{ comment = $commitMsg parentCommitIds = @($latestCommitId) treeId = $newTreeId } | ConvertTo-Json $commitResult = Invoke-RestMethod -Uri $commitUrl -Headers $authHeader -Method Post -Body $commitBody -ContentType "application/json" $newCommitId = $commitResult.commitId # Step 5: Update the target branch to point to the new commit $refUrl = "https://dev.azure.com/$org/$proj/_apis/git/repositories/$repoId/refs?api-version=7.1-preview.1" $refBody = @( @{ name = "refs/heads/$targetBranch" oldObjectId = $latestCommitId newObjectId = $newCommitId } ) | ConvertTo-Json Invoke-RestMethod -Uri $refUrl -Headers $authHeader -Method Post -Body $refBody -ContentType "application/json"
Key API Approach Notes
- Conflict Handling: The API will throw an error if
oldObjectIddoesn't match the current branch head (meaning another commit happened mid-pipeline). Add retry logic to fetch the latest commit again, or use a force update (not recommended for shared branches). - Built-in Variables: Use Azure DevOps variables like
$(System.TeamProjectCollectionUri)instead of hardcoding URLs to keep the script portable. - File Modes: Use
100644for regular files,100755for executables, and160000for submodules.
General Best Practices
- Isolate Backups: Store metadata files in a dedicated folder (e.g.,
metadata-backups/) to avoid cluttering your main codebase. - Traceability: Always include release/build IDs in commit messages to link backups to specific deployments.
- Test First: Validate the pipeline against a non-production branch before rolling it out to production.
- Monitor Failures: Set up alerts for pipeline failures so you're notified if metadata backups aren't being committed.
内容的提问来源于stack exchange,提问作者Anthony Klotz

