Add GitHub Action to build sample projects (#21396)

pull/21400/head
Scott Addie 2021-02-01 14:31:25 -06:00 committed by GitHub
parent e70b0fff1c
commit 3224107d52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 422 additions and 0 deletions

View File

@ -0,0 +1,81 @@
# This is a basic workflow to help you get started with Actions
name: Snippets 5000
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
pull_request:
paths:
- "**.cs"
- "**.vb"
- "**.fs"
- "**.xaml"
- "**.razor"
- "**.cshtml"
- "**.vbhtml"
- "**.csproj"
- "**.vbproj"
- "**.fsproj"
- "**.sln"
- "**global.json"
- "**snippets.5000.json"
branches: [ master ]
env:
DOTNET_INSTALLER_CHANNEL: 'release/5.0.1xx'
DOTNET_DO_INSTALL: 'false'
EnableNuGetPackageRestore: 'True'
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: windows-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675 #@v2
# Get the latest preview SDK (or sdk not installed by the runner)
- name: Setup .NET SDK
if: ${{ env.DOTNET_DO_INSTALL == 'true' }}
run: |
echo "Downloading dotnet-install.ps1"
Invoke-WebRequest https://raw.githubusercontent.com/dotnet/install-scripts/master/src/dotnet-install.ps1 -OutFile dotnet-install.ps1
echo "Installing dotnet version ${{ env.DOTNET_INSTALLER_CHANNEL }}"
.\dotnet-install.ps1 -InstallDir "c:\program files\dotnet" -Channel "${{ env.DOTNET_INSTALLER_CHANNEL }}"
# Print dotnet info
- name: Display .NET info
run: |
dotnet --info
# Install locate projs global tool
- name: Install LocateProjects tool
run: |
dotnet tool install --global --add-source ./.github/workflows/dependencies/ DotnetDocsTools.LocateProjects
# Run locate projs tool
- name: Locate projects for PR
env:
GitHubKey: ${{ secrets.GITHUB_TOKEN }}
LocateExts: ".cs;.vb;.fs;.cpp;.h;.xaml;.razor;.cshtml;.vbhtml;.csproj;.fsproj;.vbproj;.sln"
run: |
./.github/workflows/dependencies/Get-MSBuildResults.ps1 "${{ github.workspace }}" -PullRequest ${{ github.event.number }} -RepoOwner ${{ github.repository_owner }} -RepoName ${{ github.event.repository.name }}
# Update build output json file
- name: Upload build results
uses: actions/upload-artifact@3446296876d12d4e3a0f3145a3c87e67bf0a16b5 #@v1
with:
name: build
path: ./output.json
# Return status based on json file
- name: Report status
run: |
./.github/workflows/dependencies/Out-GithubActionStatus.ps1

View File

@ -0,0 +1,288 @@
<#
.SYNOPSIS
Invokes dotnet build on the samples sln and project files.
.DESCRIPTION
Invokes dotnet build on the samples sln and project files.
.PARAMETER RepoRootDir
The directory of the repository files on the local machine.
.PARAMETER PullRequest
The pull requst to process. If 0 or not passed, processes the whole repo
.PARAMETER RepoOwner
The name of the repository owner.
.PARAMETER RepoName
The name of the repository.
.PARAMETER RangeStart
A range of results to process.
.PARAMETER RangeEnd
A range of results to process.
.INPUTS
None
.OUTPUTS
None
.NOTES
Version: 1.4
Author: adegeo@microsoft.com
Creation Date: 12/11/2020
Purpose/Change: Add support for config file. Select distinct on project files.
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true, ValueFromPipeline = $false)]
[System.String] $RepoRootDir = $env:RepoRootDir,
[Parameter(Mandatory = $false, ValueFromPipeline = $false)]
[System.Int64] $PullRequest = 0,
[Parameter(Mandatory = $false, ValueFromPipeline = $false)]
[System.String] $RepoOwner = "",
[Parameter(Mandatory = $false, ValueFromPipeline = $false)]
[System.String] $RepoName = "",
[Parameter(Mandatory = $false, ValueFromPipeline = $false)]
[System.Int32] $RangeStart = $env:rangestart,
[Parameter(Mandatory = $false, ValueFromPipeline = $false)]
[System.Int32] $RangeEnd = $env:rangeend
)
$Global:statusOutput = @()
Write-Host "Gathering solutions and projects..."
if ($PullRequest -ne 0) {
Write-Host "Running `"LocateProjects `"$RepoRootDir`" --pullrequest $PullRequest --owner $RepoOwner --repo $RepoName`""
$output = Invoke-Expression "LocateProjects `"$RepoRootDir`" --pullrequest $PullRequest --owner $RepoOwner --repo $RepoName"
}
else {
Write-Host "Running `"LocateProjects `"$RepoRootDir`""
$output = Invoke-Expression "LocateProjects `"$RepoRootDir`""
}
if ($LASTEXITCODE -ne 0)
{
$output
throw "Error on running LocateProjects"
}
function New-Result($inputFile, $projectFile, $exitcode, $outputText)
{
$info = @{}
$info.InputFile = $inputFile
$info.ProjectFile = $projectFile
$info.ExitCode = $exitcode
$info.Output = $outputText
$object = New-Object -TypeName PSObject -Prop $info
$Global:statusOutput += $object
}
$workingSet = $output
if (($RangeStart -ne 0) -and ($RangeEnd -ne 0)){
$workingSet = $output[$RangeStart..$RangeEnd]
}
# Log working set items prior to filtering
$workingSet | Write-Host
# Remove duplicated projects
$projects = @()
$workingSetTemp = @()
foreach ($item in $workingSet) {
$data = $item.Split('|')
if ($projects.Contains($data[2].Trim())) {
continue
}
if ($data[2].Trim() -ne "") {
$projects += $data[2].Trim()
}
$workingSetTemp += $item
}
$workingSet = $workingSetTemp
# Process working set
$counter = 1
$length = $workingSet.Count
$thisExitCode = 0
$ErrorActionPreference = "Continue"
foreach ($item in $workingSet) {
try {
Write-Host "$counter/$length :: $Item"
$data = $item.Split('|')
# Project found, build it
if ([int]$data[0] -eq 0) {
$projectFile = Resolve-Path "$RepoRootDir\$($data[2])"
$configFile = [System.IO.Path]::Combine([System.IO.Path]::GetDirectoryName($projectFile), "snippets.5000.json")
# Create the default build command
"dotnet build `"$projectFile`"" | Out-File ".\run.bat"
# Check for config file
if ([System.IO.File]::Exists($configFile) -eq $true) {
Write-Host "- Config file found"
$settings = $configFile | Get-ChildItem | Get-Content | ConvertFrom-Json
if ($settings.host -eq "visualstudio") {
Write-Host "- Using visual studio as build host"
# Create the visual studio build command
"CALL `"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat`"`n" +
"msbuild.exe `"$projectFile`" -restore:True" `
| Out-File ".\run.bat"
}
elseif ($settings.host -eq "custom") {
Write-Host "- Using custom build host: $($settings.command)"
$ExecutionContext.InvokeCommand.ExpandString($settings.command) | Out-File ".\run.bat"
}
elseif ($settings.host -eq "dotnet") {
Write-Host "- Using dotnet build host"
"dotnet build `"$projectFile`"" | Out-File ".\run.bat"
}
else {
throw "snippets.5000.json file isn't valid."
}
}
$result = Invoke-Expression ".\run.bat" | Out-String
$thisExitCode = 0
if ($LASTEXITCODE -ne 0) {
$thisExitCode = 4
}
New-Result $data[1] $projectFile $thisExitCode $result
}
# No project found
elseif ([int]$data[0] -eq 1) {
New-Result $data[1] "" 1 "😵 Project missing. A project (and optionally a solution file) must be in this directory or one of the parent directories to validate and build this code."
$thisExitCode = 1
}
# Too many projects found
elseif ([int]$data[0] -eq 2) {
New-Result $data[1] $data[2] 2 "😕 Too many projects found. A single project or solution must existing in this directory or one of the parent directories."
$thisExitCode = 2
}
# Solution found, but no project
elseif ([int]$data[0] -eq 3) {
New-Result $data[1] $data[2] 2 "😲 Solution found, but missing project. A project is required to compile this code."
$thisExitCode = 3
}
}
catch {
New-Result $data[1] $projectFile 1000 "ERROR: $($_.Exception)"
$thisExitCode = 4
Write-Host $_.Exception.Message -Foreground "Red"
Write-Host $_.ScriptStackTrace -Foreground "DarkGray"
}
$counter++
}
$resultItems = $Global:statusOutput | Select-Object InputFile, ProjectFile, ExitCode, Output
# Add our output type
$typeResult = @"
public class ResultItem
{
public string ProjectFile;
public string InputFile;
public int ExitCode;
public string BuildOutput;
public MSBuildError[] Errors;
public int ErrorCount;
public class MSBuildError
{
public string Line;
public string Error;
}
}
"@
Add-Type $typeResult
$transformedItems = $resultItems | ForEach-Object { New-Object ResultItem -Property @{
ProjectFile = $_.ProjectFile.Path;
InputFile = $_.InputFile;
ExitCode = $_.ExitCode;
BuildOutput = $_.Output;
Errors = @();
ErrorCount = 0}
}
# Transform the build output to break it down into MSBuild result entries
foreach ($item in $transformedItems) {
$list = @()
# Clean
if ($item.ExitCode -eq 0) {
#$list += New-Object -TypeName "ResultItem+MSBuildError" -Property @{ Line = $item.BuildOutput; Error = $item.BuildOutput }
}
# No project found
# Too many projects found
# Solution found, but no project
elseif ($item.ExitCode -ne 4) {
$list += New-Object -TypeName "ResultItem+MSBuildError" -Property @{ Line = $item.BuildOutput; Error = $item.BuildOutput }
$item.ErrorCount = 1
}
else {
$errorInfo = $item.BuildOutput -Split [System.Environment]::NewLine |
Select-String ": (?:Solution file error|error) ([^:]*)" | `
Select-Object Line -ExpandProperty Matches | `
Select-Object Line, Groups | `
Sort-Object Line | Get-Unique -AsString
$item.ErrorCount = $errorInfo.Count
foreach ($err in $errorInfo) {
$list += New-Object -TypeName "ResultItem+MSBuildError" -Property @{ Line = $err.Line; Error = $err.Groups[1].Value }
}
# Error count of 0 here means that no error was detected from build results, but there was still a failure of some kind
if ($item.ErrorCount -eq 0) {
$list += New-Object -TypeName "ResultItem+MSBuildError" -Property @{ Line = "Unknown error occurred. Check log and build output."; Error = "4" }
$item.ErrorCount = 1
}
}
$item.Errors = $list
}
$transformedItems | ConvertTo-Json -Depth 3 | Out-File 'output.json'
exit 0
# Sample snippets.5000.json file
<#
{
"host": "visualstudio"
}
#>

View File

@ -0,0 +1,53 @@
<#
.SYNOPSIS
Reads the output.json file and outputs status to GitHub Actions
.DESCRIPTION
Reads the output.json file and outputs status to GitHub Actions
.INPUTS
None
.OUTPUTS
None
.NOTES
Version: 1.1
Author: adegeo@microsoft.com
Creation Date: 06/24/2020
Purpose/Change: Change reporting items
#>
[CmdletBinding()]
Param(
)
$json = Get-Content output.json | ConvertFrom-Json
$errors = $json | Where-Object ErrorCount -ne 0 | Select-Object InputFile -ExpandProperty Errors | Select-Object InputFile, Error, Line
if ($errors.Count -eq 0) {
Write-Host "All builds passed"
exit 0
}
Write-Host "Total errors: $($errors.Count)"
foreach ($er in $errors) {
$lineColMatch = $er.Line | Select-String "(^.*)\((\d*),(\d*)\)" | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Groups
$errorFile = $er.InputFile
$errorLineNumber = 0
$errorColNumber = 0
if ($lineColMatch.Count -eq 4) {
$errorFile = $lineColMatch[1].Value.Replace("D:\a\docs\docs\", "").Replace("\", "/")
$errorLineNumber = $lineColMatch[2].Value
$errorColNumber = $lineColMatch[3].Value
}
Write-Host "::error file=$errorFile,line=$errorLineNumber,col=$errorColNumber::$($er.Line)"
}
exit 1