earthly / lib

Mozilla Public License 2.0
7 stars 11 forks source link

Saving an image with `DO rust+CARGO` as `ENTRYPOINT` #51

Closed JohnCMoon closed 5 months ago

JohnCMoon commented 6 months ago

I have a unit test which depends on an external postgres database to run. With GitLab CI, I'm able to run the test like this:

unit-test:
  ...
  variables:
    POSTGRES_DB: keylay-test
    POSTGRES_USER: keylay
    POSTGRES_PASSWORD: keylay
  services:
    - postgres:latest
  script:
    - >
      KEYLAY_TEST_DATABASE_URL="postgres://keylay:keylay@postgres/keylay-test"
      cargo test --release --frozen --offline --features postgres

I'm trying to figure out how to express the same test with Earthly (using lib/rust). I understand how to use WITH DOCKER to start up services, but I'm not sure how to run cargo test in that context.

If I were dealing with the cargo commands directly, I could do something like this at the end of my binary build container:

ENTRYPOINT ["cargo", "test", ... "--features", "postgres"]
SAVE IMAGE cargo-test:postgres

And then run the resultant container in the WITH DOCKER context alongside the postgres container, but I don't see a way to do that. I realize this may be an odd use case, but I'm curious if there's an existing solution. If not, I'd be happy to help work on a solution!

JohnCMoon commented 5 months ago

I believe I found a suitable solution. Instead of making the ENTRYPOINT the cargo test invocation, I just saved the actual test binary off as the entrypoint and used that instead. Like this:

postgres-unit-test-image:
    FROM +pre-unit-test
    # Remove existing output
    RUN rm -rf target
    # Build the test binary
    DO rust+CARGO --args="build --tests --release --frozen --offline --features postgres" --output="release/deps/keylay-[^\./]+"
    # Copy the test binary as the container entrypoint
    RUN cp -a ./target/release/deps/keylay-* ./keylay-test
    ENTRYPOINT ["./keylay-test", "--test-threads=1"]

postgres-unit-test:
    FROM docker.io/earthly/dind:alpine-3.19-docker-25.0.2-r0
    WITH DOCKER \
        --load test-image:latest=(+postgres-unit-test-image)
        RUN docker images && \
            docker run --rm --name pg \
                            -e POSTGRES_DB=keylay-test \
                            -e POSTGRES_USER=keylay \
                            -e POSTGRES_PASSWORD=keylay \
                            -d docker.io/library/postgres:latest && \
            sleep 3 && \
            docker run \
              --network container:pg \
              --rm \
              -e KEYLAY_TEST_DATABASE_URL="postgres://keylay:keylay@127.0.0.1/keylay-test" \
              test-image:latest
    END

I wouldn't call it a particularly pretty solution, but it'll serve me well enough! I did encounter a bug with the --output processing in this library which added the need for the RUN rm -rf target line. I'll file a separate bug and PR to address that.