Merge pull request #509 from reqnroll/chore/husky-lint-staged-precommit #431
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
| # --------------------------------------------------------------------------- | |
| # ci.yml — single top-level CI workflow for all three IDE consumers (VS | |
| # extension, VS Code extension, Rider plugin). | |
| # | |
| # This replaces three separate top-level workflows (build-vs-extension.yml, | |
| # build-vscode-extension.yml, build-rider-plugin.yml) that each independently | |
| # triggered on overlapping paths (all three included src/Core/** and | |
| # src/LSP/**) and each called the shared test-lsp.yml reusable workflow via | |
| # `uses:`. Because workflow_call reusable workflows are scoped to the run of | |
| # whichever top-level workflow invokes them, three separate top-level runs | |
| # meant three separate, non-sharing executions of the LSP build/test/publish | |
| # chain (~11-15 min each) for the same commit — see issue #149. Consolidating | |
| # into one workflow with one `lsp:` job fixes that: the LSP layer is now built | |
| # and tested at most once per run, and the per-IDE jobs below are gated by | |
| # dorny/paths-filter on whether that IDE's own files (or the shared | |
| # Core/LSP files all of them depend on) actually changed. | |
| # | |
| # A further wrinkle: every consumer still needs a server-<rid> artifact | |
| # published *this run* even if src/Core and src/LSP are completely untouched | |
| # (e.g. a Rider-only Kotlin change), since GitHub Actions artifacts don't | |
| # carry over between separate workflow runs. So the `lsp` job itself can't be | |
| # skipped in that case — but re-running its unit-test-lsp/spec-test-lsp jobs | |
| # would just re-validate LSP code that didn't change. The `core_lsp` filter | |
| # below drives test-lsp.yml's skip-tests input so that case publishes | |
| # straight off build-lsp instead (see test-lsp.yml for the mechanics). | |
| # | |
| # Job graph: | |
| # changes (paths-filter) | |
| # └─> lsp (test-lsp.yml) [if vs || vscode || rider] | |
| # ├─> build-vs-extension ─┬─> test-vs-extension ──┐ [if vs] | |
| # │ └─> test-vs-wizards ─────┴─> publish-vsix | |
| # ├─> build-vscode-extension (VSIX) [if vscode] | |
| # └─> build-rider-plugin ─┐ [if rider] | |
| # tsc-only (VS Code, no LSP dependency) [if vscode] | |
| # test-rider-plugin (Rider, no LSP dependency) ────────────┴─> publish-rider-plugin | |
| # | |
| # NOTE: this changes the required-status-check contexts branch protection | |
| # rules see (workflow name / job name pairs) — the old | |
| # "Build VS Extension / ...", "Build VS Code Extension / ...", and | |
| # "Build Rider Plugin / ..." contexts are replaced by "CI / ...". Branch | |
| # protection rules referencing the old contexts need to be updated after this | |
| # merges. | |
| # | |
| # Job display names (issue #412) follow a "<Component> / <Stage>" convention | |
| # — VS/VSCode/Rider job names, and the LSP reusable workflow's own job names | |
| # (Build/Test (Unit)/Test (Spec)/Publish), which the Actions UI automatically | |
| # prefixes with the caller job's name ("LSP / Build", "LSP / Test (Unit)", | |
| # etc.) — so any required-status-check contexts already configured for the | |
| # old per-job names ("Unit Tests (VS Extension)", "Build Rider Plugin", "Test | |
| # LSP / Unit Tests (LSP)", ...) need to be re-pointed at the new ones. | |
| # --------------------------------------------------------------------------- | |
| name: CI | |
| on: | |
| push: | |
| branches: | |
| - 'master' | |
| paths: | |
| - 'src/Core/**' | |
| - 'src/LSP/**' | |
| - 'src/VisualStudio/**' | |
| - 'src/VSCode/**' | |
| - 'src/Rider/**' | |
| - 'tests/Core/**' | |
| - 'tests/VisualStudio/**' | |
| - 'tests/LSP/**' | |
| - 'tests/Reqnroll.SampleProjectGenerator/**' | |
| - 'tests/Reqnroll.SampleProjectGenerator.Core/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/test-lsp.yml' | |
| - '.github/actions/setup-rider-gradle-env/**' | |
| pull_request: | |
| paths: | |
| - 'src/Core/**' | |
| - 'src/LSP/**' | |
| - 'src/VisualStudio/**' | |
| - 'src/VSCode/**' | |
| - 'src/Rider/**' | |
| - 'tests/Core/**' | |
| - 'tests/VisualStudio/**' | |
| - 'tests/LSP/**' | |
| - 'tests/Reqnroll.SampleProjectGenerator/**' | |
| - 'tests/Reqnroll.SampleProjectGenerator.Core/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/test-lsp.yml' | |
| - '.github/actions/setup-rider-gradle-env/**' | |
| workflow_dispatch: | |
| # Cancel a superseded run (e.g. a new push to the same PR) rather than letting both finish. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Least-privilege default: every job here only checks out code and uploads its own artifacts. | |
| permissions: | |
| contents: read | |
| env: | |
| DOTNET_VERSION: '10.0.x' | |
| CONFIGURATION: Release | |
| NODE_VERSION: '22.x' | |
| RIDER_DIR: src/Rider | |
| VSCODE_DIR: src/VSCode | |
| # See test-lsp.yml for what this feeds (VersionPrefix -> AssemblyInformationalVersion -> | |
| # ServerInfo.Version). Applied to every project built here so the whole run carries the | |
| # same build number. | |
| BUILD_NUMBER_ARG: -p:ReqnrollBuildNumber=${{ github.run_number }} | |
| EXTENSION_PROJECT: src/VisualStudio/Reqnroll.IdeSupport.VisualStudio.Extension/Reqnroll.IdeSupport.VisualStudio.Extension.csproj | |
| TESTS_PROJECT: tests/VisualStudio/Reqnroll.VisualStudio.Tests/Reqnroll.VisualStudio.Tests.csproj | |
| WIZARDS_TESTS_PROJECT: tests/VisualStudio/Reqnroll.IdeSupport.VisualStudio.Wizards.Tests/Reqnroll.IdeSupport.VisualStudio.Wizards.Tests.csproj | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Job 0: Detect which IDE(s) are actually affected by this change, so the | |
| # jobs below (and the shared lsp job) only run for the IDEs that need them. | |
| # Each filter includes the shared Core/LSP paths too, since a change there | |
| # affects every consumer. | |
| # --------------------------------------------------------------------------- | |
| changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| vs: ${{ steps.filter.outputs.vs }} | |
| vscode: ${{ steps.filter.outputs.vscode }} | |
| rider: ${{ steps.filter.outputs.rider }} | |
| core_lsp: ${{ steps.filter.outputs.core_lsp }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Filter changed paths | |
| id: filter | |
| uses: dorny/paths-filter@v4 | |
| with: | |
| filters: | | |
| vs: | |
| - 'src/Core/**' | |
| - 'src/LSP/**' | |
| - 'src/VisualStudio/**' | |
| - 'tests/Core/**' | |
| - 'tests/VisualStudio/**' | |
| - 'tests/LSP/**' | |
| - 'tests/Reqnroll.SampleProjectGenerator/**' | |
| - 'tests/Reqnroll.SampleProjectGenerator.Core/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/test-lsp.yml' | |
| vscode: | |
| - 'src/Core/**' | |
| - 'src/LSP/**' | |
| - 'src/VSCode/**' | |
| - 'tests/Core/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/test-lsp.yml' | |
| rider: | |
| - 'src/Core/**' | |
| - 'src/LSP/**' | |
| - 'src/Rider/**' | |
| - 'tests/Core/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/test-lsp.yml' | |
| - '.github/actions/setup-rider-gradle-env/**' | |
| # Whether the LSP layer test-lsp.yml builds/tests actually changed. Drives | |
| # the lsp job's skip-tests input: false here means re-running | |
| # unit-test-lsp/spec-test-lsp would just re-validate unchanged code, so | |
| # publish-lsp-server proceeds straight off build-lsp instead (see test-lsp.yml). | |
| core_lsp: | |
| - 'src/Core/**' | |
| - 'src/LSP/**' | |
| - 'tests/Core/**' | |
| - 'tests/LSP/**' | |
| - 'tests/Reqnroll.SampleProjectGenerator/**' | |
| - 'tests/Reqnroll.SampleProjectGenerator.Core/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/test-lsp.yml' | |
| # --------------------------------------------------------------------------- | |
| # Job 1: Build + test the LSP layer, and publish self-contained server | |
| # binaries for every supported RID. See test-lsp.yml. Runs at most once per | |
| # push/PR, shared by whichever of the three IDE job chains below actually run. | |
| # | |
| # Every consumer still needs a server-<rid> artifact published *this run* | |
| # (GitHub Actions artifacts don't carry over between runs), so this job | |
| # can't be skipped outright just because src/Core and src/LSP are untouched | |
| # — but skip-tests tells it to skip re-validating LSP code that didn't | |
| # change (e.g. a Rider-only Kotlin commit), publishing straight off | |
| # build-lsp instead of waiting on unit-test-lsp/spec-test-lsp. | |
| # --------------------------------------------------------------------------- | |
| lsp: | |
| name: LSP | |
| needs: [changes] | |
| if: needs.changes.outputs.vs == 'true' || needs.changes.outputs.vscode == 'true' || needs.changes.outputs.rider == 'true' | |
| uses: ./.github/workflows/test-lsp.yml | |
| with: | |
| skip-tests: ${{ needs.changes.outputs.core_lsp != 'true' }} | |
| # =========================================================================== | |
| # Visual Studio extension | |
| # =========================================================================== | |
| # --------------------------------------------------------------------------- | |
| # Build VS extension — builds the extension (which also republishes the LSP | |
| # server into the VSIX via IncludeLspServerInVsix) and uploads the resulting | |
| # .vsix as a candidate artifact for the test/publish jobs below. | |
| # | |
| # Passes -p:UseExternalLspServerBuild=true plus -p:LspServerBuildDir=<downloaded | |
| # artifact path> so the Extension project's ProjectReference to LSP.Server is | |
| # dropped in favor of the win-x64 artifact the lsp job already published, | |
| # instead of rebuilding it a second time. | |
| # --------------------------------------------------------------------------- | |
| build-vs-extension: | |
| name: VS / Build | |
| needs: [changes, lsp] | |
| if: needs.changes.outputs.vs == 'true' | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Setup .NET ${{ env.DOTNET_VERSION }} | |
| uses: actions/setup-dotnet@v6 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Add MSBuild to PATH | |
| uses: microsoft/setup-msbuild@v3 | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.nuget/packages | |
| key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} | |
| restore-keys: | | |
| nuget-${{ runner.os }}- | |
| - name: Download published LSP server (win-x64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-win-x64 | |
| path: lsp-server-win-x64 | |
| - name: Restore Extension | |
| run: dotnet restore ${{ env.EXTENSION_PROJECT }} -p:UseExternalLspServerBuild=true "-p:LspServerBuildDir=${{ github.workspace }}\lsp-server-win-x64\" | |
| - name: Build VSIX (${{ env.CONFIGURATION }}) | |
| run: dotnet build ${{ env.EXTENSION_PROJECT }} --no-restore --configuration ${{ env.CONFIGURATION }} -p:UseExternalLspServerBuild=true "-p:LspServerBuildDir=${{ github.workspace }}\lsp-server-win-x64\" ${{ env.BUILD_NUMBER_ARG }} | |
| - name: Upload VSIX candidate artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: reqnroll-vs-extension-vsix-candidate | |
| path: src/VisualStudio/Reqnroll.IdeSupport.VisualStudio.Extension/bin/${{ env.CONFIGURATION }}/net481/*.vsix | |
| if-no-files-found: error | |
| # --------------------------------------------------------------------------- | |
| # Test VS extension — Reqnroll.VisualStudio.Tests (client parse/transform | |
| # logic; see src/VisualStudio/CONTRIBUTING.md for what belongs here vs. the | |
| # LSP server specs). Runs in parallel with test-vs-wizards. | |
| # --------------------------------------------------------------------------- | |
| test-vs-extension: | |
| name: VS / Test (Extension) | |
| needs: [build-vs-extension] | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Setup .NET ${{ env.DOTNET_VERSION }} | |
| uses: actions/setup-dotnet@v6 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Add MSBuild to PATH | |
| uses: microsoft/setup-msbuild@v3 | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.nuget/packages | |
| key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} | |
| restore-keys: | | |
| nuget-${{ runner.os }}- | |
| - name: Download published LSP server (win-x64) | |
| # Reqnroll.VisualStudio.Tests references the Extension project, which by default | |
| # builds LSP.Server itself via ProjectReference — see build-vs-extension's identical | |
| # step for why this instead reuses the artifact the lsp job already published. | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-win-x64 | |
| path: lsp-server-win-x64 | |
| - name: Restore | |
| run: dotnet restore ${{ env.TESTS_PROJECT }} -p:UseExternalLspServerBuild=true "-p:LspServerBuildDir=${{ github.workspace }}\lsp-server-win-x64\" | |
| - name: Test | |
| run: dotnet test ${{ env.TESTS_PROJECT }} --no-restore --configuration ${{ env.CONFIGURATION }} --logger trx --results-directory TestResults -p:UseExternalLspServerBuild=true "-p:LspServerBuildDir=${{ github.workspace }}\lsp-server-win-x64\" ${{ env.BUILD_NUMBER_ARG }} | |
| - name: Upload Test Result TRX Files | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: vs-extension-tests-trx | |
| if-no-files-found: error | |
| path: "TestResults/*.trx" | |
| # --------------------------------------------------------------------------- | |
| # Test VS wizards — New Project/New Item wizard + welcome-dialog unit tests. | |
| # Runs in parallel with test-vs-extension. | |
| # --------------------------------------------------------------------------- | |
| test-vs-wizards: | |
| name: VS / Test (Wizards) | |
| needs: [build-vs-extension] | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Setup .NET ${{ env.DOTNET_VERSION }} | |
| uses: actions/setup-dotnet@v6 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Add MSBuild to PATH | |
| uses: microsoft/setup-msbuild@v3 | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.nuget/packages | |
| key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} | |
| restore-keys: | | |
| nuget-${{ runner.os }}- | |
| - name: Restore Wizards Tests | |
| run: dotnet restore ${{ env.WIZARDS_TESTS_PROJECT }} | |
| - name: Test Wizards | |
| run: dotnet test ${{ env.WIZARDS_TESTS_PROJECT }} --no-restore --configuration ${{ env.CONFIGURATION }} --logger trx --results-directory TestResults | |
| - name: Upload Test Result TRX Files | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: vs-wizards-tests-trx | |
| if-no-files-found: error | |
| path: "TestResults/*.trx" | |
| # --------------------------------------------------------------------------- | |
| # Publish VSIX — promotes the candidate .vsix built in build-vs-extension to | |
| # its final artifact name, but only once every LSP and VS-extension test | |
| # suite above has passed. Does not push to the Visual Studio Marketplace (no | |
| # marketplace credentials are configured for this repo yet; see | |
| # reqnroll/Reqnroll.VisualStudio's `release` job for the | |
| # CodingWithCalvin/GHA-VSMarketplacePublisher pattern to adopt once | |
| # publishing is desired). | |
| # --------------------------------------------------------------------------- | |
| publish-vsix: | |
| name: VS / Publish | |
| needs: [test-vs-extension, test-vs-wizards] | |
| runs-on: windows-latest | |
| steps: | |
| - name: Download VSIX candidate artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: reqnroll-vs-extension-vsix-candidate | |
| path: vsix | |
| - name: Upload VSIX artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: reqnroll-vs-extension-vsix | |
| path: vsix/*.vsix | |
| if-no-files-found: error | |
| # =========================================================================== | |
| # VS Code extension | |
| # =========================================================================== | |
| # --------------------------------------------------------------------------- | |
| # Extension build — compiles TypeScript, bundles the server binaries | |
| # published by the lsp job, and produces the .vsix package. Does not publish | |
| # to the Marketplace (same rationale as the VS extension above). | |
| # | |
| # extension.ts's resolveServerPath() looks for server/<rid>/<binary>, not | |
| # server/server-<rid>/<binary> — so each RID is downloaded to an explicit | |
| # path below rather than via a single `pattern: server-*` download: with | |
| # merge-multiple left at its default (false), actions/download-artifact@v8 | |
| # nests pattern-matched artifacts one level deeper, under a directory named | |
| # after the artifact itself (server-<rid>/<files>) rather than the bare | |
| # RID. Downloading each one explicitly by name avoids that extra nesting | |
| # level (issue #147). Same fix build-rider-plugin uses below for the | |
| # equivalent problem. | |
| # --------------------------------------------------------------------------- | |
| build-vscode-extension: | |
| name: VSCode / Build | |
| needs: [changes, lsp] | |
| if: needs.changes.outputs.vscode == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Node.js ${{ env.NODE_VERSION }} | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| cache-dependency-path: ${{ env.VSCODE_DIR }}/package-lock.json | |
| - name: Download server (win-x64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-win-x64 | |
| path: ${{ env.VSCODE_DIR }}/server/win-x64 | |
| - name: Download server (linux-x64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-linux-x64 | |
| path: ${{ env.VSCODE_DIR }}/server/linux-x64 | |
| - name: Download server (osx-x64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-osx-x64 | |
| path: ${{ env.VSCODE_DIR }}/server/osx-x64 | |
| - name: Download server (osx-arm64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-osx-arm64 | |
| path: ${{ env.VSCODE_DIR }}/server/osx-arm64 | |
| - name: Restore executable bit on downloaded server/connector binaries | |
| # actions/upload-artifact + download-artifact round-trip through a zip that doesn't | |
| # reliably preserve the Unix executable bit (issue #252 investigation) — every | |
| # extensionless native apphost (the LSP server itself, and each per-TFM | |
| # reqnroll-ide-connector) comes back non-executable, so `npm test`'s client.start() | |
| # would silently fail to spawn it (swallowed by extension.ts's .catch(), no console | |
| # output — just a timeout waiting for State.Running). Same binaries a packaged VSIX | |
| # ships to real Mac/Linux users, so this isn't just a test-fixture problem. | |
| run: | | |
| find "${{ env.VSCODE_DIR }}/server/linux-x64" "${{ env.VSCODE_DIR }}/server/osx-x64" "${{ env.VSCODE_DIR }}/server/osx-arm64" \ | |
| \( -name 'Reqnroll.IdeSupport.LSP.Server' -o -name 'reqnroll-ide-connector' \) \ | |
| -type f -exec chmod +x {} + | |
| - name: Install dependencies | |
| run: npm ci | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Compile TypeScript | |
| run: npm run compile | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Run extension tests | |
| # xvfb-run gives the Extension Development Host (a real Electron/VS Code window) a | |
| # display to render into on this headless Linux runner; ubuntu-latest ships Xvfb | |
| # preinstalled for exactly this kind of GUI test. Only runs here (not in tsc-only) | |
| # because it needs the server binaries downloaded above to actually start the LSP | |
| # client — see issue #205/#249 and the workspace-root fix in runTest.ts for #252. | |
| run: xvfb-run -a npm test | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Lint | |
| run: npm run lint | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Validate semantic token scopes | |
| run: npm run validate:tokens | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Prettier check | |
| run: npm run format:check | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Package VSIX | |
| run: npx @vscode/vsce package --out "reqnroll-ide-support-${{ github.sha }}.vsix" | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Upload VSIX artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: reqnroll-ide-support-vsix | |
| path: ${{ env.VSCODE_DIR }}/reqnroll-ide-support-*.vsix | |
| if-no-files-found: error | |
| # --------------------------------------------------------------------------- | |
| # TypeScript only (fast path for quick-checks on unrelated changes) — no LSP | |
| # dependency, so it doesn't need the lsp job at all. | |
| # --------------------------------------------------------------------------- | |
| tsc-only: | |
| name: VSCode / Compile (TS only) | |
| needs: [changes] | |
| if: needs.changes.outputs.vscode == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Node.js ${{ env.NODE_VERSION }} | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| cache-dependency-path: ${{ env.VSCODE_DIR }}/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Compile TypeScript | |
| run: npm run compile | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Lint | |
| run: npm run lint | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Validate semantic token scopes | |
| run: npm run validate:tokens | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| - name: Prettier check | |
| run: npm run format:check | |
| working-directory: ${{ env.VSCODE_DIR }} | |
| # =========================================================================== | |
| # Rider plugin | |
| # =========================================================================== | |
| # --------------------------------------------------------------------------- | |
| # Plugin build — bundles the server binaries published by the lsp job for | |
| # every RID and produces the plugin .zip, then runs the Plugin Verifier | |
| # against it. Uploads a *candidate* artifact; publish-rider-plugin below | |
| # promotes it to the final artifact name once test-rider-plugin has also | |
| # passed, mirroring the VS extension's build/test/publish-vsix chain. | |
| # | |
| # Gradle never invokes `dotnet` in CI: -PlspServerBuildDir tells | |
| # build.gradle.kts's prepareSandbox task to bundle the already-downloaded | |
| # server-<rid> directories directly instead of running its local-dev-only | |
| # publishServer task. | |
| # | |
| # Rider runs on every desktop OS, so the plugin bundles all four RIDs into | |
| # one universal .zip and picks the right one at runtime | |
| # (ReqnrollServerPathResolver.currentRid()). Each RID is downloaded to an | |
| # explicit path below rather than via a single `pattern: server-*` download: | |
| # with merge-multiple left at its default (false), | |
| # actions/download-artifact@v8 nests pattern-matched artifacts one level | |
| # deeper, under a directory named after the artifact itself | |
| # (server-<rid>/<files>) rather than the bare RID — downloading each one | |
| # explicitly by name avoids that extra nesting level ending up inside the | |
| # plugin. | |
| # | |
| # The Gradle wrapper (gradlew, gradle/wrapper/*) is committed, pinned to | |
| # 8.10 — this job calls ./gradlew directly rather than bootstrapping from | |
| # the runner's system `gradle` (currently 9.6.1 on ubuntu-latest, which is | |
| # NOT what build.gradle.kts is written/tested against — see | |
| # src/Rider/CONTRIBUTING.md). | |
| # --------------------------------------------------------------------------- | |
| build-rider-plugin: | |
| name: Rider / Build | |
| needs: [changes, lsp] | |
| if: needs.changes.outputs.rider == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Setup JDK and Gradle cache | |
| uses: ./.github/actions/setup-rider-gradle-env | |
| - name: Download server (win-x64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-win-x64 | |
| path: ${{ env.RIDER_DIR }}/downloaded-server/win-x64 | |
| - name: Download server (linux-x64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-linux-x64 | |
| path: ${{ env.RIDER_DIR }}/downloaded-server/linux-x64 | |
| - name: Download server (osx-x64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-osx-x64 | |
| path: ${{ env.RIDER_DIR }}/downloaded-server/osx-x64 | |
| - name: Download server (osx-arm64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: server-osx-arm64 | |
| path: ${{ env.RIDER_DIR }}/downloaded-server/osx-arm64 | |
| - name: Build plugin | |
| run: ./gradlew buildPlugin -PlspServerBuildDir="${{ github.workspace }}/${{ env.RIDER_DIR }}/downloaded-server" | |
| working-directory: ${{ env.RIDER_DIR }} | |
| - name: Verify plugin | |
| run: ./gradlew verifyPlugin -PlspServerBuildDir="${{ github.workspace }}/${{ env.RIDER_DIR }}/downloaded-server" | |
| working-directory: ${{ env.RIDER_DIR }} | |
| - name: Upload plugin candidate artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: reqnroll-ide-support-rider-plugin-candidate | |
| path: ${{ env.RIDER_DIR }}/build/distributions/*.zip | |
| if-no-files-found: error | |
| # Only the raw Action log was available for a buildPlugin/verifyPlugin failure otherwise — | |
| # this captures the Plugin Verifier's own report (and any other build report) for download. | |
| - name: Upload build reports on failure | |
| uses: actions/upload-artifact@v7 | |
| if: failure() | |
| with: | |
| name: rider-plugin-build-reports | |
| path: ${{ env.RIDER_DIR }}/build/reports/ | |
| if-no-files-found: ignore | |
| # --------------------------------------------------------------------------- | |
| # Kotlin unit tests. Runs independently of the lsp job/server bundling — | |
| # nothing under src/Rider launches the LSP server yet (see | |
| # src/Rider/CONTRIBUTING.md); once a functional test does, give it a `needs: | |
| # lsp` dependency and download the server the same way build-rider-plugin | |
| # does above. Also runs in parallel with build-rider-plugin (neither needs | |
| # the other) — publish-rider-plugin below is what actually gates on both. | |
| # --------------------------------------------------------------------------- | |
| test-rider-plugin: | |
| name: Rider / Test | |
| needs: [changes] | |
| if: needs.changes.outputs.rider == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Setup JDK and Gradle cache | |
| uses: ./.github/actions/setup-rider-gradle-env | |
| - name: Test | |
| run: ./gradlew test | |
| working-directory: ${{ env.RIDER_DIR }} | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: rider-plugin-test-results | |
| path: ${{ env.RIDER_DIR }}/build/test-results/**/*.xml | |
| if-no-files-found: ignore | |
| # --------------------------------------------------------------------------- | |
| # Publish Rider plugin — promotes the candidate .zip built in | |
| # build-rider-plugin to its final artifact name, but only once | |
| # test-rider-plugin has also passed. Mirrors publish-vsix above. | |
| # --------------------------------------------------------------------------- | |
| publish-rider-plugin: | |
| name: Rider / Publish | |
| needs: [build-rider-plugin, test-rider-plugin] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download plugin candidate artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: reqnroll-ide-support-rider-plugin-candidate | |
| path: plugin | |
| - name: Upload plugin artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: reqnroll-ide-support-rider-plugin | |
| path: plugin/*.zip | |
| if-no-files-found: error |