Skip to content

Fix ignore rule parsing and loading edge cases #2840

Fix ignore rule parsing and loading edge cases

Fix ignore rule parsing and loading edge cases #2840

Workflow file for this run

name: Build and Test
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'CLAUDE.md'
- 'LICENSE'
pull_request:
branches:
- main
paths-ignore:
- '**.md'
- 'CLAUDE.md'
- 'LICENSE'
workflow_dispatch:
permissions:
contents: read
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
test-framework: [net8.0, net9.0]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# The Windows lane is still dominated by temp-heavy test I/O even after
# the Defender exclusions from #394. Pinning TMP/TEMP to RUNNER_TEMP
# moves Path.GetTempPath()-driven fixtures onto the same faster, already
# CI-owned volume as the checkout workspace instead of the default user
# profile temp under C:\Users\runneradmin\AppData\Local\Temp.
# GITHUB_ENV is written before the Defender-exclusion step so the later
# verification sees the actual effective TMP/TEMP/GetTempPath values.
# Windows lane は #394 の Defender 除外後も temp-heavy なテスト I/O が
# 支配的なため、TMP/TEMP を RUNNER_TEMP 配下へ固定する。これにより
# Path.GetTempPath() を使う fixture 群が、既定の
# C:\Users\runneradmin\AppData\Local\Temp ではなく checkout と同じ
# CI 管理下の高速ボリュームを使う。Defender 除外 step より前に
# GITHUB_ENV へ書き込むことで、後続の検証が実際の TMP/TEMP /
# GetTempPath 値をそのまま確認できるようにする。
- name: Pin Windows TMP/TEMP to runner temp
if: runner.os == 'Windows'
shell: pwsh
run: |
$tempRoot = Join-Path $env:RUNNER_TEMP "cdidx-temp"
New-Item -ItemType Directory -Force -Path $tempRoot | Out-Null
"TMP=$tempRoot" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"TEMP=$tempRoot" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
$env:TMP = $tempRoot
$env:TEMP = $tempRoot
Write-Host "Pinned Windows TMP/TEMP to: $tempRoot"
Write-Host ".NET Path.GetTempPath() now resolves to: $([System.IO.Path]::GetTempPath())"
# Windows Defender real-time scanning of every temp file created by the
# test suite (temp projects, SQLite DBs, .cdidx directories, synthetic
# source files) dominates the Windows lane of this matrix; see issue #394.
# Excluding the workspace plus the effective temp roots before build/test
# and the immutable NuGet global package cache keeps Defender from
# repeatedly scanning the restore/build inputs that dotnet touches on
# Windows. This also prevents silent regression if the runner image or
# TMP/TEMP wiring changes again in the future.
# We rely on -ExclusionPath only: -ExclusionProcess expects full image
# paths, so bare filenames like 'dotnet.exe' would silently fail to take
# effect. We include $env:TMP and the live [IO.Path]::GetTempPath() value
# in addition to $env:TEMP / RUNNER_TEMP because .NET's Path.GetTempPath()
# consults TMP before TEMP and may resolve to a path that differs from
# $env:TEMP in pwsh. Paths are trimmed of trailing separators so the
# Get-MpPreference -notcontains check matches the stored form exactly.
# Every Add-MpPreference call uses -ErrorAction Stop, and a final
# Get-MpPreference verification throws if any exclusion did not register
# so the step fails loudly instead of degrading silently. The list of
# effective exclusions is also echoed to the log so future investigations
# of Windows lane variance can see exactly which paths were covered.
# テストスイートが大量に作る一時ファイル(temp project / SQLite DB /
# .cdidx / 合成ソース)を Windows Defender が都度スキャンする影響で
# Windows lane だけ極端に遅くなる(issue #394)。build/test 前に
# workspace と実効 temp root 群に加えて変更されない NuGet global package
# cache も除外し、Windows で dotnet が繰り返し触る restore/build 入力を
# Defender に再スキャンさせない。これで runner image や TMP/TEMP の
# 配線が今後変わっても silent regression しないようにする。
# -ExclusionProcess はフルパスを要求する仕様のため、bare filename では
# 黙って no-op になる。ここでは -ExclusionPath だけに寄せる。.NET の
# Path.GetTempPath() は TMP → TEMP → USERPROFILE の順で参照し、pwsh の
# $env:TEMP と異なるパスへ解決されうるため、$env:TMP と実行時の
# [IO.Path]::GetTempPath() も追加でカバーする。末尾区切り文字を揃え、
# Get-MpPreference -notcontains の照合を保存形式と完全一致させる。
# 各呼び出しを -ErrorAction Stop で明示失敗させ、最後に Get-MpPreference
# で登録を検証し、silent degradation を起こさないようにする。最終的に
# 適用された除外パス一覧はログにも出力し、今後 Windows lane のばらつき
# を調査するときにどのパスが対象になったかを追えるようにする。
- name: Exclude workspace and temp paths from Windows Defender (Windows only)
if: runner.os == 'Windows'
shell: pwsh
run: |
$candidates = @(
"${{ github.workspace }}",
$env:RUNNER_TEMP,
$env:TEMP,
$env:TMP,
[System.IO.Path]::GetTempPath(),
$env:NUGET_PACKAGES,
(Join-Path $env:USERPROFILE ".nuget\packages"),
(Join-Path $env:LOCALAPPDATA "NuGet\packages")
)
$paths = $candidates |
Where-Object { $_ } |
ForEach-Object { $_.TrimEnd('\','/') } |
Where-Object { $_ } |
Select-Object -Unique
Write-Host "Windows Defender exclusion candidates:"
foreach ($path in $paths) {
Write-Host " $path"
}
foreach ($path in $paths) {
Add-MpPreference -ExclusionPath $path -ErrorAction Stop
}
$prefs = Get-MpPreference
foreach ($path in $paths) {
if ($prefs.ExclusionPath -notcontains $path) {
throw "Windows Defender exclusion was not applied: $path"
}
}
- name: Set up .NET
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
with:
dotnet-version: |
8.0.x
9.0.x
- name: Cache NuGet packages
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: |
~/.nuget/packages
~\AppData\Local\NuGet\packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json', '**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
# --locked-mode requires every resolved package to match the committed
# packages.lock.json so an unexpected transitive bump (including silent
# native swaps under SQLitePCLRaw.bundle_e_sqlite3) fails the build
# instead of slipping into CI/release artifacts. See issue #1556.
# --locked-mode は packages.lock.json と完全一致する解決を強制するため、
# SQLitePCLRaw.bundle_e_sqlite3 の native を含む推移依存の予期せぬ
# bump が CI / release アーティファクトに紛れ込まずビルド失敗で気付ける。
# 詳細は issue #1556 参照。
- name: Restore dependencies
run: dotnet restore CodeIndex.sln --locked-mode
- name: Audit NuGet package vulnerabilities
shell: pwsh
run: |
$auditOutput = dotnet list src/CodeIndex/CodeIndex.csproj package --vulnerable --include-transitive --no-restore 2>&1
$auditExitCode = $LASTEXITCODE
$auditOutput | ForEach-Object { Write-Host $_ }
if ($auditExitCode -ne 0) {
exit $auditExitCode
}
if ($auditOutput -match '\b(High|Critical)\b') {
throw "High or critical NuGet vulnerability detected."
}
- name: Build
run: dotnet build tests/CodeIndex.Tests/CodeIndex.Tests.csproj --configuration Release --framework ${{ matrix.test-framework }} --no-restore
- name: Test
run: dotnet test tests/CodeIndex.Tests/CodeIndex.Tests.csproj --configuration Release --framework ${{ matrix.test-framework }} --no-build --nologo --logger "trx;LogFileName=test_results.trx" --results-directory ./TestResults
- name: Summarize TRX telemetry
if: always()
run: dotnet run --project tools/CodeIndex.TestTelemetry -- summarize --results-directory ./TestResults --top 10
- name: Upload test results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: TestResults-${{ matrix.os }}-${{ matrix.test-framework }}
if-no-files-found: warn
path: TestResults/**/*.trx
- name: Publish
if: matrix.os == 'ubuntu-latest' && matrix.test-framework == 'net8.0'
run: dotnet publish src/CodeIndex/CodeIndex.csproj --configuration Release --no-build --output publish
- name: Upload build artifact
if: matrix.os == 'ubuntu-latest' && matrix.test-framework == 'net8.0'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: CodeIndex
path: publish/**