GitHub Actions: reduce permissions #23
Workflow file for this run
This file contains 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
# General links | |
# https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables | |
# https://docs.github.com/en/actions/learn-github-actions/contexts#github-context | |
# https://docs.github.com/en/webhooks-and-events/webhooks/webhook-events-and-payloads | |
# https://docs.github.com/en/actions/learn-github-actions/expressions | |
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net | |
name: Build | |
on: | |
push: | |
branches: [ 'master', 'release/**' ] | |
pull_request: | |
branches: [ 'master', 'release/**' ] | |
tags: | |
- 'v*' | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref }} | |
cancel-in-progress: true | |
env: | |
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true | |
DOTNET_CLI_TELEMETRY_OPTOUT: true | |
# The Windows runner image has PostgreSQL pre-installed and sets the PGPASSWORD environment variable to "root". | |
# This conflicts with the default password "postgres", which is used by ikalnytskyi/action-setup-postgres. | |
# Because action-setup-postgres forgets to update the environment variable accordingly, we do so here. | |
PGPASSWORD: "postgres" | |
jobs: | |
build-and-test: | |
timeout-minutes: 60 | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest, windows-latest, macos-latest] | |
runs-on: ${{ matrix.os }} | |
permissions: | |
contents: read | |
steps: | |
- name: Setup PostgreSQL | |
uses: ikalnytskyi/action-setup-postgres@v4 | |
with: | |
username: postgres | |
password: postgres | |
- name: Setup .NET | |
uses: actions/setup-dotnet@v3 | |
with: | |
dotnet-version: 6.0.x | |
- name: Setup PowerShell (Ubuntu) | |
if: matrix.os == 'ubuntu-latest' | |
run: | | |
dotnet tool install --global PowerShell | |
- name: Setup PowerShell (Windows) | |
if: matrix.os == 'windows-latest' | |
shell: cmd | |
run: | | |
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 | |
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 | |
- name: Setup PowerShell (macOS) | |
if: matrix.os == 'macos-latest' | |
run: | | |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
brew install --cask powershell | |
- name: Show installed versions | |
shell: pwsh | |
run: | | |
Write-Host "$(pwsh --version) is installed at $PSHOME" | |
psql --version | |
Write-Host "Active .NET SDK: $(dotnet --version)" | |
- name: Git checkout | |
uses: actions/checkout@v3 | |
- name: Restore tools | |
run: | | |
dotnet tool restore | |
- name: Restore packages | |
run: | | |
dotnet restore | |
- name: Calculate version suffix | |
shell: pwsh | |
run: | | |
if ($env:GITHUB_REF_TYPE -eq 'tag') { | |
# Get the version prefix/suffix from the git tag. For example: 'v1.0.0-preview1-final' => '1.0.0' and 'preview1-final' | |
$segments = $env:GITHUB_REF_NAME -split "-" | |
$versionPrefix = $segments[0].TrimStart('v') | |
$versionSuffix = $segments[1..-1] -join "-" | |
[xml]$xml = Get-Content Directory.Build.props | |
$configuredVersionPrefix = $xml.Project.PropertyGroup[0].JsonApiDotNetCoreVersionPrefix | |
if ($configuredVersionPrefix -ne $versionPrefix) { | |
Write-Error "Version prefix from git release tag '$versionPrefix' does not match version prefix '$configuredVersionPrefix' stored in Directory.Build.props." | |
# To recover from this: | |
# - Delete the GitHub release | |
# - Run: git push --delete the-invalid-tag-name | |
# - Adjust JsonApiDotNetCoreVersionPrefix in Directory.Build.props, commit and push | |
# - Recreate the GitHub release | |
} | |
} | |
else { | |
# Get the version suffix from the auto-incrementing build number. For example: '123' => 'master-00123' | |
$revision = "{0:D5}" -f [convert]::ToInt32($env:GITHUB_RUN_NUMBER, 10) | |
$versionSuffix = "$(![string]::IsNullOrEmpty($env:GITHUB_HEAD_REF) ? $env:GITHUB_HEAD_REF : $env:GITHUB_REF_NAME)-$revision" | |
} | |
Write-Output "Using version suffix: $versionSuffix" | |
Write-Output "PACKAGE_VERSION_SUFFIX=$versionSuffix" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
- name: Build | |
shell: pwsh | |
run: | | |
dotnet build --no-restore --configuration Release --version-suffix=$env:PACKAGE_VERSION_SUFFIX | |
- name: Test | |
run: | | |
dotnet test --no-build --configuration Release --collect:"XPlat Code Coverage" --logger "GitHubActions;summary.includeSkippedTests=true" -- RunConfiguration.CollectSourceInformation=true DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.DeterministicReport=true | |
- name: Upload coverage to codecov.io | |
if: matrix.os == 'ubuntu-latest' | |
uses: codecov/codecov-action@v3 | |
- name: Generate packages | |
shell: pwsh | |
run: | | |
dotnet pack --no-build --configuration Release --output $env:GITHUB_WORKSPACE/artifacts/packages --version-suffix=$env:PACKAGE_VERSION_SUFFIX | |
- name: Upload packages to artifacts | |
if: matrix.os == 'ubuntu-latest' | |
uses: actions/upload-artifact@v3 | |
with: | |
name: packages | |
path: artifacts/packages | |
- name: Generate documentation | |
shell: pwsh | |
env: | |
# This contains the git tag name on release; in that case we build the docs without publishing them. | |
DOCFX_SOURCE_BRANCH_NAME: ${{ github.base_ref || github.ref_name }} | |
run: | | |
cd docs | |
& ./generate-examples.ps1 | |
dotnet docfx docfx.json | |
if ($LastExitCode -ne 0) { | |
Write-Error "docfx failed with exit code $LastExitCode." | |
} | |
Copy-Item CNAME _site/CNAME | |
Copy-Item home/*.html _site/ | |
Copy-Item home/*.ico _site/ | |
New-Item -Force _site/styles -ItemType Directory | Out-Null | |
Copy-Item -Recurse home/assets/* _site/styles/ | |
- name: Upload documentation to artifacts | |
if: matrix.os == 'ubuntu-latest' | |
uses: actions/upload-artifact@v3 | |
with: | |
name: documentation | |
path: docs/_site | |
inspect-code: | |
timeout-minutes: 60 | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest, windows-latest, macos-latest] | |
runs-on: ${{ matrix.os }} | |
permissions: | |
contents: read | |
steps: | |
- name: Git checkout | |
uses: actions/checkout@v3 | |
- name: Setup .NET | |
uses: actions/setup-dotnet@v3 | |
with: | |
dotnet-version: 6.0.x | |
- name: Restore tools | |
run: | | |
dotnet tool restore | |
- name: InspectCode | |
shell: pwsh | |
run: | | |
$inspectCodeOutputPath = Join-Path $env:RUNNER_TEMP 'jetbrains-inspectcode-results.xml' | |
Write-Output "INSPECT_CODE_OUTPUT_PATH=$inspectCodeOutputPath" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
dotnet jb inspectcode JsonApiDotNetCore.sln --build --output="$inspectCodeOutputPath" --profile=WarningSeverities.DotSettings --properties:Configuration=Release --properties:ContinuousIntegrationBuild=false --severity=WARNING --verbosity=WARN -dsl=GlobalAll -dsl=GlobalPerProduct -dsl=SolutionPersonal -dsl=ProjectPersonal | |
- name: Verify outcome | |
shell: pwsh | |
run: | | |
[xml]$xml = Get-Content $env:INSPECT_CODE_OUTPUT_PATH | |
if ($xml.report.Issues -and $xml.report.Issues.Project) { | |
foreach ($project in $xml.report.Issues.Project) { | |
if ($project.Issue.Count -gt 0) { | |
$project.ForEach({ | |
Write-Output "`nProject $($project.Name)" | |
$failed = $true | |
$_.Issue.ForEach({ | |
$issueType = $xml.report.IssueTypes.SelectSingleNode("IssueType[@Id='$($_.TypeId)']") | |
$severity = $_.Severity ?? $issueType.Severity | |
Write-Output "[$severity] $($_.File):$($_.Line) $($_.TypeId): $($_.Message)" | |
}) | |
}) | |
} | |
} | |
if ($failed) { | |
Write-Error "One or more projects failed code inspection." | |
} | |
} | |
cleanup-code: | |
timeout-minutes: 60 | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-latest, windows-latest, macos-latest] | |
runs-on: ${{ matrix.os }} | |
permissions: | |
contents: read | |
steps: | |
- name: Git checkout | |
uses: actions/checkout@v3 | |
with: | |
fetch-depth: 2 | |
- name: Setup .NET | |
uses: actions/setup-dotnet@v3 | |
with: | |
dotnet-version: 6.0.x | |
- name: Restore tools | |
run: | | |
dotnet tool restore | |
- name: Restore packages | |
run: | | |
dotnet restore | |
- name: CleanupCode (on PR diff) | |
if: github.event_name == 'pull_request' | |
shell: pwsh | |
run: | | |
# 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. | |
# 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. | |
$headCommitHash = git rev-parse HEAD | |
$baseCommitHash = git rev-parse HEAD~1 | |
Write-Output "Running code cleanup on commit range $baseCommitHash..$headCommitHash in pull request." | |
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 | |
- name: CleanupCode (on branch) | |
if: github.event_name == 'push' | |
shell: pwsh | |
run: | | |
Write-Output "Running code cleanup on all files." | |
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 | |
publish: | |
timeout-minutes: 60 | |
runs-on: ubuntu-latest | |
needs: [ build-and-test, inspect-code, cleanup-code ] | |
if: ${{ !github.event.pull_request.head.repo.fork }} | |
permissions: | |
packages: write | |
contents: write | |
steps: | |
- name: Download artifacts | |
uses: actions/download-artifact@v3 | |
- name: Publish to GitHub Packages | |
if: github.event_name == 'push' | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
shell: pwsh | |
run: | | |
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' | |
dotnet nuget push "$env:GITHUB_WORKSPACE/packages/*.nupkg" --api-key "$env:GITHUB_TOKEN" --source 'github' | |
- name: Publish documentation | |
if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
uses: peaceiris/actions-gh-pages@v3 | |
with: | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
publish_branch: gh-pages | |
publish_dir: ./documentation | |
commit_message: 'Auto-generated documentation from' | |
- name: Publish to NuGet | |
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') | |
env: | |
NUGET_ORG_API_KEY: ${{ secrets.NUGET_ORG_API_KEY }} | |
shell: pwsh | |
run: | | |
dotnet nuget push "$env:GITHUB_WORKSPACE/packages/*.nupkg" --api-key "$env:NUGET_ORG_API_KEY" --source 'nuget.org' |