Skip to content

Speed up CI/CD runs, scope the developer CLI, and harden workflow hygiene #4

Speed up CI/CD runs, scope the developer CLI, and harden workflow hygiene

Speed up CI/CD runs, scope the developer CLI, and harden workflow hygiene #4

Workflow file for this run

name: Code Style
on:
push:
branches:
- main
paths:
- "application/**"
- "developer-cli/**"
- ".github/workflows/code-style.yml"
- "!**.md"
pull_request:
paths:
- "application/**"
- "developer-cli/**"
- ".github/workflows/code-style.yml"
- "!**.md"
workflow_dispatch:
permissions:
id-token: write
contents: read
pull-requests: write
jobs:
detect-changes:
name: Detect Changes
runs-on: ubuntu-24.04
outputs:
backend_scope: ${{ steps.scope.outputs.backend_scope }}
backend_label: ${{ steps.scope.outputs.backend_label }}
steps:
- name: Checkout Code
uses: actions/checkout@v6
with:
# Need history to diff against the base ref
fetch-depth: 0
- name: Resolve Backend Scope
id: scope
env:
BASE_REF: ${{ github.event.pull_request.base.sha || format('{0}~1', github.sha) }}
HEAD_REF: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
# Run scoped commands only when exactly one SCS's backend changed and nothing shared.
# Anything shared (shared-kernel, AppGateway, root, or developer-cli) forces a full pass,
# since per-SCS slnf scopes don't cover those projects.
changed=$(git diff --name-only "$BASE_REF" "$HEAD_REF")
account=false
main=false
other=false
while IFS= read -r path; do
case "$path" in
application/account/Api/*|application/account/Core/*|application/account/Workers/*|application/account/Tests/*)
account=true ;;
application/main/Api/*|application/main/Core/*|application/main/Workers/*|application/main/Tests/*)
main=true ;;
application/AppGateway/*|application/shared-kernel/*|developer-cli/*)
other=true ;;
application/*)
# Files directly under application/ (slnx, package.json, etc.) — treat as shared.
# Subdirectories matched the cases above.
other=true ;;
esac
done <<< "$changed"
if [[ "$other" == "true" ]] || { [[ "$account" == "true" ]] && [[ "$main" == "true" ]]; }; then
echo "backend_scope=" >> "$GITHUB_OUTPUT"
echo "backend_label=full backend (PlatformPlatform.slnx)" >> "$GITHUB_OUTPUT"
elif [[ "$account" == "true" ]]; then
echo "backend_scope=--self-contained-system account" >> "$GITHUB_OUTPUT"
echo "backend_label=account only" >> "$GITHUB_OUTPUT"
elif [[ "$main" == "true" ]]; then
echo "backend_scope=--self-contained-system main" >> "$GITHUB_OUTPUT"
echo "backend_label=main only" >> "$GITHUB_OUTPUT"
else
echo "backend_scope=" >> "$GITHUB_OUTPUT"
echo "backend_label=full backend (default — no backend paths matched)" >> "$GITHUB_OUTPUT"
fi
- name: Print Scope
run: echo "Backend scope - ${{ steps.scope.outputs.backend_label }}"
code-linting:
name: Code Linting
needs: detect-changes
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@v6
- name: Setup Node.js Environment
uses: actions/setup-node@v6
with:
node-version: 24
- name: Install Node Modules
working-directory: application
run: npm ci
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v5
with:
global-json-file: application/global.json
- name: Restore .NET Tools
working-directory: application
run: dotnet tool restore
- name: Restore .NET Dependencies
working-directory: application
run: dotnet restore
- name: Build Backend Solution
working-directory: developer-cli
run: dotnet run -- build --backend ${{ needs.detect-changes.outputs.backend_scope }} --quiet
- name: Run Backend Linting
working-directory: developer-cli
run: |
dotnet run lint --backend ${{ needs.detect-changes.outputs.backend_scope }} --no-build | tee lint-output.log
if ! grep -q "No backend issues found!" lint-output.log; then
echo "Code linting issues found."
exit 1
fi
- name: Build Frontend Artifacts
working-directory: application
run: npm run build
- name: Run Frontend Linting
working-directory: developer-cli
run: dotnet run -- lint --frontend
- name: Run Frontend Format Check
working-directory: developer-cli
run: |
dotnet run -- format --frontend
git diff --exit-code || {
echo "Formatting issues detected. Please run 'dotnet run --project developer-cli -- format --frontend' locally and commit the formatted code."
exit 1
}
code-formatting:
name: Code Formatting
needs: detect-changes
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@v6
- name: Setup Node.js Environment
uses: actions/setup-node@v6
with:
node-version: 24
- name: Install Node Modules
working-directory: application
run: npm ci
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v5
with:
global-json-file: application/global.json
- name: Restore .NET Tools
working-directory: application
run: dotnet tool restore
- name: Restore .NET Dependencies
working-directory: application
run: dotnet restore
- name: Build Backend Solution
working-directory: developer-cli
run: dotnet run -- build --backend ${{ needs.detect-changes.outputs.backend_scope }} --quiet
- name: Check for Code Formatting Issues
working-directory: developer-cli
run: |
dotnet run format --backend ${{ needs.detect-changes.outputs.backend_scope }} --no-build
git diff --exit-code || {
echo "Formatting issues detected. Please run 'dotnet run --project developer-cli -- format --backend ${{ needs.detect-changes.outputs.backend_scope }}' locally and commit the formatted code."
exit 1
}
sonarcloud:
name: SonarCloud Analysis
needs: detect-changes
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@v6
- name: Setup Node.js Environment
uses: actions/setup-node@v6
with:
node-version: 24
- name: Install Node Modules
working-directory: application
run: npm ci
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v5
with:
global-json-file: application/global.json
- name: Restore .NET Tools
working-directory: application
run: dotnet tool restore
- name: Restore .NET Dependencies
working-directory: application
run: dotnet restore
- name: Generate and Set User Secret for Token Signing Key
working-directory: application/shared-kernel/SharedKernel
run: |
# Extract UserSecretsId from the .csproj file
USER_SECRETS_ID=$(grep -oP '(?<=<UserSecretsId>).*?(?=</UserSecretsId>)' SharedKernel.csproj)
# Generate a 512-bit key and set it as a user secret that can be use for token signing when running tests
dotnet user-secrets set "authentication-token-signing-key" "$(openssl rand -base64 64)" --id $USER_SECRETS_ID
- name: Setup Java JDK for SonarScanner
uses: actions/setup-java@v5
with:
distribution: "microsoft"
java-version: "17"
- name: Build Email Templates
working-directory: application
run: npx turbo run build --filter=@repo/emails
- name: Run SonarCloud Analysis
working-directory: application
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
if [[ "${{ vars.SONAR_PROJECT_KEY }}" == "" ]] || [[ "${{ vars.SONAR_ORGANIZATION }}" == "" ]] || [[ "${{ secrets.SONAR_TOKEN }}" == "" ]]; then
echo "SonarCloud is not enabled. Skipping SonarCloud analysis."
exit 0
fi
dotnet sonarscanner begin /k:"${{ vars.SONAR_PROJECT_KEY }}" /o:"${{ vars.SONAR_ORGANIZATION }}" /d:sonar.host.url="https://sonarcloud.io" &&
dotnet build PlatformPlatform.slnx --no-restore &&
dotnet test PlatformPlatform.slnx --no-build &&
dotnet sonarscanner end