Skip to content

Promote Slack in athlete emails #3142

Promote Slack in athlete emails

Promote Slack in athlete emails #3142

Workflow file for this run

# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
name: .NET
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
permissions:
contents: read
issues: write
pull-requests: write
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: .node-version
cache: npm
cache-dependency-path: LongevityWorldCup.Website/package-lock.json
- name: Restore frontend dependencies
working-directory: LongevityWorldCup.Website
run: npm ci --ignore-scripts --no-audit --no-fund
- name: Type-check and build frontend
working-directory: LongevityWorldCup.Website
run: npm run build
- name: Verify generated frontend assets stay untracked
shell: bash
run: |
tracked="$(git ls-files -- 'LongevityWorldCup.Website/wwwroot/js')"
if [[ -n "$tracked" ]]; then
echo "$tracked"
exit 1
fi
- name: Restore dependencies with NuGet audit
run: >
dotnet restore
-p:NuGetAudit=true
-p:NuGetAuditMode=all
-p:NuGetAuditLevel=low
-p:WarningsAsErrors=NU1900%3BNU1901%3BNU1902%3BNU1903%3BNU1904%3BNU1905
- name: Build
run: dotnet build --no-restore -p:BuildFrontend=false
- name: Verify Node-free publish contract
shell: bash
run: |
set -euo pipefail
publish_output="$RUNNER_TEMP/longevityworldcup-publish"
deny_node_bin="$RUNNER_TEMP/longevityworldcup-deny-node"
source_manifest="$RUNNER_TEMP/longevityworldcup-source-js.sha256"
published_manifest="$RUNNER_TEMP/longevityworldcup-published-js.sha256"
frontend_manifest() {
local root="$1"
(
cd "$root"
find . -type f -name '*.js' -print0 \
| LC_ALL=C sort -z \
| xargs -0 -r sha256sum
)
}
rm -rf LongevityWorldCup.Website/node_modules "$publish_output" "$deny_node_bin"
mkdir -p "$deny_node_bin"
printf '#!/usr/bin/env bash\necho "Node.js is forbidden in the BuildFrontend=false publish contract." >&2\nexit 1\n' > "$deny_node_bin/node"
cp "$deny_node_bin/node" "$deny_node_bin/npm"
chmod +x "$deny_node_bin/node" "$deny_node_bin/npm"
frontend_manifest LongevityWorldCup.Website/wwwroot/js > "$source_manifest"
test -s "$source_manifest"
PATH="$deny_node_bin:$PATH" dotnet publish LongevityWorldCup.Website/LongevityWorldCup.Website.csproj \
--configuration Release \
--no-restore \
--output "$publish_output" \
-p:BuildFrontend=false
frontend_manifest "$publish_output/wwwroot/js" > "$published_manifest"
if ! cmp -s "$source_manifest" "$published_manifest"; then
echo "Published frontend assets differ from the generated source assets." >&2
diff -u "$source_manifest" "$published_manifest" || true
exit 1
fi
test -z "$(find "$publish_output" -type f -name '*.ts' -print -quit)"
- name: Install Playwright Chromium
run: pwsh LongevityWorldCup.Tests/bin/Debug/net10.0/playwright.ps1 install chromium
- name: Test with coverage
run: >
dotnet test
--no-build
--verbosity normal
-p:CollectCoverage=true
-p:CoverletOutput=TestResults/Coverage/
-p:CoverletOutputFormat=cobertura
- name: Summarize .NET coverage
id: coverage
shell: bash
run: |
set -euo pipefail
coverage_file="$(find . -name coverage.cobertura.xml -print | head -n 1)"
if [[ -z "$coverage_file" ]]; then
echo "coverage.cobertura.xml was not produced." >&2
exit 1
fi
python3 - "$coverage_file" <<'PY' | tee coverage-summary.md
import sys
import xml.etree.ElementTree as ET
root = ET.parse(sys.argv[1]).getroot()
line_coverage = float(root.attrib.get("line-rate", "0")) * 100
branch_coverage = float(root.attrib.get("branch-rate", "0")) * 100
print("## .NET test coverage")
print()
print(f"- Line coverage: {line_coverage:.1f}%")
print(f"- Branch coverage: {branch_coverage:.1f}%")
PY
cat coverage-summary.md >> "$GITHUB_STEP_SUMMARY"
{
echo "markdown<<DOTNET_COVERAGE_SUMMARY"
cat coverage-summary.md
echo "DOTNET_COVERAGE_SUMMARY"
} >> "$GITHUB_OUTPUT"
- name: Comment .NET coverage on PR
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
uses: actions/github-script@v9
env:
COVERAGE_MARKDOWN: ${{ steps.coverage.outputs.markdown }}
with:
script: |
const marker = '<!-- dotnet-coverage-summary -->';
const body = [marker, process.env.COVERAGE_MARKDOWN].join('\n');
const { owner, repo } = context.repo;
const issue_number = context.issue.number;
try {
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number,
per_page: 100
});
const existing = comments.find(comment =>
comment.user?.type === 'Bot' && comment.body?.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body
});
}
} catch (error) {
if (error.status === 403) {
core.warning('Could not update the PR coverage comment with GITHUB_TOKEN; the coverage report is still available in the job summary.');
} else {
throw error;
}
}