So I wrote this powershell script to be ran by the deployment group agents who have access to the server locally.
Param(
[string]$JenkinsPatArg
)
$isRunningLocal = $false
$jenkinsUrlBase = "[public ipaddress]"
if(Test-Connection -ComputerName "[private ipaddress/DNS name]" -Quiet)
{
$isRunningLocal = $true
$jenkinsUrlBase = "[private ipaddress/dns name]"
}
$buildDefinitionName = $env:RELEASE_ARTIFACTS_GAMEZIP_DEFINITIONNAME
$buildTeamProject = [Uri]::EscapeDataString($env:SYSTEM_TEAMPROJECT)
$targetBuildNumber = $env:RELEASE_ARTIFACTS_[Artifact Alias]_BUILDNUMBER
$Auth = "$($env:username):$($JenkinsPatArg)"
$Bytes = [System.Text.Encoding]::UTF8.GetBytes($Auth)
$Base64bytes = [System.Convert]::ToBase64String($Bytes)
$Headers = @{ "Authorization" = "Basic $Base64bytes"}
Write-Host "Searching for $($targetBuildNumber) in project $($buildTeamProject)->$($buildDefinitionName)"
$correctBuild
Write-Host "Querying: http://$($jenkinsUrlBase):[port number]/job/$($buildTeamProject)/job/$($buildDefinitionName)/api/json?tree=builds[id,url,actions[buildNumber]]"
ForEach($build in (Invoke-RestMethod -Uri "http://$($jenkinsUrlBase):[port number]/job/$($buildTeamProject)/job/$($buildDefinitionName)/api/json?tree=builds[id,url,actions[buildNumber]]" -ContentType json -Headers $Headers).builds)
{
if($build.actions.buildNumber -eq $targetBuildNumber)
{
$correctBuild = $build
Write-Host $build.id
Write-Host $build.url
Write-Host $build.actions.buildNumber
break
}
}
if($correctBuild -eq $null)
{
Write-Error "Build not found. Must rebuild source to obtain artifact"
return;
}
if($isRunningLocal){$correctBuild.url = $correctBuild.url.Replace("[public ip address]", "[local ipaddress/DNS name]")}
$targetZip = "$Env:temp/$($buildDefinitionName)_$($correctBuild.id).zip"
(Invoke-RestMethod -Uri "$($correctBuild.url)/artifact/$($buildDefinitionName)/*zip*/$($buildDefinitionName)_$($correctBuild.id).zip" -ContentType Application/zip -Headers $Headers -OutFile $targetZip)
Add-Type -AssemblyName System.IO.Compression.FileSystem;[System.IO.Compression.ZipFile]::ExtractToDirectory($targetZip, $env:targetDirectory);
#Expand-Archive -Path $targetZip -DestinationPath $env:targetDirectory -Force
Remove-Item $targetZip;
passing in the a personal API key (created by Jenkins user manager to use by visual studio team services), this script first checks if it is can access the server using local connections, if so set the variables appropriately.
From there we create local handlers for environmental variables. Our release artifact name defined in VSTS is the same as that in our jenkins server. The build number used is created by VSTS and passed to jenkins and stored by the VSTS plugin(Jenkins TFS Plugin download). We get this version number from the environment as the artifact build number. We also ensure that our team project path url is windows URL encoded brief explanation. Next we hold our authentication which is stored as a variable in our VSTS variables. The $JenkinsPatArg
is marked as secret. As such, we must pass it in as it isn't visible as an environment variable. We then encode the authentication and add it to our request headers.
We then add a debug line to print what target we are looking for and what project we are looking in, just to make sure we are looking for the right thing. We create a variable to hold the build information that we find and do one more debug write stating what are query url is so that we can manually run it if we run into any issues.
Next we then run this url query against the build server and iterate over all the builds returned. The query filters out all the JSON to just the build ID, it's absolute url, and the VSTS build number. We check to see if the build we are examining has the same build number as the artifact we are deploying, if so store it in the $correctBuild
variable, print the was found for debugging, and exit the loop.
Coming out of the loop we check to see if we found a result. If we did not find a build (due to it being cleaned up most likely) we inform the user that the artifact needs to be rebuild from source. Otherwise we download the artifact zip to a temporary location from the jenkins server and extract it to the target directory, defined as a variable. Lastly we delete the downloaded zip.
This is ran as a powershell script task and due to it's length, can not be an inline script. So to deploy this, i have a devops git repo for my scripts and I just include this as an artifact that is downloaded and ran. This task is preceded by other tasks which stop the current process from running, and delete the current files in place before running this task. After this task is ran, more scripts are ran to run the downloaded artifacts.
I hope this helps someone else trying to coordinate and link VSTS builds with Jenkins artifacts.