Skip to content

Latest commit

 

History

234 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cip: reproducing CI failures locally

cip runs a Perl distribution's build and test suite inside a Docker container matching a specific Perl release, so you can reproduce a failing GitHub Actions job on your own machine instead of debugging from logs alone. It's the same tooling used by uperl's .github/workflows/linux.yml CI setup.

Prerequisites

  • Docker, running locally.
  • This repo's bin/ directory on your PATH, or invoke it by full path (~/dev/cip/bin/cip ...).
export PATH="$HOME/dev/cip/bin:$PATH"

Quick start

Run these from the root of the project you're debugging (that directory gets bind-mounted into the container at /work) — not from this cip checkout.

cd ~/dev/some-project
export CIP_TAG=5.20        # the Perl version to reproduce
cip start                  # pull/start a container for that version
cip install                # install dzil + CPAN dependencies
cip script                 # build and run the test suite

CIP_TAG selects the Docker image tag (plicease/ciperl:<tag>) and should match the failing job's name in the Actions run — a job titled perl (5.8) means CIP_TAG=5.8. The project's .github/workflows/*.yml lists the full set of versions it tests under matrix.cip_tag.

Export CIP_TAG once per shell session rather than repeating it on every command; cip doesn't remember it between invocations otherwise.

Common commands

Command What it does
cip start Start (or reuse) the container for $CIP_TAG.
cip install Run dzil authordeps/dzil build, then install the built distribution's dependencies via cpanm.
cip script / cip test Build and run the test suite the way CI does.
cip exec <cmd...> Run one command inside the container, non-interactively.
cip bash Open an interactive shell in the container.
cip stop Stop this version's container.
cip clean Stop the container and drop its dependency cache.
cip stop_all / cip clean_all Stop/clean every cip container across all versions.

The container keeps running between commands, so you don't need to start again before every install or script.

Debugging one failing test

Rather than re-running the whole suite, target the file that's failing:

cip exec bash -c "cd /work && PERL5LIB=lib:/home/cip/perl5/lib/perl5 perl -Ilib t/the-failing-test.t"

The two PERL5LIB entries matter: /home/cip/perl5/lib/perl5 is where cip install put the CPAN dependencies, and lib is the project's own source. Setting PERL5LIB yourself overrides the container's default, so both paths need to be listed explicitly or you'll lose access to the installed dependencies.

Iterating on a fix

cip install is what builds the distribution (via dzil build) into a <Name>-<Version>/ directory in your project root; cip script just tests whatever is already in that directory. That means editing your source and re-running cip script alone will silently re-test the old code. After any source change, re-run cip install first to rebuild it, then cip script (or cip exec) again.

That build directory is listed in .gitignore and safe to delete, but if your local tooling blocks recursive-force rm outside a small list of build directories, move it aside instead:

mv Devel-ebug-0.64 Devel-ebug-0.64.tar.gz /tmp/
cip install

Known rough edges

  • Test::Expect / IO::Tty often time out on the first install. cpanm's default 60-second configure timeout isn't always enough, especially when the container is running under emulation (see below). If cip install reports Configuring IO-Tty-... ! Timed out, install it directly with a longer timeout and try again:

    cip exec bash -c "curl -sL https://cpanmin.us | perl - --notest --configure-timeout 300 IO::Tty Expect Expect::Simple Test::Expect"
    cip install
    
  • Dev/test-only dependencies can be missing. Modules only needed by a project's bin/ scripts, or declared as develop/test requirements that don't make it into the built distribution's metadata, won't get installed automatically. Install them by hand: cip exec cpanm -n Foo.

  • Apple Silicon runs the (amd64) image under emulation. Expect things to run noticeably slower than on a native Linux box — a test file that takes a few seconds locally can take a minute in-container. Don't mistake this for a hang.

  • Containers and caches are named per version. A container is cip-<project directory name>-<CIP_TAG>; caches live under ~/.cip/install-cache/<CIP_TAG> and ~/.cip/dzil-cache/<CIP_TAG>. If something seems stuck in a bad state for one Perl version, cip clean clears just that version without touching the others.

Reproducing a specific failing job, end to end

  1. Open the failing job in the GitHub Actions run and note its name, e.g. perl (5.16).
  2. cd into the project and export CIP_TAG=5.16.
  3. cip start && cip install (apply the Test::Expect workaround above if it times out).
  4. cip script to run the full suite, or cip exec to run just the failing test file.
  5. Fix the code, cip install again to rebuild, then re-test.
  6. cip stop when you're done, or leave it running for next time.

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages