From 8655ed1ccaee6dce5e65ca44b9072230ab9fccf6 Mon Sep 17 00:00:00 2001 From: Nicolas Bennett <3158446+nbenn@users.noreply.github.com> Date: Sat, 29 Aug 2026 06:26:54 +0000 Subject: [PATCH] Add reverse-dependency CI against the dialect packages This package's own suite dispatches on a test dialect, which is what keeps it free of database dependencies -- and also means nothing in it can catch a change that breaks a real dialect. That signal only exists downstream, so this brings it back to where the change is made. Each leg installs the dialect's dependencies, then overwrites sqlr with the build from this branch, then runs the dialect's suite. Two steps guard against a green run that tested nothing: one fails if the overwrite did not take and main's sqlr is still installed, the other fails if the postgres service is unreachable, since the round-trip tests skip themselves in that case and a skip reads as a pass in the summary. --- .github/workflows/revdep.yaml | 144 ++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 .github/workflows/revdep.yaml diff --git a/.github/workflows/revdep.yaml b/.github/workflows/revdep.yaml new file mode 100644 index 0000000..820affe --- /dev/null +++ b/.github/workflows/revdep.yaml @@ -0,0 +1,144 @@ +# Reverse-dependency CI: run each dialect package's test suite against the +# sqlr in this branch rather than the one on main. +# +# Core's own suite dispatches on a test dialect, which keeps this package free +# of database dependencies but means nothing here can catch a change that +# breaks a real dialect. That signal lives downstream, so this workflow brings +# it back upstream where the change is being made. +# +# To cover a new dialect, add its repository to the matrix below. + +on: + push: + branches: [main] + pull_request: + branches: [main] + +name: revdep + +jobs: + + revdep: + + runs-on: ubuntu-latest + + timeout-minutes: 30 + + name: ${{ matrix.pkg }} + + strategy: + fail-fast: false + matrix: + pkg: + - nbenn/sqlr.postgres + - nbenn/sqlr.sqlite + + # Attached to every leg rather than only the postgres one. A service + # cannot be declared per matrix entry, and the alternative -- splitting + # into two near-identical jobs -- costs more in duplication than the few + # seconds the sqlite leg spends ignoring a container it never opens. + services: + postgres: + image: postgres:17 + env: + POSTGRES_USER: dbi + POSTGRES_PASSWORD: dbi + POSTGRES_DB: dbi + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U dbi -d dbi" + --health-interval 5s + --health-timeout 5s + --health-retries 10 + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + + - uses: actions/checkout@v4 + with: + path: pkg + + - uses: actions/checkout@v4 + with: + repository: ${{ matrix.pkg }} + path: revdep + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + # Resolves the dialect's own dependencies, including its + # `Remotes: nbenn/sqlr`. That pulls sqlr from main -- which is the wrong + # sqlr for this workflow, and is overwritten by the next step. + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + working-directory: revdep + extra-packages: any::testthat + + - name: Install sqlr from this branch + run: R CMD INSTALL pkg + + # Ordering the two installs the other way round, or a future change to + # how the dialect names its remote, would leave main's sqlr in place and + # the suite would pass while testing nothing this branch changed. A + # local install records no RemoteType; an install from GitHub does. + - name: Verify the branch build is the one installed + run: | + Rscript -e ' + desc <- packageDescription("sqlr") + if (!is.null(desc$RemoteType)) { + stop( + "sqlr was installed from ", desc$RemoteType, + ", not from this branch", + call. = FALSE + ) + } + cat("sqlr under test:", desc$Version, "from this branch\n") + ' + + # Without a reachable server the round-trip tests skip themselves, and a + # skip is indistinguishable from a pass in the summary line. Failing here + # keeps a broken service from being reported as a green revdep. + - name: Assert the database is reachable + if: matrix.pkg == 'nbenn/sqlr.postgres' + run: | + Rscript -e ' + con <- DBI::dbConnect( + RPostgres::Postgres(), + host = "localhost", port = 5432, + user = "dbi", password = "dbi", dbname = "dbi" + ) + on.exit(DBI::dbDisconnect(con)) + cat("postgres reachable:", DBI::dbGetQuery(con, "SHOW server_version")[[1L]], "\n") + ' + + - name: Run the dialect test suite + run: | + Rscript -e 'testthat::test_local("revdep", stop_on_failure = TRUE)' + + # A single stable check name for branch protection, so the required-checks + # list does not have to change when a dialect is added to the matrix. + revdep-all: + + needs: revdep + + if: always() + + runs-on: ubuntu-latest + + timeout-minutes: 5 + + steps: + - name: Aggregate revdep matrix + env: + RESULT: ${{ needs.revdep.result }} + run: | + echo "revdep matrix result: $RESULT" + case "$RESULT" in + success|skipped) exit 0 ;; + *) exit 1 ;; + esac