diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..33efdbf --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +# Continuous integration: configure + build (-Werror), formatting check, and the +# unit + UI test suites on a macOS runner (the project's primary platform). +# +# Integration tests need PostgreSQL, which macOS runners cannot provide via +# Docker; they are opt-in (MODULO_TEST_DB_URL) and therefore report as Skipped +# here. A Linux job with a Postgres service container arrives with the +# containerized backend (Increment 9). + +name: CI + +on: + push: + branches: [main, "increment-*"] + pull_request: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-and-test: + name: Build & test (macOS, Apple Silicon) + runs-on: macos-15 + timeout-minutes: 45 + + steps: + - name: Check out + uses: actions/checkout@v4 + + - name: Install dependencies + # clang-format (small formula) instead of the full llvm keg; scripts/format.sh + # picks it up through CLANG_FORMAT. + run: brew install ninja qt libpq libpqxx libsodium clang-format + + - name: Show toolchain versions + run: | + cmake --version | head -1 + ninja --version + brew list --versions qt libpqxx libsodium clang-format + "$(brew --prefix clang-format)/bin/clang-format" --version + + - name: Configure + run: cmake --preset ci + + - name: Build + run: cmake --build --preset ci + + - name: Check formatting + env: + CLANG_FORMAT: /opt/homebrew/opt/clang-format/bin/clang-format + run: scripts/format.sh --check + + - name: Run tests (unit + ui; integration skips without a database) + run: ctest --preset ci diff --git a/CMakePresets.json b/CMakePresets.json index 28203e7..44d33ca 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,6 +1,10 @@ { "version": 6, - "cmakeMinimumRequired": { "major": 3, "minor": 28, "patch": 0 }, + "cmakeMinimumRequired": { + "major": 3, + "minor": 28, + "patch": 0 + }, "configurePresets": [ { "name": "base", @@ -10,7 +14,8 @@ "cacheVariables": { "CMAKE_PREFIX_PATH": "/opt/homebrew/opt/qt", "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", - "WrapOpenGL_AGL": "/Library/Developer/CommandLineTools/SDKs/MacOSX15.4.sdk/System/Library/Frameworks/AGL.framework" + "WrapOpenGL_AGL": "/Library/Developer/CommandLineTools/SDKs/MacOSX15.4.sdk/System/Library/Frameworks/AGL.framework", + "PostgreSQL_ROOT": "/opt/homebrew/opt/libpq" } }, { @@ -45,37 +50,88 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } + }, + { + "name": "ci", + "displayName": "Continuous integration (GitHub Actions macOS runner)", + "inherits": "dev", + "cacheVariables": { + "WrapOpenGL_AGL": "" + } } ], "buildPresets": [ - { "name": "dev", "configurePreset": "dev" }, - { "name": "dev-asan", "configurePreset": "dev-asan" }, - { "name": "dev-tidy", "configurePreset": "dev-tidy" }, - { "name": "release", "configurePreset": "release" } + { + "name": "dev", + "configurePreset": "dev" + }, + { + "name": "dev-asan", + "configurePreset": "dev-asan" + }, + { + "name": "dev-tidy", + "configurePreset": "dev-tidy" + }, + { + "name": "release", + "configurePreset": "release" + }, + { + "name": "ci", + "configurePreset": "ci" + } ], "testPresets": [ { "name": "unit", "configurePreset": "dev", - "filter": { "include": { "label": "^unit$" } }, - "output": { "outputOnFailure": true } + "filter": { + "include": { + "label": "^unit$" + } + }, + "output": { + "outputOnFailure": true + } }, { "name": "integration", "configurePreset": "dev", - "filter": { "include": { "label": "^integration$" } }, - "output": { "outputOnFailure": true } + "filter": { + "include": { + "label": "^integration$" + } + }, + "output": { + "outputOnFailure": true + } }, { "name": "ui", "configurePreset": "dev", - "filter": { "include": { "label": "^ui$" } }, - "output": { "outputOnFailure": true } + "filter": { + "include": { + "label": "^ui$" + } + }, + "output": { + "outputOnFailure": true + } }, { "name": "all", "configurePreset": "dev", - "output": { "outputOnFailure": true } + "output": { + "outputOnFailure": true + } + }, + { + "name": "ci", + "configurePreset": "ci", + "output": { + "outputOnFailure": true + } } ] } diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a3e8614 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Angelo Barbu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index d3e72fc..4fee2bd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Modulo +[![CI](https://github.com/angelobarbu/Modulo/actions/workflows/ci.yml/badge.svg)](https://github.com/angelobarbu/Modulo/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-00ffa3.svg)](LICENSE) + A personal investment tracker for crypto and stock assets — transactions, bank↔exchange transfers, aggregated holdings with dashboards, uploaded documents, and daily exchange-rate updates. @@ -35,7 +38,7 @@ keeping the future container's migration entrypoint minimal. [Development database](#development-database) · [Testing](#testing) · [Code style](#code-style) · [Development workflow](#development-workflow) · [Repository layout](#repository-layout) · [Roadmap](#roadmap) · -[Implementation log](#implementation-log) +[Implementation log](#implementation-log) · [License](#license) ## Architecture @@ -70,6 +73,9 @@ brew install cmake ninja llvm libpqxx libsodium qt - **Qt 6.8+** is expected at `/opt/homebrew/opt/qt` (the CMake presets bake this path in). - **llvm** provides `clang-format`/`clang-tidy`; it is keg-only, so scripts and CMake reference `/opt/homebrew/opt/llvm/bin` by absolute path. +- **libpqxx** pulls in the keg-only `libpq`; the presets point CMake at it + (`PostgreSQL_ROOT=/opt/homebrew/opt/libpq`) so the build never depends on a stray + local PostgreSQL installation. - **Docker** (Docker Desktop or any `docker compose` v2) must be running for the development database. - The local Homebrew PostgreSQL (if any) can run in parallel - the dockerized database uses @@ -105,6 +111,7 @@ cmake --build --preset dev # build | `dev-asan` | `dev` + address & undefined-behavior sanitizers | | `dev-tidy` | `dev` + clang-tidy on every compile | | `release` | RelWithDebInfo | +| `ci` | `dev` without the local AGL SDK pin — used by GitHub Actions | Build directories are generated in `build//`. All dependencies are Homebrew binary libraries — nothing is downloaded at configure time. @@ -228,6 +235,13 @@ Work is organized in **increments** (a coherent feature area) made of small **st - every step ships with its README update (see the [Implementation log](#implementation-log)) and must pass a clean `-Werror` build, `scripts/format.sh --check`, and `ctest --preset all`. +**Continuous integration** ([`.github/workflows/ci.yml`](.github/workflows/ci.yml)) runs on +every push to `main`/`increment-*` and on pull requests: a macOS (Apple Silicon) runner +installs the Homebrew dependencies, configures with the `ci` preset (identical to `dev` +minus the machine-specific AGL pin), builds with `-Werror`, checks formatting, and runs +the unit and UI suites. Integration tests report as *Skipped* in CI until a Linux job with +a PostgreSQL service container arrives alongside the containerized backend. + ## Repository layout ``` @@ -280,3 +294,8 @@ CMakePresets.json configure/build/test presets (dev, dev-asan, dev-tidy, release | 1.6 — Test scaffolding | One passing suite per layer: core, api (DTO + `require*` rejection paths), config, in-process HTTP integration (opt-in via `MODULO_TEST_DB_URL`, Skipped otherwise), QML smoke (offscreen); toolkit auto-discovers `tests/` dirs | | 1.6b — Qt Test everywhere | Decision: Qt Test replaces Catch2 (one framework for C++ and QML); Catch2 + CPM removed — the project now has zero source-level dependencies | | 1.7 — Docs finalization | README restructured for a public audience (status, contents, architecture, workflow, roadmap); HLD gained the test-architecture view; local working agreement (CLAUDE.md) refreshed | +| 1.8 — Public-repo readiness | MIT `LICENSE`; GitHub Actions CI (macOS runner: brew deps, `ci` preset, `-Werror` build, format check, unit + ui tests); README badges + License section; repository made public and tagged `v0.1.0` | + +## License + +Modulo is released under the [MIT License](LICENSE).