numops
March 22, 2026 · View on GitHub
A trivial C++ arithmetic library demonstrating a fully automated CI/CD pipeline with Conan 2 packaging, multi-platform builds, and label-driven release workflows.
Overview
This project implements a complete DevOps CI/CD pipeline for a small C++ library. The library itself is intentionally simple — the focus is on the build, test, packaging, and release automation.
Library
numops provides basic arithmetic operations:
add(int a, int b)— additionsubtract(int a, int b)— subtractionmultiply(int a, int b)— multiplication
Building
Prerequisites
- C++17 compatible compiler
- mise (or asdf) for tool version management
- clang-format (install via
Homebrew:
brew install clang-format)
Setup
mise install # installs Python, CMake, and linter tools
pip install -r requirements.txt # installs Conan into .venv
Tool versions are pinned in .tool-versions (compatible with both mise and asdf).
A mise.toml configures a Python virtual environment (.venv/) so that IDE
tools like Pylance and mypy can resolve Conan imports.
Build from source
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build
Build with Conan
conan create .
CI/CD Pipeline
Pull Request Verification
Every PR triggers two workflows automatically:
- Lint (
lint.yml) — MegaLinter (YAML, Markdown, Python, CMake, shell) + clang-format checks for C++ viacpp-linter-action - Build (
build.yml) — CMake configure, build, and unit tests (ctest) on:- Linux (ubuntu-latest, GCC)
- macOS (macos-latest, Apple Clang)
- Windows (windows-latest, MSVC)
Label-Driven Workflows
verifylabel (verify.yml) — full end-to-end integration test:- Builds RC packages (
X.Y.Z-dev-<short-sha>) and uploads toconan-rc - A separate consumer project installs the package from
conan-rcviaconan install --requires=numops/<ref> - Consumer builds with
find_package(numops CONFIG REQUIRED), links, and runs - All three steps run on every platform (Linux, macOS, Windows)
- Builds RC packages (
publishlabel (publish.yml):- Validates that
CMakeLists.txtversion is bumped vs the PR base branch - Checks that the release version does not already exist in
conan-stable - Builds RC packages on all platforms
- Uploads RC packages to
conan-rcremote (JFrog Artifactory)
- Validates that
Note: The repo has two consumer test mechanisms:
test_package/is the standard Conan test package (validates the package duringconan create), whiletests/integration/is a standalone CMake consumer that tests installation from a real Conan remote — exercising the full dependency resolution, download, and linking flow.
Release on Merge
When a publish-labeled PR is merged (release.yml):
- Version is extracted from
CMakeLists.txt - Git tag
vX.Y.Zis created - GitHub Release is created with auto-generated release notes
- Conan packages are built and published to
conan-stablefor all platforms - Platform-specific
.tar.gzartifacts (headers + libraries) are attached to the GitHub Release
Versioning
- Semantic versioning (SemVer)
- Version source of truth:
CMakeLists.txtproject(VERSION X.Y.Z) - Pre-merge RC builds:
numops/X.Y.Z-dev-<short-sha> - Release builds:
numops/X.Y.Z publish-labeled PRs must bump version above base branch before RC publish
Conan Package
Remotes
The project uses two Conan remotes hosted on JFrog Artifactory:
conan-rc— release candidate packages (pre-merge,X.Y.Z-dev-<sha>)conan-stable— final release packages (post-merge,X.Y.Z)
Installation
conan remote add conan-stable <JFROG_URL>/conan-stable
conan install --requires=numops/<version> -r conan-stable
Usage in CMake
find_package(numops CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE numops::numops)
Deterministic Builds
- Conan CLI is pinned (
conan==2.26.2) and CI uses checked-in platform profiles fromconan/profiles/. - RC/release workflows generate and use Conan lockfiles (
conan lock create+--lockfile) beforeconan create/conan install. - Unit-test dependency
googletestis pinned to immutable commitb514bdc898e2951020cbdca1304b75f5950d1f59.
Required GitHub Secrets
| Secret | Description |
|---|---|
JFROG_URL | JFrog Artifactory Conan API base URL |
JFROG_USER | JFrog username or email |
JFROG_TOKEN | JFrog access token |
Linting
Linting runs automatically on every PR via GitHub Actions. To run locally:
clang-format --dry-run --Werror include/**/*.h src/*.cpp tests/*.cpp
markdownlint-cli2 "**/*.md"
yamllint -c .yamllint.yml .github/workflows/*.yml
ruff check .
Project Structure
├── CMakeLists.txt # Build system (version source of truth)
├── conanfile.py # Conan 2 package recipe
├── .tool-versions # Tool versions for mise/asdf
├── requirements.txt # Python dependencies (Conan)
├── cmake/ # CMake package config template
├── conan/profiles/ # Platform-specific Conan profiles
├── include/numops/ # Public headers
├── src/ # Implementation
├── tests/ # Unit tests (GoogleTest)
├── tests/integration/ # E2E consumer test (installs from remote)
├── test_package/ # Conan test package (local cache validation)
├── scripts/ # Repository setup automation
├── .github/workflows/ # CI/CD pipelines
├── .clang-format # C++ formatting rules
├── .clang-tidy # C++ static analysis config
├── .mega-linter.yml # MegaLinter configuration
├── .markdownlint.yml # Markdown linting rules
└── .yamllint.yml # YAML linting rules