Skip to content

Commit 3d428cf

Browse files
gountharclaude
andauthored
feat(buildkit): add Debian and RPM packaging for BuildKit (#218)
* feat(buildkit): add Debian and RPM packaging for BuildKit Add packaging infrastructure for BuildKit RISC-V64 binaries: Debian packaging (debian-buildkit/): - control: Package metadata with containerd/docker recommendations - rules: Skip build (pre-built binaries) - install: Install buildkitd and buildctl to /usr/bin - changelog, copyright, source/format RPM packaging (rpm-buildkit/): - buildkit.spec: RPM spec for both binaries Workflows: - build-buildkit-package.yml: Triggered by weekly build, creates .deb - build-buildkit-rpm.yml: Triggered by weekly build, creates .rpm Both workflows support: - Development builds (buildkit-v20251209-dev) - Official releases (buildkit-v0.17.3-riscv64) - Automatic version extraction from release tags - Skip if packages already exist Package name aligned with official Debian packaging work at salsa.debian.org/go-team/packages/golang-github-moby-buildkit * feat(buildkit): add release tracking workflow Automatically detects new BuildKit releases from moby/buildkit daily at 08:00 UTC. When a new release is found, triggers buildkit-weekly-build.yml and creates a tracking issue. Features: - Filters for stable releases (excludes dockerfile/* and pre-releases) - Checks if release already built before triggering - Creates GitHub issue to track build progress * feat(buildkit): add BuildKit to APT/RPM repository workflows Update repository update workflows to include BuildKit packages: APT Repository (update-apt-repo.yml): - Add 'Build BuildKit Debian Package' workflow trigger - Add buildkit-v* pattern to release detection regex - Add BuildKit release detection and package download - Add buildkit to cleanup patterns - Add buildkit package type handling in commit logic RPM Repository (update-rpm-repo.yml): - Add 'Build BuildKit RPM Package' workflow trigger - Add buildkit-v pattern to release detection regex This ensures BuildKit packages are automatically added to the APT and RPM repositories when new BuildKit releases are built. * fix(buildkit): address PR review comments for improved robustness Changes based on automated code review feedback: Workflow improvements: - Add proper retry loop error handling (fail if all retries exhausted) - Add explicit --repo parameter to gh release commands - Add binary architecture validation (RISC-V64 check) - Add static/dynamic linking verification - Add version extraction error handling for edge cases - Fix variable quoting in shell scripts - Improve gh CLI installation error handling Packaging fixes: - Fix Recommends/Suggests semantics in Debian control: - containerd is Recommended (required runtime backend) - Docker is Suggested (optional, for buildx integration) - Fix Recommends/Suggests semantics in RPM spec: - containerd is Recommended - docker-ce and moby-engine are Suggested 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(buildkit): add strict error handling to package build steps Add `set -euo pipefail` and explicit package verification to prevent silent failures in build steps. If dpkg-buildpackage or rpmbuild fails but leaves partial artifacts, the step will now correctly fail. Addresses CodeRabbit review comment on error handling. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor(buildkit): extract version logic to shared script - Create .github/scripts/extract-buildkit-version.sh for DRY version extraction - Update both Debian and RPM workflows to use the shared script - Improve gh CLI availability check with fail-fast error handling - Add verification that gh is actually available after installation Addresses CodeRabbit review suggestions for code deduplication and better error diagnostics. --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 12e04a5 commit 3d428cf

File tree

13 files changed

+752
-33
lines changed

13 files changed

+752
-33
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/bin/bash
2+
# Extract version from BuildKit release tag
3+
# Usage: extract-buildkit-version.sh <release_tag>
4+
# Output: Prints extracted version to stdout
5+
#
6+
# Supported formats:
7+
# buildkit-v20251209-dev -> 0.0.20251209
8+
# buildkit-v0.17.3-riscv64 -> 0.17.3
9+
# buildkit-v0.17.3 -> 0.17.3
10+
11+
set -euo pipefail
12+
13+
if [ $# -ne 1 ]; then
14+
echo "Usage: $0 <release_tag>" >&2
15+
exit 1
16+
fi
17+
18+
RELEASE_TAG="$1"
19+
20+
# Dev build: buildkit-v20251209-dev -> 0.0.20251209
21+
if [[ "$RELEASE_TAG" =~ ^buildkit-v([0-9]{8})-dev$ ]]; then
22+
DATE_VER="${BASH_REMATCH[1]}"
23+
echo "0.0.${DATE_VER}"
24+
# Official with suffix: buildkit-v0.17.3-riscv64 -> 0.17.3
25+
elif [[ "$RELEASE_TAG" =~ ^buildkit-v([0-9]+\.[0-9]+\.[0-9]+)-riscv64$ ]]; then
26+
echo "${BASH_REMATCH[1]}"
27+
# Official without suffix: buildkit-v0.17.3 -> 0.17.3
28+
elif [[ "$RELEASE_TAG" =~ ^buildkit-v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
29+
echo "${BASH_REMATCH[1]}"
30+
else
31+
echo "Error: Unrecognized release tag format: $RELEASE_TAG" >&2
32+
echo "Expected formats: buildkit-vYYYYMMDD-dev, buildkit-vX.Y.Z-riscv64, or buildkit-vX.Y.Z" >&2
33+
exit 1
34+
fi
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
name: Build BuildKit Debian Package
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Weekly BuildKit RISC-V64 Build"]
6+
types: [completed]
7+
branches: [main]
8+
workflow_dispatch:
9+
inputs:
10+
release_tag:
11+
description: 'BuildKit release tag'
12+
required: true
13+
default: 'buildkit-v20251209-dev'
14+
15+
permissions:
16+
contents: write
17+
18+
jobs:
19+
build-deb:
20+
runs-on: [self-hosted, riscv64]
21+
if: github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch'
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v6
26+
27+
- name: Check if new release exists
28+
id: check_release
29+
env:
30+
GH_TOKEN: ${{ github.token }}
31+
run: |
32+
set -euo pipefail
33+
34+
# Skip check for manual dispatch
35+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
36+
echo "Manual dispatch - proceeding with build"
37+
echo "skip=false" >> $GITHUB_OUTPUT
38+
exit 0
39+
fi
40+
41+
# Find the latest BuildKit release (matches both dev and official releases)
42+
# gh release list outputs: Title<TAB>Status<TAB>Tag<TAB>Date
43+
# Match buildkit-v* pattern (dev: buildkit-v20251209-dev, official: buildkit-v0.17.3-riscv64)
44+
RELEASE_TAG=$(gh release list --repo gounthar/docker-for-riscv64 --limit 20 | \
45+
awk -F'\t' '$3 ~ /^buildkit-v/ {print $3; exit}')
46+
47+
if [ -z "$RELEASE_TAG" ]; then
48+
echo "No BuildKit release found - skipping package build"
49+
echo "skip=true" >> $GITHUB_OUTPUT
50+
exit 0
51+
fi
52+
53+
echo "Found release: $RELEASE_TAG"
54+
55+
# Check if release already has .deb packages
56+
ASSETS=$(gh release view "$RELEASE_TAG" --json assets --jq '.assets[].name' 2>/dev/null || echo "")
57+
if echo "$ASSETS" | grep -q 'buildkit.*\.deb$'; then
58+
echo "Release $RELEASE_TAG already has Debian packages - skipping build"
59+
echo "skip=true" >> $GITHUB_OUTPUT
60+
else
61+
echo "Release $RELEASE_TAG needs Debian packages - proceeding with build"
62+
echo "skip=false" >> $GITHUB_OUTPUT
63+
fi
64+
65+
- name: Install build dependencies
66+
if: steps.check_release.outputs.skip != 'true'
67+
run: |
68+
set -euo pipefail
69+
sudo apt-get update
70+
sudo apt-get install -y build-essential debhelper dh-make dpkg-dev lintian devscripts libdistro-info-perl
71+
# gh CLI is required - install if missing and verify availability
72+
if ! command -v gh >/dev/null 2>&1; then
73+
echo "gh CLI not found, attempting to install..."
74+
if ! sudo apt-get install -y gh; then
75+
echo "Error: gh CLI is required but installation failed"
76+
exit 1
77+
fi
78+
fi
79+
# Verify gh is actually available
80+
if ! command -v gh >/dev/null 2>&1; then
81+
echo "Error: gh CLI is not available after installation attempt"
82+
exit 1
83+
fi
84+
echo "gh CLI version: $(gh --version | head -1)"
85+
86+
- name: Download BuildKit binaries
87+
if: steps.check_release.outputs.skip != 'true'
88+
env:
89+
GH_TOKEN: ${{ github.token }}
90+
run: |
91+
set -euo pipefail
92+
# Get release tag from workflow_run or manual input
93+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
94+
RELEASE_TAG="${{ github.event.inputs.release_tag }}"
95+
else
96+
# Find the latest buildkit release created by the workflow
97+
RELEASE_TAG=$(gh release list --repo gounthar/docker-for-riscv64 --limit 20 | \
98+
awk -F'\t' '$3 ~ /^buildkit-v/ {print $3; exit}')
99+
fi
100+
101+
if [ -z "$RELEASE_TAG" ]; then
102+
echo "Error: Could not determine release tag"
103+
exit 1
104+
fi
105+
106+
echo "Building package for release: $RELEASE_TAG"
107+
echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_ENV
108+
109+
# Download binaries with explicit repo parameter
110+
gh release download "$RELEASE_TAG" -p buildkitd -p buildctl --repo gounthar/docker-for-riscv64
111+
112+
# Validate binaries were downloaded
113+
if [ ! -f buildkitd ] || [ ! -f buildctl ]; then
114+
echo "Error: Failed to download BuildKit binaries from release $RELEASE_TAG"
115+
exit 1
116+
fi
117+
118+
chmod +x buildkitd buildctl
119+
120+
# Verify binary architecture (RISC-V64)
121+
echo "=== Verifying buildkitd ==="
122+
file ./buildkitd
123+
if ! file ./buildkitd | grep -qi "riscv"; then
124+
echo "Warning: buildkitd may not be a RISC-V64 binary"
125+
fi
126+
./buildkitd --version || echo "Version check skipped (may require runtime dependencies)"
127+
128+
echo "=== Verifying buildctl ==="
129+
file ./buildctl
130+
if ! file ./buildctl | grep -qi "riscv"; then
131+
echo "Warning: buildctl may not be a RISC-V64 binary"
132+
fi
133+
./buildctl --version || echo "Version check skipped (may require runtime dependencies)"
134+
135+
# Verify statically linked (for proper packaging)
136+
echo ""
137+
echo "=== Checking linking ==="
138+
if ldd ./buildkitd 2>&1 | grep -q "not a dynamic executable"; then
139+
echo "buildkitd: statically linked"
140+
else
141+
echo "buildkitd: dynamically linked (checking dependencies)"
142+
ldd ./buildkitd || true
143+
fi
144+
if ldd ./buildctl 2>&1 | grep -q "not a dynamic executable"; then
145+
echo "buildctl: statically linked"
146+
else
147+
echo "buildctl: dynamically linked (checking dependencies)"
148+
ldd ./buildctl || true
149+
fi
150+
151+
ls -lh buildkitd buildctl
152+
153+
- name: Update package version in changelog
154+
if: steps.check_release.outputs.skip != 'true'
155+
run: |
156+
set -euo pipefail
157+
RELEASE_TAG="${{ env.RELEASE_TAG }}"
158+
159+
# Extract version using shared script
160+
VERSION=$(bash .github/scripts/extract-buildkit-version.sh "$RELEASE_TAG")
161+
162+
echo "Package version: $VERSION"
163+
164+
# Set DEBEMAIL to avoid interactive prompt
165+
export DEBEMAIL="github-actions[bot]@users.noreply.github.com"
166+
export DEBFULLNAME="GitHub Actions"
167+
168+
# Copy packaging and update changelog with dch
169+
cp -r debian-buildkit debian
170+
cd debian
171+
dch --check-dirname-level 0 \
172+
--force-distribution \
173+
--newversion "${VERSION}-riscv64-1" \
174+
--distribution trixie \
175+
"RISC-V64 prebuilt BuildKit ${VERSION}"
176+
cd ..
177+
178+
- name: Build package
179+
if: steps.check_release.outputs.skip != 'true'
180+
run: |
181+
set -euo pipefail
182+
# Build package (debian/ already created in previous step)
183+
dpkg-buildpackage -us -uc -b
184+
185+
# Verify package was created
186+
if ! ls ../*.deb 1>/dev/null 2>&1; then
187+
echo "Error: No .deb packages were created"
188+
exit 1
189+
fi
190+
191+
ls -lh ../*.deb
192+
193+
- name: Run lintian checks
194+
if: steps.check_release.outputs.skip != 'true'
195+
run: |
196+
lintian --info --display-info ../*.deb || true
197+
198+
- name: Package info
199+
if: steps.check_release.outputs.skip != 'true'
200+
run: |
201+
for deb in ../*.deb; do
202+
echo "============================================"
203+
echo "=== Package: $(basename $deb) ==="
204+
echo "============================================"
205+
echo ""
206+
echo "=== Package Contents ==="
207+
dpkg-deb --contents "$deb" | head -50
208+
echo ""
209+
echo "=== Package Info ==="
210+
dpkg-deb --info "$deb"
211+
echo ""
212+
echo "=== Package Size ==="
213+
ls -lh "$deb"
214+
echo ""
215+
done
216+
217+
- name: Upload packages to release
218+
if: steps.check_release.outputs.skip != 'true'
219+
env:
220+
GH_TOKEN: ${{ github.token }}
221+
run: |
222+
set -euo pipefail
223+
RELEASE_TAG="${{ env.RELEASE_TAG }}"
224+
225+
echo "Uploading packages to release $RELEASE_TAG"
226+
echo ""
227+
228+
UPLOAD_FAILED=0
229+
for deb in ../*.deb; do
230+
echo "Uploading $(basename "$deb")..."
231+
UPLOAD_SUCCESS=0
232+
for i in {1..3}; do
233+
if gh release upload "$RELEASE_TAG" "$deb" --clobber --repo gounthar/docker-for-riscv64; then
234+
echo "Successfully uploaded $(basename "$deb")"
235+
UPLOAD_SUCCESS=1
236+
break
237+
fi
238+
echo "Retry $i/3..."
239+
sleep 3
240+
done
241+
if [ "$UPLOAD_SUCCESS" -eq 0 ]; then
242+
echo "Error: Failed to upload $(basename "$deb") after 3 attempts"
243+
UPLOAD_FAILED=1
244+
fi
245+
done
246+
247+
if [ "$UPLOAD_FAILED" -eq 1 ]; then
248+
echo "Error: One or more uploads failed"
249+
exit 1
250+
fi
251+
252+
echo ""
253+
echo "BuildKit Debian package uploaded successfully!"
254+
echo ""
255+
echo "Packages built:"
256+
ls -lh ../*.deb
257+
echo ""
258+
echo "Install with:"
259+
echo " wget https://github.com/gounthar/docker-for-riscv64/releases/download/${RELEASE_TAG}/buildkit_*.deb"
260+
echo " sudo dpkg -i buildkit_*.deb"
261+
echo " buildkitd --version"
262+
echo " buildctl --version"

0 commit comments

Comments
 (0)