Linux CI Testing with Docker
Overview
When to read this page
This is for developers on macOS who want to catch Linux or GitHub Actions build failures before pushing. It is not the installation procedure for using MygramDB.
This guide explains how to test your code in the same Linux environment used by GitHub Actions CI, catching platform-specific issues (like missing headers or compiler differences) before pushing to CI.
Problem
When developing on macOS, certain issues only appear in Linux environments:
- Missing header includes (e.g.,
<cstdint>,<climits>) - Compiler differences (Clang vs GCC behavior)
- Library version differences
- Path handling differences
These issues often only get detected in CI, leading to failed builds after pushing.
Solution
We provide Docker-based Linux testing that mirrors the GitHub Actions CI environment (Ubuntu 22.04 with the same dependencies).
Quick Start
1. Run Full CI Checks (Recommended before git push)
make docker-ci-checkThis runs the complete CI pipeline:
- Code formatting check
- Build (with same flags as CI)
- Clang-tidy linting
- All tests
Use this before every push to catch CI failures early.
2. Run Individual Steps
# Build only
make docker-build-linux
# Test only
make docker-test-linux
# Lint only
make docker-lint-linux
# Format check only
make docker-format-check-linux3. Interactive Development Shell
make docker-dev-shellThis gives you an interactive bash shell inside the Linux container where you can run commands manually:
# Inside the container
make build
make test
make lint
./build/bin/mygramdb --helpHow It Works
Docker Image: support/dev/Dockerfile
The support/dev/Dockerfile creates a Linux development environment that exactly matches the GitHub Actions CI environment:
- Base: Ubuntu 22.04
- Compiler: GCC (same as CI)
- Tools: clang-format-18, clang-tidy-18, ccache
- Dependencies: libmysqlclient-dev, libicu-dev, etc.
Makefile Targets
All Linux testing targets follow the pattern docker-*-linux:
| Target | Description |
|---|---|
docker-dev-build | Build the Linux Docker image (auto-run by other targets) |
docker-dev-shell | Interactive shell in Linux container |
docker-build-linux | Build project in Linux (mimics CI) |
docker-test-linux | Run tests in Linux |
docker-lint-linux | Run clang-tidy in Linux |
docker-format-check-linux | Check formatting in Linux |
docker-clean-linux | Clean build in Linux |
docker-ci-check | Run all CI checks (recommended) |
Recommended Workflow
Option 1: Pre-push Check (Recommended)
# After making changes
make format # Format code (macOS)
make build # Quick build check (macOS)
make docker-ci-check # Full Linux CI check before push
git commit -m "..."
git pushOption 2: Continuous Testing
If you're working on Linux-specific issues or want to test frequently:
# Terminal 1: Keep building in Linux
make docker-build-linux
# Terminal 2: Keep testing in Linux
make docker-test-linux
# Or use interactive shell for faster iteration
make docker-dev-shell
# Inside container: make build && make testOption 3: Debug Specific CI Failures
If CI failed with a specific error:
# Reproduce the exact CI environment
make docker-dev-shell
# Inside container, run the failing step
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=ON -DENABLE_COVERAGE=ON -DUSE_ICU=ON -DUSE_MYSQL=ON ..
make -j$(nproc)
make lint
# Fix the issue, exit, and verify
exit
make docker-ci-checkPerformance Tips
1. Image Caching
The Docker image is cached after the first build. Subsequent runs are much faster:
- First run: ~5-10 minutes (downloads and installs LLVM, dependencies)
- Subsequent runs: ~10-30 seconds (only builds your code)
2. Incremental Builds
The build/ directory is mounted as a volume, so builds are incremental:
# First build: full compilation
make docker-build-linux
# Second build: only changed files
make docker-build-linux # Much faster!3. Parallel Testing
Tests run in parallel using all available CPU cores:
make docker-test-linux # Uses $(nproc) cores4. ccache
What is ccache?
ccache caches compilation results and reuses them. Files whose headers and compile options have not changed are not recompiled, which makes repeat builds much faster.
The container uses ccache to speed up compilation. This is shared across builds.
Troubleshooting
Issue: "permission denied" errors
The container runs as root, but files are owned by your user. If you encounter permission issues:
# Clean build directory
make docker-clean-linux
# Or manually
sudo rm -rf build/Issue: Docker image is outdated
If dependencies changed (e.g., new LLVM version, new libraries):
# Rebuild the development image
docker build -f support/dev/Dockerfile -t mygramdb-dev:latest --no-cache .Issue: Disk space
Docker images can consume disk space. To clean up:
# Remove development image
docker rmi mygramdb-dev:latest
# Clean all unused Docker resources
docker system prune -aIssue: Slow builds
If builds are slow even with caching:
# Check ccache stats
make docker-dev-shell
ccache --show-stats
# Increase ccache size if needed (inside container)
ccache --set-config=max_size=1GCI Environment Details
The support/dev/Dockerfile environment matches .github/workflows/ci.yml:
| Component | Version |
|---|---|
| OS | Ubuntu 22.04 |
| Compiler | GCC (default) + Clang 18 |
| CMake | Latest from apt |
| clang-format | 18 |
| clang-tidy | 18 |
| MySQL Client | libmysqlclient-dev |
| ICU | libicu-dev |
| Readline | libreadline-dev |
| Coverage | lcov |
| Cache | ccache |
Integration with Git Hooks
You can add a pre-push hook to automatically run CI checks:
# .git/hooks/pre-push
#!/bin/bash
echo "Running CI checks before push..."
make docker-ci-check
if [ $? -ne 0 ]; then
echo "CI checks failed. Push aborted."
exit 1
fichmod +x .git/hooks/pre-pushAdvanced Usage
Custom CMake Options
# Build with different options
docker run --rm -v $(pwd):/workspace -w /workspace mygramdb-dev:latest \
bash -c "mkdir -p build && cd build && \
cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_ASAN=ON .. && \
make -j$(nproc)"Run Specific Tests
docker run --rm -v $(pwd):/workspace -w /workspace mygramdb-dev:latest \
bash -c "cd build && ctest -R 'MyTest.*' --verbose"Generate Coverage Report
make docker-dev-shell
# Inside container
cd build
make coverage
# View coverage/html/index.htmlComparison: macOS vs Linux Testing
| Aspect | macOS (make build) | Linux (make docker-build-linux) |
|---|---|---|
| Speed | Fast (native) | Slower (containerized) |
| Environment | Your macOS | CI environment (Ubuntu 22.04) |
| Use case | Quick iteration | Pre-push verification |
| Compiler | Clang (macOS) | GCC (Linux) |
| Headers | More permissive | Stricter (catches missing includes) |
Recommendation: Use both!
- macOS for rapid development
- Linux for pre-push verification