fix: Keep uni_curl_shim.c buildable on Windows so downstream Native builds link #1771
Workflow file for this run
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: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| jobs: | |
| changes: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: read | |
| outputs: | |
| src: ${{ steps.filter.outputs.src }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dorny/paths-filter@v4 | |
| id: filter | |
| with: | |
| filters: | | |
| src: | |
| - '.github/workflows/test.yml' | |
| - '.github/scripts/**' | |
| - 'project/**' | |
| - '**.scala' | |
| - '**.sbt' | |
| - '**.c' | |
| - '**.conf' | |
| - '**.json' | |
| - '**.js' | |
| - '**.html' | |
| - '**.css' | |
| - '**.ts' | |
| - 'pnpm-lock.yaml' | |
| - SCALA_VERSION | |
| code_format: | |
| name: Code format | |
| needs: changes | |
| if: ${{ needs.changes.outputs.src == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: scalafmt | |
| run: ./sbt scalafmtCheckAll | |
| test_scala_3: | |
| name: Scala 3 | |
| needs: changes | |
| if: ${{ needs.changes.outputs.src == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '23' | |
| cache: sbt | |
| - name: Scala 3.x test | |
| run: JVM_OPTS="-Xms2g -Xmx4g" ./sbt "projectJVM/test" | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@v6 | |
| if: always() # always run even if the previous step fails | |
| with: | |
| report_paths: '**/target/test-reports/TEST-*.xml' | |
| check_name: Test Report Scala 3.x | |
| annotate_only: true | |
| detailed_summary: true | |
| test_js: | |
| name: Scala.js | |
| needs: changes | |
| if: ${{ needs.changes.outputs.src == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '23' | |
| - uses: pnpm/action-setup@v6 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| - name: Install Node dependencies | |
| run: pnpm install --frozen-lockfile | |
| # uni-dom-test runs in a real headless Chromium via Playwright (replaces jsdom, so ES | |
| # modules work). Pin to the same version as the Java Playwright runtime (1.49.0) so the | |
| # installed Chromium build matches what com.microsoft.playwright expects, and pull in the | |
| # OS-level libraries Chromium needs on the runner. | |
| - name: Install Playwright Chromium | |
| run: pnpm dlx playwright@1.49.0 install --with-deps chromium | |
| - name: Scala.js test | |
| run: NODE_OPTIONS=--max-old-space-size=4096 JVM_OPTS=-Xmx4g ./sbt "projectJS/test" | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@v6 | |
| if: always() # always run even if the previous step fails | |
| with: | |
| report_paths: '**/target/test-reports/TEST-*.xml' | |
| check_name: Test Report Scala.js | |
| annotate_only: true | |
| detailed_summary: true | |
| test_native_3: | |
| name: Scala Native | |
| needs: changes | |
| if: ${{ needs.changes.outputs.src == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '23' | |
| - name: Install libcurl | |
| run: sudo apt-get update && sudo apt-get install -y libcurl4-openssl-dev | |
| - name: Scala Native test | |
| run: JVM_OPTS=-Xmx4g ./sbt "projectNative/test" | |
| # This build passes -lcurl unconditionally, so no Scala Native job here — on any OS — can | |
| # notice uni_curl_shim.c growing a reference to a libcurl symbol. Downstream projects that | |
| # never link libcurl can, and their build breaks (issue #622). Check the object directly. | |
| - name: Assert the curl shim references no libcurl symbol | |
| run: .github/scripts/check-curl-shim.sh | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@v6 | |
| if: always() # always run even if the previous step fails | |
| with: | |
| report_paths: '**/target/test-reports/TEST-*.xml' | |
| check_name: Test Report Scala Native | |
| annotate_only: true | |
| detailed_summary: true | |
| test_native_3_windows: | |
| # Scala Native compiles every .c under resources/scala-native/ from every jar on the classpath, | |
| # so uni's native C (uni_curl_shim.c) lands in each downstream Windows binary — including ones | |
| # that never call curl. uni had no Windows Native build, so v2026.1.17 shipped a POSIX-only | |
| # `#include <dlfcn.h>` and broke those consumers instead of this repo's CI. | |
| name: Scala Native (Windows) | |
| needs: changes | |
| if: ${{ needs.changes.outputs.src == 'true' }} | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '23' | |
| - uses: ilammy/msvc-dev-cmd@v1 | |
| - name: Install LLVM | |
| run: choco install llvm -y | |
| shell: pwsh | |
| - name: Cache vcpkg artifacts | |
| uses: actions/cache@v4 | |
| id: vcpkg-cache | |
| with: | |
| path: C:\vcpkg\installed | |
| key: vcpkg-windows-x64-curl-zlib-openssl-v2 | |
| - name: Install libcurl, zlib and OpenSSL | |
| if: steps.vcpkg-cache.outputs.cache-hit != 'true' | |
| run: vcpkg install curl:x64-windows zlib:x64-windows openssl:x64-windows | |
| shell: pwsh | |
| - name: Expose the native libraries to the compiler, the linker and the test binary | |
| # Each `-lfoo` / @link("foo") reaches clang in MSVC mode as a request for `foo.lib`: | |
| # `-lcurl -lz` from this build, and `-lcrypto -lssl` from Scala Native's own javalib. | |
| # vcpkg installs those import libraries under their upstream names, so alias them across. | |
| run: | | |
| $root = "$env:VCPKG_INSTALLATION_ROOT\installed\x64-windows" | |
| $libDir = "$root\lib" | |
| @{ | |
| "curl.lib" = "libcurl.lib" | |
| "z.lib" = "zlib.lib" | |
| "crypto.lib" = "libcrypto.lib" | |
| "ssl.lib" = "libssl.lib" | |
| }.GetEnumerator() | ForEach-Object { | |
| $dst = Join-Path $libDir $_.Key | |
| $src = Join-Path $libDir $_.Value | |
| if (-not (Test-Path $dst) -and (Test-Path $src)) { | |
| Write-Host "Copying $($_.Value) -> $($_.Key)" | |
| Copy-Item $src $dst -Force | |
| } | |
| } | |
| Get-ChildItem $libDir -Filter *.lib | Select-Object -ExpandProperty Name | Sort-Object | |
| # Scala Native's own javalib ships a z.c that includes <zlib.h>, so the headers must be | |
| # reachable too, not just the import libraries. | |
| echo "C_INCLUDE_PATH=$root\include" >> $env:GITHUB_ENV | |
| echo "INCLUDE=$root\include;$env:INCLUDE" >> $env:GITHUB_ENV | |
| # LIB is where lld-link searches; bin is where the linked test binary finds libcurl.dll. | |
| echo "LIB=$libDir;$env:LIB" >> $env:GITHUB_ENV | |
| echo "$root\bin" >> $env:GITHUB_PATH | |
| shell: pwsh | |
| # Runs NativeCurlClientTest against a local server, so this also exercises the shim's Windows | |
| # symbol lookup (EnumProcessModules + GetProcAddress) at runtime, not just its compilation. | |
| - name: Scala Native test | |
| run: JVM_OPTS=-Xmx4g ./sbt "projectNative/test" | |
| shell: bash | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@v6 | |
| if: always() # always run even if the previous step fails | |
| with: | |
| report_paths: '**/target/test-reports/TEST-*.xml' | |
| check_name: Test Report Scala Native (Windows) | |
| annotate_only: true | |
| detailed_summary: true | |
| package_src: | |
| name: Verify packageSrc | |
| needs: changes | |
| if: ${{ needs.changes.outputs.src == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '23' | |
| - uses: pnpm/action-setup@v6 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| - name: Install Node dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Install libcurl | |
| run: sudo apt-get update && sudo apt-get install -y libcurl4-openssl-dev | |
| - name: Verify packageSrc (detect cross-platform class name conflicts) | |
| run: ./sbt "projectJVM/packageSrc" "projectJS/packageSrc" "projectNative/packageSrc" | |
| test_sbt_plugin: | |
| name: sbt plugin scripted test | |
| needs: changes | |
| if: ${{ needs.changes.outputs.src == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '23' | |
| cache: sbt | |
| - name: Install sbt | |
| uses: sbt/setup-sbt@v1 | |
| - name: Publish uni locally and get version | |
| id: publish | |
| run: | | |
| ./sbt "coreJVM/publishLocal; uniJVM/publishLocal" | |
| UNI_VERSION=$(./sbt "print uniJVM/version" 2>/dev/null | sed 's/\x1b\[[0-9;]*m//g' | grep -E '^[0-9]' | tail -1 | tr -d '[:space:]') | |
| echo "UNI_VERSION=${UNI_VERSION}" | |
| echo "UNI_VERSION=${UNI_VERSION}" >> "$GITHUB_OUTPUT" | |
| - name: Build and test sbt plugin | |
| working-directory: sbt-uni | |
| run: | | |
| echo "Using UNI_VERSION=${{ steps.publish.outputs.UNI_VERSION }}" | |
| UNI_VERSION=${{ steps.publish.outputs.UNI_VERSION }} sbt "scalafmtCheckAll; publishLocal; scripted" | |
| test_sbt_uni_playwright: | |
| name: sbt-uni-playwright scripted test | |
| needs: changes | |
| if: ${{ needs.changes.outputs.src == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '23' | |
| cache: sbt | |
| - name: Install sbt | |
| uses: sbt/setup-sbt@v1 | |
| - uses: pnpm/action-setup@v6 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '22' | |
| # The scripted test downloads Chromium via the Java Playwright runtime, which needs the | |
| # OS-level libraries. Pin to the same version as the Playwright runtime so the cached build | |
| # matches; --with-deps also installs those libraries. | |
| - name: Install Playwright Chromium | |
| run: pnpm dlx playwright@1.49.0 install --with-deps chromium | |
| - name: Build and scripted-test the plugin (runs Scala.js tests in headless Chromium) | |
| working-directory: sbt-uni-playwright | |
| run: sbt "scalafmtCheckAll; publishLocal; scripted" | |
| test_sbt_uni_crossproject: | |
| name: sbt-uni-crossproject scripted test | |
| needs: changes | |
| if: ${{ needs.changes.outputs.src == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '23' | |
| cache: sbt | |
| - name: Install sbt | |
| uses: sbt/setup-sbt@v1 | |
| # The scripted test cross-compiles for JVM, Scala.js, and Scala Native. It only compiles the | |
| # Native sources to NIR (no nativeLink/run), so no clang/LLVM toolchain or Node.js is needed. | |
| - name: Build and scripted-test the plugin | |
| working-directory: sbt-uni-crossproject | |
| run: sbt "scalafmtCheckAll; publishLocal; scripted" |