CI #4325
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
name: CI | |
on: | |
workflow_dispatch: # Allows you to run this workflow manually from the Actions tab | |
push: | |
paths-ignore: | |
- '.github/workflows/deploy-site.yml' | |
- 'Docs/**' | |
- 'Site/**' | |
pull_request: | |
paths-ignore: | |
- '.github/workflows/deploy-site.yml' | |
- 'Docs/**' | |
- 'Site/**' | |
schedule: | |
# Run daily at 00:00 so we get notified if CI is broken before a pull request | |
# is submitted. | |
- cron: '0 0 * * *' | |
env: | |
DOTNET_NOLOGO: true | |
jobs: | |
# Check some basic style rules. | |
check-style: | |
# Do not run this job for pull requests where both branches are from the same repo. | |
# Jobs that depend on this one will be skipped too. | |
# This prevents duplicate CI runs for our own pull requests, whilst preserving the ability to | |
# run the CI for each branch push to a fork, and for each pull request originating from a fork. | |
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || github.event_name == 'push' || github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id | |
needs: | |
- check-style-line-lengths | |
- check-style-line-endings | |
- check-style-copyright-headers | |
runs-on: ubuntu-latest | |
steps: | |
- run: echo "All style checks done" | |
check-style-line-lengths: | |
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || github.event_name == 'push' || github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id | |
runs-on: windows-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Check line length | |
run: .github/workflows/Scripts/CheckLineLength.ps1 -path Src | |
check-style-line-endings: | |
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || github.event_name == 'push' || github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id | |
runs-on: windows-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Check T4 line endings | |
run: .github/workflows/Scripts/CheckT4LineEndings.ps1 -path Src | |
check-style-copyright-headers: | |
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || github.event_name == 'push' || github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Setup the latest .NET 8 SDK | |
uses: actions/[email protected] | |
with: | |
dotnet-version: 8.0.x | |
- name: Check Copyright Headers | |
run: | | |
dotnet run --configuration=Release -p:TreatWarningsAsErrors=true --project Tools/CopyrightUpdateTool | |
if [[ -z "$(git status --porcelain)" ]]; then | |
exit 0 | |
else | |
git status --porcelain | |
exit 1 | |
fi | |
# Setup the OS matrix so that CUDA tests do not run on forks, as it needs self-hosted runners. | |
# Skip running on macOS in most cases. | |
setup-os-matrix: | |
# Do not run this job for pull requests where both branches are from the same repo. | |
# Jobs that depend on this one will be skipped too. | |
# This prevents duplicate CI runs for our own pull requests, whilst preserving the ability to | |
# run the CI for each branch push to a fork, and for each pull request originating from a fork. | |
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || github.event_name == 'push' || github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id | |
runs-on: ubuntu-latest | |
steps: | |
- name: Check if repo is fork | |
id: is-fork | |
run: echo "fork=$(gh api repos/${{ github.repository }} | jq .fork)" >> $GITHUB_OUTPUT | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- name: Setup OS matrix | |
id: setup-os-matrix | |
run: | | |
os=("ubuntu-latest" "windows-latest") | |
# runs on macOS only if there is a push to master, or a tag is | |
# pushed, we do this since macOS builds last too long and ILGPU | |
# is rarely used on a macOS | |
( | |
[ "${{ github.event_name }}" == "workflow_dispatch" ] || | |
[ "${{ github.event_name }}" == "schedule" ] || | |
( | |
[ "${{ github.event_name }}" == "push" ] && | |
( | |
[ "${{ github.ref }}" == "refs/heads/master" ] || | |
[[ "${{ github.ref }}" =~ "refs/tags/v" ]] | |
) | |
) | |
) && os+=("macos-latest") | |
[ "${{ steps.is-fork.outputs.fork }}" == "false" ] && os+=("cuda") | |
echo "os=$(jq -cn '$ARGS.positional' --args ${os[@]})" >> $GITHUB_OUTPUT | |
outputs: | |
os: ${{ steps.setup-os-matrix.outputs.os }} | |
# Check that building the entire solution for all target frameworks works. | |
build: | |
# Do not run this job for pull requests where both branches are from the same repo. | |
# Jobs that depend on this one will be skipped too. | |
# This prevents duplicate CI runs for our own pull requests, whilst preserving the ability to | |
# run the CI for each branch push to a fork, and for each pull request originating from a fork. | |
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || github.event_name == 'push' || github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id | |
runs-on: windows-latest | |
strategy: | |
matrix: | |
path: [Src, Samples, Tools] | |
fail-fast: false | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Setup the latest .NET 8 SDK | |
uses: actions/[email protected] | |
with: | |
dotnet-version: 8.0.x | |
- name: Build | |
run: dotnet build ${{ matrix.path }} --configuration=Release -p:TreatWarningsAsErrors=true | |
# Run tests for all supported combinations of OS/library/framework. | |
test-library: | |
needs: setup-os-matrix | |
strategy: | |
matrix: | |
os: ${{ fromJson(needs.setup-os-matrix.outputs.os) }} | |
library: [ILGPU, ILGPU.Algorithms, ILGPU.Analyzers] | |
framework: [net6.0, net7.0, net8.0] | |
flavor: [CPU, Velocity, Velocity128] | |
exclude: | |
- library: ILGPU.Algorithms | |
flavor: Velocity | |
- library: ILGPU.Algorithms | |
flavor: Velocity128 | |
- library: ILGPU.Analyzers | |
flavor: Velocity | |
- library: ILGPU.Analyzers | |
flavor: Velocity128 | |
- os: cuda | |
flavor: Velocity | |
- os: cuda | |
flavor: Velocity128 | |
- os: cuda | |
library: ILGPU.Analyzers | |
fail-fast: false | |
runs-on: ${{ matrix.os }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Setup the latest .NET 6 SDK | |
if: matrix.framework == 'net6.0' | |
uses: actions/[email protected] | |
with: | |
dotnet-version: 6.0.x | |
- name: Setup the latest .NET 7 SDK | |
if: matrix.framework == 'net7.0' | |
uses: actions/[email protected] | |
with: | |
dotnet-version: 7.0.x | |
- name: Setup the latest .NET 8 SDK | |
uses: actions/[email protected] | |
with: | |
dotnet-version: 8.0.x | |
- name: Set test flavor | |
id: test-flavor | |
shell: bash | |
run: | | |
flavor="Tests.${{ matrix.flavor }}" | |
[[ "${{ matrix.os }}" == cuda ]] && flavor="Tests.Cuda" | |
[[ "${{ matrix.library }}" == "ILGPU.Analyzers" ]] && flavor="Tests" | |
echo "flavor=$flavor" >> $GITHUB_OUTPUT | |
- name: Build and test | |
run: dotnet test Src/${{ matrix.library }}.${{ steps.test-flavor.outputs.flavor }} --configuration=Release --framework=${{ matrix.framework }} -p:TreatWarningsAsErrors=true | |
env: | |
ILGPU_CLEAN_TESTS: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || (github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))) }} | |
# Ensure that ILGPU libraries are built using the same version tag. | |
check-version: | |
# Do not run this job for pull requests where both branches are from the same repo. | |
# Jobs that depend on this one will be skipped too. | |
# This prevents duplicate CI runs for our own pull requests, whilst preserving the ability to | |
# run the CI for each branch push to a fork, and for each pull request originating from a fork. | |
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || github.event_name == 'push' || github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Check version | |
id: version | |
shell: pwsh | |
run: | | |
$xpath = "/Project/PropertyGroup/LibraryVersionPrefix/text()" | |
$main_version = (Select-Xml -path Src/Directory.Build.props -XPath $xpath).Node.Value | |
if ("${{ github.ref }}" -like "refs/tags/v*") { | |
$tag = "${{ github.ref }}".SubString(11) | |
if (-not ($tag -eq $main_version)) { | |
echo "::error ::There is a mismatch between the project version ($main_version) and the tag ($tag)" | |
exit 1 | |
} | |
} | |
if (-not ("${{ github.ref }}" -like "refs/tags/v*")) { | |
$suffix = "preview-$(Get-Date -Format yyyyMMddHHmmss -AsUTC)-$(git rev-parse --short HEAD)" | |
$main_version = "$main_version-$suffix" | |
} | |
echo "version=$main_version" >> $env:GITHUB_OUTPUT | |
echo "suffix=$suffix" >> $env:GITHUB_OUTPUT | |
outputs: | |
version: ${{ steps.version.outputs.version }} | |
suffix: ${{ steps.version.outputs.suffix }} | |
# Create the NuGet packages, with fixes for portable symbols. | |
package-library: | |
needs: check-version | |
runs-on: windows-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Setup the latest .NET 8 SDK | |
uses: actions/[email protected] | |
with: | |
dotnet-version: 8.0.x | |
- name: Create NuGet packages | |
run: | | |
$suffix = "${{ needs.check-version.outputs.suffix }}" | |
if ([bool]$suffix) { | |
$params = "--version-suffix", $suffix | |
} | |
dotnet pack Src --configuration=Release @params | |
- name: Upload NuGet package artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: nuget-packages | |
path: ./Bin/Release/ILGPU*.${{ needs.check-version.outputs.version }}.*nupkg | |
# Create the Samples zip file, replacing ILGPU project references with equivalent NuGet package references. | |
package-samples: | |
needs: | |
- check-version | |
- package-library | |
runs-on: windows-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Setup the latest .NET 8 SDK | |
uses: actions/[email protected] | |
with: | |
dotnet-version: 8.0.x | |
# Change the ILGPU project references to NuGet package references | |
- name: Update sample references | |
id: package | |
run: .github/workflows/Scripts/UpdateSampleReferences.ps1 -version "${{ needs.check-version.outputs.version }}" -suffix "${{ needs.check-version.outputs.suffix }}" | |
# Compress the Samples folder | |
- name: Compress samples | |
run: | | |
$artifactPath = "Samples-${{ needs.check-version.outputs.version }}.zip" | |
Compress-Archive .\Samples\* -DestinationPath $artifactPath | |
# Verify that the sample projects can compile after switching to NuGet references | |
- name: Download NuGet package artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: nuget-packages | |
path: local-nuget-packages | |
- name: Compile sample projects | |
run: | | |
# Decompress sample projects into temp folder | |
$tempFolder = Join-Path $env:RUNNER_TEMP "TempSamples" | |
Expand-Archive "Samples-*.zip" -DestinationPath $tempFolder | |
# Add local nuget packages | |
# NB: We use a fully qualified path because relative paths are relative to the | |
# NuGet.Config file. This could either be the NuGet.Config file in the samples, | |
# or the global NuGet.Config file (if we did not create one in the samples) | |
pushd $tempFolder | |
$repoPath = Resolve-Path (Join-Path $env:GITHUB_WORKSPACE "local-nuget-packages") | |
dotnet nuget add source $repoPath --name "ILGPU Local NuGet Packages" | |
# Ensure sample projects can compile | |
dotnet build --configuration=Release -p:TreatWarningsAsErrors=true | |
popd | |
# Upload samples artifact (for version tags and master branch only) | |
- name: Upload Samples artifact | |
uses: actions/upload-artifact@v4 | |
if: github.event_name == 'push' && !github.event.repository.fork && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v')) | |
with: | |
name: samples | |
path: ./Samples-*.zip | |
# Virtual job that can be configured as a required check before a PR can be | |
# merged. | |
# As GitHub considers a check as successful if it is skipped, we need to | |
# check its status in another workflow (check-required.yml) and create a | |
# check there. | |
all-required-checks-done: | |
needs: | |
- check-style | |
- build | |
- test-library | |
- package-library | |
- package-samples | |
runs-on: ubuntu-latest | |
steps: | |
- run: echo "All required checks done" | |
# Publish a preview version of the NuGet packages on feedz.io when there is | |
# a push to master. | |
publish-preview: | |
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && !github.event.repository.fork | |
needs: all-required-checks-done | |
runs-on: ubuntu-latest | |
steps: | |
- name: Download NuGet package artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: nuget-packages | |
- name: Publish to FeedzIO | |
run: dotnet nuget push "*.nupkg" --api-key ${{ secrets.FEEDZIO_API_KEY }} --source https://f.feedz.io/ilgpu/preview/nuget/index.json | |
# Create a GitHub release and publish the NuGet packages to nuget.org when | |
# a tag is pushed. | |
publish-release: | |
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && !github.event.repository.fork | |
# Depends explictly on the 'check-version' job so we can access its output | |
needs: | |
- all-required-checks-done | |
- check-version | |
runs-on: ubuntu-latest | |
steps: | |
- name: Download NuGet package artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: nuget-packages | |
- name: Download Samples artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: samples | |
# if tag contains "-" treat it as pre-release | |
# example: 1.0.0-beta1 | |
- name: Create release | |
uses: softprops/action-gh-release@v2 | |
with: | |
name: Release v${{ needs.check-version.outputs.version }} | |
draft: true | |
prerelease: ${{ contains(needs.check-version.outputs.version, '-') }} | |
files: | | |
*.nupkg | |
Samples-*.zip | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- name: Publish to NuGet | |
run: dotnet nuget push "*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json |