param ( [switch]$Force, [switch]$UseExistingMsi ) $script:Constants = @{ AccountName = 'PowerShell' UrlBase = 'https://ci.appveyor.com' ApiUrl = 'https://ci.appveyor.com/api' ProjectName = 'powershell-f975h' TestImageName = "remotetestimage" MsiName = "PSCore.msi" Token = "" # in this particular use we don't need a token } function Get-AppVeyorBuildArtifact { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$build, [string]$downloadFolder = '.', [string]$artifactFilter = '*.msi', [string]$artifactLocalFileName = $Constants.MsiName ) $headers = @{ 'Authorization' = "Bearer {0}" -f $Constants.Token 'Content-type' = 'application/json' } # get project with last build details $URL = "{0}/projects/{1}/{2}/build/$build" -f $Constants.ApiUrl,$Constants.AccountName,$Constants.ProjectName,$build $project = Invoke-RestMethod -Method Get -Uri $URL -Headers $headers # we assume here that build has a single job # get this job id $jobId = $project.build.jobs[0].jobId # get job artifacts (just to see what we've got) $URL = "{0}/buildjobs/{1}/artifacts" -f $Constants.ApiUrl,$jobid $artifacts = Invoke-RestMethod -Method Get -Uri $URL -Headers $headers # here we just take the first artifact, but you could specify its file name # $artifactFileName = 'MyWebApp.zip' $artifact = $artifacts | Where-Object {$_.fileName -like $artifactFilter} | Select-Object -First 1 $artifactFileName = $artifact.fileName # artifact will be downloaded as $localArtifactPath = "$downloadFolder\$artifactLocalFileName" # download artifact # -OutFile - is local file name where artifact will be downloaded into $URI = "{0}/buildjobs/{1}/artifacts/{2}" -f $Constants.ApiUrl,$jobId,$artifactFileName Invoke-RestMethod -Method Get -Uri $URI -OutFile $localArtifactPath -Headers $headers return $localArtifactPath } # Get a collection of appveyor objects representing the builds for the last day function Get-AppVeyorBuilds { [CmdletBinding()] param( [ValidateNotNullOrEmpty()] [string]$ExtensionBranch = 'master', [ValidateRange(1,7)][int]$Days = 7, [int]$Last = 1 ) [datetime]$start = ((get-date).AddDays(-${Days})) $results = Get-AppVeyorBuildRange -Start $start -LastBuildId $null -ExtensionBranch $ExtensionBranch $results } function Get-AppVeyorBuildRange { [CmdletBinding()] param ( [Parameter(Mandatory=$true, Position=0)] [string] $ExtensionBranch = 'dev', [Parameter(Mandatory=$true, Position=1)] [datetime] $Start, [Parameter(Mandatory=$true, Position=2)] [AllowNull()] [Object] $LastBuildId, [Parameter(Mandatory=$false, Position=3)] [int] $Records = 20, [switch] $IncludeRunning ) $result = @{ builds = @() LastBuildId = '' FoundLast = $false } if($LastBuildId) { $startBuildIdString = "&startBuildId=$LastBuildId" } $URI = "{0}/projects/{1}/{2}/history?recordsNumber={3}{4}&branch{5}" -f $Constants.ApiUrl,$Constants.AccountName, $Constants.ProjectName,$Records,$startBuildIdString,$ExtensionBranch $project = Invoke-RestMethod -Method Get -Uri $URI foreach($build in $project.builds) { if($build.Status -ne 'running' -or $IncludeRunning) { $createdString = $build.created $created = [datetime]::Parse($createdString) if($created -gt $Start) { $version = $build.version $result.lastBuildId = $build.buildId $URI = "{0}/projects/{1}/{2}/build/{3}" -f $Constants.ApiUrl, $Constants.AccountName, $Constants.ProjectName,$version $buildProject = Invoke-RestMethod -Method Get -Uri $URI -Headers $headers -verbose:$false $result.builds += Convert-AppVeyorBuildJson -build $buildProject.Build } else { $result.foundLast = $true } } } return $result } # Convert AppVeyor Build Json into a more usable PSObject function Convert-AppVeyorBuildJson { [CmdletBinding()] param ( [Parameter(Mandatory=$true, Position=0)] [Object] $build ) $Job = $build.jobs[0] $status = $build.status [datetime] $started = [datetime]::MinValue [datetime] $finished = [datetime]::MaxValue if($build.started) { [datetime] $started = [datetime]::Parse($build.started) } if($build.finished) { [datetime] $finished = [datetime]::Parse($build.finished) } $duration = $null if($status -ne 'running') { $duration = $finished.Subtract($started) } $version = $build.version $link = 'Results' -f $Constants.BaseUrl,$Constants.AccountName, $Constants.ProjectName, $version $tests = @() $tag = [string]::Empty if($build.message.StartsWith('[') -and $build.message.Contains(']')) { $tag = $build.message.Substring(1,$build.message.IndexOf(']')).Replace(']','') if($tag.Contains('(')) { $tagParts = $tag.Split('(') $tag = $tagParts[0] for($i=1;$i -lt $tagParts.Count; $i++) { $tests += $tagParts[$i].Replace(')','') } } $tag = $tag } $testString = $tests -join ',' $result = [PsCustomObject]@{ version = $version Id = $build.BuildId author = $build.authorName branch = $Build.branch status = $status started = $started StartedDay = [datetime]$started.Date finished = $finished duration = $duration message = $build.message testsCount = $Job.testsCount passedTestsCount = $Job.passedTestsCount failedTestsCount = $Job.failedTestsCount link = $link JobId = $Job.JobId Tests = $testString Tag = $tag } $result.pstypenames.Clear() $result.pstypenames.Add('AppVeyorBuildSummary') $result } ############ ### MAIN ### ############ #### DOCKER OPS ##### # is docker installed? $dockerExe = get-command docker -ea silentlycontinue if ( $dockerExe.name -ne "docker.exe" ) { throw "Cannot find docker, is it installed?" } # Check to see if we already have an image, and if so # delete it if -Force was used, otherwise throw and exit $TestImage = docker images $Constants.TestImageName --format '{{.Repository}}' if ( $TestImage -eq $Constants.TestImageName) { if ( $Force ) { docker rmi $Constants.TestImageName } else { throw ("{0} already exists, use '-Force' to remove" -f $Constants.TestImageName) } } # check again - there could be some permission problems $TestImage = docker images $Constants.TestImageName --format '{{.Repository}}' if ( $TestImage -eq $Constants.TestImageName) { throw ("'{0}' still exists, giving up" -f $Constants.TestImageName) } #### MSI CHECKS #### # check to see if the MSI is present $MsiExists = test-path $Constants.MsiName $msg = "{0} exists, use -Force to remove or -UseExistingMsi to use" -f $Constants.MsiName if ( $MsiExists -and ! ($force -or $useExistingMsi)) { throw $msg } # remove the msi if ( $MsiExists -and $Force -and ! $UseExistingMsi ) { Remove-Item -force $Constants.MsiName $MsiExists = $false } # a couple of checks before downloading or using the existing one # if the msi exists and -UseExistingMsi is present, we'll use the # one we found if ( ! $MsiExists -and $UseExistingMsi ) { throw ("{0} does not exist" -f $Constants.MsiName) } elseif ( $MsiExists -and ! $UseExistingMsi ) { throw $msg } elseif ( ! ($MsiExists -and $UseExistingMsi) ) # download the msi { $builds = Get-AppVeyorBuilds -ExtensionBranch master $build = $builds.builds | sort-object finished | select-object -last 1 Get-AppVeyorBuildArtifact -build $build.version } # last check before bulding the image if ( ! (test-path $Constants.MsiName) ) { throw ("{0} does not exist, giving up" -f $Constants.MsiName) } # collect the builds and select the last one Docker build --tag $Constants.TestImageName .