Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 0 additions & 81 deletions .github/workflows/build.yml

This file was deleted.

171 changes: 171 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: Client validation

on:
workflow_call:
inputs:
collect-coverage:
description: Emit Visual Studio XML coverage for the SonarQube Cloud analysis workflow.
type: boolean
default: false

permissions:
contents: read

defaults:
run:
shell: pwsh

env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
MSBUILDDISABLENODEREUSE: true

jobs:
validate:
name: Validate packages, template, and AOT graph
runs-on: windows-latest
timeout-minutes: 35

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- name: Install pinned .NET SDK
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
global-json-file: global.json
cache: true
cache-dependency-path: |
**/packages.lock.json
Directory.Packages.props

- name: Restore locked dependency graph
run: dotnet restore CheatEngine.Client.slnx --locked-mode

- name: Build Release
run: dotnet build CheatEngine.Client.slnx --configuration Release --no-restore --warnaserror

- name: Run unit tests through Microsoft Testing Platform
env:
COLLECT_COVERAGE: ${{ inputs.collect-coverage }}
run: |
$projects = @(Get-ChildItem -Path tests -Filter '*.Tests.csproj' -Recurse -File | Sort-Object Name)
if ($projects.Count -eq 0) {
throw 'No *.Tests.csproj project found under tests.'
}

foreach ($project in $projects) {
$results = Join-Path 'artifacts/test-results' $project.BaseName
$options = @(
'--project', $project.FullName,
'--configuration', 'Release',
'--no-build', '--no-restore',
'--report-trx',
'--results-directory', $results,
'--fail-skips', 'on'
)
if ($env:COLLECT_COVERAGE -eq 'true') {
$options += '--coverage', '--coverage-output-format', 'xml', '--coverage-output', 'coverage.xml'
}

dotnet test @options
}

- name: Summarize test results
if: ${{ !cancelled() }}
run: |
$reports = @(Get-ChildItem -Path artifacts/test-results -Filter *.trx -Recurse -File -ErrorAction SilentlyContinue)
if ($reports.Count -eq 0) {
throw 'Microsoft Testing Platform did not produce a TRX test report.'
}

$results = @($reports | ForEach-Object {
([xml](Get-Content -LiteralPath $_.FullName -Raw)).TestRun.Results.UnitTestResult
} | Where-Object { $_ })
$passed = @($results | Where-Object outcome -eq 'Passed').Count
$skipped = @($results | Where-Object outcome -eq 'NotExecuted').Count
$failed = @($results | Where-Object { $_.outcome -notin 'Passed', 'NotExecuted' })

@(
'### Test results',
'',
'| Total | Passed | Failed | Skipped |',
'| ---: | ---: | ---: | ---: |',
"| $($results.Count) | $passed | $($failed.Count) | $skipped |"
) | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8

- name: Upload test results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-results
path: artifacts/test-results/**/*.trx
if-no-files-found: warn
retention-days: 14

- name: Upload Sonar coverage
if: ${{ inputs.collect-coverage && !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-client
path: artifacts/test-results/*/coverage.xml
if-no-files-found: error
retention-days: 7

- name: Pack and validate public package APIs
run: dotnet pack CheatEngine.Client.slnx --configuration Release --no-build --no-restore

- name: Smoke test isolated package consumption
shell: pwsh
run: ./eng/Invoke-PackageSmoke.ps1 -PackageSource ./artifacts/packages

- name: Smoke test local template installation
run: ./eng/Invoke-TemplateSmoke.ps1 -PackageSource ./artifacts/packages

- name: Upload package artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: nuget-packages
path: |
artifacts/packages/*.nupkg
artifacts/packages/*.snupkg
if-no-files-found: error
retention-days: 14

- name: Publish Native AOT reference probe
run: dotnet publish tests/CheatEngine.Client.AotProbe/CheatEngine.Client.AotProbe.csproj --configuration Release --runtime win-x64 --no-restore --output ./artifacts/aot-probe

- name: Run Native AOT reference probe
run: ./artifacts/aot-probe/CheatEngine.Client.AotProbe.exe

- name: Upload Native AOT probe
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: native-aot-probe
path: artifacts/aot-probe
if-no-files-found: warn
retention-days: 14

gate:
name: Gate
if: ${{ always() }}
needs: validate
runs-on: windows-latest
timeout-minutes: 5
permissions: {}

steps:
- name: Check validation result
env:
VALIDATE_RESULT: ${{ needs.validate.result }}
run: |
"| Job | Result |", "| --- | --- |", "| validate | $env:VALIDATE_RESULT |" |
Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
if ($env:VALIDATE_RESULT -ne 'success') {
Write-Host "::error::Validation finished with '$env:VALIDATE_RESULT'."
exit 1
}
45 changes: 45 additions & 0 deletions .github/workflows/main-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Main CI

on:
push:
branches: [main]
paths:
- '.editorconfig'
- '.github/**'
- 'CheatEngine.Client.slnx'
- 'Directory.Build.props'
- 'Directory.Build.targets'
- 'Directory.Packages.props'
- 'README.md'
- 'eng/**'
- 'global.json'
- 'libs/**'
- 'src/**'
- 'templates/**'
- 'tests/**'
merge_group:
types: [checks_requested]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

permissions:
contents: read

jobs:
ci:
name: CI
uses: ./.github/workflows/ci.yml
with:
collect-coverage: ${{ github.ref == 'refs/heads/main' }}

# Main analysis is the SonarQube Cloud baseline for pull-request new-code comparisons.
sonar:
name: Sonar
needs: ci
if: github.ref == 'refs/heads/main'
uses: ./.github/workflows/sonar.yml
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
79 changes: 79 additions & 0 deletions .github/workflows/pull-request-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Pull request CI

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- '.editorconfig'
- '.github/**'
- 'CheatEngine.Client.slnx'
- 'Directory.Build.props'
- 'Directory.Build.targets'
- 'Directory.Packages.props'
- 'README.md'
- 'eng/**'
- 'global.json'
- 'libs/**'
- 'src/**'
- 'templates/**'
- 'tests/**'

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read

jobs:
ci:
name: CI
if: github.event.pull_request.draft == false
uses: ./.github/workflows/ci.yml
with:
collect-coverage: >-
${{ github.event.pull_request.head.repo.full_name == github.repository
&& github.actor != 'dependabot[bot]' }}

# Fork and Dependabot pull requests receive no repository secret. Keep this condition equal to collect-coverage.
sonar:
name: Sonar
needs: ci
if: >-
github.event.pull_request.head.repo.full_name == github.repository
&& github.actor != 'dependabot[bot]'
uses: ./.github/workflows/sonar.yml
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

lint-workflows:
name: Lint workflows
if: github.event.pull_request.draft == false
runs-on: windows-latest
timeout-minutes: 5
env:
ACTIONLINT_VERSION: 1.7.12
ACTIONLINT_SHA256: 6e7241b51e6817ea6a047693d8e6fed13b31819c9a0dd6c5a726e1592d22f6e9

steps:
- name: Checkout workflow definitions
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
sparse-checkout: .github
persist-credentials: false

- name: Run actionlint
run: |
$ErrorActionPreference = 'Stop'
$archive = Join-Path $env:RUNNER_TEMP 'actionlint.zip'
$url = "https://github.com/rhysd/actionlint/releases/download/v$env:ACTIONLINT_VERSION/actionlint_$($env:ACTIONLINT_VERSION)_windows_amd64.zip"
Invoke-WebRequest -Uri $url -OutFile $archive -MaximumRetryCount 3 -RetryIntervalSec 5

$actual = (Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash.ToLowerInvariant()
if ($actual -ne $env:ACTIONLINT_SHA256) {
throw "actionlint $env:ACTIONLINT_VERSION has SHA-256 $actual, expected $env:ACTIONLINT_SHA256."
}

$destination = Join-Path $env:RUNNER_TEMP 'actionlint'
Expand-Archive -LiteralPath $archive -DestinationPath $destination
& (Join-Path $destination 'actionlint.exe') -color
Loading