Skip to content

Commit bc29015

Browse files
barnabasbusaclaude
andauthored
Add caplin image build support (#342)
## Summary - Adds Docker image building for the **caplin** binary (Erigon's embedded consensus layer client) - Uses a lightweight multi-stage Dockerfile: Go builder → `debian:bookworm-slim` with only `ca-certificates` - Pushes to `ethpandaops/erigon` with `caplin-` prefixed tags (e.g. `ethpandaops/erigon:caplin-main`) - Adds `TARGET_OVERRIDES` mechanism in `generate_config.py` for clients that share a target repository ## Changes - `caplin/Dockerfile` — lightweight multi-stage build that compiles only the caplin binary - `branches.yaml` — adds caplin with `main` branch - `platforms.yaml` — adds caplin for linux/amd64 and linux/arm64 - `generate_config.py` — adds caplin to DEFAULT_REPOS and TARGET_OVERRIDES for shared repo tagging - `.github/workflows/build-push-caplin.yml` — manual build workflow ## Context Ref: ethpandaops/ethereum-package#1337 ## Test plan - [ ] Verify `generate_config.py` produces valid config with `caplin-main` tag targeting `ethpandaops/erigon` - [ ] Validate schema passes - [ ] Trigger manual workflow build to verify Dockerfile builds successfully - [ ] Confirm resulting image contains only the `caplin` binary 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ce94817 commit bc29015

5 files changed

Lines changed: 157 additions & 4 deletions

File tree

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: Build caplin docker image
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
repository:
7+
description: The source erigon repository to build from
8+
default: erigontech/erigon
9+
type: string
10+
required: true
11+
ref:
12+
description: The branch, tag or SHA to checkout and build from
13+
default: main
14+
type: string
15+
required: true
16+
docker_tag:
17+
description: Override target docker tag (defaults to the above source ref if left blank)
18+
type: string
19+
required: false
20+
21+
jobs:
22+
prepare:
23+
runs-on: ubuntu-latest
24+
outputs:
25+
platforms: ${{ steps.setup.outputs.platforms }}
26+
target_tag: ${{ steps.tag.outputs.docker_tag }}
27+
steps:
28+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
29+
- name: Prepare Matrix
30+
id: setup
31+
uses: ./.github/actions/prepare
32+
with:
33+
client: 'caplin'
34+
- name: Generate target tag
35+
id: tag
36+
uses: ./.github/actions/docker-tag
37+
with:
38+
input: caplin-${{ inputs.docker_tag || inputs.ref }}
39+
repository: ${{ inputs.repository }}
40+
upstream_repository: erigontech/erigon
41+
docker_tag: caplin-${{ inputs.docker_tag || inputs.ref }}
42+
deploy:
43+
needs:
44+
- prepare
45+
runs-on: ${{ matrix.runner }}
46+
continue-on-error: true
47+
strategy:
48+
matrix:
49+
include: ${{fromJson(needs.prepare.outputs.platforms)}}
50+
outputs:
51+
git_commit_hash: ${{ steps.set_output.outputs.git_commit_hash }}
52+
steps:
53+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
54+
- uses: ./.github/actions/install-deps
55+
with:
56+
repository: ${{ inputs.repository }}
57+
- uses: ./.github/actions/deploy
58+
id: deploy
59+
with:
60+
source_repository: ${{ inputs.repository }}
61+
source_ref: ${{ inputs.ref }}
62+
target_tag: ${{ needs.prepare.outputs.target_tag }}-${{ matrix.slug }}
63+
target_repository: ethpandaops/erigon
64+
target_dockerfile: ./caplin/Dockerfile
65+
platform: ${{ matrix.platform }}
66+
67+
DOCKER_USERNAME: "${{ vars.DOCKER_USERNAME }}"
68+
DOCKER_PASSWORD: "${{ secrets.DOCKER_PASSWORD }}"
69+
MACOS_PASSWORD: "${{ secrets.MACOS_PASSWORD }}"
70+
GOPROXY: "${{ vars.GOPROXY }}"
71+
HARBOR_USERNAME: "${{ vars.HARBOR_USERNAME }}"
72+
HARBOR_PASSWORD: "${{ secrets.HARBOR_PASSWORD }}"
73+
harbor_registry: ${{ vars.HARBOR_REGISTRY }}
74+
75+
- name: Set job output
76+
id: set_output
77+
run: echo "git_commit_hash=${{ steps.deploy.outputs.git_commit_hash }}" >> $GITHUB_OUTPUT
78+
shell: bash
79+
manifest:
80+
needs:
81+
- prepare
82+
- deploy
83+
runs-on: ubuntu-latest
84+
steps:
85+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
86+
- uses: ./.github/actions/manifest
87+
with:
88+
source_repository: ${{ inputs.repository }}
89+
source_ref: ${{ inputs.ref }}
90+
target_tag: ${{ needs.prepare.outputs.target_tag }}
91+
target_repository: ethpandaops/erigon
92+
platforms: ${{ needs.prepare.outputs.platforms }}
93+
harbor_registry: ${{ vars.HARBOR_REGISTRY }}
94+
HARBOR_USERNAME: "${{ vars.HARBOR_USERNAME }}"
95+
HARBOR_PASSWORD: "${{ secrets.HARBOR_PASSWORD }}"
96+
git_commit_hash: ${{ needs.deploy.outputs.git_commit_hash }}
97+
98+
DOCKER_USERNAME: "${{ vars.DOCKER_USERNAME }}"
99+
DOCKER_PASSWORD: "${{ secrets.DOCKER_PASSWORD }}"
100+
notify:
101+
name: Discord Notification
102+
runs-on: ubuntu-latest
103+
needs:
104+
- prepare
105+
- deploy
106+
- manifest
107+
if: failure()
108+
steps:
109+
- name: Notify
110+
uses: nobrayner/discord-webhook@1766a33bf571acdcc0678f00da4fb83aad01ebc7 # v1
111+
with:
112+
github-token: ${{ secrets.github_token }}
113+
discord-webhook: ${{ secrets.DISCORD_WEBHOOK }}

branches.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ besu:
1111
- bal-devnet-2-with-prefetch
1212
- bal-devnet-3
1313

14+
caplin:
15+
branches:
16+
- main
17+
1418
erigon:
1519
branches:
1620
- main

caplin/Dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
ARG GOLANG_VERSION=1.24
2+
3+
FROM golang:${GOLANG_VERSION}-bookworm AS builder
4+
5+
RUN apt-get update && apt-get install -y --no-install-recommends make gcc g++ && rm -rf /var/lib/apt/lists/*
6+
7+
COPY . erigon
8+
9+
RUN cd erigon && make caplin && cp build/bin/caplin /usr/local/bin/caplin
10+
11+
FROM debian:bookworm-slim
12+
RUN apt-get update && apt-get install -y --no-install-recommends \
13+
ca-certificates \
14+
&& apt-get clean \
15+
&& rm -rf /var/lib/apt/lists/*
16+
COPY --from=builder /usr/local/bin/caplin /usr/local/bin/caplin
17+
ENTRYPOINT ["caplin"]

generate_config.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# Default repository mapping for known clients
88
DEFAULT_REPOS = {
99
'besu': 'besu-eth/besu',
10+
'caplin': 'erigontech/erigon',
1011
'erigon': 'erigontech/erigon',
1112
'ethereumjs': 'ethereumjs/ethereumjs-monorepo',
1213
'ethrex': 'lambdaclass/ethrex',
@@ -47,6 +48,12 @@
4748
# Add more defaults as needed
4849
}
4950

51+
# Clients that share a target repository with a tag prefix
52+
# Maps client_name -> (target_repo_name, tag_prefix)
53+
TARGET_OVERRIDES = {
54+
'caplin': ('erigon', 'caplin-'),
55+
}
56+
5057
# Build argument defaults for special cases
5158
BUILD_ARGS = {
5259
'mev-rs/main-minimal': 'FEATURES=minimal-preset',
@@ -313,17 +320,25 @@ def get_build_args(client_name, source_repo, branch, target_tag):
313320

314321
return None
315322

323+
def get_target_repo_and_tag(client_name, target_tag):
324+
"""Apply target overrides for clients that share a repository"""
325+
if client_name in TARGET_OVERRIDES:
326+
repo_name, tag_prefix = TARGET_OVERRIDES[client_name]
327+
return f'ethpandaops/{repo_name}', f'{tag_prefix}{target_tag}'
328+
return f'ethpandaops/{client_name}', target_tag
329+
316330
def process_branch(client_name, source_repo, branch, target_tag, config_list):
317331
"""Process a single branch configuration"""
332+
target_repo, final_tag = get_target_repo_and_tag(client_name, target_tag)
318333
# Create the basic configuration
319334
config = {
320335
'source': {
321336
'repository': source_repo,
322337
'ref': branch
323338
},
324339
'target': {
325-
'tag': target_tag,
326-
'repository': f'ethpandaops/{client_name}'
340+
'tag': final_tag,
341+
'repository': target_repo
327342
}
328343
}
329344

@@ -346,15 +361,16 @@ def process_branch(client_name, source_repo, branch, target_tag, config_list):
346361

347362
def process_branch_custom(client_name, source_repo, branch, target_tag, config_list, source_patch=None):
348363
"""Process a single custom branch configuration with optional patch"""
364+
target_repo, final_tag = get_target_repo_and_tag(client_name, target_tag)
349365
# Create the basic configuration
350366
config = {
351367
'source': {
352368
'repository': source_repo,
353369
'ref': branch
354370
},
355371
'target': {
356-
'tag': target_tag,
357-
'repository': f'ethpandaops/{client_name}'
372+
'tag': final_tag,
373+
'repository': target_repo
358374
}
359375
}
360376

platforms.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ eleel:
66
dummy-el:
77
- linux/amd64
88
- linux/arm64
9+
caplin:
10+
- linux/amd64
11+
- linux/arm64
912
erigon:
1013
- linux/amd64
1114
- linux/arm64

0 commit comments

Comments
 (0)