diff --git a/.github/workflows/build-validation.yml b/.github/workflows/build-validation.yml new file mode 100644 index 0000000000000..f61ab18d9c2e8 --- /dev/null +++ b/.github/workflows/build-validation.yml @@ -0,0 +1,67 @@ +# 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" + - "**.cpp" + - "**.h" + - "**.xaml" + - "**.razor" + - "**.cshtml" + - "**.vbhtml" + - "**.*proj" + - "**global.json" + branches: [ master ] + +env: + DOTNET_VERSION: '3.1.300' # set this to the dot net version to use + +# 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@v2 + - name: Setup .NET Core SDK + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + # 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@v1 + with: + name: build + path: ./output.json + + # Return status based on json file + - name: Report status + run: | + ./.github/workflows/dependencies/Out-GithubActionStatus.ps1 + + + diff --git a/.github/workflows/dependencies/DotnetDocsTools.LocateProjects.1.0.3.nupkg b/.github/workflows/dependencies/DotnetDocsTools.LocateProjects.1.0.3.nupkg new file mode 100644 index 0000000000000..ea544437baf2a Binary files /dev/null and b/.github/workflows/dependencies/DotnetDocsTools.LocateProjects.1.0.3.nupkg differ diff --git a/.github/workflows/dependencies/Get-MSBuildResults.ps1 b/.github/workflows/dependencies/Get-MSBuildResults.ps1 new file mode 100644 index 0000000000000..d4234c34ef22c --- /dev/null +++ b/.github/workflows/dependencies/Get-MSBuildResults.ps1 @@ -0,0 +1,213 @@ +<# + +.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.1 + Author: adegeo@microsoft.com + Creation Date: 06/17/2020 + Purpose/Change: Update to GitHub actions and new framework. +#> + +[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] +} + +$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])" + $result = Invoke-Expression "dotnet build `"$projectFile`"" | 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 "No project found" + $thisExitCode = 1; + } + + # Too many projects found + elseif ([int]$data[0] -eq 2) { + New-Result $data[1] $data[2] 2 "Too many projects found" + $thisExitCode = 2; + } + + # Solution found, but no project + elseif ([int]$data[0] -eq 3) { + New-Result $data[1] $data[2] 2 "Top-level solution found, but no project" + $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 = @() + + # No project found OR + if ($item.ExitCode -eq 0) { + $list += New-Object -TypeName "ResultItem+MSBuildError" -Property @{ Line = ""; Error = $item.BuildOutput } + } + elseif ($item.ExitCode -ne 4) { + $list += New-Object -TypeName "ResultItem+MSBuildError" -Property @{ Line = ""; Error = $item.BuildOutput } + $item.ErrorCount = 1 + } + elseif ($item.ExitCode -ne 0) { + $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 } + } + } + + $item.Errors = $list + +} + +$transformedItems | ConvertTo-Json -Depth 3 | Out-File 'output.json' + +exit 0 \ No newline at end of file diff --git a/.github/workflows/dependencies/Out-GithubActionStatus.ps1 b/.github/workflows/dependencies/Out-GithubActionStatus.ps1 new file mode 100644 index 0000000000000..73d8cd6ba1c6c --- /dev/null +++ b/.github/workflows/dependencies/Out-GithubActionStatus.ps1 @@ -0,0 +1,43 @@ +<# + +.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.0 + Author: adegeo@microsoft.com + Creation Date: 06/17/2020 + Purpose/Change: Initial release +#> + +[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) { + Write-Host "::error file=$($er.InputFile)::----FILE: $($er.InputFile)" + Write-Host "::error file=$($er.InputFile):: ERROR: $($er.Error)" + Write-Host "::error file=$($er.InputFile):: LINE: $($er.Line)" +} + +exit 1 \ No newline at end of file