10 Commits
Author SHA1 Message Date
torsten b3d047b838 Merge pull request 'Finalizes documentation for basic gitea/jenkins setup' (#5) from feature/finalizies-doc-for-basic-setup into main
sandbox/pipeline/head This commit looks good
Reviewed-on: http://127.0.0.1:3001/lifemaps/sandbox/pulls/5
Reviewed-by: torsten <torsten.wierschin@life-maps.com>
2026-08-04 18:22:58 +00:00
torsten e3d6cd21be Removes basic hook and rule check files.
sandbox/pipeline/pr-main This commit looks good
sandbox/pipeline/head This commit looks good
Fixes Pr checks bug.
Adds documentations.
2026-08-04 20:21:17 +02:00
torsten 95044caecd Finalizes documentation for basic gitea/jenkins setup
sandbox/pipeline/head There was a failure building this commit
sandbox/pipeline/pr-main This commit looks good
2026-08-04 20:10:13 +02:00
torsten 0a5abbb1ee Merge pull request 'Adds testcase for PR policy checks' (#4) from feature/pr-policy-checks into main
sandbox/pipeline/head This commit looks good
Reviewed-on: http://127.0.0.1:3001/lifemaps/sandbox/pulls/4
Reviewed-by: torsten <torsten.wierschin@life-maps.com>
2026-08-04 18:03:22 +00:00
torsten 78de7eae91 Reformats sources accordingly
sandbox/pipeline/pr-main This commit looks good
sandbox/pipeline/head There was a failure building this commit
2026-08-04 19:59:08 +02:00
torsten 684ad1cd3a Add minimal C++ example and pass PR policy checks
sandbox/pipeline/pr-main There was a failure building this commit
2026-08-04 19:57:01 +02:00
torsten 58c3cd0559 Fix PR policy target ref resolution
sandbox/pipeline/pr-main There was a failure building this commit
2026-08-04 19:44:36 +02:00
torsten 5910e6747d Slims jenkins setup b/c resource shortage
sandbox/pipeline/pr-main There was a failure building this commit
2026-08-04 19:40:03 +02:00
torsten 87b2580e9a Fix dockerfile agent checkout ordering
sandbox/pipeline/pr-main Something is wrong with the build of this commit
2026-08-04 19:20:42 +02:00
torsten 6d986b8967 Adds testcase for PR policy checks
sandbox/pipeline/head There was a failure building this commit
sandbox/pipeline/pr-main There was a failure building this commit
2026-08-04 19:09:13 +02:00
11 changed files with 500 additions and 8 deletions

No files matched your search

+28
View File
@@ -0,0 +1,28 @@
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: Never
ColumnLimit: 120
Language: Cpp
Standard: c++20
PointerAlignment: Left
ReferenceAlignment: Left
SortIncludes: true
IncludeBlocks: Regroup
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
BeforeCatch: true
BeforeElse: true
AllowShortIfStatementsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
NamespaceIndentation: None
IndentCaseLabels: true
AlignTrailingComments: true
SeparateDefinitionBlocks: Always
SpaceBeforeParens: ControlStatements
Cpp11BracedListStyle: true
+24
View File
@@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.20)
project(sandbox LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(sandbox main.cpp)
enable_testing()
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
add_executable(test_main tests/test_main.cpp)
target_link_libraries(test_main GTest::gtest_main)
include(GoogleTest)
gtest_discover_tests(test_main)
+17
View File
@@ -0,0 +1,17 @@
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y --no-install-recommends \
python3 \
clang-format \
cmake \
ninja-build \
git \
g++ \
make \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
Vendored
+43 -3
View File
@@ -1,22 +1,62 @@
pipeline {
agent any
agent {
docker {
image 'lifemaps/ci-cpp:latest'
reuseNode true
args '-u root:root'
}
}
options {
timestamps()
disableConcurrentBuilds()
}
environment {
BUILD_DIR = "build"
CHANGE_TARGET = "${env.CHANGE_TARGET ?: 'origin/main'}"
}
stages {
stage('Checkout') {
steps {
checkout scm
sh 'git fetch --all --prune'
sh 'git submodule update --init --recursive || true'
}
}
stage('Policy Checks') {
steps {
sh 'python3 ci/check_pr_policies.py'
}
}
stage('Configure') {
steps {
sh 'cmake -S . -B ${BUILD_DIR} -G Ninja -DCMAKE_BUILD_TYPE=Debug'
}
}
stage('Build') {
steps {
sh 'echo Build works'
sh 'cmake --build ${BUILD_DIR} --parallel'
}
}
stage('Test') {
steps {
sh 'echo Tests work'
sh 'ctest --test-dir ${BUILD_DIR} --output-on-failure'
}
}
}
post {
always {
script {
if (getContext(hudson.FilePath)) {
cleanWs deleteDirs: true, disableDeferredWipeout: true
}
}
}
}
+227 -2
View File
@@ -1,6 +1,231 @@
# sandbox
jenkins testing repobranch protection test
Test- und Beispiel-Repository für einen lokalen Dev-Platform-Stack mit:
- **Gitea 1.22.x**
- **Jenkins Multibranch Pipeline**
- **Webhook-Trigger von Gitea nach Jenkins**
- **C++/CMake/Ninja Build**
- **PR Policy Checks**
- **Docker-basiertem CI-Agent**
branch main protection test
---
## Aktueller Funktionsumfang
Dieses Repository und das zugehörige Jenkins/Gitea-Setup können aktuell:
### SCM / Repository
- Repository in **Gitea** hosten
- Änderungen per **Git Push** empfangen
- **Pull Requests** in Gitea verwalten
- Webhooks von Gitea an Jenkins senden
### Jenkins / CI
- Jenkins als **Multibranch Pipeline** verwenden
- Branches und Pull Requests automatisch erkennen
- Builds durch **Push Events** automatisch starten
- Build-Status an Gitea zurückmelden
### Build-Umgebung
- Pipeline-Schritte in einem **Docker-Container** ausführen
- dafür ein vorbereitetes CI-Image verwenden
- folgende Tools im CI bereitstellen:
- `python3`
- `clang-format`
- `cmake`
- `ninja`
- `git`
- `g++`
- `make`
### C++ Projektbasis
- minimales Beispielprogramm über `main.cpp`
- Build mit **CMake**
- Testausführung über **CTest**
- Testdateien unter `tests/`
---
## Repository-Struktur
```text
.
├── .clang-format
├── CMakeLists.txt
├── Dockerfile.ci
├── Jenkinsfile
├── README.md
├── ci/
│ └── check_pr_policies.py
├── main.cpp
└── tests/
└── test_main.cpp
```
---
## CI / Jenkins Pipeline
Die Jenkins-Pipeline umfasst aktuell diese Schritte:
1. **Checkout**
- Repository aus Gitea auschecken
- zusätzliche Fetch-/Submodule-Schritte ausführen
2. **Policy Checks**
- `ci/check_pr_policies.py` ausführen
- Formatierung und Testbezug prüfen
3. **Configure**
- CMake-Buildverzeichnis erzeugen
4. **Build**
- Projekt mit CMake/Ninja bauen
5. **Test**
- Tests über `ctest` ausführen
6. **Cleanup**
- Workspace am Ende bereinigen
---
## PR Policy Checks
Für geänderte C/C++-Dateien werden in der CI folgende Regeln geprüft:
- `.clang-format` muss im Repository vorhanden sein
- geänderte C/C++-Dateien müssen mit `clang-format` konform sein
- zu geänderten C/C++-Dateien muss ein passender Test unter `tests/` oder `test/` vorhanden sein
### Vergleichsbasis der Policy
Die Policy unterscheidet zwischen Pull-Request-Builds und normalen Branch-Builds:
- **bei Pull Requests** wird gegen den Zielbranch verglichen, z. B. `origin/main`
- **bei normalen Branch-Builds** wird auf eine lokale Vergleichsbasis zurückgefallen, z. B. `HEAD~1`, falls kein Zielbranch-Ref verfügbar ist
Damit funktioniert die Policy sowohl in PR-Builds als auch bei regulären Branch-Indexing- oder Branch-Build-Läufen.
---
## Docker-basierter CI-Agent
Die Pipeline verwendet ein vorbereitetes Docker-Image statt bei jedem Lauf ein neues Build-Image zu erzeugen.
### Beispiel
Das Image wird lokal oder auf dem Build-Host gebaut:
```bash
docker build -t lifemaps/ci-cpp:latest -f Dockerfile.ci .
```
Danach nutzt Jenkins dieses Image als Build-Agent.
### Vorteile
- schnellere PR-Builds
- reproduzierbare Toolchain
- keine langen `apt install`-Phasen pro Build
- saubere Trennung zwischen Jenkins-Controller und Build-Umgebung
---
## Branch- und PR-Workflow
Der aktuelle Workflow unterstützt:
- Arbeiten auf Feature-Branches
- Öffnen von Pull Requests gegen `main`
- automatisches Bauen von PRs
- Rückmeldung des Build-Status an Gitea
Empfohlen ist:
- keine direkten Änderungen auf `main`
- Änderungen über Feature-Branch + Pull Request
- Merge erst nach erfolgreichem CI-Lauf
---
## Lokales Arbeiten
### Formatierung prüfen
```bash
clang-format --dry-run --Werror main.cpp tests/test_main.cpp
```
### Formatierung anwenden
```bash
clang-format -i main.cpp tests/test_main.cpp
```
### CI-Policy lokal testen
```bash
python3 ci/check_pr_policies.py
```
### Build lokal ausführen
```bash
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
cmake --build build --parallel
ctest --test-dir build --output-on-failure
```
---
## Voraussetzungen auf Jenkins-Seite
Für das Setup werden u. a. folgende Jenkins-Plugins benötigt:
- `docker-workflow`
- `pipeline-model-definition`
- `workflow-scm-step`
- `workflow-cps`
- `ws-cleanup`
- `gitea`
- `git`
- `git-client`
- `scm-api`
- `workflow-multibranch`
Zusätzlich muss der Jenkins-Container Zugriff auf Docker haben, z. B. über:
- Docker CLI im Jenkins-Container
- Mount von `/var/run/docker.sock`
---
## Webhook / Automatischer Trigger
Gitea ist so konfiguriert, dass **Push Events** an Jenkins gemeldet werden.
Beispiel-Endpunkt:
```text
https://jenkins.life-maps.com/gitea-webhook/post
```
Damit können automatisch Jenkins-Builds für Branches und Pull Requests ausgelöst werden.
---
## Beispielziel des Repositories
Dieses Repository dient aktuell als:
- Referenz für Jenkins/Gitea-Integration
- Testumgebung für PR-Policies
- Minimalbeispiel für C++/CMake-basierte CI
- Grundlage für weitere CI- und Policy-Erweiterungen
---
## Status
Aktuell ist das Setup geeignet für:
- Jenkins/Gitea-Webhook-Integration
- Pull-Request-basierte CI
- C++/CMake/Ninja Beispielprojekte
- Policy-basierte Qualitätsprüfungen im PR-Prozess
+148
View File
@@ -0,0 +1,148 @@
#!/usr/bin/env python3
import os
import subprocess
import sys
from pathlib import Path
ROOT = Path(".").resolve()
TEST_DIRS = [ROOT / "tests", ROOT / "test"]
CPP_EXTENSIONS = {".c", ".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".hxx"}
TEST_PATTERNS = [
"test_{name}.cpp",
"test_{name}.h",
"{name}_test.cpp",
"{name}_test.h",
"{name}test.cpp",
"{name}test.h",
"{name}gtest.cpp",
"{name}gtest.h",
]
def run(cmd: str) -> str:
return subprocess.check_output(cmd, shell=True, text=True).strip()
def git_ref_exists(ref: str) -> bool:
try:
subprocess.check_call(
f"git rev-parse --verify --quiet '{ref}'",
shell=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
return True
except subprocess.CalledProcessError:
return False
def is_pull_request_build() -> bool:
return bool(os.environ.get("CHANGE_ID"))
def resolve_target_ref() -> str | None:
raw = os.environ.get("CHANGE_TARGET", "").strip()
candidates = []
if raw:
candidates.append(raw)
if not raw.startswith("origin/"):
candidates.append(f"origin/{raw}")
candidates.extend(["origin/main", "main"])
seen = set()
for ref in candidates:
if ref and ref not in seen:
seen.add(ref)
if git_ref_exists(ref):
return ref
return None
def changed_files():
target = resolve_target_ref()
if target:
print(f"Vergleiche gegen Ziel-Ref: {target}")
out = run(f"git diff --name-only {target}...HEAD")
return [line.strip() for line in out.splitlines() if line.strip()]
if is_pull_request_build():
print("ERROR: Kein gültiger Ziel-Branch-Ref für PR-Build gefunden.")
sys.exit(1)
if git_ref_exists("HEAD~1"):
print("Kein Ziel-Branch-Ref gefunden, verwende HEAD~1 für Branch-Build.")
out = run("git diff --name-only HEAD~1..HEAD")
return [line.strip() for line in out.splitlines() if line.strip()]
print("Keine Vergleichsbasis gefunden, behandle alle versionierten Dateien als geändert.")
out = run("git ls-files")
return [line.strip() for line in out.splitlines() if line.strip()]
def is_cpp_file(path: Path) -> bool:
return path.suffix.lower() in CPP_EXTENSIONS
def require_clang_format():
if not (ROOT / ".clang-format").exists():
print("ERROR: .clang-format fehlt im Repository-Root.")
sys.exit(1)
def check_format(path: Path):
subprocess.check_call(f"clang-format --dry-run --Werror '{path}'", shell=True)
def candidate_names(path: Path):
stem = path.stem.lower()
names = {stem}
for suffix in ["_p", "_impl", "_private", "_priv", "_ui"]:
if stem.endswith(suffix):
names.add(stem[:-len(suffix)])
return sorted(n for n in names if n)
def iter_test_files():
for test_dir in TEST_DIRS:
if test_dir.exists():
yield from (p for p in test_dir.rglob("*") if p.is_file())
def has_related_test(path: Path) -> bool:
test_files = list(iter_test_files())
if not test_files:
return False
test_names = [p.name.lower() for p in test_files]
for name in candidate_names(path):
for pattern in TEST_PATTERNS:
if pattern.format(name=name).lower() in test_names:
return True
for test_name in test_names:
if name in test_name and ("test" in test_name or "gtest" in test_name):
return True
return False
def main():
require_clang_format()
files = changed_files()
if not files:
print("Keine geänderten Dateien erkannt.")
return
for rel in files:
path = ROOT / rel
if not path.exists():
continue
if is_cpp_file(path):
print(f"Prüfe: {rel}")
try:
check_format(path)
except subprocess.CalledProcessError:
print(f"ERROR: Formatfehler in {rel}")
sys.exit(1)
if not has_related_test(path):
print(f"ERROR: Kein passender Test unter tests/ oder test/ für {rel} gefunden.")
sys.exit(1)
print("Policy-Checks erfolgreich.")
if __name__ == "__main__":
main()
-1
View File
@@ -1 +0,0 @@
hook test Di 4. Aug 00:08:29 CEST 2026
+7
View File
@@ -0,0 +1,7 @@
#include <iostream>
int main()
{
std::cout << "Hello from sandbox\n";
return 0;
}
-1
View File
@@ -1 +0,0 @@
should fail
-1
View File
@@ -1 +0,0 @@
push-hook-test Di 4. Aug 00:11:58 CEST 2026
+6
View File
@@ -0,0 +1,6 @@
#include <gtest/gtest.h>
TEST(MainTest, Smoke)
{
EXPECT_TRUE(true);
}