Skip to content

Commit 3dd4a8b

Browse files
committed
Build the Docker image stack for fork PRs without pushing
Add a build-only workflow that builds depends, base, models and sipnet in one job using local tags. Each image stays in the runner image store so the next build resolves its parent locally, no registry or secrets needed. Scoped to the core chain to fit the default runner disk.
1 parent 15bb8b6 commit 3dd4a8b

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: Docker build (fork PRs)
2+
3+
# Pull requests opened from forks get a read-only GITHUB_TOKEN and cannot push
4+
# to ghcr.io/pecanproject, so the normal Docker GHA workflow (docker.yml) skips
5+
# them (see the gate on its `rversion` job). This workflow gives those PRs a
6+
# real "does the image stack still build" signal without pushing anything.
7+
#
8+
# The images build on top of each other (depends -> base -> models -> sipnet).
9+
# The normal workflow runs each as a separate job and pulls the parent back from
10+
# ghcr, which needs a registry we can't push to from a fork. Here we build the
11+
# whole chain in a single job with plain `docker build`, so each image stays in
12+
# the runner's local image store and the next `FROM pecan/<parent>:latest`
13+
# resolves locally. No registry, no push, no secrets.
14+
#
15+
# Scope is the core linear chain only (depends -> base -> models -> sipnet). It
16+
# fits the default runner disk (~19 GB free; the resident stack is ~5-6 GB). The
17+
# other model binaries, baseplus (docs/executor/api) and extras images are not
18+
# built here to keep the job within disk and time budget.
19+
20+
on:
21+
pull_request:
22+
23+
permissions:
24+
contents: read
25+
26+
jobs:
27+
build-stack:
28+
# Only fork PRs. Same-repo PRs are already covered by docker.yml, which can
29+
# push pr-* tags to ghcr because they run with a writable token.
30+
if: github.event.pull_request.head.repo.full_name != github.repository
31+
runs-on: ubuntu-latest
32+
env:
33+
R_VERSION: "4.4"
34+
steps:
35+
- uses: actions/checkout@v6
36+
37+
- name: Disk space before build
38+
run: df -h /
39+
40+
# NOTE: do not add docker/setup-buildx-action here. Plain `docker build`
41+
# uses the default docker-engine builder, which resolves each
42+
# `FROM pecan/<parent>:latest` from the local image store built by the
43+
# previous step. The docker-container buildx driver would not see those
44+
# local images and every FROM after depends would fail.
45+
- name: Build depends -> base -> models -> sipnet (no push)
46+
run: |
47+
set -euxo pipefail
48+
49+
# depends: FROM rocker/tidyverse:${R_VERSION}
50+
docker build -f docker/depends/Dockerfile \
51+
--build-arg R_VERSION="${R_VERSION}" \
52+
-t pecan/depends:latest \
53+
docker/depends
54+
55+
# base: FROM pecan/depends:latest (resolved from the local store)
56+
docker build -f docker/base/Dockerfile \
57+
-t pecan/base:latest \
58+
.
59+
60+
# models: FROM pecan/base:latest
61+
docker build -f docker/models/Dockerfile \
62+
-t pecan/models:latest \
63+
docker/models
64+
65+
# sipnet: FROM pecan/models:latest
66+
docker build -f models/sipnet/Dockerfile \
67+
--build-arg MODEL_VERSION=git \
68+
-t pecan/model-sipnet-git:latest \
69+
models/sipnet
70+
71+
- name: Disk space after build
72+
if: always()
73+
run: df -h /

0 commit comments

Comments
 (0)