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.
- Docker, running locally.
- This repo's
bin/directory on yourPATH, or invoke it by full path (~/dev/cip/bin/cip ...).
export PATH="$HOME/dev/cip/bin:$PATH"
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.
| 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.
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.
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
-
Test::Expect/IO::Ttyoften 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). Ifcip installreportsConfiguring 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 asdevelop/testrequirements 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 cleanclears just that version without touching the others.
- Open the failing job in the GitHub Actions run and note its name, e.g.
perl (5.16). cdinto the project andexport CIP_TAG=5.16.cip start && cip install(apply theTest::Expectworkaround above if it times out).cip scriptto run the full suite, orcip execto run just the failing test file.- Fix the code,
cip installagain to rebuild, then re-test. cip stopwhen you're done, or leave it running for next time.