diff --git a/.github/docker/Dockerfile b/.github/docker/Dockerfile index 9b650f3..1e7a120 100644 --- a/.github/docker/Dockerfile +++ b/.github/docker/Dockerfile @@ -53,9 +53,20 @@ ENV LANG=en_US.UTF-8 RUN git config --global --add safe.directory '*' -# Install latest stable Rust toolchain (rocker images may ship an outdated version) -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="/root/.cargo/bin:${PATH}" +# Install latest stable Rust toolchain into fixed, $HOME-independent paths so +# that pak can find cargo regardless of the HOME GitHub Actions injects at runtime. +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ + | sh -s -- -y --no-modify-path +ENV PATH="/usr/local/cargo/bin:${PATH}" + +# Register Rust with dpkg so pkgdepends' bundled sysreqs DB treats it as +# already installed and skips any apt/rustup install attempts at runtime. +RUN RUSTC_VER=$(rustc --version | awk '{print $2}') \ + && CARGO_VER=$(cargo --version | awk '{print $2}') \ + && printf 'Package: rustc\nStatus: install ok installed\nArchitecture: amd64\nVersion: %s\nDescription: stub; real Rust managed by rustup\n\nPackage: cargo\nStatus: install ok installed\nArchitecture: amd64\nVersion: %s\nDescription: stub; real Rust managed by rustup\n\n' \ + "$RUSTC_VER" "$CARGO_VER" >> /var/lib/dpkg/status # Rocker images configure repos to PPM's Linux binary endpoint, which doesn't # index packages needing non-standard build tools (e.g. Rust). Add CRAN source @@ -71,6 +82,13 @@ RUN Rscript -e 'install.packages("pak")' COPY install-packages.R /tmp/install-packages.R RUN Rscript /tmp/install-packages.R && rm /tmp/install-packages.R +# Use pkgdepends' bundled sysreqs DB at runtime rather than downloading the +# live r-hub DB. The live DB's Rust rule runs rustup unconditionally (empty +# packages list bypasses the dpkg check), which fails inside GHA containers +# where HOME is remapped. The bundled DB uses a proper dpkg-based check. +# Rebuild the image with a newer pkgdepends to pick up bundled DB updates. +ENV PKG_SYSREQS_DB_UPDATE=false + # GitHub Copilot's injected "Prepare Copilot" step uses `set -o pipefail` via # `shell: sh`, which dash (Debian's default /bin/sh) doesn't support. Redirect # /bin/sh to bash, which is already installed and is a superset of POSIX sh. diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 7830bdb..d5dffcf 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -15,7 +15,6 @@ jobs: # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. copilot-setup-steps: runs-on: ubuntu-latest - container: ghcr.io/api2r/pkgskills-ci:release permissions: contents: read @@ -25,7 +24,6 @@ jobs: - uses: ./.github/workflows/install with: - use-container: "true" token: ${{ secrets.GITHUB_TOKEN }} cache-version: copilot needs: build, check, website diff --git a/.github/workflows/install/action.yml b/.github/workflows/install/action.yml index e73dc55..44ed875 100644 --- a/.github/workflows/install/action.yml +++ b/.github/workflows/install/action.yml @@ -39,10 +39,6 @@ runs: - if: inputs.use-container != 'true' uses: r-lib/actions/setup-pandoc@v2 - # Always run setup-r, even in containers. With install-r: false it - # skips the R download but still sets R_LIBS_USER, TZ, NOT_CRAN, etc. - # in GITHUB_ENV — the official way to align the environment for - # setup-r-dependencies and actions/cache. - uses: r-lib/actions/setup-r@v2 with: install-r: ${{ inputs.use-container != 'true' }} @@ -62,7 +58,34 @@ runs: mkdir -p "$lib" touch "$lib/.keep" - - uses: r-lib/actions/setup-r-dependencies@v2 + # Container path: call pak::pak() directly so it checks .libPaths() and + # only installs/updates packages that are genuinely missing or outdated. + # setup-r-dependencies always runs a full lockfile-create → lockfile-install + # cycle which reinstalls everything even when the container already has it. + - if: inputs.use-container == 'true' + name: Update R package dependencies (container) + shell: Rscript {0} + env: + GITHUB_PAT: ${{ inputs.token }} + run: | + # Replicate needs → Config/Needs/ expansion from r-lib/actions + needs_parts <- strsplit("${{ inputs.needs }}", "[[:space:],]+")[[1]] + needs_parts <- needs_parts[nzchar(needs_parts)] + needs <- sprintf("Config/Needs/%s", needs_parts) + + extra_deps <- strsplit("${{ inputs.extra-packages }}", "[[:space:],]+")[[1]] + extra_deps <- extra_deps[nzchar(extra_deps)] + + pak::pak( + c("deps::.", extra_deps), + dependencies = c(needs, "all"), + upgrade = TRUE, + ask = FALSE + ) + + # Non-container path: standard setup-r-dependencies flow with caching. + - if: inputs.use-container != 'true' + uses: r-lib/actions/setup-r-dependencies@v2 env: GITHUB_PAT: ${{ inputs.token }} with: diff --git a/NEWS.md b/NEWS.md index 782bd2a..30d50a2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,5 @@ # pkgskills (development version) -* `use_github_copilot()` now installs a container-based `copilot-setup-steps.yml` for faster agent startup (#67). * `AGENTS.md` and `tdd-workflow` skill instructions now explicitly explain how to determine the GitHub issue number and warn agents never to guess or invent one (@copilot, #61). * `use_agent()` template is reconciled with this package's `AGENTS.md` file (#59). * `tdd-workflow` skill now documents `stbl::expect_pkg_error_snapshot()` with an explicit `package` argument instead of a helper-defined version (#51). diff --git a/inst/templates/workflows/copilot-setup-steps.yml b/inst/templates/workflows/copilot-setup-steps.yml index fb03545..e299ee3 100644 --- a/inst/templates/workflows/copilot-setup-steps.yml +++ b/inst/templates/workflows/copilot-setup-steps.yml @@ -15,7 +15,6 @@ jobs: # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. copilot-setup-steps: runs-on: ubuntu-latest - container: ghcr.io/api2r/pkgskills-ci:release permissions: contents: read @@ -25,7 +24,6 @@ jobs: - uses: ./.github/workflows/install with: - use-container: "true" token: ${{ secrets.GITHUB_TOKEN }} cache-version: copilot needs: build, check, website