Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions .github/workflows/zswatch-ci-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
- main
- zswatch_*
paths:
- Dockerfile.zswatch-base
- Dockerfile.zswatch-ci
- Dockerfile.base
- Dockerfile.ci
- .github/workflows/zswatch-ci-image.yml
Expand All @@ -23,6 +25,14 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Free disk space
run: |
df -h
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android /opt/hostedtoolcache/CodeQL
docker system prune -af || true
docker volume prune -f || true
df -h

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

Expand All @@ -37,11 +47,14 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.base
file: ./Dockerfile.zswatch-base
push: true
tags: |
ghcr.io/zswatch/ci-base:${{ github.ref_name }}
ghcr.io/zswatch/ci-base:latest
ghcr.io/zswatch/ci-base-slim:${{ github.ref_name }}
ghcr.io/zswatch/ci-base-slim:latest

- name: Prune buildx cache
run: docker buildx prune -af --keep-storage 5GB

- name: Build and push CI image
uses: docker/build-push-action@v5
Expand All @@ -53,4 +66,4 @@ jobs:
ghcr.io/zswatch/zswatch-ci:latest
ghcr.io/zswatch/zswatch-ci:${{ github.ref_name }}
build-args: |
BASE_IMAGE=ghcr.io/zswatch/ci-base:${{ github.ref_name }}
BASE_IMAGE=ghcr.io/zswatch/ci-base-slim:${{ github.ref_name }}
122 changes: 122 additions & 0 deletions Dockerfile.zswatch-base
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# ZSWatch slim base image
# Minimal tooling for nRF5340 and native_sim builds; omits extras from the upstream base.

FROM ubuntu:24.04

ARG USERNAME=user
ARG UID=1000
ARG GID=1000
ARG PYTHON_VENV_PATH=/opt/python/venv
ARG UBUNTU_MIRROR_ARCHIVE=archive.ubuntu.com/ubuntu
ARG UBUNTU_MIRROR_SECURITY=security.ubuntu.com/ubuntu
ARG UBUNTU_MIRROR_PORTS=ports.ubuntu.com/ubuntu-ports

# Set default shell during Docker image build to bash
SHELL ["/bin/bash", "-eo", "pipefail", "-c"]

# Set non-interactive frontend for apt-get to skip any user confirmations
ENV DEBIAN_FRONTEND=noninteractive

# Install a trimmed set of APT packages
RUN <<EOF
# Set up custom Ubuntu APT mirrors
pushd /etc/apt/sources.list.d
cp ubuntu.sources ubuntu.sources.bak
sed -i "s#archive.ubuntu.com/ubuntu#${UBUNTU_MIRROR_ARCHIVE}#" ubuntu.sources
sed -i "s#security.ubuntu.com/ubuntu#${UBUNTU_MIRROR_SECURITY}#" ubuntu.sources
sed -i "s#ports.ubuntu.com/ubuntu-ports#${UBUNTU_MIRROR_PORTS}#" ubuntu.sources
popd

apt-get -y update

# Core build and tooling stack
apt-get install --no-install-recommends -y \
build-essential \
ca-certificates \
ccache \
cmake \
dfu-util \
device-tree-compiler \
file \
gdb \
git \
gperf \
libffi-dev \
libncursesw6 \
libreadline8 \
libssl-dev \
libusb-1.0-0 \
libyaml-0-2 \
libsdl2-dev \
locales \
ninja-build \
openssh-client \
pkg-config \
python3 \
python3-dev \
python3-pip \
python3-setuptools \
python3-wheel \
python3-venv \
python-is-python3 \
sudo \
unzip \
wget \
xz-utils

apt-get autoremove --purge -y
apt-get clean -y
rm -rf /var/lib/apt/lists/*

# Restore original Ubuntu mirrors
pushd /etc/apt/sources.list.d
mv -f ubuntu.sources.bak ubuntu.sources
popd
EOF

# Initialise system locale
RUN locale-gen en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8

# Set up Python virtual environment for Zephyr
RUN <<EOF
mkdir -p ${PYTHON_VENV_PATH}
python3 -m venv ${PYTHON_VENV_PATH}
source ${PYTHON_VENV_PATH}/bin/activate

pip install --no-cache-dir --upgrade pip setuptools wheel
pip install --no-cache-dir \
-r https://raw.githubusercontent.com/zephyrproject-rtos/zephyr/main/scripts/requirements.txt \
-r https://raw.githubusercontent.com/zephyrproject-rtos/mcuboot/main/scripts/requirements.txt \
'esptool>=5.0.2' \
GitPython \
imgtool \
junitparser \
junit2html \
nrf-regtool~=9.0.1 \
numpy \
protobuf \
grpcio-tools \
PyGithub \
pylint \
sh \
statistics \
west
EOF

# Make Zephyr Python virtual environment available globally
ENV PATH=${PYTHON_VENV_PATH}/bin:$PATH

# Create user account
RUN <<EOF
userdel -r ubuntu || true
groupadd -g $GID -o $USERNAME
useradd -u $UID -m -g $USERNAME -G plugdev $USERNAME
echo $USERNAME ' ALL = NOPASSWD: ALL' > /etc/sudoers.d/$USERNAME
chmod 0440 /etc/sudoers.d/$USERNAME
EOF

# Ensure that container runs in the 'root' user context
USER root
54 changes: 53 additions & 1 deletion Dockerfile.zswatch-ci
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ ARG UBUNTU_MIRROR_PORTS=ports.ubuntu.com/ubuntu-ports

ARG ZSDK_VERSION=0.17.4
ENV ZSDK_VERSION=$ZSDK_VERSION
# Limit installed SDK content to the toolchains used by ZSWatch to keep the image lean.
ARG ZSDK_TOOLCHAINS="arm-zephyr-eabi,x86_64-zephyr-elf"
ENV ZSDK_TOOLCHAINS=$ZSDK_TOOLCHAINS

# Install minimal extra APT packages required for ZSWatch CI
RUN <<EOF
Expand All @@ -24,14 +27,63 @@ RUN <<EOF
rm -rf /var/lib/apt/lists/*
EOF

# Remove large tooling from ci-base that ZSWatch does not need (keeps image small)
RUN <<'EOF'
if [ "${HOSTTYPE}" = "x86_64" ]; then
# Drop 32-bit support and multilib toolchains not needed for nRF/native_sim_64
apt-get update -y
apt-get purge --auto-remove -y \
gcc-multilib g++-multilib \
libc6-dbg:i386 libfuse-dev:i386 libsdl2-dev:i386 || true
dpkg --remove-architecture i386 || true
Comment on lines +37 to +38
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing i386 architecture may cause issues with the existing PKG_CONFIG_PATH environment variable on line 79, which points to /usr/lib/i386-linux-gnu/pkgconfig. After this change, that directory will no longer exist, potentially causing package config lookups to fail.

Consider verifying whether i386 package config support is needed, and if not, update the PKG_CONFIG_PATH in a subsequent change to remove the i386 reference.

Copilot uses AI. Check for mistakes.
fi

# Remove heavy debug/coverage/doc tools unused in ZSWatch CI builds
apt-get update -y
apt-get purge --auto-remove -y \
valgrind \
lcov \
gcovr \
doxygen \
thrift-compiler || true
Comment on lines +43 to +48
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The apt-get purge command is executed without first running apt-get update. When running in a fresh Docker layer, the package manager's cache may be stale or empty, which could cause the purge operation to fail or behave unexpectedly. Although the commands have || true as a safeguard, it's better practice to run apt-get update before package operations.

Consider adding:

apt-get update -y
apt-get purge --auto-remove -y \
    valgrind \
    ...

Copilot uses AI. Check for mistakes.

apt-get update -y
apt-get purge --auto-remove -y \
libgtk2.0-0 \
libcairo2-dev \
libglib2.0-dev \
libpcap-dev \
ovmf \
parallel || true

apt-get clean -y
rm -rf /var/lib/apt/lists/*
rm -rf /usr/share/doc /usr/share/man /usr/share/info
EOF

# Reinstall SDL2 dev headers explicitly (native_sim needs sdl2.pc)
RUN <<EOF
apt-get update -y
apt-get install --no-install-recommends -y libsdl2-dev
apt-get clean -y
rm -rf /var/lib/apt/lists/*
EOF

# Install Zephyr SDK
RUN <<EOF
mkdir -p /opt/toolchains
cd /opt/toolchains
wget ${WGET_ARGS} https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${ZSDK_VERSION}/zephyr-sdk-${ZSDK_VERSION}_linux-${HOSTTYPE}.tar.xz
tar xf zephyr-sdk-${ZSDK_VERSION}_linux-${HOSTTYPE}.tar.xz
zephyr-sdk-${ZSDK_VERSION}/setup.sh -t all -h -c
# Convert comma/space separated toolchain list into repeated -t flags (required by setup.sh)
set --
for toolchain in $(printf '%s' "$ZSDK_TOOLCHAINS" | tr ',' ' '); do
set -- "$@" -t "$toolchain"
done
set -- "$@" -h -c
zephyr-sdk-${ZSDK_VERSION}/setup.sh "$@"
rm zephyr-sdk-${ZSDK_VERSION}_linux-${HOSTTYPE}.tar.xz
find zephyr-sdk-${ZSDK_VERSION}/sysroots -maxdepth 4 -type d \( -name doc -o -name man -o -name info \) -exec rm -rf '{}' +
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The find command with -exec rm -rf '{}' + may fail when removing parent directories before their children are processed. When multiple directories match (e.g., nested doc folders), removing a parent doc directory will cause subsequent attempts to remove its child directories to fail because they no longer exist.

Consider using -prune instead or changing + to \; to process one directory at a time:

find zephyr-sdk-${ZSDK_VERSION}/sysroots -maxdepth 4 -type d \( -name doc -o -name man -o -name info \) -exec rm -rf '{}' \;

or use -prune to avoid descending into matched directories:

find zephyr-sdk-${ZSDK_VERSION}/sysroots -maxdepth 4 \( -name doc -o -name man -o -name info \) -prune -exec rm -rf '{}' +
Suggested change
find zephyr-sdk-${ZSDK_VERSION}/sysroots -maxdepth 4 -type d \( -name doc -o -name man -o -name info \) -exec rm -rf '{}' +
find zephyr-sdk-${ZSDK_VERSION}/sysroots -maxdepth 4 -type d \( -name doc -o -name man -o -name info \) -exec rm -rf '{}' \;

Copilot uses AI. Check for mistakes.
EOF

# Run the Zephyr SDK setup script as 'user' in order to ensure that the
Expand Down