mirror of
https://github.com/projectatomic/rpm-ostree.git
synced 2026-02-05 09:45:27 +01:00
Add build+test infra mirroring bootc
This introduces a Justfile and Dockerfile to enable building rpm-ostree from source in a container, following the pattern established in the bootc project. See the `Justfile` for key entrypoints. Those are now used in a new GHA flow, which we'll try to move things over to. A key difference though vs bootc is because rpm-ostree has a lot of C++ too we use sccache which greatly speeds things up across incremental rebuilds. Just one side cleanup of this is before it was *terribly* painful and manual to hack on `test-container.sh`, and now it's easy, fast and optimized. Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
@@ -5,7 +5,7 @@ srpm:
|
||||
# if we have a git repo with remotes, fetch tags so `git describe` gives a nice NEVRA when
|
||||
# building the RPM
|
||||
if git remote | grep origin; then git fetch origin --tags; fi
|
||||
git submodule update --init --recursive
|
||||
if [ -d .git ]; then git submodule update --init --recursive; fi
|
||||
# Our primary CI build goes via RPM rather than direct to binaries
|
||||
# to better test that path, including our vendored spec file, etc.
|
||||
make -C packaging -f Makefile.dist-packaging srpm
|
||||
|
||||
@@ -1,3 +1,54 @@
|
||||
.cosa
|
||||
target
|
||||
compose-cache/
|
||||
# Exclude everything by default, then include just what we need
|
||||
# Especially note this means that .git is not included, and not tests/
|
||||
# to avoid spurious rebuilds.
|
||||
*
|
||||
|
||||
# Autotools build files
|
||||
!Makefile*.am
|
||||
!Makefile-*.am
|
||||
!Makefile*.inc
|
||||
!Makefile.bindings
|
||||
!configure.ac
|
||||
!autogen.sh
|
||||
|
||||
# Generated C++/Rust bridge files (checked into git)
|
||||
!rpmostree-cxxrs.h
|
||||
!rpmostree-cxxrs.cxx
|
||||
!rpmostree-cxxrsutil.hpp
|
||||
|
||||
# Build configuration
|
||||
!buildutil/
|
||||
!build-aux/
|
||||
!m4/
|
||||
|
||||
# Source code
|
||||
!src/
|
||||
!rust/
|
||||
|
||||
# Rust build files
|
||||
!Cargo.toml
|
||||
!Cargo.lock
|
||||
!build.rs
|
||||
!.cargo/
|
||||
|
||||
# Git submodules (needed by autogen.sh)
|
||||
!libglnx/
|
||||
!libdnf/
|
||||
|
||||
# Build system integration
|
||||
!packaging/
|
||||
!ci/
|
||||
!.copr/
|
||||
|
||||
# Test data for integration tests
|
||||
!tests/
|
||||
|
||||
# Documentation (for man pages, etc.)
|
||||
!docs/
|
||||
!man/
|
||||
|
||||
# Shell completion
|
||||
!completion/
|
||||
|
||||
# API documentation generation
|
||||
!api-doc/
|
||||
|
||||
58
.github/workflows/container-build.yml
vendored
Normal file
58
.github/workflows/container-build.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# Container Build CI Workflow
|
||||
#
|
||||
# Builds rpm-ostree from source in a container using the Dockerfile and Justfile.
|
||||
# This workflow follows the pattern established in bootc for containerized builds.
|
||||
name: Container Build
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch: {}
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Build container and run basic validation
|
||||
build-and-validate:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
base_image:
|
||||
- name: fedora-42
|
||||
image: quay.io/fedora/fedora-bootc:42
|
||||
# TODO: Enable CentOS Stream 10 once tests support it
|
||||
# - name: centos-10
|
||||
# image: quay.io/centos-bootc/centos-bootc:stream10
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Bootc Ubuntu Setup
|
||||
uses: ./.github/actions/bootc-ubuntu-setup
|
||||
|
||||
- name: Run validation
|
||||
run: |
|
||||
just validate
|
||||
|
||||
- name: Build container
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
just build --build-arg=base=${{ matrix.base_image.image }}
|
||||
|
||||
- name: Run container integration tests
|
||||
run: |
|
||||
just test-container-integration
|
||||
25
Cargo.toml
25
Cargo.toml
@@ -134,3 +134,28 @@ bin-unit-tests = []
|
||||
sanitizers = []
|
||||
|
||||
default = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[workspace.lints.rust]
|
||||
# Absolutely must handle errors
|
||||
unused_must_use = "forbid"
|
||||
missing_debug_implementations = "deny"
|
||||
# Feel free to comment this one out locally during development of a patch.
|
||||
dead_code = "deny"
|
||||
|
||||
# We aren't using these yet
|
||||
# [workspace.lints.rust]
|
||||
# unsafe_code = "deny"
|
||||
# missing_docs = "deny"
|
||||
|
||||
[workspace.lints.clippy]
|
||||
disallowed_methods = "deny"
|
||||
# These should only be in local code
|
||||
dbg_macro = "deny"
|
||||
todo = "deny"
|
||||
# These two are in my experience the lints which are most likely
|
||||
# to trigger, and among the least valuable to fix.
|
||||
needless_borrow = "allow"
|
||||
needless_borrows_for_generic_args = "allow"
|
||||
|
||||
123
Dockerfile
Normal file
123
Dockerfile
Normal file
@@ -0,0 +1,123 @@
|
||||
# Build this project from source and write the updated content
|
||||
# (i.e. /usr/bin/rpm-ostree and related binaries) to a new derived container
|
||||
# image. See the `Justfile` for an example
|
||||
#
|
||||
# Use e.g. --build-arg=base=quay.io/centos-bootc/centos-bootc:stream10 to target
|
||||
# CentOS instead.
|
||||
|
||||
ARG base=quay.io/fedora/fedora-bootc:42
|
||||
|
||||
# This first image captures a snapshot of the source code,
|
||||
# note all the exclusions in .dockerignore.
|
||||
FROM scratch as src
|
||||
COPY . /src
|
||||
|
||||
# This is basically a no-op now, but we could make any other final tweaks we want
|
||||
# here.
|
||||
FROM $base as base
|
||||
|
||||
# Fetch sccache
|
||||
FROM base as sccache
|
||||
ARG SCCACHE_VERSION=0.8.2
|
||||
# Install sccache for compiler caching
|
||||
RUN <<EORUN
|
||||
set -xeuo pipefail
|
||||
target=$(arch)-unknown-linux-musl
|
||||
v=sccache-v${SCCACHE_VERSION}-${target}
|
||||
curl -fSsL "https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/${v}.tar.gz" \
|
||||
| tar xz -C /usr/local/bin --strip-components=1 "${v}/sccache"
|
||||
chmod +x /usr/local/bin/sccache
|
||||
EORUN
|
||||
|
||||
# This image installs build deps, pulls in our source code, and installs updated
|
||||
# rpm-ostree binaries in /out. The intention is that the target rootfs is extracted from /out
|
||||
# back into a final stage (without the build deps etc) below.
|
||||
FROM base as build
|
||||
# This installs our package dependencies, and we want to cache it independently of the rest.
|
||||
# Basically we don't want changing a .rs file to blow out the cache of packages. So we only
|
||||
# copy files necessary for dependency installation.
|
||||
COPY packaging /tmp/packaging
|
||||
COPY ci/installdeps.sh ci/libbuild.sh /tmp/ci/
|
||||
RUN <<EORUN
|
||||
set -xeuo pipefail
|
||||
. /usr/lib/os-release
|
||||
case $ID in
|
||||
centos|rhel) dnf config-manager --set-enabled crb;;
|
||||
fedora) dnf -y install dnf-utils 'dnf5-command(builddep)';;
|
||||
esac
|
||||
# Handle version skew, upgrade core dependencies
|
||||
dnf -y distro-sync ostree{,-libs} libmodulemd
|
||||
# Install build requirements
|
||||
cd /tmp && ./ci/installdeps.sh
|
||||
rm /tmp/{packaging,ci} -rf
|
||||
EORUN
|
||||
COPY --from=sccache /usr/local/bin/* /usr/local/bin/
|
||||
# Now copy the rest of the source
|
||||
COPY --from=src /src /src
|
||||
WORKDIR /src
|
||||
# See https://www.reddit.com/r/rust/comments/126xeyx/exploring_the_problem_of_faster_cargo_docker/
|
||||
# We aren't using the full recommendations there, just the simple bits.
|
||||
# First step, ensure we have the crates downloaded
|
||||
RUN --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothome cargo fetch
|
||||
# Then this all runs without networking
|
||||
RUN --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothome --mount=type=cache,target=/var/cache/sccache --network=none <<EORUN
|
||||
set -xeuo pipefail
|
||||
# Configure sccache for C/C++ and Rust compilation caching
|
||||
export SCCACHE_DIR=/var/cache/sccache
|
||||
export CC="sccache gcc"
|
||||
export CXX="sccache g++"
|
||||
export RUSTC_WRAPPER=sccache
|
||||
sccache --show-stats || true
|
||||
env NOCONFIGURE=1 ./autogen.sh
|
||||
./configure --prefix=/usr --libdir=/usr/lib64 --sysconfdir=/etc
|
||||
make -j $(nproc)
|
||||
make install DESTDIR=/out
|
||||
sccache --show-stats
|
||||
EORUN
|
||||
|
||||
# This just does syntax checking and basic validation
|
||||
FROM build as validate
|
||||
RUN grep -vEe '^#' ci/packages-build-extra.txt | xargs dnf -y install
|
||||
RUN --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothome --mount=type=cache,target=/var/cache/sccache --network=none <<EORUN
|
||||
set -xeuo pipefail
|
||||
# Use sccache in validate stage too
|
||||
export SCCACHE_DIR=/var/cache/sccache
|
||||
export CC="sccache gcc"
|
||||
export CXX="sccache g++"
|
||||
export RUSTC_WRAPPER=sccache
|
||||
# Only gate on correctness and a few specific lints by default
|
||||
cargo clippy -- -A clippy::all -D clippy::correctness -D clippy::suspicious -D clippy::disallowed-methods -Dunused_imports -Ddead_code
|
||||
# Basic syntax checks
|
||||
make check-local
|
||||
EORUN
|
||||
|
||||
# The final image that derives from the original base and adds the release binaries
|
||||
FROM base as final
|
||||
# Create a layer that is our new binaries
|
||||
COPY --from=build /out/ /
|
||||
# Only in this containerfile, inject a file which signifies
|
||||
# this comes from this development image. This can be used in
|
||||
# tests to know we're doing upstream CI.
|
||||
RUN touch /usr/lib/.rpm-ostree-dev-stamp
|
||||
|
||||
# Integration test build
|
||||
FROM build as integration-build
|
||||
RUN <<EORUN
|
||||
set -xeuo pipefail
|
||||
grep -vEe '^#' ci/packages-build-extra.txt | xargs dnf -y install
|
||||
grep -vEe '^#' ci/integration-runtime.txt | xargs dnf -y install
|
||||
EORUN
|
||||
# Copy test scripts
|
||||
COPY ci/test-container.sh /out/usr/bin/rpm-ostree-test-container.sh
|
||||
# Copy test data if it exists
|
||||
COPY --from=src /src/tests /usr/share/rpm-ostree/tests
|
||||
RUN <<EORUN
|
||||
set -xeuo pipefail
|
||||
make -C tests/kolainst install DESTDIR=/out
|
||||
EORUN
|
||||
|
||||
FROM final as integration
|
||||
COPY ci/ /run/ci/
|
||||
RUN grep -vEe '^#' /run/ci/integration-runtime.txt | xargs dnf -y install
|
||||
COPY --from=integration-build /out/ /
|
||||
FROM final
|
||||
46
Justfile
Normal file
46
Justfile
Normal file
@@ -0,0 +1,46 @@
|
||||
# The default entrypoint to working on this project.
|
||||
# Commands here typically wrap e.g. `podman build` or
|
||||
# other tools which might launch local virtual machines.
|
||||
#
|
||||
# See also `Makefile`. Commands which end in `-local`
|
||||
# skip containerization (and typically just proxy `make`).
|
||||
#
|
||||
# Rules written here are *often* used by the Github Action flows,
|
||||
# and should support being configurable where that makes sense (e.g.
|
||||
# the `build` rule supports being provided a base image).
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# Build the container image from current sources.
|
||||
# Note commonly you might want to override the base image via e.g.
|
||||
# `just build --build-arg=base=quay.io/fedora/fedora-bootc:42`
|
||||
build *ARGS:
|
||||
podman build --jobs=4 -t localhost/rpm-ostree {{ARGS}} .
|
||||
|
||||
# Perform validation (build, linting) in a container build environment
|
||||
validate:
|
||||
podman build --jobs=4 --target validate .
|
||||
|
||||
# Directly run validation using host tools
|
||||
validate-local:
|
||||
make check
|
||||
|
||||
# Build the integration test container image
|
||||
build-integration:
|
||||
podman build --jobs=4 --target integration -t localhost/rpm-ostree-integration .
|
||||
|
||||
# Run container integration tests
|
||||
test-container-integration: build-integration
|
||||
podman run --rm localhost/rpm-ostree-integration rpm-ostree-test-container.sh
|
||||
|
||||
# Build and run a shell in the build environment for debugging
|
||||
shell:
|
||||
podman build --jobs=4 --target build -t localhost/rpm-ostree-build .
|
||||
podman run --rm -it localhost/rpm-ostree-build /bin/bash
|
||||
|
||||
# Build RPMs in a container
|
||||
rpm *ARGS:
|
||||
podman build --jobs=4 --ignorefile packaging/.dockerignore -f packaging/Containerfile {{ARGS}} -t localhost/rpm-ostree-rpm .
|
||||
podman create --name rpm-ostree-rpm-tmp localhost/rpm-ostree-rpm
|
||||
podman cp rpm-ostree-rpm-tmp:/ .
|
||||
podman rm rpm-ostree-rpm-tmp
|
||||
4
ci/integration-runtime.txt
Normal file
4
ci/integration-runtime.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
# Packages needed for integration tests
|
||||
rsync
|
||||
rpm-build
|
||||
createrepo_c
|
||||
8
ci/packages-build-extra.txt
Normal file
8
ci/packages-build-extra.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# Extra packages needed in the build container for Fedora derivatives
|
||||
# that aren't actually used to build the code necessarily, but
|
||||
# are used by targets in the Dockerfile.
|
||||
rustfmt
|
||||
clippy
|
||||
git-core
|
||||
jq
|
||||
rsync
|
||||
@@ -9,17 +9,6 @@ fatal() {
|
||||
|
||||
versionid=$(. /usr/lib/os-release && echo $VERSION_ID)
|
||||
|
||||
# This allows running this test in a podman container locally by running
|
||||
# `SELF_BOOTSTRAP=1 ci/test-container.sh`.
|
||||
if [ -n "${SELF_BOOTSTRAP:-}" ]; then
|
||||
rm -rf "$PWD/installtree"
|
||||
make install DESTDIR="$PWD/installtree"
|
||||
make -C tests/kolainst install DESTDIR="$PWD/installtree"
|
||||
exec podman run -ti --rm --security-opt=label=disable -v "$PWD":/var/srv -w /var/srv \
|
||||
quay.io/fedora/fedora-coreos:stable sh -c \
|
||||
'rsync -rlv installtree/ / && /var/srv/ci/test-container.sh'
|
||||
fi
|
||||
|
||||
# Test overrides
|
||||
# These hardcoded versions can be kept until Fedora GC's them
|
||||
ignition_url_suffix=2.17.0/4.fc40/x86_64/ignition-2.17.0-4.fc40."$(arch)".rpm
|
||||
|
||||
5
packaging/.dockerignore
Normal file
5
packaging/.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
||||
# For RPM builds, we need minimal exclusions
|
||||
# since we need .git for creating source tarballs
|
||||
target/
|
||||
.cosa/
|
||||
compose-cache/
|
||||
61
packaging/Containerfile
Normal file
61
packaging/Containerfile
Normal file
@@ -0,0 +1,61 @@
|
||||
# Build RPMs for rpm-ostree
|
||||
# This containerfile builds RPMs in a containerized environment.
|
||||
|
||||
ARG base=quay.io/fedora/fedora-bootc:42
|
||||
|
||||
FROM scratch as src
|
||||
# For RPM builds, we need the git repository
|
||||
COPY .git /src/.git
|
||||
COPY . /src
|
||||
|
||||
FROM $base as build
|
||||
# Install build dependencies
|
||||
COPY packaging /tmp/packaging
|
||||
COPY ci/installdeps.sh ci/libbuild.sh /tmp/ci/
|
||||
RUN <<EORUN
|
||||
set -xeuo pipefail
|
||||
. /usr/lib/os-release
|
||||
case $ID in
|
||||
centos|rhel) dnf config-manager --set-enabled crb;;
|
||||
fedora) dnf -y install dnf-utils 'dnf5-command(builddep)';;
|
||||
esac
|
||||
# Handle version skew, upgrade core dependencies
|
||||
dnf -y distro-sync ostree{,-libs} libmodulemd
|
||||
# Install git for RPM source tarball creation and rpm-build for rpmbuild
|
||||
dnf -y install git-core rpm-build
|
||||
# Install build requirements
|
||||
cd /tmp && ./ci/installdeps.sh
|
||||
# Move cargo-vendor-filterer to a persistent location
|
||||
if [ -d /tmp/target/cargo-vendor-filterer ]; then
|
||||
mkdir -p /usr/local/cargo-vendor-filterer
|
||||
cp -r /tmp/target/cargo-vendor-filterer/* /usr/local/cargo-vendor-filterer/
|
||||
ln -sf /usr/local/cargo-vendor-filterer/bin/cargo-vendor-filterer /usr/local/bin/
|
||||
fi
|
||||
rm /tmp/{packaging,ci} -rf
|
||||
rm -rf /tmp/target
|
||||
EORUN
|
||||
|
||||
# Copy source and build RPM
|
||||
COPY --from=src /src /src
|
||||
WORKDIR /src
|
||||
# Initialize submodules if we have a git repo
|
||||
RUN <<EORUN
|
||||
set -xeuo pipefail
|
||||
if [ -d .git ]; then
|
||||
# Configure git safe.directory without --global to avoid needing /root/.gitconfig
|
||||
git config --system --add safe.directory '*' || git config --global --add safe.directory '*' || true
|
||||
git submodule update --init --recursive
|
||||
fi
|
||||
EORUN
|
||||
WORKDIR /src/packaging
|
||||
# Set CARGO_HOME to avoid /root/.cargo issues and RPM topdir to avoid /root issues
|
||||
ENV CARGO_HOME=/tmp/cargo
|
||||
RUN mkdir -p /tmp/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||
RUN echo '%_topdir /tmp/rpmbuild' > /etc/rpm/macros
|
||||
RUN make -f Makefile.dist-packaging rpm
|
||||
|
||||
# Extract RPMs to /out for easy access
|
||||
RUN mkdir -p /out && cp -v *.rpm x86_64/*.rpm /out/
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /out/ /
|
||||
@@ -1,8 +1,16 @@
|
||||
# -*- mode: Makefile -*-
|
||||
|
||||
# Handle builds both with and without a git repository
|
||||
ifeq ($(shell test -d ../.git && echo yes),yes)
|
||||
GITREV = $$(git describe --always --tags)
|
||||
GITREV_FOR_PKG = $(shell echo "$(GITREV)" | sed -e 's,-,\.,g' -e 's,^v,,')
|
||||
GITTIMESTAMP = $$(git show --no-patch --format=%ci)
|
||||
else
|
||||
# Fallback when no git repo is available
|
||||
GITREV = unknown
|
||||
GITREV_FOR_PKG = 9999.0.0
|
||||
GITTIMESTAMP = $(shell date -u +"%Y-%m-%d %H:%M:%S %z")
|
||||
endif
|
||||
|
||||
srcdir=$(shell dirname `pwd`)
|
||||
PACKAGE=rpm-ostree
|
||||
|
||||
Reference in New Issue
Block a user