From 5dca75031ab3bece9170996bedf37d230f898fcf Mon Sep 17 00:00:00 2001 From: Haowen Liu Date: Sun, 10 Mar 2024 23:13:31 -0400 Subject: [PATCH] CI: Use Docker for CI **Changes** 1. Under `tests/docker`, added two dockerfiles that builds docker images for testing cps-config. The two dockerfiles are for ubuntu and rockylinux currently. More platforms can be added later. 2. In GitHub Actions workflow, switched from building and testing directly within the workflow to building and using docker images. 3. Partly to demonstrate the benefits of this approach, added testing for rockylinux within CI pipeline. 4. Because the CI pipeline is no longer testing ubuntu specifically, rename the pipeline to "test", expecting that in the future, more workflows, like "lint", would be added. **Benefits** 1. Developers would be better able to reproduce CI results without repetitively pushing and triggering GitHub Actions. 2. A single GitHub Actions workflow file would be able to run tests on multiple distributions seamlessly, where all the platform-specific behaviors are handled within dockerfiles for each distribution. 3. In the future, other CI workflows, like running clang-tidy on the codebase, might be interesting. With docker, we will be able to reuse platform-specific setups and have one workflow file per type of check. 4. Docker builds can be cached. This could lead to much faster CI pipeline builds. **Limitation and future work** 1. It is not entirely clear to me whether docker build cache includes ccache mounted with type=cache. Intuitively, it should, but I couldn't find official docs that say so. It that is not cached, this would be a step back from the previous CI setup. In that case, a future PR that caches ccache artifacts would be needed. 2. Currently building the dockerfile also builds cps-config. This might not be necessary for some workflows. It might be interesting to do that as part of the workflow rather than the image build process. 3. It would be nice to document local workflows to test cps-config with those dockerfiles, even if it's "go look at what is being used in test.yml". But that would fit into `docs/dev.md` which is currently WIP in #42. I will follow up with a docs PR once `docs/dev.md` is merged. --- .dockerignore | 16 ++++++++++ .github/workflows/test.yml | 46 ++++++++++++++++++++++++++++ .github/workflows/ubuntu.yml | 49 ------------------------------ tests/docker/rockylinux.Dockerfile | 40 ++++++++++++++++++++++++ tests/docker/ubuntu.Dockerfile | 35 +++++++++++++++++++++ 5 files changed, 137 insertions(+), 49 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/test.yml delete mode 100644 .github/workflows/ubuntu.yml create mode 100644 tests/docker/rockylinux.Dockerfile create mode 100644 tests/docker/ubuntu.Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c46ead8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,16 @@ +# Build directory + +builddir/ + +# Irrelevant files + +.github/ +.clang-format +.gitignore +LICENSE +*/*/*.md + +# Dockerfiles + +*/*/*Dockerfile +*/*/*Dockerfile.in diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..4a3bb23 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,46 @@ +name: Test + +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ main ] + pull_request: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + cfg: + - { id: ubuntu-gcc, platform: ubuntu, cc: gcc, cpp: g++, setup_options: ""} + - { id: ubuntu-gcc-sanitize, platform: ubuntu, cc: gcc, cpp: g++, setup_options: "-Db_sanitize=address,undefined"} + - { id: ubuntu-clang, platform: ubuntu, cc: clang, cpp: clang++, setup_options: ""} + - { id: rockylinux-gcc, platform: ubuntu, cc: gcc, cpp: g++, setup_options: ""} + - { id: rockylinux-gcc-sanitize, platform: ubuntu, cc: gcc, cpp: g++, setup_options: "-Db_sanitize=address,undefined"} + - { id: rockylinux-clang, platform: ubuntu, cc: clang, cpp: clang++, setup_options: ""} + + steps: + - uses: actions/checkout@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + push: false + load: true + tags: ${{ matrix.cfg.id }} + file: tests/docker/${{ matrix.cfg.platform }}.Dockerfile + build-args: | + cc=${{ matrix.cfg.cc }} + cxx=${{ matrix.cfg.cpp }} + setup_options=${{ matrix.cfg.setup_options }} + cache-from: type=gha + cache-to: type=gha,mode=max + - name: Run tests + run: | + docker run ${{ matrix.cfg.id }} ninja -C builddir test diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml deleted file mode 100644 index 8e2f336..0000000 --- a/.github/workflows/ubuntu.yml +++ /dev/null @@ -1,49 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: Ubuntu Latest - -# Controls when the workflow will run -on: - # Triggers the workflow on push or pull request events but only for the main branch - push: - branches: [ main ] - pull_request: - branches: [ main ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - meson: - # The type of runner that the job will run on - runs-on: ubuntu-latest - strategy: - matrix: - cfg: - - { id: gcc, cc: gcc, cpp: g++, setup_options: null} - - { id: gcc-sanitize, cc: gcc, cpp: g++, setup_options: "-Db_sanitize=address,undefined"} - - { id: clang, cc: clang, cpp: clang++, setup_options: null} - - env: - CC: ccache ${{ matrix.cfg.cc }} - CXX: ccache ${{ matrix.cfg.cpp }} - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - name: apt - run: | - sudo apt update - sudo apt install ccache clang libjsoncpp-dev libexpected-dev cmake libgtest-dev libfmt-dev libcxxopts-dev ninja-build - - uses: actions/checkout@v2 - - uses: actions/setup-python@v1 - - name: Setup ccache - uses: hendrikmuhs/ccache-action@v1.0.5 - with: - key: ${{ matrix.cfg.id }} - - uses: BSFishy/meson-build@v1.0.3 - with: - meson-version: 1.0.0 - setup-options: ${{ matrix.cfg.setup_options }} - action: test - directory: builddir \ No newline at end of file diff --git a/tests/docker/rockylinux.Dockerfile b/tests/docker/rockylinux.Dockerfile new file mode 100644 index 0000000..0749aae --- /dev/null +++ b/tests/docker/rockylinux.Dockerfile @@ -0,0 +1,40 @@ +FROM rockylinux:9 + +# Enable EPEL +RUN dnf update -y +RUN dnf install -y 'dnf-command(config-manager)' +RUN dnf config-manager --set-enabled crb -y +RUN dnf install epel-release -y + +# Install dependencies +RUN dnf install -y \ + python3.11 \ + python3-pip \ + ccache \ + clang \ + g++ \ + ninja-build \ + cmake \ + jsoncpp-devel \ + expected-devel \ + gtest-devel \ + fmt-devel \ + cxxopts-devel +RUN dnf clean all +RUN update-alternatives --install /usr/local/bin/python python /usr/bin/python3.11 10 +# Install meson from pip +RUN python3 -m pip install -U meson + +# Copy code +WORKDIR /workarea +COPY ./ ./ + +ARG cc=gcc +ARG cxx=g++ +ARG setup_options= + +# Build cps-config and tests +ENV CC="ccache $cc" CXX="ccache $cxx" +ENV CCACHE_DIR=/ccache +RUN meson setup builddir $setup_options +RUN --mount=type=cache,target=/ccache/ ninja -C builddir diff --git a/tests/docker/ubuntu.Dockerfile b/tests/docker/ubuntu.Dockerfile new file mode 100644 index 0000000..90a2242 --- /dev/null +++ b/tests/docker/ubuntu.Dockerfile @@ -0,0 +1,35 @@ +FROM ubuntu:22.04 + +# Install dependencies +RUN apt-get update +RUN apt-get install -y \ + python3.11 \ + python3-pip \ + ccache \ + clang \ + g++ \ + ninja-build \ + cmake \ + libjsoncpp-dev \ + libexpected-dev \ + libgtest-dev \ + libfmt-dev \ + libcxxopts-dev +RUN apt-get clean +RUN update-alternatives --install /usr/local/bin/python python /usr/bin/python3.11 10 +# Install meson from pip +RUN python3 -m pip install -U meson + +# Copy code +WORKDIR /workarea +COPY ./ ./ + +ARG cc=gcc +ARG cxx=g++ +ARG setup_options= + +# Build cps-config and tests +ENV CC="ccache $cc" CXX="ccache $cxx" +ENV CCACHE_DIR=/ccache +RUN meson setup builddir $setup_options +RUN --mount=type=cache,target=/ccache/ ninja -C builddir