-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Scripts for building and testing PowerShell repository code on Linux on VSTS. #6953
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
c0c891e
PowerShell linux build scripts for vsts.
kalgiz cae5add
Scripts corrections.
kalgiz 8650637
Merge branch 'master' of https://github.com/kalgiz/PowerShell into li…
kalgiz 69a219c
PowerShell linux build scripts for vsts.
kalgiz 82b391a
Scripts corrections.
kalgiz ca033d9
Throw exception in case of build / test failure
kalgiz d89e1ee
Merge branch 'linux-builds-on-vsts' of https://github.com/kalgiz/Powe…
kalgiz 55b26c6
Throw the exception in case of build / test failures.
kalgiz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| resources: | ||
| - repo: self | ||
| clean: true | ||
| steps: | ||
| #- task: <task type name>@<version> | ||
| # inputs: | ||
| # <task specific inputs> | ||
| # displayName: '<display name of task>' | ||
| - task: ShellScript@2 | ||
| inputs: | ||
| scriptPath: './tools/linux_vsts.sh' | ||
| args: 'Install' | ||
| displayName: 'Install stage' | ||
| - task: ShellScript@2 | ||
| inputs: | ||
| scriptPath: './tools/linux_vsts.sh' | ||
| args: 'Bootstrap' | ||
| displayName: 'Bootstrap stage' | ||
| - task: ShellScript@2 | ||
| inputs: | ||
| scriptPath: './tools/linux_vsts.sh' | ||
| args: 'Build' | ||
| displayName: 'Build stage' | ||
| - task: ShellScript@2 | ||
| inputs: | ||
| scriptPath: './tools/linux_vsts.sh' | ||
| args: 'Test' | ||
| displayName: 'Test stage' | ||
| continueOnError: true | ||
| - task: ShellScript@2 | ||
| inputs: | ||
| scriptPath: './tools/linux_vsts.sh' | ||
| args: 'AfterTest' | ||
| displayName: ' After test stage' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,316 @@ | ||
| $repoRoot = Join-Path $PSScriptRoot '..' | ||
| Import-Module (Join-Path $repoRoot 'build.psm1') -Scope Global | ||
| $isPR = $env:BUILD_REASON -eq "PullRequest" | ||
| $commitMessage = git log --format=%B -n 1 $env:BUILD_SOURCEVERSIONMESSAGE | ||
| Write-Host $commitMessage | ||
| $hasFeatureTag = $commitMessage -match '\[feature\]' | ||
| $hasPackageTag = $commitMessage -match '\[package\]' | ||
| $createPackages = -not $isPr -or $hasPackageTag | ||
| $hasRunFailingTestTag = $commitMessage -match '\[includeFailingTest\]' | ||
| $isDailyBuild = $env:BUILD_REASON -eq 'Schedule' | ||
| $isFullBuild = $isDailyBuild -or $hasFeatureTag | ||
|
|
||
| function Send-DailyWebHook | ||
| { | ||
| param ( | ||
| [Parameter(Mandatory=$true,Position=0)][ValidateSet("Pass","Fail")]$result | ||
| ) | ||
|
|
||
| # Only send web hook if the environment variable is present | ||
| # Varible should be set in Travis-CI.org settings | ||
| if ($env:WebHookUrl) | ||
| { | ||
| Write-Log "Sending DailyWebHook with result '$result'." | ||
| $webhook = $env:WebHookUrl | ||
|
|
||
| $Body = @{ | ||
| 'text'= @" | ||
| Build Result: $result </br> | ||
| OS Type: $($PSVersionTable.OS) </br> | ||
| <a href="https://travis-ci.org/$env:TRAVIS_REPO_SLUG/builds/$env:TRAVIS_BUILD_ID">Build $env:TRAVIS_BUILD_NUMBER</a> </br> | ||
| <a href="https://travis-ci.org/$env:TRAVIS_REPO_SLUG/jobs/$env:TRAVIS_JOB_ID">Job $env:TRAVIS_JOB_NUMBER</a> | ||
| "@ | ||
| } | ||
|
|
||
| $params = @{ | ||
| Headers = @{'accept'='application/json'} | ||
| Body = $Body | convertto-json | ||
| Method = 'Post' | ||
| URI = $webhook | ||
| } | ||
|
|
||
| Invoke-RestMethod @params | ||
| } | ||
| else | ||
| { | ||
| Write-Log "Skipping DailyWebHook. WebHookUrl environment variable not present." | ||
| } | ||
| } | ||
|
|
||
|
|
||
| function Get-ReleaseTag | ||
| { | ||
| $metaDataPath = Join-Path -Path $PSScriptRoot -ChildPath 'metadata.json' | ||
| $metaData = Get-Content $metaDataPath | ConvertFrom-Json | ||
|
|
||
| $releaseTag = $metadata.NextReleaseTag | ||
| if($env:BUILD_BUILDNUMBER) | ||
| { | ||
| $releaseTag = $releaseTag.split('.')[0..2] -join '.' | ||
| # If the Build number has a dot in it, only the string before dot is inserted into releaseTag. | ||
| $buildMajorNumber = $env:BUILD_BUILDNUMBER | ||
| $dotPos = $buildMajorNumber.IndexOf(".") | ||
| if ($dotPos -ne -1) { | ||
| $buildMajorNumber = $buildMajorNumber.Substring(0, $dotPos) | ||
| } | ||
| $releaseTag = $releaseTag+'.'+$buildMajorNumber | ||
| } | ||
|
|
||
| return $releaseTag | ||
| } | ||
|
|
||
| # This function retrieves the appropriate svg to be used when presenting | ||
| # the daily test run badge | ||
| # the location in azure is public readonly | ||
| function Get-DailyBadge | ||
| { | ||
| param ( | ||
| [Parameter(Mandatory=$true,Position=0)][ValidateSet("Pass","Fail")]$result | ||
| ) | ||
| $PASS = "https://jimtru1979.blob.core.windows.net/badges/DailyBuild.Pass.svg" | ||
| $FAIL = "https://jimtru1979.blob.core.windows.net/badges/DailyBuild.Fail.svg" | ||
|
|
||
| if ( $result -eq "Pass" ) { $BadgeUrl = $PASS } else { $BadgeUrl = $FAIL } | ||
| $response = Invoke-WebRequest -Uri $BadgeUrl | ||
| if ( $response.StatusCode -ne 200 ) { throw "Could not read badge '$BadgeUrl'" } | ||
| $response.Content | ||
| } | ||
|
|
||
| # This function uses Azure REST api to update the daily test pass results | ||
| # it relies on writing a specific SVG into a constant location so the | ||
| # README.MD can report on the status of the daily test pass | ||
| # it also relies on two environment variables which need to be set in the | ||
| # Travis-CI config which is the account name and key for the azure blob location | ||
| # | ||
| # the best way to do this would be if travis-ci supported a webcall to get | ||
| # the status of cron_job builds, but it doesn't, so we have this | ||
| # also, since we can have a build on Linux which succeeds and one on macOS which | ||
| # doesn't we'll set the appropriate badge so the the README can pick it up | ||
| function Set-DailyBuildBadge | ||
| { | ||
| [CmdletBinding(SupportsShouldProcess=$true)] | ||
| param ( [Parameter(Mandatory=$true,Position=0)]$content ) | ||
| $method = "PUT" | ||
| $headerDate = '2015-12-11' | ||
|
|
||
| $storageAccountName = $Env:TestResultAccountName | ||
| $storageAccountKey = $Env:TestResultAccountKey | ||
|
|
||
| # this is the url referenced in README.MD which displays the badge | ||
| $platform = "Linux" | ||
| $Url = "https://jimtru1979.blob.core.windows.net/badges/DailyBuildStatus.${platform}.svg" | ||
|
|
||
| $body = $content | ||
| $bytes = ([System.Text.Encoding]::UTF8.GetBytes($body)) | ||
| $contentLength = $bytes.length | ||
|
|
||
| $now = [datetime]::UtcNow.ToString("R", [System.Globalization.CultureInfo]::InvariantCulture) | ||
| $headers = @{ | ||
| "x-ms-date" = $now | ||
| "cache-control" = "no-cache" | ||
| "x-ms-blob-type" = "BlockBlob" | ||
| "x-ms-version" = "$headerDate" | ||
| } | ||
|
|
||
| $contentType = "image/svg+xml" | ||
| # more info: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/put-blob | ||
| $sb = [text.stringbuilder]::new() | ||
| # can't use AppendLine because the `r`n causes the command to fail, it must be `n and only `n | ||
| $null = $sb.Append("$method`n") | ||
| $null = $sb.Append("`n") | ||
| $null = $sb.Append("`n") | ||
| $null = $sb.Append("$contentLength`n") | ||
| $null = $sb.Append("`n") | ||
| $null = $sb.Append("$contentType`n") | ||
| $null = $sb.Append("`n") | ||
| $null = $sb.Append("`n") | ||
| $null = $sb.Append("`n") | ||
| $null = $sb.Append("`n") | ||
| $null = $sb.Append("`n") | ||
| $null = $sb.Append("`n") | ||
|
|
||
| $null = $sb.Append("x-ms-blob-type:" + $headers["x-ms-blob-type"] + "`n") | ||
| $null = $sb.Append("x-ms-date:" + $headers["x-ms-date"] + "`n") | ||
| $null = $sb.Append("x-ms-version:" + $headers["x-ms-version"] + "`n") | ||
| $null = $sb.Append("/" + $storageAccountName + ([System.Uri]::new($url).AbsolutePath)) | ||
|
|
||
| $dataToMac = [System.Text.Encoding]::UTF8.GetBytes($sb.ToString()) | ||
| $accountKeyBytes = [System.Convert]::FromBase64String($storageAccountKey) | ||
| $hmac = [System.Security.Cryptography.HMACSHA256]::new($accountKeyBytes) | ||
| $signature = [System.Convert]::ToBase64String($hmac.ComputeHash($dataToMac)) | ||
|
|
||
| $headers["Authorization"] = "SharedKey " + $storageAccountName + ":" + $signature | ||
|
|
||
| if ( $PSCmdlet.ShouldProcess("$signaturestring")) | ||
| { | ||
| # if this fails, it will throw, you can't check the response for a success code | ||
| $response = Invoke-RestMethod -Uri $Url -Method $method -headers $headers -Body $body -ContentType "image/svg+xml" | ||
| } | ||
| } | ||
|
|
||
| function Invoke-PSBootstrap { | ||
| Write-Host -Foreground Green "Executing Linux vsts -BootStrap `$isPR='$isPr' - $commitMessage" | ||
| # Make sure we have all the tags | ||
| Sync-PSTags -AddRemoteIfMissing | ||
| Start-PSBootstrap -Package:$createPackages | ||
| } | ||
|
|
||
| function Invoke-PSBuild { | ||
| $releaseTag = Get-ReleaseTag | ||
|
|
||
| Write-Host -Foreground Green "Executing Linux vsts `$isPR='$isPr' `$isFullBuild='$isFullBuild' - $commitMessage" | ||
| $originalProgressPreference = $ProgressPreference | ||
| $ProgressPreference = 'SilentlyContinue' | ||
| try { | ||
| Start-PSBuild -CrossGen -PSModuleRestore -CI -ReleaseTag $releaseTag -Configuration 'Release' | ||
| Save-PSOptions | ||
| } | ||
| finally{ | ||
| $ProgressPreference = $originalProgressPreference | ||
| } | ||
| } | ||
|
|
||
| function Invoke-PSTest { | ||
| Restore-PSOptions | ||
| $testResultsNoSudo = "$pwd/TestResultsNoSudo.xml" | ||
| $testResultsSudo = "$pwd/TestResultsSudo.xml" | ||
| $output = Split-Path -Parent (Get-PSOutput -Options (New-PSOptions)) | ||
| $pesterParam = @{ | ||
| 'binDir' = $output | ||
| 'PassThru' = $true | ||
| 'Terse' = $true | ||
| 'Tag' = @() | ||
| 'ExcludeTag' = @('RequireSudoOnUnix') | ||
| 'OutputFile' = $testResultsNoSudo | ||
| 'ThrowOnFailure' = $true | ||
| } | ||
|
|
||
| if ($isFullBuild) { | ||
| $pesterParam['Tag'] = @('CI','Feature','Scenario') | ||
| } else { | ||
| $pesterParam['Tag'] = @('CI') | ||
| } | ||
|
|
||
| if ($hasRunFailingTestTag) | ||
| { | ||
| $pesterParam['IncludeFailingTest'] = $true | ||
| } | ||
|
|
||
| # Remove telemetry semaphore file in CI | ||
| $telemetrySemaphoreFilepath = Join-Path $output DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY | ||
| if ( Test-Path "${telemetrySemaphoreFilepath}" ) { | ||
| Remove-Item -force ${telemetrySemaphoreFilepath} | ||
| } | ||
|
|
||
| # Running tests which do not require sudo. | ||
| $pesterPassThruNoSudoObject = Start-PSPester @pesterParam | ||
|
|
||
| # Running tests, which require sudo. | ||
| $pesterParam['Tag'] = @('RequireSudoOnUnix') | ||
| $pesterParam['ExcludeTag'] = @() | ||
| $pesterParam['Sudo'] = $true | ||
| $pesterParam['OutputFile'] = $testResultsSudo | ||
| $pesterPassThruSudoObject = Start-PSPester @pesterParam | ||
|
|
||
| # Determine whether the build passed | ||
| $result = "PASS" | ||
| try { | ||
| @($pesterPassThruNoSudoObject) | ForEach-Object { Test-PSPesterResults -ResultObject $_ } | ||
| } | ||
| catch { | ||
| $resultError = $_ | ||
| $result = "FAIL" | ||
| } | ||
|
|
||
| try { | ||
| $SequentialXUnitTestResultsFile = "$pwd/SequentialXUnitTestResults.xml" | ||
| $ParallelXUnitTestResultsFile = "$pwd/ParallelXUnitTestResults.xml" | ||
|
|
||
| Start-PSxUnit -SequentialTestResultsFile $SequentialXUnitTestResultsFile -ParallelTestResultsFile $ParallelXUnitTestResultsFile | ||
| # If there are failures, Test-XUnitTestResults throws | ||
| $SequentialXUnitTestResultsFile, $ParallelXUnitTestResultsFile | ForEach-Object { Test-XUnitTestResults -TestResultsFile $_ } | ||
| } | ||
| catch { | ||
| $result = "FAIL" | ||
| if (!$resultError) | ||
| { | ||
| $resultError = $_ | ||
| } | ||
| } | ||
|
|
||
| if ($createPackages) { | ||
|
|
||
| $packageParams = @{} | ||
| $packageParams += @{ReleaseTag=Get-ReleaseTag} | ||
|
|
||
| # Only build packages for branches, not pull requests | ||
| $packages = @(Start-PSPackage @packageParams -SkipReleaseChecks) | ||
| # Packaging AppImage depends on the deb package | ||
| $packages += Start-PSPackage @packageParams -Type AppImage -SkipReleaseChecks | ||
| foreach($package in $packages) | ||
| { | ||
| # Publish the packages to the nuget feed if: | ||
| # 1 - It's a Daily build (already checked, for not a PR) | ||
| # 2 - We have the info to publish (NUGET_KEY and NUGET_URL) | ||
| # 3 - it's a nupkg file | ||
| if($isDailyBuild -and $env:NUGET_KEY -and $env:NUGET_URL -and [system.io.path]::GetExtension($package) -ieq '.nupkg') | ||
| { | ||
| Write-Log "pushing $package to $env:NUGET_URL" | ||
| Start-NativeExecution -sb {dotnet nuget push $package --api-key $env:NUGET_KEY --source "$env:NUGET_URL/api/v2/package"} -IgnoreExitcode | ||
| } | ||
| } | ||
|
|
||
| # Create and package Raspbian .tgz | ||
| Start-PSBuild -PSModuleRestore -Clean -Runtime linux-arm | ||
| Start-PSPackage @packageParams -Type tar-arm -SkipReleaseChecks | ||
| } | ||
|
|
||
| # if the tests did not pass, throw the reason why | ||
| if ( $result -eq "FAIL" ) { | ||
| Throw $resultError | ||
| } | ||
| } | ||
|
|
||
| function Invoke-PSAfterTest { | ||
| $result = 'PASS' | ||
| if ($env:AGENT_JOBSTATUS -eq "Failed" -or $env:AGENT_JOBSTATUS -eq "SucceededWithIssues") { | ||
| $result = 'FAIL' | ||
| } | ||
|
|
||
| if ($isDailyBuild) { | ||
| # update the badge if you've done a cron build, these are not fatal issues | ||
| try { | ||
| $svgData = Get-DailyBadge -result $result | ||
| if (!$svgData ) { | ||
| write-warning "Could not retrieve $result badge" | ||
| } | ||
| else { | ||
| Write-Log "Setting status badge to '$result'" | ||
| Set-DailyBuildBadge -content $svgData | ||
| } | ||
| } | ||
| catch { | ||
| Write-Warning "Could not update status badge: $_" | ||
| } | ||
|
|
||
| try { | ||
| Send-DailyWebHook -result $result | ||
| } | ||
| catch { | ||
| Write-Warning "Could not send webhook: $_" | ||
| } | ||
| } | ||
| else { | ||
| Write-Log 'We only send bagde or webhook update for Cron builds' | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| #!/bin/bash | ||
| if [ $1 == "Install" ]; then | ||
| # Install dependencies and clean up | ||
| ./install-powershell.sh | ||
| nvm install 6.4.0 | ||
| npm install -g markdown-spellcheck@0.11.0; | ||
| apt-get install less | ||
| elif [ $1 == "Bootstrap" ]; then | ||
| pwsh -command ". ./linux_vsts.ps1; Invoke-PSBootstrap" | ||
| elif [ $1 == "Build" ]; then | ||
| pwsh -command ". ./linux_vsts.ps1; Invoke-PSBuild" | ||
| elif [ $1 == "Test" ]; then | ||
| cd .. | ||
| pwsh -command ". ./tools/linux_vsts.ps1; Invoke-PSTest" | ||
| elif [ $1 == "AfterTest" ]; then | ||
| pwsh -command ". ./linux_vsts.ps1; Invoke-PSAfterTest" | ||
| fi |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[System.Environment]::NewLinemight be better thann. But if stringbuilder usesr`n on Linux, this sounds more like a bug in .Net Core (or maybe I misunderstood its usage)