Day 4: Give the gift of time

Lately, Santa was getting lots of letters that went a bit like this

Dear Santa:
I've been mostly good, with 98% coverage this year, so what I want for Christmas is... time.
You know, I have great Rakulang GitHub Actions for stuff, but when I need to install some external package and also many distributions, it takes a loooong time to run, 10 minutes or so, and I can't do anything meaningful during that time, so I wander off elsewhere and I barely remember where I was.
So can I please have time?

Santa thought a bit about this. And that. And that other thing, too. Setting a cache for installed modules was no big deal; raku-test-action does precisely that. Setting a cache for that and modules that need to be installed, well, that’s something different altogether.

If there were a couple of things Santa knew, that was Raku and wrapping. So that was that. Just wrap everything nicely in a single image, a Dockerfile to bundle it all.

FROM jjmerelo/raku-test:latest

ENV PKGS="openssl-dev"
USER root
RUN apk update && apk upgrade && apk add --no-cache $PKGS
USER raku

WORKDIR /home/raku

COPY META6.json .

RUN zef install --deps-only . && rm META6.json

ENTRYPOINT ["zef","--debug","test","."]

We use as base image the tried and true raku-test image, which includes the bare basic to run your tests, and has been optimized (through multi-stage builds) to take the minimum amount of space.

Which means time, of course: less weight for an image, less time it will take to download it from the repository. So we’re good here, only 74.92 MB.

Then we bundle the packages we need inside the image. We just need 4 statements here; and one of them is just to make it a bit more generic. You want to bundle some other (Alpine) package within the image, change the PKGS variable and you’re good.

But then, we need to bundle the dependencies that are going to be used for testing, basically all production dependencies plus the ones declared as “test” (Also build dependencies, not so common, though). The only thing we need to install these is to copy the META6.json file in the build, fire the installation command, and then delete it, because we are not going to need it any more.

We add an ENTRYPOINT for good measure, but we don’t really need it here, because we are going to run test inside the container.

You probably know this needs to be saved to a Dockerfile in your root directory, so I need not repeat it here

Next step is to create a workflow that uploads it automatically to an image registry. Easiest to access is the GitHub Container Registry, so we will use this workflow to build and upload to that registry:

name: Test-create and publish Docker images

on:
  push:
    paths:
      - Dockerfile
      - META6.json
      - .github/workflows/test-upload-ghcr.yaml

env:
  REGISTRY: ghcr.io

jobs:
  build-and-push-image:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Check out source
        uses: actions/checkout@v3

      - name: Log in to GHCR
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push image
        uses: docker/build-push-action@v3.2.0
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/raku-community-modules/raku-test-www

This is longish, but pretty straightforward. First, run only when pushing to main; then, in an Ubuntu runner, establish permissions (need to be able to read contents, and also push to the registry), check out source, log in to the registry, and then build and push the image. Since this is a very common operation, we simply use existing github actions for that.

Only thing you’ll need to change here is the tags key: use the name of the organization/user you are working with instead of raku-community-modules, and the name you want to give your image instead of raku-test-www.

You need to save that with the same name that’s in the third paths key; that way, it will try to run every time this workflow changes, or when META6.json does.

We’re almost there. When this image is built, you need to integrate it in your testing workflows. Like this:

name: "Test"
on:
  push:
    paths:
      - META6.json
      - lib/*
      - t/*
  pull_request:
    paths:
      - META6.json
      - lib/*
      - t/*
jobs:
  test:
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/raku-community-modules/raku-test-www:latest
      env:
        ONLINE_TESTING: 1
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Test
        run: zef --debug test .

Of course, you’ll need to change the name of the image to whatever you’ve named it. Other than that, also pretty straightforward: check out the image, run the tests. Only thing here is that all the packages and distros will already be baked in the image, so you will only have to wait to download the image and to run your tests.

The gift of time

Santa was happy about this; by baking a container image every time some dependency changed, it gave all that time to Raku devs, who only needed to wait a paltry few seconds to download the image. Of course, they needed to wait for the tests, but they wrote that, so it’s on them.

With that, Santa wishes every one a merry Christmas and spend your time wisely helping others and making the world a better place to live.

Published by jjmerelo

Servidor de ustedes

2 thoughts on “Day 4: Give the gift of time

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: