Skip to content

Bump System.Text.Encoding.CodePages from 10.0.9 to 10.0.10 #1106

Bump System.Text.Encoding.CodePages from 10.0.9 to 10.0.10

Bump System.Text.Encoding.CodePages from 10.0.9 to 10.0.10 #1106

Workflow file for this run

name: Build and Test
on:
push:
branches:
- main
- pre-main-integration
pull_request:
branches:
- main
- pre-main-integration
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up .NET
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@v6
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
run: dotnet restore FolderDiffIL4DotNet.sln
- name: Build
run: dotnet build FolderDiffIL4DotNet.sln --configuration Release --no-restore
- name: Install DocFX
run: dotnet tool update --global docfx --version '2.*'
- name: Generate documentation site
run: |
export PATH="$PATH:$HOME/.dotnet/tools"
docfx metadata docfx.json
docfx build docfx.json
- name: Install real disassembler for E2E tests
if: ${{ hashFiles('FolderDiffIL4DotNet.Tests/FolderDiffIL4DotNet.Tests.csproj') != '' }}
run: |
dotnet tool install --global dotnet-ildasm
echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH"
DOTNET_ROLL_FORWARD=Major "$HOME/.dotnet/tools/dotnet-ildasm" --version
- name: Restore local tools
run: dotnet tool restore
- name: Test with coverage
if: ${{ hashFiles('FolderDiffIL4DotNet.Tests/FolderDiffIL4DotNet.Tests.csproj') != '' }}
env:
DOTNET_ROLL_FORWARD: Major
FOLDERDIFF_RUN_E2E: true
run: dotnet test FolderDiffIL4DotNet.Tests/FolderDiffIL4DotNet.Tests.csproj --configuration Release --no-build --nologo --settings coverlet.runsettings --logger "trx;LogFileName=test_results.trx" --collect:"XPlat Code Coverage" --results-directory ./TestResults
- name: Generate coverage report
if: ${{ hashFiles('FolderDiffIL4DotNet.Tests/FolderDiffIL4DotNet.Tests.csproj') != '' }}
run: |
dotnet tool run reportgenerator \
-reports:"TestResults/**/coverage.cobertura.xml" \
-targetdir:"CoverageReport" \
-reporttypes:"MarkdownSummaryGithub;Cobertura;HtmlInline_AzurePipelines"
if [ -f "CoverageReport/SummaryGithub.md" ]; then
cat CoverageReport/SummaryGithub.md >> "$GITHUB_STEP_SUMMARY"
fi
- name: Enforce coverage thresholds
if: ${{ hashFiles('FolderDiffIL4DotNet.Tests/FolderDiffIL4DotNet.Tests.csproj') != '' }}
run: |
python3 - <<'PY'
import glob
import sys
import xml.etree.ElementTree as ET
line_threshold = 80.0
branch_threshold = 75.0
# Per-class baseline floors for core diff logic.
# コア差分ロジックに対するクラス単位のベースライン下限。
core_class_line_threshold = 85.0
core_class_branch_threshold = 65.0
core_classes = [
"FolderDiffIL4DotNet.Services.FileDiffService",
"FolderDiffIL4DotNet.Services.FolderDiffService",
"FolderDiffIL4DotNet.Services.FileComparisonService",
]
matches = glob.glob("TestResults/**/coverage.cobertura.xml", recursive=True)
if not matches:
print("coverage.cobertura.xml was not found.", file=sys.stderr)
sys.exit(1)
root = ET.parse(matches[0]).getroot()
line_rate = float(root.attrib["line-rate"]) * 100.0
branch_rate = float(root.attrib["branch-rate"]) * 100.0
print(f"Total line coverage : {line_rate:.2f}% (threshold {line_threshold:.2f}%)")
print(f"Total branch coverage: {branch_rate:.2f}% (threshold {branch_threshold:.2f}%)")
failures = []
if line_rate < line_threshold:
failures.append(f"line coverage {line_rate:.2f}% < {line_threshold:.2f}%")
if branch_rate < branch_threshold:
failures.append(f"branch coverage {branch_rate:.2f}% < {branch_threshold:.2f}%")
# Check per-class thresholds for core diff classes.
# Partial classes produce multiple <class> entries with the same name
# but different filenames — aggregate line/branch hits across all entries.
# コア差分クラスのクラス単位閾値をチェック。
# Partial class は同名で異なるファイルの複数 <class> エントリを生成するため、
# 全エントリの行数・ブランチ数を集約してから判定する。
print()
print("--- Core class coverage ---")
from collections import defaultdict
agg = defaultdict(lambda: {"lines_covered": 0, "lines_total": 0,
"branches_covered": 0, "branches_total": 0})
for pkg in root.findall(".//package"):
for cls in pkg.findall(".//class"):
cls_name = cls.attrib.get("name", "")
if cls_name not in core_classes:
continue
for line in cls.findall(".//line"):
agg[cls_name]["lines_total"] += 1
if int(line.attrib.get("hits", "0")) > 0:
agg[cls_name]["lines_covered"] += 1
if line.attrib.get("branch", "false").lower() == "true":
cc = line.attrib.get("condition-coverage", "")
# Format: "X% (covered/total)"
# 形式: "X% (covered/total)"
if "(" in cc and "/" in cc:
inner = cc.split("(")[1].rstrip(")")
cov, tot = inner.split("/")
agg[cls_name]["branches_covered"] += int(cov)
agg[cls_name]["branches_total"] += int(tot)
core_warnings = []
for cls_name in core_classes:
d = agg[cls_name]
if d["lines_total"] == 0:
print(f" {cls_name}: no coverage data found [MISSING]")
core_warnings.append(f"{cls_name} coverage data was not found")
continue
cls_line = d["lines_covered"] / d["lines_total"] * 100.0
cls_branch = (d["branches_covered"] / d["branches_total"] * 100.0
if d["branches_total"] > 0 else 100.0)
status = "OK"
if cls_line < core_class_line_threshold or cls_branch < core_class_branch_threshold:
status = "BELOW TARGET"
print(f" {cls_name}: line {cls_line:.2f}%, branch {cls_branch:.2f}% [{status}]")
if cls_line < core_class_line_threshold:
core_warnings.append(
f"{cls_name} line coverage {cls_line:.2f}% < {core_class_line_threshold:.2f}%"
)
if cls_branch < core_class_branch_threshold:
core_warnings.append(
f"{cls_name} branch coverage {cls_branch:.2f}% < {core_class_branch_threshold:.2f}%"
)
if core_warnings:
print("\nCore class coverage threshold check failed:", file=sys.stderr)
for w in core_warnings:
print(f" - {w}", file=sys.stderr)
failures.extend(core_warnings)
if failures:
print("\nCoverage threshold check failed:", file=sys.stderr)
for failure in failures:
print(f" - {failure}", file=sys.stderr)
sys.exit(1)
PY
- name: Validate test scope map
if: ${{ hashFiles('FolderDiffIL4DotNet.Tests/FolderDiffIL4DotNet.Tests.csproj') != '' }}
continue-on-error: true
run: python3 scripts/validate-test-scope-map.py
- name: Upload test and coverage artifacts
if: ${{ always() && hashFiles('FolderDiffIL4DotNet.Tests/FolderDiffIL4DotNet.Tests.csproj') != '' }}
uses: actions/upload-artifact@v7
with:
name: TestAndCoverage
if-no-files-found: warn
path: |
TestResults/**/*.trx
TestResults/**/coverage.cobertura.xml
CoverageReport/**
- name: Upload documentation artifact
uses: actions/upload-artifact@v7
with:
name: DocumentationSite
path: _site/**
- name: Publish
run: dotnet publish FolderDiffIL4DotNet.csproj --configuration Release --no-build --output publish
- name: Remove debugging symbols
run: find publish -name '*.pdb' -delete
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: FolderDiffIL4DotNet
path: publish/**
mutation-testing:
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request'
permissions:
contents: read
issues: write
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up .NET
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@v6
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
run: dotnet restore FolderDiffIL4DotNet.sln
- name: Build
run: dotnet build FolderDiffIL4DotNet.sln --configuration Release --no-restore
- name: Restore local tools
run: dotnet tool restore
- name: Install real disassembler for E2E tests
run: |
dotnet tool install --global dotnet-ildasm
echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH"
DOTNET_ROLL_FORWARD=Major "$HOME/.dotnet/tools/dotnet-ildasm" --version
- name: Run Stryker mutation testing
env:
DOTNET_ROLL_FORWARD: Major
run: dotnet tool run dotnet-stryker --config-file stryker-config.json --output StrykerOutput
- name: Generate mutation visibility summary
if: always()
run: >
python3 scripts/generate-mutation-summary.py
--output-root StrykerOutput
--run-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
--summary-artifact-name "StrykerSummary-${{ github.run_number }}-${{ github.run_attempt }}"
--report-artifact-name "StrykerReport-${{ github.run_number }}-${{ github.run_attempt }}"
- name: Post mutation summary to job summary
if: always()
run: cat StrykerOutput/mutation-summary.md >> "$GITHUB_STEP_SUMMARY"
- name: Post mutation summary to pull request
if: always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
continue-on-error: true
uses: actions/github-script@v7
with:
script: |
const { upsertMutationSummaryComment } = require('./scripts/update-mutation-pr-comment.js');
await upsertMutationSummaryComment({
github,
context,
summaryPath: 'StrykerOutput/mutation-summary.md',
});
- name: Upload mutation visibility summary
if: always()
uses: actions/upload-artifact@v7
with:
name: StrykerSummary-${{ github.run_number }}-${{ github.run_attempt }}
if-no-files-found: error
path: |
StrykerOutput/mutation-summary.md
StrykerOutput/mutation-summary.json
- name: Upload mutation testing report
if: always()
uses: actions/upload-artifact@v7
with:
name: StrykerReport-${{ github.run_number }}-${{ github.run_attempt }}
if-no-files-found: warn
path: StrykerOutput/**
benchmark:
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch'
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up .NET
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@v6
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
run: dotnet restore FolderDiffIL4DotNet.Benchmarks/FolderDiffIL4DotNet.Benchmarks.csproj
- name: Run benchmarks
run: dotnet run --project FolderDiffIL4DotNet.Benchmarks/FolderDiffIL4DotNet.Benchmarks.csproj --configuration Release -- --exporters json github
- name: Upload benchmark results
if: always()
uses: actions/upload-artifact@v7
with:
name: BenchmarkResults
if-no-files-found: warn
path: BenchmarkDotNet.Artifacts/**
test-windows:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up .NET
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@v6
with:
path: ~\AppData\Local\NuGet\packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
run: dotnet restore FolderDiffIL4DotNet.sln
- name: Build
run: dotnet build FolderDiffIL4DotNet.sln --configuration Release --no-restore
- name: Install real disassembler for E2E tests
shell: pwsh
run: |
dotnet tool install --global dotnet-ildasm
$toolPath = Join-Path $env:USERPROFILE ".dotnet\tools"
$toolPath | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
& (Join-Path $toolPath "dotnet-ildasm.exe") --version
env:
DOTNET_ROLL_FORWARD: Major
- name: Test
run: dotnet test FolderDiffIL4DotNet.Tests/FolderDiffIL4DotNet.Tests.csproj --configuration Release --no-build --nologo
env:
DOTNET_ROLL_FORWARD: Major
FOLDERDIFF_RUN_E2E: true