|
| 1 | +# General links |
| 2 | +# https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables |
| 3 | +# https://docs.github.com/en/actions/learn-github-actions/contexts#github-context |
| 4 | +# https://docs.github.com/en/webhooks-and-events/webhooks/webhook-events-and-payloads |
| 5 | +# https://docs.github.com/en/actions/learn-github-actions/expressions |
| 6 | +# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net |
| 7 | + |
| 8 | +name: Build |
| 9 | + |
| 10 | +on: |
| 11 | + push: |
| 12 | + branches: [ 'master', 'release/**' ] |
| 13 | + pull_request: |
| 14 | + branches: [ 'master', 'release/**' ] |
| 15 | + tags: |
| 16 | + - 'v*' |
| 17 | + |
| 18 | +concurrency: |
| 19 | + group: ${{ github.workflow }}-${{ github.ref }} |
| 20 | + cancel-in-progress: true |
| 21 | + |
| 22 | +env: |
| 23 | + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true |
| 24 | + DOTNET_CLI_TELEMETRY_OPTOUT: true |
| 25 | + # The Windows runner image has PostgreSQL pre-installed and sets the PGPASSWORD environment variable to "root". |
| 26 | + # This conflicts with the default password "postgres", which is used by ikalnytskyi/action-setup-postgres. |
| 27 | + # Because action-setup-postgres forgets to update the environment variable accordingly, we do so here. |
| 28 | + PGPASSWORD: "postgres" |
| 29 | + |
| 30 | +jobs: |
| 31 | + build-and-test: |
| 32 | + timeout-minutes: 60 |
| 33 | + strategy: |
| 34 | + fail-fast: false |
| 35 | + matrix: |
| 36 | + os: [ubuntu-latest, windows-latest, macos-latest] |
| 37 | + runs-on: ${{ matrix.os }} |
| 38 | + steps: |
| 39 | + - name: Setup PostgreSQL |
| 40 | + uses: ikalnytskyi/action-setup-postgres@v4 |
| 41 | + with: |
| 42 | + username: postgres |
| 43 | + password: postgres |
| 44 | + - name: Setup .NET |
| 45 | + uses: actions/setup-dotnet@v3 |
| 46 | + with: |
| 47 | + dotnet-version: 6.0.x |
| 48 | + - name: Setup PowerShell (Ubuntu) |
| 49 | + if: matrix.os == 'ubuntu-latest' |
| 50 | + run: | |
| 51 | + dotnet tool install --global PowerShell |
| 52 | + - name: Setup PowerShell (Windows) |
| 53 | + if: matrix.os == 'windows-latest' |
| 54 | + shell: cmd |
| 55 | + run: | |
| 56 | + curl --location --output "%RUNNER_TEMP%\PowerShell-7.3.6-win-x64.msi" https://github.com/PowerShell/PowerShell/releases/download/v7.3.6/PowerShell-7.3.6-win-x64.msi |
| 57 | + msiexec.exe /package "%RUNNER_TEMP%\PowerShell-7.3.6-win-x64.msi" /quiet USE_MU=1 ENABLE_MU=1 ADD_PATH=1 DISABLE_TELEMETRY=1 |
| 58 | + - name: Setup PowerShell (macOS) |
| 59 | + if: matrix.os == 'macos-latest' |
| 60 | + run: | |
| 61 | + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" |
| 62 | + brew install --cask powershell |
| 63 | + - name: Show installed versions |
| 64 | + shell: pwsh |
| 65 | + run: | |
| 66 | + Write-Host "$(pwsh --version) is installed at $PSHOME" |
| 67 | + psql --version |
| 68 | + Write-Host "Active .NET SDK: $(dotnet --version)" |
| 69 | + - name: Git checkout |
| 70 | + uses: actions/checkout@v3 |
| 71 | + - name: Restore tools |
| 72 | + run: | |
| 73 | + dotnet tool restore |
| 74 | + - name: Restore packages |
| 75 | + run: | |
| 76 | + dotnet restore |
| 77 | + - name: Calculate version suffix |
| 78 | + shell: pwsh |
| 79 | + run: | |
| 80 | + if ($env:GITHUB_REF_TYPE -eq 'tag') { |
| 81 | + # Get the version prefix/suffix from the git tag. For example: 'v1.0.0-preview1-final' => '1.0.0' and 'preview1-final' |
| 82 | + $segments = $env:GITHUB_REF_NAME -split "-" |
| 83 | + $versionPrefix = $segments[0].TrimStart('v') |
| 84 | + $versionSuffix = $segments[1..-1] -join "-" |
| 85 | +
|
| 86 | + [xml]$xml = Get-Content Directory.Build.props |
| 87 | + $configuredVersionPrefix = $xml.Project.PropertyGroup[0].JsonApiDotNetCoreVersionPrefix |
| 88 | + if ($configuredVersionPrefix -ne $versionPrefix) { |
| 89 | + Write-Error "Version prefix from git release tag '$versionPrefix' does not match version prefix '$configuredVersionPrefix' stored in Directory.Build.props." |
| 90 | + # To recover from this: |
| 91 | + # - Delete the GitHub release |
| 92 | + # - Run: git push --delete the-invalid-tag-name |
| 93 | + # - Adjust JsonApiDotNetCoreVersionPrefix in Directory.Build.props, commit and push |
| 94 | + # - Recreate the GitHub release |
| 95 | + } |
| 96 | + } |
| 97 | + else { |
| 98 | + # Get the version suffix from the auto-incrementing build number. For example: '123' => 'master-00123' |
| 99 | + $revision = "{0:D5}" -f [convert]::ToInt32($env:GITHUB_RUN_NUMBER, 10) |
| 100 | + $versionSuffix = "$($env:GITHUB_HEAD_REF ?? $env:GITHUB_REF_NAME)-$revision" |
| 101 | + } |
| 102 | + Write-Output "Using version suffix: $versionSuffix" |
| 103 | + Write-Output "PACKAGE_VERSION_SUFFIX=$versionSuffix" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append |
| 104 | + - name: Build |
| 105 | + shell: pwsh |
| 106 | + run: | |
| 107 | + dotnet build --no-restore --configuration Release --version-suffix=$env:PACKAGE_VERSION_SUFFIX |
| 108 | + - name: Test |
| 109 | + run: | |
| 110 | + dotnet test --no-build --configuration Release --collect:"XPlat Code Coverage" --logger "GitHubActions;summary.includeSkippedTests=true" -- RunConfiguration.CollectSourceInformation=true DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.DeterministicReport=true |
| 111 | + - name: Upload coverage to codecov.io |
| 112 | + if: matrix.os == 'ubuntu-latest' |
| 113 | + uses: codecov/codecov-action@v3 |
| 114 | + - name: Generate packages |
| 115 | + shell: pwsh |
| 116 | + run: | |
| 117 | + dotnet pack --no-build --configuration Release --output $env:GITHUB_WORKSPACE/artifacts/packages --version-suffix=$env:PACKAGE_VERSION_SUFFIX |
| 118 | + - name: Upload packages to artifacts |
| 119 | + if: matrix.os == 'ubuntu-latest' |
| 120 | + uses: actions/upload-artifact@v3 |
| 121 | + with: |
| 122 | + name: packages |
| 123 | + path: artifacts/packages |
| 124 | + - name: Generate documentation |
| 125 | + shell: pwsh |
| 126 | + env: |
| 127 | + # This contains the git tag name on release; in that case we build the docs without publishing them. |
| 128 | + DOCFX_SOURCE_BRANCH_NAME: ${{ github.base_ref || github.ref_name }} |
| 129 | + run: | |
| 130 | + cd docs |
| 131 | + & ./generate-examples.ps1 |
| 132 | + dotnet docfx docfx.json |
| 133 | + if ($LastExitCode -ne 0) { |
| 134 | + Write-Error "docfx failed with exit code $LastExitCode." |
| 135 | + } |
| 136 | + Copy-Item CNAME _site/CNAME |
| 137 | + Copy-Item home/*.html _site/ |
| 138 | + Copy-Item home/*.ico _site/ |
| 139 | + New-Item -Force _site/styles -ItemType Directory | Out-Null |
| 140 | + Copy-Item -Recurse home/assets/* _site/styles/ |
| 141 | + - name: Upload documentation to artifacts |
| 142 | + if: matrix.os == 'ubuntu-latest' |
| 143 | + uses: actions/upload-artifact@v3 |
| 144 | + with: |
| 145 | + name: documentation |
| 146 | + path: docs/_site |
| 147 | + |
| 148 | + inspect-code: |
| 149 | + timeout-minutes: 60 |
| 150 | + strategy: |
| 151 | + fail-fast: false |
| 152 | + matrix: |
| 153 | + os: [ubuntu-latest, windows-latest, macos-latest] |
| 154 | + runs-on: ${{ matrix.os }} |
| 155 | + steps: |
| 156 | + - name: Git checkout |
| 157 | + uses: actions/checkout@v3 |
| 158 | + - name: Setup .NET |
| 159 | + uses: actions/setup-dotnet@v3 |
| 160 | + with: |
| 161 | + dotnet-version: 6.0.x |
| 162 | + - name: Restore tools |
| 163 | + run: | |
| 164 | + dotnet tool restore |
| 165 | + - name: InspectCode |
| 166 | + shell: pwsh |
| 167 | + run: | |
| 168 | + $inspectCodeOutputPath = Join-Path $env:RUNNER_TEMP 'jetbrains-inspectcode-results.xml' |
| 169 | + Write-Output "INSPECT_CODE_OUTPUT_PATH=$inspectCodeOutputPath" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append |
| 170 | + dotnet jb inspectcode JsonApiDotNetCore.sln --build --output="$inspectCodeOutputPath" --profile=WarningSeverities.DotSettings --properties:Configuration=Release --severity=WARNING --verbosity=WARN -dsl=GlobalAll -dsl=GlobalPerProduct -dsl=SolutionPersonal -dsl=ProjectPersonal |
| 171 | + - name: Verify outcome |
| 172 | + shell: pwsh |
| 173 | + run: | |
| 174 | + [xml]$xml = Get-Content $env:INSPECT_CODE_OUTPUT_PATH |
| 175 | + if ($xml.report.Issues -and $xml.report.Issues.Project) { |
| 176 | + foreach ($project in $xml.report.Issues.Project) { |
| 177 | + if ($project.Issue.Count -gt 0) { |
| 178 | + $project.ForEach({ |
| 179 | + Write-Output "`nProject $($project.Name)" |
| 180 | + $failed = $true |
| 181 | +
|
| 182 | + $_.Issue.ForEach({ |
| 183 | + $issueType = $xml.report.IssueTypes.SelectSingleNode("IssueType[@Id='$($_.TypeId)']") |
| 184 | + $severity = $_.Severity ?? $issueType.Severity |
| 185 | +
|
| 186 | + Write-Output "[$severity] $($_.File):$($_.Line) $($_.TypeId): $($_.Message)" |
| 187 | + }) |
| 188 | + }) |
| 189 | + } |
| 190 | + } |
| 191 | +
|
| 192 | + if ($failed) { |
| 193 | + Write-Error "One or more projects failed code inspection." |
| 194 | + } |
| 195 | + else { |
| 196 | + Write-Output "No issues found." |
| 197 | + } |
| 198 | + } |
| 199 | +
|
| 200 | + cleanup-code: |
| 201 | + timeout-minutes: 60 |
| 202 | + strategy: |
| 203 | + fail-fast: false |
| 204 | + matrix: |
| 205 | + os: [ubuntu-latest, windows-latest, macos-latest] |
| 206 | + runs-on: ${{ matrix.os }} |
| 207 | + steps: |
| 208 | + - name: Git checkout |
| 209 | + uses: actions/checkout@v3 |
| 210 | + with: |
| 211 | + fetch-depth: 2 |
| 212 | + - name: Setup .NET |
| 213 | + uses: actions/setup-dotnet@v3 |
| 214 | + with: |
| 215 | + dotnet-version: 6.0.x |
| 216 | + - name: Restore tools |
| 217 | + run: | |
| 218 | + dotnet tool restore |
| 219 | + - name: Restore packages |
| 220 | + run: | |
| 221 | + dotnet restore |
| 222 | + - name: CleanupCode (on PR diff) |
| 223 | + if: github.event_name == 'pull_request' |
| 224 | + shell: pwsh |
| 225 | + run: | |
| 226 | + # Not using the environment variables for SHAs, because they may be outdated. This may happen on force-push after the build is queued, but before it starts. |
| 227 | + # The below works because HEAD is detached (at the merge commit), so HEAD~1 is at the base branch. When a PR contains no commits, this job will not run. |
| 228 | + $headCommitHash = git rev-parse HEAD |
| 229 | + $baseCommitHash = git rev-parse HEAD~1 |
| 230 | +
|
| 231 | + Write-Output "Running code cleanup on commit range $baseCommitHash..$headCommitHash in pull request." |
| 232 | + dotnet regitlint -s JsonApiDotNetCore.sln --print-command --skip-tool-check --max-runs=5 --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN -f commits -a $headCommitHash -b $baseCommitHash --fail-on-diff --print-diff |
| 233 | + - name: CleanupCode (on branch) |
| 234 | + if: github.event_name == 'push' |
| 235 | + shell: pwsh |
| 236 | + run: | |
| 237 | + Write-Output "Running code cleanup on all files." |
| 238 | + dotnet regitlint -s JsonApiDotNetCore.sln --print-command --skip-tool-check --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --verbosity=WARN --fail-on-diff --print-diff |
| 239 | +
|
| 240 | + publish: |
| 241 | + timeout-minutes: 60 |
| 242 | + runs-on: ubuntu-latest |
| 243 | + needs: [ build-and-test, inspect-code, cleanup-code ] |
| 244 | + if: ${{ !github.event.pull_request.head.repo.fork }} |
| 245 | + permissions: |
| 246 | + packages: write |
| 247 | + contents: write |
| 248 | + steps: |
| 249 | + - name: Download artifacts |
| 250 | + uses: actions/download-artifact@v3 |
| 251 | + - name: Publish to GitHub Packages |
| 252 | + env: |
| 253 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 254 | + shell: pwsh |
| 255 | + run: | |
| 256 | + dotnet nuget add source --username 'json-api-dotnet' --password "$env:GITHUB_TOKEN" --store-password-in-clear-text --name 'github' 'https://nuget.pkg.github.com/json-api-dotnet/index.json' |
| 257 | + dotnet nuget push "$env:GITHUB_WORKSPACE/packages/*.nupkg" --api-key "$env:GITHUB_TOKEN" --source 'github' |
| 258 | + - name: Publish documentation |
| 259 | + if: github.event_name == 'push' && github.ref == 'refs/heads/master' |
| 260 | + uses: peaceiris/actions-gh-pages@v3 |
| 261 | + with: |
| 262 | + github_token: ${{ secrets.GITHUB_TOKEN }} |
| 263 | + publish_branch: gh-pages |
| 264 | + publish_dir: ./documentation |
| 265 | + commit_message: 'Auto-generated documentation from' |
| 266 | + - name: Publish to NuGet |
| 267 | + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') |
| 268 | + env: |
| 269 | + NUGET_ORG_API_KEY: ${{ secrets.NUGET_ORG_API_KEY }} |
| 270 | + shell: pwsh |
| 271 | + run: | |
| 272 | + dotnet nuget push "$env:GITHUB_WORKSPACE/packages/*.nupkg" --api-key "$env:NUGET_ORG_API_KEY" --source 'nuget.org' |
0 commit comments