feature: randomize compressor feedback + library-seed constants (#69) #51
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: lint | |
| # GitHub Actions minutes are limited. Linting is done locally with | |
| # scripts/local-ci.sh (dotnet format whitespace/style/analyzers). This workflow | |
| # runs automatically only for PRs into `main`; for PRs into `develop` it runs only | |
| # when an admin adds the `run-ci` label (re-add to trigger each run) or dispatches | |
| # it manually. The previous any-branch `push` trigger was removed to stop a lint | |
| # run firing on every push. See the `if:` on the lint job below. | |
| on: | |
| pull_request: | |
| branches: [main, develop] | |
| types: [opened, synchronize, reopened, labeled] | |
| paths-ignore: ['**.md', 'docs/**', 'LICENSE*'] | |
| workflow_dispatch: | |
| concurrency: | |
| group: lint-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| lint: | |
| # Auto for PRs into main and manual dispatch; for develop PRs only when an | |
| # admin adds the `run-ci` label. | |
| if: >- | |
| github.event_name == 'workflow_dispatch' || | |
| github.base_ref == 'main' || | |
| (github.event.action == 'labeled' && github.event.label.name == 'run-ci') | |
| runs-on: windows-2025 | |
| timeout-minutes: 5 | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| env: | |
| NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ github.workspace }}/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.vcxproj') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nuget- | |
| - name: Restore | |
| run: dotnet restore Confuser2.sln | |
| - name: Check whitespace | |
| id: whitespace | |
| run: dotnet format whitespace Confuser2.sln --verify-no-changes --verbosity minimal 2>&1 | Tee-Object -Variable wsOutput | |
| shell: pwsh | |
| continue-on-error: true | |
| - name: Check style | |
| id: style | |
| run: dotnet format style Confuser2.sln --verify-no-changes --severity warn 2>&1 | Tee-Object -Variable styleOutput | |
| shell: pwsh | |
| continue-on-error: true | |
| - name: Check analyzers | |
| id: analyzers | |
| run: dotnet format analyzers Confuser2.sln --verify-no-changes --severity warn 2>&1 | Tee-Object -Variable analyzerOutput | |
| shell: pwsh | |
| continue-on-error: true | |
| - name: Build lint report | |
| if: always() | |
| id: report | |
| shell: pwsh | |
| run: | | |
| $ws = '${{ steps.whitespace.outcome }}' | |
| $st = '${{ steps.style.outcome }}' | |
| $an = '${{ steps.analyzers.outcome }}' | |
| $anyFailed = ($ws -eq 'failure') -or ($st -eq 'failure') -or ($an -eq 'failure') | |
| $md = @() | |
| $md += '## Lint Results' | |
| $md += '' | |
| if (-not $anyFailed) { | |
| $md += '> :white_check_mark: **All checks passed**' | |
| } else { | |
| $md += '> :warning: **Issues found** — run `dotnet format Confuser2.sln` locally to fix' | |
| } | |
| $md += '' | |
| $md += '| Check | Result |' | |
| $md += '|-------|--------|' | |
| $icon = if ($ws -eq 'success') { ':white_check_mark:' } else { ':x:' } | |
| $md += "| Whitespace (indentation, line endings) | $icon |" | |
| $icon = if ($st -eq 'success') { ':white_check_mark:' } else { ':x:' } | |
| $md += "| Style (IDE rules, naming, var usage) | $icon |" | |
| $icon = if ($an -eq 'success') { ':white_check_mark:' } else { ':x:' } | |
| $md += "| Analyzers (CA*, RCS* rules) | $icon |" | |
| # Get specific violations if any failed | |
| if ($anyFailed) { | |
| $md += '' | |
| $md += '<details><summary><strong>Details (click to expand)</strong></summary>' | |
| $md += '' | |
| $md += '```' | |
| # Re-run to capture output | |
| $violations = dotnet format Confuser2.sln --verify-no-changes --verbosity diagnostic 2>&1 | Select-String 'error|warning' | Select-Object -First 30 | |
| foreach ($v in $violations) { $md += $v.ToString().Trim() } | |
| if ($violations.Count -ge 30) { $md += '... (truncated, run dotnet format locally for full list)' } | |
| $md += '```' | |
| $md += '' | |
| $md += '</details>' | |
| } | |
| $md -join "`n" | Set-Content -Path 'lint-report.md' -Encoding utf8 | |
| $md -join "`n" >> $env:GITHUB_STEP_SUMMARY | |
| echo "any_failed=$anyFailed" >> $env:GITHUB_OUTPUT | |
| - name: Post PR comment | |
| if: always() && github.event_name == 'pull_request' | |
| uses: marocchino/sticky-pull-request-comment@v2 | |
| with: | |
| header: lint-report | |
| path: lint-report.md | |
| - name: Post issue comment | |
| if: always() && github.event_name == 'push' && github.event.pull_request == null | |
| shell: pwsh | |
| run: | | |
| # Extract issue number from branch name (e.g. 54-nuget-packages → 54) | |
| $branch = "${{ github.ref_name }}" | |
| if ($branch -match '^(\d+)-') { | |
| $issueNumber = $Matches[1] | |
| $marker = '<!-- lint-bot -->' | |
| $body = $marker + "`n" + (Get-Content 'lint-report.md' -Raw) | |
| # Find existing lint comment | |
| $comments = gh api "repos/${{ github.repository }}/issues/$issueNumber/comments" --jq '.[] | select(.body | startswith("<!-- lint-bot -->")) | .id' 2>$null | |
| if ($comments) { | |
| # Update existing | |
| gh api "repos/${{ github.repository }}/issues/comments/$comments" -X PATCH -f body="$body" 2>$null | |
| } else { | |
| # Create new | |
| gh issue comment $issueNumber --repo ${{ github.repository }} --body "$body" 2>$null | |
| } | |
| } | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Fail if issues found | |
| if: always() && steps.report.outputs.any_failed == 'True' | |
| shell: pwsh | |
| run: | | |
| Write-Host "::warning::Lint issues found. Run 'dotnet format Confuser2.sln' locally to fix." | |
| exit 1 |