Azure DevOps API: получение всех файлов (исходных и целевых) запроса на слияние

Я довольно много поискал, нашел здесь несколько потоков (например, это , это и многое другое), но я не смог найти ответа на следующую задачу: использовать Azure DevOps API для получения изменений содержимого (в основном файл до и после) всех файлов конкретного PR.

Я могу найти PR, могу перебирать изменения, итерации, коммиты (в различных комбинациях), но я не смог загрузить ни первую, ни последнюю версию каждого или файлов (и должен быть способ, как я могу просмотреть до и после в PR в DevOps).

Любые подсказки, где / как я могу получить обе версии файла определенной фиксации / изменения / итерации?

Спасибо заранее!

Ура, Удо

1 ответ

Спасибо за все подсказки. Похоже, мне удалось найти ват, чтобы тянуть его. Пожалуйста, не стесняйтесь исправлять мой подход.

Вот полный файл PowerShell:

      [CmdletBinding()]
param (
    [int]
    $pullRequestId,
    [string]
    $repoName
)

# --- your own values ---
$pat = 'your-personal access token for Azure DevOps'
$urlOrganization = 'your Azure DevOps organization'
$urlProject = 'your Azure DevOps project'
$basePath = "$($env:TEMP)/pullRequest/" # a location to store all the data
# --- your own values ---

if (!$repoName)
{
    $userInput = Read-Host "Please enter the repository name"
    if (!$userInput)
    {
        Write-Error "No repository name given."
        exit
    }
    $repoName = $userInput
}

if (!$pullRequestId)
{
    $userInput = Read-Host "Please enter the PullRequest ID for $($repoName)"
    if (!$userInput)
    {
        Write-Error "No PullRequest ID given."
        exit
    }
    $pullRequestId = $userInput
}

$prPath = "$($basePath)$($pullRequestId)"
$sourcePath = "$($basePath)$($pullRequestId)/before"
$targetPath = "$($basePath)$($pullRequestId)/after"

# --- helper methods ---
function CleanLocation([string]$toBeCreated)
{
    RemoveLocation $toBeCreated
    CreateLocation $toBeCreated
    if (!(Test-Path $toBeCreated))
    {
        Write-Error "Path '$toBeCreated' could not be created"
    }
}

function CreateLocation([string]$toBeCreated)
{
    if (!(Test-Path $toBeCreated)) { New-Item -ErrorAction Ignore -ItemType directory -Path $toBeCreated > $null }
}

function RemoveLocation([string]$toBeDeleted)
{
    if (Test-Path $toBeDeleted) { Remove-Item -Path $toBeDeleted -Recurse -Force }
}

function DeleteFile([string]$toBeDeleted)
{
    if (Test-Path $toBeDeleted) { Remove-Item -Path $toBeDeleted -Force }
}
# --- helper methods ---

# --- Azure DevOps helper methods ---
function GetFromDevOps($url)
{
    $patToken = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($pat)"))
    $repoHeader = @{ "Authorization" = "Basic $patToken" }
    $response = $(Invoke-WebRequest $url -Headers $repoHeader)
    if ($response.StatusCode -ne 200)
    {
        Write-Error "FAILED: $($response.StatusDescription)"
    }
    return $response
}

function JsonFromDevOps($url)
{
    $response = GetFromDevOps $url
    return ConvertFrom-Json -InputObject $response.Content
}

function DownloadFromDevOps($url, $filename)
{
    $patToken = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($pat)"))
    $repoHeader = @{ "Authorization" = "Basic $patToken" }
    $ProgressPreference = 'SilentlyContinue'
    Invoke-WebRequest $url -Headers $repoHeader -OutFile $filename
    $ProgressPreference = 'Continue'
}

function DownloadAndSaveFile($itemUrl, $outputPath, $path, $overwrite)
{
    $outFile = "$outputPath$($path)"
    $fileExists = Test-Path $outFile
    if (!$fileExists -or $overwrite)
    {
        $outPath = [System.IO.Path]::GetDirectoryName($outFile)
        CreateLocation $outPath
        if ($fileExists)
        {
            Write-Host "    overwriting to $outputPath"
        }
        else
        {
            Write-Host "    downloading to $outputPath"
        }
        DownloadFromDevOps $itemUrl $outFile
    }
}

function DownloadFiles($changes, $beforePath, $beforeCommitId, $afterPath, $afterCommitId)
{
    foreach ($change in $changes)
    {
        $item = $change.item

        if ($item.isFolder)
        {
            continue;
        }
        $path = $item.path
        $originalPath = $change.originalPath
        if (!$path)
        {
            $path = $change.originalPath
        }
        $displayPath = $path ?? $originalPath
        $changeType = $change.changeType
        Write-Host "[$($changeType)] $($displayPath)"
        if (($changeType -eq "edit, rename"))
        {
            $itemUrl = "$($urlRepository)/items?path=$($originalPath)&versionDescriptor.version=$($beforeCommitId)&versionDescriptor.versionOptions=0&versionDescriptor.versionType=2&download=true"
            DownloadAndSaveFile $itemUrl $beforePath $originalPath
        }
        # just get the source/before version
        if ($changeType -eq "delete")
        {
            $itemUrl = "$($urlRepository)/items?path=$($originalPath)&versionDescriptor.version=$($beforeCommitId)&versionDescriptor.versionOptions=0&versionDescriptor.versionType=2&download=true"
            DownloadAndSaveFile $itemUrl $beforePath $originalPath
            DeleteFile "$($afterPath)$($originalPath)"
        }
        if ($changeType -eq "edit")
        {
            $itemUrl = "$($urlRepository)/items?path=$($path)&versionDescriptor.version=$($beforeCommitId)&versionDescriptor.versionOptions=0&versionDescriptor.versionType=2&download=true"
            DownloadAndSaveFile $itemUrl $beforePath $path
        }
        if (($changeType -eq "add") -or ($changeType -eq "edit") -or ($changeType -eq "edit, rename"))
        {
            $itemUrl = "$($urlRepository)/items?path=$($path)&versionDescriptor.version=$($afterCommitId)&versionDescriptor.versionOptions=0&versionDescriptor.versionType=2&download=true"
            DownloadAndSaveFile $itemUrl $afterPath $path $true
        }
        $validChangeTypes = @('add', 'delete', 'edit', 'edit, rename')
        if (!($validChangeTypes.Contains($changeType)))
        {
            Write-Warning "Unknown change type $($changeType)"
        }
    }
}
# --- Azure DevOps helper methods ---

$urlBase = "https://dev.azure.com/$($urlOrganization)/$($urlProject)/_apis"
$urlRepository = "$($urlBase)/git/repositories/$($repoName)"
$urlPullRequests = "$($urlRepository)/pullRequests"
$urlPullRequest = "$($urlPullRequests)/$($pullRequestId)"
$urlIterations = "$($urlPullRequest)/iterations"

CleanLocation $prPath

$iterations = JsonFromDevOps $urlIterations
foreach ($iteration in $iterations.value)
{
    # the modified file
    $srcId = $iteration.sourceRefCommit.commitId
    # the original file
    $comId = $iteration.commonRefCommit.commitId
    $comId = $iteration.targetRefCommit.commitId

    $urlIterationChanges = "$($urlIterations)/$($iteration.id)/changes"
    $iterationChanges = JsonFromDevOps $urlIterationChanges

    DownloadFiles $iterationChanges.changeEntries $sourcePath $comId $targetPath $srcId
}
Другие вопросы по тегам