Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 130 additions & 2 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ concurrency:

env:
OCAMLRUNPARAM: b
# When changing the setup-ocaml version, also adjust it in the setup step
# further below.
SETUP_OCAML_VERSION: 3.6.0 # OPAM <2.6.0

jobs:
coverage:
runs-on: ubuntu-24.04-arm
env:
OS: ubuntu-24.04-arm
OCAML_COMPILER: 5.3.0
RUST_TARGET: aarch64-unknown-linux-gnu
steps:
- name: Checkout
uses: actions/checkout@v6
Expand All @@ -35,38 +42,159 @@ jobs:
packages: bubblewrap darcs g++-multilib gcc-multilib mercurial musl-tools rsync cmake
version: v4

# --- rewatch build cache ---------------------------------------------
# `make coverage` shells out to `make` which builds rewatch; cache the
# cargo target dir so subsequent runs skip the Rust toolchain install
# and the cargo build when the rewatch sources haven't changed.
- name: Restore rewatch build cache
id: rewatch-build-cache
uses: actions/cache@v5
with:
path: rewatch/target
key: rewatch-build-v3-${{ env.RUST_TARGET }}-${{ hashFiles('rewatch/src/**', 'rewatch/Cargo.lock') }}

- name: Determine Rust toolchain version
id: rust-version
run: |
version="$(awk -F '"' '/^rust-version[[:space:]]*=/ { print $2; exit }' rewatch/Cargo.toml)"
echo "version=${version}" >> "$GITHUB_OUTPUT"

- name: Install Rust toolchain
if: steps.rewatch-build-cache.outputs.cache-hit != 'true'
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.rust-version.outputs.version }}
components: clippy, rustfmt

- name: Build rewatch
if: steps.rewatch-build-cache.outputs.cache-hit != 'true'
run: cargo build --manifest-path rewatch/Cargo.toml --release

- name: Copy rewatch binary
run: |
cp rewatch/target/release/rescript rescript
./scripts/copyExes.js --rewatch

- name: Use OCaml
# --- OPAM environment cache ------------------------------------------
# The OPAM install step is the dominant cost on a cold run (often >10
# min). Cache the whole opam tree, keyed on the OS, setup-ocaml
# version, compiler, and the `.opam` files. The cache also includes
# the dev-setup dependencies (e.g. bisect_ppx) so the key is distinct
# from the main CI workflow's cache.
- name: Get OPAM cache key
run: echo "opam_cache_key=opam-coverage-v1-${{ env.OS }}-${{ env.SETUP_OCAML_VERSION }}-${{ env.OCAML_COMPILER }}-${{ hashFiles('*.opam') }}" >> $GITHUB_ENV

- name: Restore OPAM environment
id: cache-opam-env
uses: actions/cache/restore@v5
with:
path: |
${{ runner.tool_cache }}/opam
~/.opam
_opam
.opam-path
key: ${{ env.opam_cache_key }}

- name: Use OCaml ${{ env.OCAML_COMPILER }}
if: steps.cache-opam-env.outputs.cache-hit != 'true'
uses: ocaml/setup-ocaml@v3.6.0
with:
ocaml-compiler: 5.3.0
ocaml-compiler: ${{ env.OCAML_COMPILER }}
opam-pin: false

- name: Get OPAM executable path
if: steps.cache-opam-env.outputs.cache-hit != 'true'
uses: actions/github-script@v9
with:
script: |
const opamPath = await io.which('opam', true);
console.log('opam executable found: %s', opamPath);

const fs = require('fs/promises');
await fs.writeFile('.opam-path', opamPath, 'utf-8');
console.log('stored path to .opam-path');

- name: Install OPAM dependencies (incl. bisect_ppx)
if: steps.cache-opam-env.outputs.cache-hit != 'true'
run: opam install . --deps-only --with-test --with-dev-setup

# Only save on master pushes. PR-scoped caches are tied to
# refs/pull/<n>/merge and can't be restored by master or other PRs,
# so they'd just consume storage and evict the shared entry. PRs
# still get full restore from the latest master-saved cache.
- name: Save OPAM environment
if: steps.cache-opam-env.outputs.cache-hit != 'true' && github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: actions/cache/save@v5
Comment on lines +125 to +127
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict OPAM cache writes to master pushes

This save step runs on every cache miss, including pull_request runs, so it will upload PR-scoped caches. Per GitHub cache semantics, cache misses auto-create a cache, and caches created on pull_request are tied to refs/pull/.../merge and are not restorable by master or other PRs; that means repeated PR misses for a new key will create isolated entries that add storage pressure and can evict the shared branch cache, reducing hit rate and increasing future OPAM install time. Gate this save to push on refs/heads/master (as done for coverage build state) to keep the cache reusable.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3a99217 — added github.event_name == 'push' && github.ref == 'refs/heads/master' to the save condition, matching the gating already used on the coverage-build-state cache. PRs still restore the latest master cache on hit; they just don't write new PR-scoped entries.

with:
path: |
${{ runner.tool_cache }}/opam
~/.opam
_opam
.opam-path
key: ${{ env.opam_cache_key }}

- name: Use cached OPAM environment
if: steps.cache-opam-env.outputs.cache-hit == 'true'
run: |
# https://github.com/ocaml/setup-ocaml/blob/v3.6.0/packages/setup-ocaml/src/installer.ts
echo "OPAMCOLOR=always" >> "$GITHUB_ENV"
echo "OPAMCONFIRMLEVEL=unsafe-yes" >> "$GITHUB_ENV"
echo "OPAMDOWNLOADJOBS=4" >> "$GITHUB_ENV"
echo "OPAMERRLOGLEN=0" >> "$GITHUB_ENV"
echo "OPAMEXTERNALSOLVER=builtin-0install" >> "$GITHUB_ENV"
echo "OPAMPRECISETRACKING=1" >> "$GITHUB_ENV"
echo "OPAMRETRIES=10" >> "$GITHUB_ENV"
echo "OPAMSOLVERTIMEOUT=600" >> "$GITHUB_ENV"
echo "OPAMYES=1" >> "$GITHUB_ENV"
echo "CLICOLOR_FORCE=1" >> "$GITHUB_ENV"
echo "OPAMROOT=$HOME/.opam" >> "$GITHUB_ENV"

OPAM_PATH="$(cat .opam-path)"
chmod +x "$OPAM_PATH"
dirname "$OPAM_PATH" >> "$GITHUB_PATH"

# --- Coverage build cache --------------------------------------------
# The bisect_ppx-instrumented dune build is a separate artifact from
# the main CI build, so it gets its own key. Only restore/save on
# master pushes — PRs share the master cache to stay fast but won't
# poison it.
- name: Coverage build state key
id: coverage-build-state-key
run: echo "value=coverage-build-state-v1-${{ env.OS }}-${{ env.SETUP_OCAML_VERSION }}-${{ env.OCAML_COMPILER }}-${{ hashFiles('*.opam', 'compiler/**', 'dune-project') }}" >> $GITHUB_OUTPUT

- name: Restore coverage build state
if: github.base_ref == 'master' || github.ref == 'refs/heads/master'
id: coverage-build-state
uses: actions/cache/restore@v5
with:
path: |
~/.cache/dune
_build
key: ${{ steps.coverage-build-state-key.outputs.value }}

- name: Run coverage
run: opam exec -- make coverage

- name: Delete stale coverage build state
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: |
gh extension install actions/gh-actions-cache
gh actions-cache delete ${{ steps.coverage-build-state-key.outputs.value }} \
-R ${{ github.repository }} \
-B "$GITHUB_REF" \
--confirm || echo "not exist"
env:
GH_TOKEN: ${{ github.token }}

- name: Save coverage build state
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: actions/cache/save@v5
with:
path: |
~/.cache/dune
_build
key: ${{ steps.coverage-build-state-key.outputs.value }}

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
- Expand `super_errors` fixture coverage for warnings and errors. https://github.com/rescript-lang/rescript/pull/8429
- Run `super_errors` fixtures in parallel (~2.4× faster locally). https://github.com/rescript-lang/rescript/pull/8430
- Expand `super_errors` fixture coverage for the remaining reachable single-file error variants. https://github.com/rescript-lang/rescript/pull/8432
- Cache OPAM env, rewatch build, and instrumented dune state in the coverage workflow. https://github.com/rescript-lang/rescript/pull/8434


# 13.0.0-alpha.4
Expand Down
Loading