Files
actions/csharp-lint-check/action.yml

212 lines
7.4 KiB
YAML

# yaml-language-server: $schema=https://json.schemastore.org/github-action.json
# permissions:
# - contents: read # Required for checking out repository
# - security-events: write # Required for uploading SARIF results
---
name: 'C# Lint Check'
description: 'Runs linters like StyleCop or dotnet-format for C# code style checks.'
author: 'Ismo Vuorinen'
branding:
icon: 'code'
color: 'blue'
inputs:
dotnet-version:
description: 'Version of .NET SDK to use.'
required: false
token:
description: 'GitHub token for authentication'
required: false
default: ''
outputs:
lint_status:
description: 'Overall lint status (success/failure)'
value: ${{ steps.dotnet-format.outcome == 'success' && 'success' || 'failure' }}
errors_count:
description: 'Number of formatting errors found'
value: ${{ steps.dotnet-format.outputs.errors_count || '0' }}
warnings_count:
description: 'Number of formatting warnings found'
value: ${{ steps.dotnet-format.outputs.warnings_count || '0' }}
runs:
using: composite
steps:
- name: Validate Inputs
id: validate
shell: sh
env:
DOTNET_VERSION: ${{ inputs.dotnet-version }}
run: |
set -eu
# Validate .NET version format if provided
if [ -n "$DOTNET_VERSION" ]; then
if ! printf '%s' "$DOTNET_VERSION" | grep -qE '^[0-9]+(\.[0-9]+(\.[0-9]+)?)?$'; then
echo "::error::Invalid dotnet-version format: '$DOTNET_VERSION'. Expected format: X.Y or X.Y.Z (e.g., 7.0, 8.0.100)"
exit 1
fi
# Check for reasonable version range (prevent malicious inputs)
major_version=$(echo "$DOTNET_VERSION" | cut -d'.' -f1)
if [ "$major_version" -lt 3 ] || [ "$major_version" -gt 20 ]; then
echo "::error::Invalid dotnet-version: '$DOTNET_VERSION'. Major version should be between 3 and 20"
exit 1
fi
fi
echo "Input validation completed successfully"
- name: Checkout Repository
uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta
with:
token: ${{ inputs.token || github.token }}
- name: Detect .NET SDK Version
id: detect-dotnet-version
shell: sh
env:
DEFAULT_VERSION: "${{ inputs.dotnet-version || '7.0' }}"
run: |
set -eu
# Function to validate version format
validate_version() {
version=$1
case "$version" in
[0-9]* | [0-9]*\.[0-9]* | [0-9]*\.[0-9]*\.[0-9]*)
return 0
;;
*)
return 1
;;
esac
}
# Function to clean version string
clean_version() {
printf '%s' "$1" | sed 's/^[vV]//' | tr -d ' \n\r'
}
detected_version=""
# Parse .tool-versions file
if [ -f .tool-versions ]; then
echo "Checking .tool-versions for dotnet..." >&2
version=$(awk '/^dotnet[[:space:]]/ {gsub(/#.*/, ""); print $2; exit}' .tool-versions 2>/dev/null || echo "")
if [ -n "$version" ]; then
version=$(clean_version "$version")
if validate_version "$version"; then
echo "Found .NET version in .tool-versions: $version" >&2
detected_version="$version"
fi
fi
fi
# Parse Dockerfile
if [ -z "$detected_version" ] && [ -f Dockerfile ]; then
echo "Checking Dockerfile for dotnet..." >&2
version=$(grep -iF "FROM" Dockerfile | grep -F "dotnet:" | head -1 | \
sed -n -E "s/.*dotnet:([0-9]+(\.[0-9]+)*)(-[^:]*)?.*/\1/p" || echo "")
if [ -n "$version" ]; then
version=$(clean_version "$version")
if validate_version "$version"; then
echo "Found .NET version in Dockerfile: $version" >&2
detected_version="$version"
fi
fi
fi
# Parse devcontainer.json
if [ -z "$detected_version" ] && [ -f .devcontainer/devcontainer.json ]; then
echo "Checking devcontainer.json for dotnet..." >&2
if command -v jq >/dev/null 2>&1; then
version=$(jq -r '.image // empty' .devcontainer/devcontainer.json 2>/dev/null | sed -n -E "s/.*dotnet:([0-9]+(\.[0-9]+)*)(-[^:]*)?.*/\1/p" || echo "")
if [ -n "$version" ]; then
version=$(clean_version "$version")
if validate_version "$version"; then
echo "Found .NET version in devcontainer: $version" >&2
detected_version="$version"
fi
fi
else
echo "jq not found; skipping devcontainer.json parsing" >&2
fi
fi
# Parse global.json
if [ -z "$detected_version" ] && [ -f global.json ]; then
echo "Checking global.json..." >&2
if command -v jq >/dev/null 2>&1; then
version=$(jq -r '.sdk.version // empty' global.json 2>/dev/null || echo "")
if [ -n "$version" ]; then
version=$(clean_version "$version")
if validate_version "$version"; then
echo "Found .NET version in global.json: $version" >&2
detected_version="$version"
fi
fi
else
echo "jq not found; skipping global.json parsing" >&2
fi
fi
# Use default version if nothing detected
if [ -z "$detected_version" ]; then
detected_version="$DEFAULT_VERSION"
echo "Using default .NET version: $detected_version" >&2
fi
# Set output
printf 'detected-version=%s\n' "$detected_version" >> "$GITHUB_OUTPUT"
echo "Final detected .NET version: $detected_version" >&2
- name: Setup .NET SDK
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: ${{ steps.detect-dotnet-version.outputs.detected-version }}
cache: true
cache-dependency-path: '**/packages.lock.json'
- name: Install dotnet-format
shell: sh
run: |
set -eu
dotnet tool install --global dotnet-format --version 7.0.1
- name: Run dotnet-format
id: dotnet-format
shell: sh
run: |
set -eu
# Initialize counters
errors_count=0
warnings_count=0
if ! dotnet format --check --report sarif --report-file dotnet-format.sarif; then
# Parse SARIF file to count errors and warnings if it exists
if [ -f "dotnet-format.sarif" ]; then
if command -v jq >/dev/null 2>&1; then
errors_count=$(jq '[.runs[].results[]? | select(.level == "error" or (.level // "error") == "error")] | length' dotnet-format.sarif 2>/dev/null || echo "0")
warnings_count=$(jq '[.runs[].results[]? | select(.level == "warning")] | length' dotnet-format.sarif 2>/dev/null || echo "0")
fi
fi
echo "errors_count=$errors_count" >> $GITHUB_OUTPUT
echo "warnings_count=$warnings_count" >> $GITHUB_OUTPUT
echo "::error::Code formatting issues found. Check the SARIF report for details."
exit 1
else
echo "errors_count=0" >> $GITHUB_OUTPUT
echo "warnings_count=0" >> $GITHUB_OUTPUT
fi
- name: Upload SARIF Report
uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
with:
sarif_file: dotnet-format.sarif