Files
actions/csharp-publish/action.yml
Ismo Vuorinen 900dd96797 feat: add action-validator and clean up CI workflows (#513)
* chore(pre-commit): update hooks and add action-validator

Update uv-pre-commit 0.10.9→0.10.11 and checkov 3.2.508→3.2.510.
Normalize single quotes to double quotes in hook args.
Add action-validator v0.8.0 hook for GitHub Actions validation.

* fix(ci): clean up workflow path filters

Remove non-existent action.yaml paths from action-security workflow.
Fix glob patterns (**.md → **/*.md) in pr-lint workflow.
Remove unused trigger paths (yarn.lock, pnpm-lock.yaml,
requirements.txt, .github/labels.yml, docs/**) from security-suite
and sync-labels workflows.

* feat(make): add lint-actions target for action-validator

Add lint-actions target that runs action-validator via pre-commit.
Include it in the lint dependency list and .PHONY declaration.

* docs: add context-mode routing rules to CLAUDE.md

Add mandatory routing rules section for context-mode MCP plugin,
documenting blocked commands, redirected tools, tool selection
hierarchy, and output constraints.

* fix(lint): resolve action-validator failure on language-version-detect

- Remove unsupported `deprecated: true` from language-version-detect/action.yml
  (deprecation already communicated via description field)
- Scope action-validator pre-commit hook to workflow and action.yml files only
- Make missing pre-commit a hard error in lint-actions target

* fix(deps): update action pins and fix trivy-action version comment

Update SHA-pinned action references to latest versions:
- github/codeql-action v4.32.6 → v4.33.0
- nick-fields/retry v3.0.2 → v4.0.0
- actions/cache v5.0.3 → v5.0.4
- oven-sh/setup-bun v2.1.3 → v2.2.0
- softprops/action-gh-release v2.5.0 → v2.6.1
- github/issue-metrics v4.1.0 → v4.1.1
- shivammathur/setup-php 2.36.0 → 2.37.0
- astral-sh/setup-uv v7.5.0 → v7.6.0
- terraform-linters/setup-tflint v6.2.1 → v6.2.2
- aquasecurity/trivy-action: pin from master to v0.35.0

Fix pinact warning in docker-build by adding missing v prefix
to trivy-action version comment (0.35.0 → v0.35.0).
2026-03-20 13:01:24 +02:00

249 lines
8.2 KiB
YAML

# yaml-language-server: $schema=https://json.schemastore.org/github-action.json
# permissions:
# - packages: write # Required for publishing to GitHub Packages
# - contents: read # Required for checking out repository
---
name: C# Publish
description: 'Publishes a C# project to GitHub Packages.'
author: 'Ismo Vuorinen'
branding:
icon: package
color: blue
inputs:
dotnet-version:
description: 'Version of .NET SDK to use.'
required: false
namespace:
description: 'GitHub namespace for the package.'
required: true
default: 'ivuorinen'
token:
description: 'GitHub token with package write permissions'
required: false
max-retries:
description: 'Maximum number of retry attempts for dependency restoration'
required: false
default: '3'
outputs:
publish_status:
description: 'Overall publish status (success/failure)'
value: ${{ steps.set-status.outputs.status }}
package_version:
description: 'Version of the published package'
value: ${{ steps.extract-version.outputs.version }}
package_url:
description: 'URL of the published package'
value: ${{ steps.publish-package.outputs.package_url }}
runs:
using: composite
steps:
- name: Mask Secrets
shell: sh
env:
API_KEY: ${{ inputs.token || github.token }}
run: |
echo "::add-mask::$API_KEY"
- name: Checkout Repository
uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta
with:
token: ${{ inputs.token || github.token }}
- name: Validate Inputs
id: validate
uses: ivuorinen/actions/validate-inputs@5cc7373a22402ee8985376bc713f00e09b5b2edb
with:
action-type: 'csharp-publish'
token: ${{ inputs.token }}
namespace: ${{ inputs.namespace }}
dotnet-version: ${{ inputs.dotnet-version }}
- name: Detect .NET SDK Version
id: detect-dotnet-version
shell: sh
env:
DEFAULT_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@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
with:
dotnet-version: ${{ inputs.dotnet-version || steps.detect-dotnet-version.outputs.detected-version }}
cache: true
cache-dependency-path: '**/packages.lock.json'
- name: Restore Dependencies
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }}
command: |
echo "Restoring .NET dependencies..."
dotnet restore --verbosity normal
- name: Build Solution
shell: sh
run: |
set -eu
dotnet build --configuration Release --no-restore
- name: Pack Solution
shell: sh
run: |
set -eu
dotnet pack --configuration Release --no-build --no-restore --output ./artifacts
- name: Extract Package Version
id: extract-version
shell: sh
run: |
set -eu
# Find the newest .nupkg file by modification time and extract version
PACKAGE_FILE=$(find ./artifacts -name "*.nupkg" -type f -printf '%T@ %p\n' | sort -rn | head -n 1 | cut -d' ' -f2-)
if [ -n "$PACKAGE_FILE" ]; then
# Extract version from filename (assumes standard naming: PackageName.Version.nupkg)
VERSION=$(basename "$PACKAGE_FILE" .nupkg | sed 's/.*\.\([0-9]\+\.[0-9]\+\.[0-9]\+.*\)$/\1/')
printf '%s\n' "version=$VERSION" >> "$GITHUB_OUTPUT"
printf '%s\n' "package_file=$PACKAGE_FILE" >> "$GITHUB_OUTPUT"
else
printf '%s\n' "version=unknown" >> "$GITHUB_OUTPUT"
printf '%s\n' "package_file=" >> "$GITHUB_OUTPUT"
fi
- name: Publish Package
id: publish-package
shell: sh
env:
API_KEY: ${{ inputs.token || github.token }}
NAMESPACE: ${{ inputs.namespace }}
run: |
set -eu
PACKAGE_URL="https://github.com/$NAMESPACE/packages/nuget"
printf '%s\n' "package_url=$PACKAGE_URL" >> "$GITHUB_OUTPUT"
# First attempt
if ! dotnet nuget push ./artifacts/*.nupkg \
--api-key "$API_KEY" \
--source "https://nuget.pkg.github.com/$NAMESPACE/index.json" \
--skip-duplicate \
--no-symbols; then
echo "::warning::First publish attempt failed, retrying after 5 seconds..."
sleep 5
dotnet nuget push ./artifacts/*.nupkg \
--api-key "$API_KEY" \
--source "https://nuget.pkg.github.com/$NAMESPACE/index.json" \
--skip-duplicate \
--no-symbols
fi
- name: Set publish status output
if: always()
id: set-status
shell: sh
env:
PUBLISH_STATUS: ${{ steps.publish-package.outcome == 'success' && 'success' || 'failure' }}
run: |-
printf '%s\n' "status=$PUBLISH_STATUS" >> "$GITHUB_OUTPUT"