Files
github-action/tools/quality-checks-csharp.sh
T
2026-10-11 16:19:45 +08:00

125 lines
4.0 KiB
Bash

#!/usr/bin/env bash
# Steps of the reusable workflow .gitea/workflows/quality-checks-csharp.yml
# (ADR-0008). The workflow checks out the calling repository, fetches this file
# into shared-scripts/ and runs one command per step:
#
# quality-checks-csharp.sh validate check the inputs, before anything is installed
# quality-checks-csharp.sh install install the exact .NET SDK version
# quality-checks-csharp.sh run run dotnet format and dotnet build on the project
#
# Settings come from the environment, never from interpolated expressions:
# WORKING_DIRECTORY, PROJECT, DOTNET_SDK_VERSION, DOTNET_ROOT (and
# QC_DOTNET_INSTALL_SCRIPT, QC_DOTNET for tests).
# Every failure is printed as ::error::[category] message.
DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
validate_inputs() {
set -u
case "$WORKING_DIRECTORY" in
"" | /* | .. | ../* | */.. | */../*)
echo "::error::[configuration] working-directory must be a relative path inside the repository."
exit 1
;;
esac
case "$PROJECT" in
/* | .. | ../* | */.. | */../*)
echo "::error::[configuration] project must be a relative path inside the working directory."
exit 1
;;
esac
# An exact stable version of the .NET SDK, 10 or later (no channel, no range).
if ! [[ "$DOTNET_SDK_VERSION" =~ ^([1-9][0-9]+)\.[0-9]+\.[0-9]+$ ]] || [ "${BASH_REMATCH[1]}" -lt 10 ]; then
echo "::error::[configuration] dotnet-sdk-version '$DOTNET_SDK_VERSION' is not an exact stable version 10 or later, such as 10.0.401."
exit 1
fi
echo "Checking C# in ${WORKING_DIRECTORY} with .NET SDK ${DOTNET_SDK_VERSION}"
}
install_sdk() {
set -eu
local script="${QC_DOTNET_INSTALL_SCRIPT:-}"
if [ -z "$script" ]; then
script="$(mktemp)"
curl -fsSL "$DOTNET_INSTALL_URL" -o "$script"
fi
bash "$script" --version "$DOTNET_SDK_VERSION" --install-dir "$DOTNET_ROOT" --no-path
"$DOTNET_ROOT/dotnet" --version
}
run_checks() {
set -u
if [ ! -d "$WORKING_DIRECTORY" ]; then
echo "::error::[configuration] working-directory '$WORKING_DIRECTORY' does not exist."
exit 1
fi
cd "$WORKING_DIRECTORY"
local dotnet="${QC_DOTNET:-$DOTNET_ROOT/dotnet}"
local sources
mapfile -t sources < <(git ls-files -- '*.cs')
if [ "${#sources[@]}" -eq 0 ]; then
echo "::notice::No C# files in '$WORKING_DIRECTORY'; nothing was checked."
echo "All selected checks passed."
exit 0
fi
local target="$PROJECT" candidates
if [ -z "$target" ]; then
mapfile -t candidates < <(git ls-files -- '*.sln' '*.slnx')
if [ "${#candidates[@]}" -eq 0 ]; then
mapfile -t candidates < <(git ls-files -- '*.csproj')
fi
case "${#candidates[@]}" in
0)
echo "::error::[configuration] C# files exist but no solution or project was found in '$WORKING_DIRECTORY'; add one or set the input project."
exit 1
;;
1) target="${candidates[0]}" ;;
*)
echo "::error::[configuration] Several solutions or projects were found (${candidates[*]}); set the input project."
exit 1
;;
esac
elif [ ! -f "$target" ]; then
echo "::error::[configuration] project '$target' does not exist in '$WORKING_DIRECTORY'."
exit 1
fi
echo "Checking $target"
export DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1
local failed=()
run_tool() {
local name="$1"
shift
echo "::group::$name"
if "$@"; then
echo "::endgroup::"
echo "PASS $name"
else
echo "::endgroup::"
echo "FAIL $name"
failed+=("$name")
fi
}
run_tool "dotnet format --verify-no-changes" "$dotnet" format "$target" --verify-no-changes
run_tool "dotnet build -warnaserror" "$dotnet" build "$target" --nologo -warnaserror
if [ "${#failed[@]}" -gt 0 ]; then
echo "::error::Quality checks failed: ${failed[*]}"
exit 1
fi
echo "All selected checks passed."
}
case "${1:-}" in
validate) validate_inputs ;;
install) install_sdk ;;
run) run_checks ;;
*)
echo "::error::[configuration] usage: quality-checks-csharp.sh validate|install|run" >&2
exit 2
;;
esac