Skip to content

Bump actions/upload-artifact from 4 to 7 #745

Bump actions/upload-artifact from 4 to 7

Bump actions/upload-artifact from 4 to 7 #745

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@v4
with:
fetch-depth: 0
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@v4
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
DOTNET_ROLL_FORWARD=Major 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
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 higher thresholds for core diff logic.
# コア差分ロジックに対するクラス単位の高い閾値。
core_class_line_threshold = 90.0
core_class_branch_threshold = 85.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 (skipped)")
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 warnings (non-blocking):", file=sys.stderr)
for w in core_warnings:
print(f" - {w}", file=sys.stderr)
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'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@v4
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
DOTNET_ROLL_FORWARD=Major 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: Post mutation score summary
if: always()
run: |
REPORT=$(find StrykerOutput -name '*.json' -path '*/reports/*' | head -1)
if [ -n "$REPORT" ] && [ -f "$REPORT" ]; then
SCORE=$(python3 -c "
import json, sys
with open('$REPORT') as f:
data = json.load(f)
score = data.get('mutationScore', data.get('files', {}).get('mutationScore', 'N/A'))
print(score)
" 2>/dev/null || echo "N/A")
echo "## Mutation Testing Results" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Mutation Score:** ${SCORE}%" >> "$GITHUB_STEP_SUMMARY"
else
echo "## Mutation Testing Results" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "⚠ Could not find Stryker JSON report to extract mutation score." >> "$GITHUB_STEP_SUMMARY"
fi
- name: Upload mutation testing report
if: always()
uses: actions/upload-artifact@v7
with:
name: StrykerReport
if-no-files-found: warn
path: StrykerOutput/**
benchmark:
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@v4
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@v4
with:
fetch-depth: 0
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@v4
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
run: dotnet tool install --global dotnet-ildasm
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