diff --git a/.entire/.gitignore b/.entire/.gitignore new file mode 100644 index 0000000..e66987d --- /dev/null +++ b/.entire/.gitignore @@ -0,0 +1,5 @@ +tmp/ +settings.local.json +metadata/ +logs/ +redactors/local/ diff --git a/.entire/settings.json b/.entire/settings.json new file mode 100644 index 0000000..b005bff --- /dev/null +++ b/.entire/settings.json @@ -0,0 +1,9 @@ +{ + "enabled": true, + "telemetry": true, + "checkpoints": { + "primary": { + "type": "git-branch" + } + } +} diff --git a/.envrc b/.envrc-example similarity index 66% rename from .envrc rename to .envrc-example index 39a5320..7a7db4e 100644 --- a/.envrc +++ b/.envrc-example @@ -7,4 +7,8 @@ export COPILOT_PROVIDER_BASE_URL="https://api.scaleway.ai/v1" export COPILOT_MODEL="${STRIX_LLM}" export COPILOT_PROVIDER_MAX_PROMPT_TOKENS="32768" -export COPILOT_PROVIDER_MAX_OUTPUT_TOKENS="8192" \ No newline at end of file +export COPILOT_PROVIDER_MAX_OUTPUT_TOKENS="8192" + +export ENTIRE_TOKEN_STORE=file +export ENTIRE_TOKEN_STORE_PATH=$HOME/.config/entire/tokens.json +export ACCESSIBLE=1 \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..bd67d49 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,56 @@ +# GitHub Copilot Repository Instructions: C++23 Modernization + +## Context +- Language: C++ +- Target standard: C++23 +- Goal: modernize legacy C++11/14/17 code safely and incrementally + +## Primary Rule +Preserve existing behavior unless functional changes are explicitly requested. + +## Balanced Modernization Policy +- Prefer modern C++23 constructs when they clearly improve safety, readability, or maintainability. +- Keep refactors focused and reviewable; avoid broad rewrites unless requested. +- Prefer standard library solutions over custom or legacy patterns. +- Respect toolchain limitations, ABI-sensitive interfaces, and repository-local style. + +## Preferred Modernizations +- Use `auto` where the type is obvious from the initializer; avoid it when it hides important type information. +- Prefer structured bindings over `std::tie` or manual pair/tuple access when clearer. +- Replace raw owning pointers and manual `delete` with RAII, usually `std::unique_ptr`. +- Use `std::make_unique` and `std::make_shared`; prefer `std::shared_ptr` only for real shared ownership. +- Use `std::string_view` for read-only string parameters only when lifetime safety is clear. +- Prefer `std::span` for non-owning contiguous ranges. +- Use `std::mdspan` only when multidimensional access is central and the change improves clarity or safety. +- Prefer `.contains()` over `find(...) != end()` where available and clearer. +- Prefer standard algorithms and ranges over manual loops when readability improves. +- Use `[[nodiscard]]` where ignoring the result is likely a bug. +- Prefer early returns over deeply nested control flow. +- Use `std::optional` monadic operations (`and_then`, `transform`, `or_else`) when they make the code simpler. +- Prefer `constexpr`, `if constexpr`, concepts, and `requires` over legacy `std::enable_if` / SFINAE where practical. +- Add `noexcept`, `override`, `final`, `= default`, and `= delete` where correct and useful. +- Prefer `enum class` over unscoped enums where practical. +- Prefer `std::print` / `std::println` for console output when supported by the project toolchain. +- Prefer typed `std::chrono` durations and `std::jthread` where appropriate. + +## Avoid +- Do not modernize mechanically if readability becomes worse. +- Do not introduce unsupported C++23 features. +- Do not introduce dangling references, dangling `std::string_view`, or unclear ownership. +- Do not silently change ABI, object lifetime, exception behavior, or performance characteristics. +- Do not rewrite unrelated code. + +## Expected Copilot Behavior +When making migration suggestions: +- produce small, focused updates +- explain non-trivial changes briefly +- call out risky refactors explicitly +- note compatibility or toolchain caveats +- leave optional follow-up improvements separate + +## Preferred Output +Provide: +- updated code +- short rationale +- compatibility/toolchain caveats +- optional next modernization steps diff --git a/.github/hooks/entire.json b/.github/hooks/entire.json new file mode 100644 index 0000000..19e54f3 --- /dev/null +++ b/.github/hooks/entire.json @@ -0,0 +1,61 @@ +{ + "hooks": { + "agentStop": [ + { + "type": "command", + "bash": "sh -c 'if ! command -v entire >/dev/null 2>&1; then exit 0; fi; exec entire hooks copilot-cli agent-stop'", + "comment": "Entire CLI" + } + ], + "errorOccurred": [ + { + "type": "command", + "bash": "sh -c 'if ! command -v entire >/dev/null 2>&1; then exit 0; fi; exec entire hooks copilot-cli error-occurred'", + "comment": "Entire CLI" + } + ], + "postToolUse": [ + { + "type": "command", + "bash": "sh -c 'if ! command -v entire >/dev/null 2>&1; then exit 0; fi; exec entire hooks copilot-cli post-tool-use'", + "comment": "Entire CLI" + } + ], + "preToolUse": [ + { + "type": "command", + "bash": "sh -c 'if ! command -v entire >/dev/null 2>&1; then exit 0; fi; exec entire hooks copilot-cli pre-tool-use'", + "comment": "Entire CLI" + } + ], + "sessionEnd": [ + { + "type": "command", + "bash": "sh -c 'if ! command -v entire >/dev/null 2>&1; then exit 0; fi; exec entire hooks copilot-cli session-end'", + "comment": "Entire CLI" + } + ], + "sessionStart": [ + { + "type": "command", + "bash": "sh -c 'if ! command -v entire >/dev/null 2>&1; then exit 0; fi; exec entire hooks copilot-cli session-start'", + "comment": "Entire CLI" + } + ], + "subagentStop": [ + { + "type": "command", + "bash": "sh -c 'if ! command -v entire >/dev/null 2>&1; then exit 0; fi; exec entire hooks copilot-cli subagent-stop'", + "comment": "Entire CLI" + } + ], + "userPromptSubmitted": [ + { + "type": "command", + "bash": "sh -c 'if ! command -v entire >/dev/null 2>&1; then exit 0; fi; exec entire hooks copilot-cli user-prompt-submitted'", + "comment": "Entire CLI" + } + ] + }, + "version": 1 +} diff --git a/.github/prompts/combined-migration-compact.prompt.md b/.github/prompts/combined-migration-compact.prompt.md new file mode 100644 index 0000000..cde7cce --- /dev/null +++ b/.github/prompts/combined-migration-compact.prompt.md @@ -0,0 +1,157 @@ +# GitHub Copilot Instructions: Qt5/C++11 to Qt6/C++23 Migration + +## Mission +Migrate the legacy Qt5/C++11 desktop application to Qt6/C++23, preserve behavior unless change is strictly required, and validate the result completely in the repository’s Docker-based CI workflow. + +## Operating Mode +- Work autonomously from analysis through validation. +- Do not stop after editing code. +- Continue until configure, build, tests, and policy checks have been attempted in Docker. +- Do not ask for confirmation during normal implementation. +- Stop early only if required source material is missing, the task is impossible, or a destructive action would be required. + +## Boundaries +- Read the legacy project from `${PROJECT_DIR}`. +- Write the migrated project to `qt6-after/qt6-migrated-benchmark`. +- Do not modify the legacy source tree in place. +- Limit changes to the target tree and only the CI/build/test files needed to support migration and validation. + +## Main Migration Targets +- Upgrade Qt5 to Qt6. +- Upgrade C++11/14/17 code to C++23. +- Keep Qt Core, Gui, and Widgets explicitly linked. +- Replace `QRegExp` with `QRegularExpression`. +- Replace `QDesktopWidget` and `QApplication::desktop()` with `QScreen`-based Qt6 APIs. +- Remove legacy `QTextCodec` usage and adopt Qt6-safe text handling. +- Replace old `SIGNAL`/`SLOT` syntax with function-pointer connect syntax. +- Replace `0`/`NULL` pointer literals with `nullptr`. +- Preserve `.ui` and `.qrc` integration. +- Preserve behavior unless Qt6 compatibility requires adaptation. + +## C++23 Modernization Rules +- Preserve semantics first; modernize second. +- Use `auto` when the type is obvious; avoid it when it hides important type information. +- Prefer structured bindings where clearer. +- Replace raw owning pointers/manual `delete` with RAII, usually `std::unique_ptr`. +- Use `std::make_unique` / `std::make_shared`; use `std::shared_ptr` only for real shared ownership. +- Use `std::string_view` only when lifetime safety is clear. +- Prefer `std::span` for non-owning contiguous data; use `std::mdspan` only when multidimensional access clearly benefits. +- Prefer `.contains()` over `find(...) != end()` where available. +- Prefer algorithms and ranges over manual loops when readability improves. +- Use `[[nodiscard]]` when ignoring a result is likely a bug. +- Prefer early returns over deeply nested control flow. +- Use `std::optional` monadic operations (`and_then`, `transform`, `or_else`) when clearer. +- Prefer `constexpr`, `if constexpr`, concepts, and `requires` over legacy `std::enable_if`/SFINAE where practical. +- Add `noexcept`, `override`, `final`, `= default`, and `= delete` where correct and useful. +- Prefer `enum class` over unscoped enums where practical. +- Prefer `std::print` / `std::println` when supported by the toolchain. +- Prefer typed `std::chrono` durations and `std::jthread` where appropriate. + +## Safety Rules +- Do not change business logic unless explicitly requested or required for Qt6 compatibility. +- Do not introduce unsupported Qt6/C++23 features. +- Do not silently change ABI, ownership, lifetime, exception behavior, performance, UI behavior, or event ordering. +- Do not worsen readability for the sake of modernization. +- Avoid dangling references, dangling `std::string_view`, and ownership ambiguity. +- Keep includes minimal and preserve repository-local formatting/style. + +## Tests +- For every code change inside a method, add at least three tests covering the changed behavior. +- Place generated tests in `qt6-after/qt6-migrated-benchmark/tests`. +- Use policy-compatible test filenames such as: + - `test_.cpp` + - `_test.cpp` + - `test.cpp` + - `gtest.cpp` +- Update CMake so the migrated app and all tests build and run with CTest. +- Ensure all tests are registered with CTest. + +## Docker-First Validation +Use `lifemaps/ci-cpp:latest` as the authoritative environment. Do not substitute host tools for missing container tools. Treat `ci/Dockerfile.ci` as the source of truth for CI dependencies. + +### Required validation sequence +1. Configure in Docker +2. Build in Docker +3. Run tests in Docker +4. If tests pass, run `python3 ci/check_pr_policies.py` in Docker + +### Recommended commands +- Configure: + `cmake -S qt6-after/qt6-migrated-benchmark -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug` +- Build: + `cmake --build build --parallel` +- Test: + `ctest --test-dir build --output-on-failure` +- Policy: + `python3 ci/check_pr_policies.py` + +Adapt paths/flags only if repository inspection proves they must differ. + +## Missing-Tool Remediation +If Docker validation fails because a required tool/package is missing: +- identify the exact missing dependency +- update `Dockerfile.ci` minimally +- rebuild `lifemaps/ci-cpp:latest` +- rerun the full validation sequence + +Continue until: +- validation succeeds, or +- the next blocker is a genuine project/code issue + +## Failure Classification +Environment failures: +- command not found +- missing compiler/toolchain utility +- missing Qt dev package +- missing CMake/Ninja/CTest support tool +- missing dependency required by `ci/check_pr_policies.py` + +Project failures: +- compile errors +- linker errors +- failing tests +- formatting/policy failures caused by migration changes + +## Policy Awareness +- `ci/check_pr_policies.py` checks formatting for changed C/C++ files, expects related tests, and verifies commit-signature conditions in its diff range. +- Ensure Docker validation runs with mounted workspace and git metadata available. +- Do not claim success unless the policy script passes. + +## Execution Plan +1. Inspect `${PROJECT_DIR}` and the target tree. +2. Identify Qt5 and legacy C++ constructs to migrate. +3. Migrate incrementally in `qt6-after/qt6-migrated-benchmark`. +4. Add/update tests with each behavior-relevant change. +5. Update CMake/test registration. +6. Validate in Docker. +7. If missing dependencies are found, update `Dockerfile.ci`, rebuild, and rerun. +8. Repeat until success or a real project defect remains. + +## Reporting +Group change explanations by: +- CMake / build-system migration +- Qt API replacements +- C++ modernization +- UI/resource preservation +- tests added +- `Dockerfile.ci` / container updates + +Also provide a concise changed-files summary. + +## Completion Criteria +Success requires: +- migrated project exists under `qt6-after/qt6-migrated-benchmark` +- configure succeeds in Docker +- build succeeds in Docker +- tests succeed in Docker +- `python3 ci/check_pr_policies.py` succeeds in Docker after tests pass + +## Final Response +- State whether migration is fully validated or which blocker remains. +- List the exact Docker commands used for image rebuild, configure, build, test, and policy check. +- For every failed attempt, include: + - exact command + - key error + - environment vs project classification + - fix applied +- End with a short summary of any remaining blocker. \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40d7bb8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.envrc +.*~ +*~ +build diff --git a/Jenkinsfile b/Jenkinsfile index 4516dad..1656542 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -16,6 +16,9 @@ pipeline { PROJECT_DIR = "qt6-after/qt6-migrated-benchmark" BUILD_DIR = "build" CHANGE_TARGET = "${env.CHANGE_TARGET ?: 'origin/main'}" + QT_QPA_PLATFORM = "offscreen" + LANG = "C.UTF-8" + LC_ALL = "C.UTF-8" } stages { @@ -41,6 +44,9 @@ pipeline { stage('Qt Diagnostics') { steps { sh ''' + echo "QT_QPA_PLATFORM=$QT_QPA_PLATFORM" + echo "LANG=$LANG" + echo "LC_ALL=$LC_ALL" dpkg -l | grep -E "qt6-base-dev|qtbase5-dev|qt6-tools" || true pkg-config --list-all | grep -i qt || true ''' @@ -67,7 +73,7 @@ pipeline { stage('Test') { steps { - sh 'ctest --test-dir ${BUILD_DIR} --output-on-failure' + sh 'QT_QPA_PLATFORM=offscreen LANG=C.UTF-8 LC_ALL=C.UTF-8 ctest --test-dir ${BUILD_DIR} --output-on-failure' } } } diff --git a/ci/Dockerfile.ci b/ci/Dockerfile.ci index b06efd7..07023e5 100644 --- a/ci/Dockerfile.ci +++ b/ci/Dockerfile.ci @@ -21,4 +21,10 @@ RUN apt-get update && \ qt6-tools-dev-tools && \ rm -rf /var/lib/apt/lists/* +# Set Qt platform for headless testing +ENV QT_QPA_PLATFORM=offscreen + +# Configure git for containerized environments +RUN git config --global --add safe.directory "*" + WORKDIR /workspace diff --git a/ci/allowed_signers b/ci/allowed_signers index 2087f6a..70a3176 100644 --- a/ci/allowed_signers +++ b/ci/allowed_signers @@ -1 +1,2 @@ -torsten.wierschin@life-maps.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG+sdfrCTkAHvZCwBGPGUaT4VFkX8YvnqprCpCrLajSH +torsten.wierschin@life-maps.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO+c+9jJKrLpTk4pLg+p1Qo0CjCYzfKfEhXEu0MAlZpj +nkana@outlook.de ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBR68AzU7UtY+NJPIRloEeIlQIZIP3xhvkWB8BediMeQ diff --git a/ci/check_pr_policies.py b/ci/check_pr_policies.py index 6f3538f..a89e27a 100644 --- a/ci/check_pr_policies.py +++ b/ci/check_pr_policies.py @@ -209,4 +209,13 @@ def main(): if not has_related_test(path): print( "ERROR: Kein passender Test unter tests/, test/ oder " - f + "qt6-after/qt6-migrated-benchmark/tests/ gefunden für: " + f"{rel}" + ) + sys.exit(1) + + print("PR-Policy-Prüfungen erfolgreich.") + + +if __name__ == "__main__": + main() diff --git a/ci/README.md b/docs/developer-push-policy.md similarity index 90% rename from ci/README.md rename to docs/developer-push-policy.md index 77d230b..1b3089f 100644 --- a/ci/README.md +++ b/docs/developer-push-policy.md @@ -196,11 +196,39 @@ clang-format -i main.cpp tests/test_main.cpp python3 ci/check_pr_policies.py ``` -### Projekt lokal bauen +## Projekt lokal im CI-Container bauen + +Zuerst das lokale CI-Image bauen: + ```bash -cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -cmake --build build --parallel -ctest --test-dir build --output-on-failure +docker build -t lifemaps/ci-cpp:latest -f Dockerfile.ci . +``` + +Danach das Projekt im Container bauen und testen: + +```bash +docker run --rm -it \ + -v "$PWD:/workspace" \ + -w /workspace \ + lifemaps/ci-cpp:latest \ + bash -lc ' + cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug && + cmake --build build --parallel && + ctest --test-dir build --output-on-failure + ' +``` + +Damit wird dieselbe Toolchain verwendet wie in der Jenkins-CI. + + +## Policy-Check lokal im CI-Container ausführen + +```bash +docker run --rm -it \ + -v "$PWD:/workspace" \ + -w /workspace \ + lifemaps/ci-cpp:latest \ + bash -lc 'python3 ci/check_pr_policies.py' ``` --- diff --git a/docs/entire-headless-in-eu-setup.md b/docs/entire-headless-in-eu-setup.md new file mode 100644 index 0000000..39f3445 --- /dev/null +++ b/docs/entire-headless-in-eu-setup.md @@ -0,0 +1,336 @@ +# Entire auf Headless-Server mit EU-Kontext einrichten + +Diese Anleitung beschreibt die Einrichtung von Entire auf einem Headless-Host mit bestehendem Git-Repository auf einem eigenen Gitea-Server und Nutzung des **EU-Kontexts**. + +## Ziel + +- Entire ohne GUI/Browser auf dem Server verwenden +- Login über Device-Code-Flow +- Tokens ohne OS-Keyring in Datei speichern +- EU-Jurisdiktion / EU-Cluster verwenden +- Entire lokal in einem bestehenden Git-Repository aktivieren + +--- + +## Voraussetzungen + +- `entire` CLI ist installiert +- Zugriff per SSH auf den Headless-Server +- funktionierendes lokales Git-Checkout +- `origin`-Remote ist gesetzt +- Browser auf einem **anderen lokalen Rechner** verfügbar + +Beispiel prüfen: + +```bash +git remote -v +``` + +Beispielausgabe: + +```bash +origin git@devel:lifemaps/qt-migration-copilot-demo.git (fetch) +origin git@devel:lifemaps/qt-migration-copilot-demo.git (push) +``` + +--- + +## 1. Token-Speicherung für Headless-Betrieb aktivieren + +Auf Headless-Systemen gibt es oft keinen Linux-Keyring (`org.freedesktop.secrets`). +Deshalb sollten Entire-Tokens in einer Datei gespeichert werden. + +Empfohlene Umgebungsvariablen: + +```bash +export ENTIRE_TOKEN_STORE=file +export ENTIRE_TOKEN_STORE_PATH="$HOME/.config/entire/tokens.json" +export ACCESSIBLE=1 +``` + +Temporär in der aktuellen Shell: + +```bash +export ENTIRE_TOKEN_STORE=file +export ENTIRE_TOKEN_STORE_PATH="$HOME/.config/entire/tokens.json" +export ACCESSIBLE=1 +``` + +Dauerhaft in `~/.bashrc`: + +```bash +echo 'export ENTIRE_TOKEN_STORE=file' >> ~/.bashrc +echo 'export ENTIRE_TOKEN_STORE_PATH="$HOME/.config/entire/tokens.json"' >> ~/.bashrc +echo 'export ACCESSIBLE=1' >> ~/.bashrc +source ~/.bashrc +``` + +--- + +## 2. Im EU-Kontext anmelden + +Für Headless-Systeme den Device-Code-Flow verwenden: + +```bash +entire login --device --server https://eu.auth.entire.io +``` + +Das CLI zeigt dann etwa: + +- einen **Device Code** +- eine **Login-URL** + +Die URL im Browser **auf dem lokalen Rechner** öffnen und die Anmeldung dort bestätigen. + +### Wichtiger Hinweis + +Wenn auf dem Server kein Browser verfügbar ist, ist eine Meldung wie diese normal: + +```text +Warning: failed to open browser: xdg-open not found +``` + +Das ist **nicht** das eigentliche Problem. + +Falls Entire versucht, Tokens im Keyring zu speichern und dabei fehlschlägt, war `ENTIRE_TOKEN_STORE=file` nicht gesetzt. + +--- + +## 3. Login prüfen + +Nach erfolgreicher Anmeldung: + +```bash +entire auth status +``` + +Beispiel: + +```text +Logged in to https://eu.auth.entire.io +Context: eu.auth.entire.io +Token: stored in file /home//.config/entire/tokens.json +``` + +Falls mehrere Kontexte existieren: + +```bash +entire auth contexts +entire auth use --help +``` + +--- + +## 4. Prüfen, ob wirklich EU verwendet wird + +Zusätzlich zum Login-Kontext sollte geprüft werden, auf welchem Cluster die Entire-Repositories liegen. + +Projekt-Repositories anzeigen: + +```bash +entire repo list +``` + +Wenn in der Spalte `CLUSTER` z. B. Folgendes erscheint: + +```text +aws-eu-central-1.entire.io +``` + +dann liegen diese Repositories auf einem **EU-Cluster**. + +### Empfohlener Doppel-Check + +```bash +entire auth status +entire repo list +``` + +EU ist praktisch bestätigt, wenn: + +- `Context: eu.auth.entire.io` aktiv ist +- die Repositories auf `aws-eu-central-1.entire.io` liegen + +--- + +## 5. Entire im lokalen Repository aktivieren + +In das lokale Repository wechseln: + +```bash +cd ~/coplint.d/qt-migration-copilot-demo +``` + +Dann Entire aktivieren: + +```bash +entire enable +``` + +Status prüfen: + +```bash +entire status +``` + +Beispiel: + +```text +● Enabled · branch bugfix/ci-pipeline-commissioning + Agents · Copilot CLI +``` + +--- + +## 6. Agent-Integration prüfen oder ergänzen + +Verfügbare Agenten anzeigen: + +```bash +entire agent list +``` + +Hilfe für das Hinzufügen: + +```bash +entire agent add --help +``` + +Neuen Agenten hinzufügen: + +```bash +entire agent add +``` + +Danach erneut prüfen: + +```bash +entire status +``` + +--- + +## 7. Unterschied zwischen lokalem Git-Repo und Entire-Repo verstehen + +Wichtig: Entire verwendet hier **zwei verschiedene Konzepte**. + +### Lokales Git-Repository +Das echte Code-Repository, z. B.: + +```bash +git@devel:lifemaps/qt-migration-copilot-demo.git +``` + +### Entire-Repository +Ein separates Objekt in Entire, verwaltet über: + +```bash +entire repo list +entire repo get --project +entire repo create --project +``` + +### Konsequenz + +`entire enable` aktiviert das **lokale Git-Repository**, +aber es erzeugt **nicht automatisch** ein neues `entire repo`-Objekt. + +Darum kann es sein, dass: + +- `entire status` = aktiviert +- aber `entire repo list ` dein lokales Repo **nicht** zeigt + +Das ist normales Verhalten. + +--- + +## 8. Optional: Entire-Repo im Projekt anlegen + +Wenn zusätzlich ein eigenes Entire-Repo-Objekt für das lokale Projekt gewünscht ist: + +```bash +entire repo create qt-migration-copilot-demo --project +``` + +Danach prüfen: + +```bash +entire repo list +``` + +### Hinweis + +Nach bisherigem CLI-Verhalten wird dabei nur ein **Entire-internes Repo-Objekt** erzeugt. +Es gibt in der gezeigten Hilfe keinen Hinweis darauf, dass dabei automatisch eine Git-URL aus Gitea importiert oder synchronisiert wird. + +--- + +## 9. Typischer Minimal-Workflow + +```bash +export ENTIRE_TOKEN_STORE=file +export ENTIRE_TOKEN_STORE_PATH="$HOME/.config/entire/tokens.json" +export ACCESSIBLE=1 + +entire login --device --server https://eu.auth.entire.io +entire auth status + +cd ~/coplint.d/qt-migration-copilot-demo +entire enable +entire status +entire agent list +``` + +--- + +## 10. Troubleshooting + +### Kein Browser auf dem Server +Normal auf Headless-Hosts. +Device-Code-URL auf lokalem Rechner öffnen. + +### Login erfolgreich, aber `Not logged in` +Ursache meist fehlender Keyring und keine Datei-Speicherung. + +Lösung: + +```bash +export ENTIRE_TOKEN_STORE=file +entire login --device --server https://eu.auth.entire.io +``` + +### Entire ist aktiviert, aber nicht in `entire repo list` +Das ist erwartbar, weil lokales Git-Repo und Entire-Projektrepo getrennte Objekte sind. + +### Diagnose +Bei Problemen: + +```bash +entire doctor +``` + +--- + +## 11. Empfehlung für dieses Setup + +Für ein Setup mit **Gitea + Jenkins + Entire** gilt: + +- **Gitea** bleibt Source-of-Truth für den Code +- **Jenkins** bleibt CI/CD-System +- **Entire** ergänzt Session-, Agent- und Checkpoint-Tracking im lokalen Repository +- **Entire-Projekte/Repos** sind zusätzliche Verwaltungsobjekte und nicht identisch mit dem Gitea-Remote + +--- + +## 12. Nützliche Befehle + +```bash +entire auth status +entire auth contexts +entire project list +entire repo list +entire enable +entire status +entire agent list +entire doctor +``` \ No newline at end of file diff --git a/scripts/README.md b/docs/scripts-usage.md similarity index 100% rename from scripts/README.md rename to docs/scripts-usage.md diff --git a/README-scaleway.md b/docs/use-scaleway-with-copilot-cli.md similarity index 100% rename from README-scaleway.md rename to docs/use-scaleway-with-copilot-cli.md diff --git a/qt6-after/qt6-migrated-benchmark/CMakeLists.txt b/qt6-after/qt6-migrated-benchmark/CMakeLists.txt new file mode 100644 index 0000000..8267920 --- /dev/null +++ b/qt6-after/qt6-migrated-benchmark/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.16) + +project(Qt6MigratedBenchmark LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets) + +qt_standard_project_setup(REQUIRES 6.5) + +add_executable(Qt6MigratedBenchmark + main.cpp + MainWindow.h + MainWindow.cpp + MainWindow.ui + resources.qrc +) + +target_link_libraries(Qt6MigratedBenchmark PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Widgets +) + +target_compile_features(Qt6MigratedBenchmark PRIVATE cxx_std_23) + +# Enable warnings +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(Qt6MigratedBenchmark PRIVATE -Wall -Wextra -pedantic) +endif() + +# Add tests +enable_testing() +add_subdirectory(tests) \ No newline at end of file diff --git a/qt6-after/qt6-migrated-benchmark/MainWindow.cpp b/qt6-after/qt6-migrated-benchmark/MainWindow.cpp new file mode 100644 index 0000000..1bd6d0c --- /dev/null +++ b/qt6-after/qt6-migrated-benchmark/MainWindow.cpp @@ -0,0 +1,55 @@ +#include "MainWindow.h" + +#include "ui_MainWindow.h" + +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget* parent) + : QMainWindow(parent), ui(new Ui::MainWindow), pattern(QRegularExpression(R"(^[A-Za-z]+\d+$)")) +{ + ui->setupUi(this); + + // Qt6 uses UTF-8 by default; no codec needed + setWindowTitle(QString::fromUtf8("Qt6 Migrated Benchmark")); + ui->label->setText(QString::fromUtf8("Bitte Text wie Test123 eingeben.")); + ui->iconLabel->setPixmap(QPixmap(":/icons/app.png").scaled(48, 48)); + + // Modern function-pointer connect syntax + connect(ui->validateButton, &QPushButton::clicked, this, &MainWindow::onValidateClicked); + connect(ui->screenButton, &QPushButton::clicked, this, &MainWindow::onScreenInfoClicked); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::onValidateClicked() +{ + const QString text = ui->lineEdit->text(); + + if (pattern.match(text).hasMatch()) + { + ui->resultLabel->setText(QString::fromUtf8("Match")); + } + else + { + ui->resultLabel->setText(QString::fromUtf8("No match")); + } +} + +void MainWindow::onScreenInfoClicked() +{ + // Qt6: Use QScreen instead of deprecated QDesktopWidget + const QScreen* screen = QApplication::primaryScreen(); + if (screen) + { + const QRect screenGeometry = screen->geometry(); + const QString info = + QString::fromUtf8("Screen: %1x%2").arg(screenGeometry.width()).arg(screenGeometry.height()); + ui->resultLabel->setText(info); + } +} \ No newline at end of file diff --git a/qt6-after/qt6-migrated-benchmark/MainWindow.h b/qt6-after/qt6-migrated-benchmark/MainWindow.h new file mode 100644 index 0000000..a1bb6fb --- /dev/null +++ b/qt6-after/qt6-migrated-benchmark/MainWindow.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Ui +{ +class MainWindow; +} + +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + + public: + explicit MainWindow(QWidget* parent = nullptr); + ~MainWindow() override; + + private slots: + void onValidateClicked(); + void onScreenInfoClicked(); + + private: + Ui::MainWindow* ui; + QRegularExpression pattern; +}; \ No newline at end of file diff --git a/qt6-after/qt6-migrated-benchmark/MainWindow.ui b/qt6-after/qt6-migrated-benchmark/MainWindow.ui new file mode 100644 index 0000000..75c99ee --- /dev/null +++ b/qt6-after/qt6-migrated-benchmark/MainWindow.ui @@ -0,0 +1,69 @@ + + + MainWindow + + + + 0 + 0 + 420 + 240 + + + + Qt5 Legacy App + + + + + + + Initial text + + + + + + + Enter value like Test123 + + + + + + + + + + + + + + + + Validate + + + + + + + Screen Info + + + + + + + + + Result appears here + + + + + + + + + diff --git a/qt6-after/qt6-migrated-benchmark/app.png b/qt6-after/qt6-migrated-benchmark/app.png new file mode 100644 index 0000000..91af3b9 Binary files /dev/null and b/qt6-after/qt6-migrated-benchmark/app.png differ diff --git a/qt6-after/qt6-migrated-benchmark/main.cpp b/qt6-after/qt6-migrated-benchmark/main.cpp new file mode 100644 index 0000000..c53542b --- /dev/null +++ b/qt6-after/qt6-migrated-benchmark/main.cpp @@ -0,0 +1,19 @@ +#include "MainWindow.h" + +#include +#include + +#if __has_include() +#include +#endif + +[[nodiscard]] auto main(int argc, char* argv[]) -> int +{ + QApplication app{argc, argv}; + + // Qt6 uses UTF-8 by default; no codec setup needed + MainWindow window; + window.show(); + + return app.exec(); +} \ No newline at end of file diff --git a/qt6-after/qt6-migrated-benchmark/resources.qrc b/qt6-after/qt6-migrated-benchmark/resources.qrc new file mode 100644 index 0000000..05f5322 --- /dev/null +++ b/qt6-after/qt6-migrated-benchmark/resources.qrc @@ -0,0 +1,5 @@ + + + app.png + + diff --git a/qt6-after/qt6-migrated-benchmark/tests/CMakeLists.txt b/qt6-after/qt6-migrated-benchmark/tests/CMakeLists.txt new file mode 100644 index 0000000..a399937 --- /dev/null +++ b/qt6-after/qt6-migrated-benchmark/tests/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.16) +project(Qt6MigratedBenchmarkTests LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Test) + +add_executable(main_test + main_test.cpp +) + +target_link_libraries(main_test PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Widgets + Qt6::Test +) + +add_test(NAME main_test COMMAND main_test) + +add_executable(MainWindow_test + MainWindow_test.cpp +) + +target_link_libraries(MainWindow_test PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Widgets + Qt6::Test +) + +add_test(NAME MainWindow_test COMMAND MainWindow_test) \ No newline at end of file diff --git a/qt6-after/qt6-migrated-benchmark/tests/MainWindow_test.cpp b/qt6-after/qt6-migrated-benchmark/tests/MainWindow_test.cpp new file mode 100644 index 0000000..b9c5d4a --- /dev/null +++ b/qt6-after/qt6-migrated-benchmark/tests/MainWindow_test.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include + +class MainWindowPatternTest : public QObject +{ + Q_OBJECT + + private slots: + void testPatternValidLettersThenDigits(); + void testPatternInvalidDigitsThenLetters(); + void testPatternInvalidSpecialCharacters(); + void testScreenGeometryExtraction(); + void testRegularExpressionContainsMethod(); +}; + +void MainWindowPatternTest::testPatternValidLettersThenDigits() +{ + QRegularExpression pattern(R"(^[A-Za-z]+\d+$)"); + + QVERIFY(pattern.match(QString::fromUtf8("Test123")).hasMatch()); + QVERIFY(pattern.match(QString::fromUtf8("ABC456")).hasMatch()); + QVERIFY(pattern.match(QString::fromUtf8("a1")).hasMatch()); +} + +void MainWindowPatternTest::testPatternInvalidDigitsThenLetters() +{ + QRegularExpression pattern(R"(^[A-Za-z]+\d+$)"); + + QVERIFY(!pattern.match(QString::fromUtf8("123Test")).hasMatch()); + QVERIFY(!pattern.match(QString::fromUtf8("1a")).hasMatch()); +} + +void MainWindowPatternTest::testPatternInvalidSpecialCharacters() +{ + QRegularExpression pattern(R"(^[A-Za-z]+\d+$)"); + + QVERIFY(!pattern.match(QString::fromUtf8("Test@123")).hasMatch()); + QVERIFY(!pattern.match(QString::fromUtf8("Test_123")).hasMatch()); + QVERIFY(!pattern.match(QString::fromUtf8("")).hasMatch()); +} + +void MainWindowPatternTest::testScreenGeometryExtraction() +{ + const QScreen* screen = QGuiApplication::primaryScreen(); + if (screen) + { + const QRect geometry = screen->geometry(); + QVERIFY(geometry.width() > 0); + QVERIFY(geometry.height() > 0); + + const QString info = QString::fromUtf8("Screen: %1x%2").arg(geometry.width()).arg(geometry.height()); + QVERIFY(!info.isEmpty()); + QVERIFY(info.contains(QString::fromUtf8("Screen:"))); + } +} + +void MainWindowPatternTest::testRegularExpressionContainsMethod() +{ + QRegularExpression pattern(R"(^[A-Za-z]+\d+$)"); + + const QString validInput = QString::fromUtf8("Test123"); + const QRegularExpressionMatch match = pattern.match(validInput); + QVERIFY(match.hasMatch()); + + const QString invalidInput = QString::fromUtf8("Invalid"); + const QRegularExpressionMatch noMatch = pattern.match(invalidInput); + QVERIFY(!noMatch.hasMatch()); +} + +QTEST_MAIN(MainWindowPatternTest) + +#include "MainWindow_test.moc" \ No newline at end of file diff --git a/qt6-after/qt6-migrated-benchmark/tests/main_test.cpp b/qt6-after/qt6-migrated-benchmark/tests/main_test.cpp new file mode 100644 index 0000000..f2a0467 --- /dev/null +++ b/qt6-after/qt6-migrated-benchmark/tests/main_test.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +class MainTest : public QObject +{ + Q_OBJECT + + private slots: + void testRegularExpressionValidation_data(); + void testRegularExpressionValidation(); + void testQStringUtf8Conversion(); + void testRegularExpressionPattern(); +}; + +void MainTest::testRegularExpressionValidation_data() +{ + QTest::addColumn("input"); + QTest::addColumn("expectedMatch"); + + QTest::newRow("valid_input_Test123") << QString::fromUtf8("Test123") << true; + QTest::newRow("valid_input_ABC456") << QString::fromUtf8("ABC456") << true; + QTest::newRow("valid_input_a1") << QString::fromUtf8("a1") << true; + QTest::newRow("invalid_input_123Test") << QString::fromUtf8("123Test") << false; + QTest::newRow("invalid_input_special") << QString::fromUtf8("Test@123") << false; + QTest::newRow("invalid_input_empty") << QString::fromUtf8("") << false; +} + +void MainTest::testRegularExpressionValidation() +{ + QFETCH(QString, input); + QFETCH(bool, expectedMatch); + + QRegularExpression pattern(R"(^[A-Za-z]+\d+$)"); + const bool matches = pattern.match(input).hasMatch(); + + QCOMPARE(matches, expectedMatch); +} + +void MainTest::testQStringUtf8Conversion() +{ + const QString title = QString::fromUtf8("Qt6 Migrated Benchmark"); + QCOMPARE(title, QString::fromUtf8("Qt6 Migrated Benchmark")); + + const QString label = QString::fromUtf8("Bitte Text wie Test123 eingeben."); + QCOMPARE(label, QString::fromUtf8("Bitte Text wie Test123 eingeben.")); +} + +void MainTest::testRegularExpressionPattern() +{ + QRegularExpression pattern(R"(^[A-Za-z]+\d+$)"); + QVERIFY(pattern.isValid()); + + const QRegularExpressionMatch match = pattern.match(QString::fromUtf8("Test123")); + QVERIFY(match.hasMatch()); + + const QRegularExpressionMatch noMatch = pattern.match(QString::fromUtf8("123Test")); + QVERIFY(!noMatch.hasMatch()); +} + +QTEST_MAIN(MainTest) + +#include "main_test.moc" \ No newline at end of file diff --git a/scripts/combined-migration-compact.prompt b/scripts/combined-migration-compact.prompt new file mode 100644 index 0000000..031c9ff --- /dev/null +++ b/scripts/combined-migration-compact.prompt @@ -0,0 +1,157 @@ +# GitHub Copilot Instructions: Qt5/C++11 to Qt6/C++23 Migration + +## Mission +Migrate the legacy Qt5/C++11 desktop application to Qt6/C++23, preserve behavior unless change is strictly required, and validate the result completely in the repository’s Docker-based CI workflow. + +## Operating Mode +- Work autonomously from analysis through validation. +- Do not stop after editing code. +- Continue until configure, build, tests, and policy checks have been attempted in Docker. +- Do not ask for confirmation during normal implementation. +- Stop early only if required source material is missing, the task is impossible, or a destructive action would be required. + +## Boundaries +- Read the legacy project from `${PROJECT_DIR}`. +- Write the migrated project to `qt6-after/qt6-migrated-benchmark`. +- Do not modify the legacy source tree in place. +- Limit changes to the target tree and only the CI/build/test files needed to support migration and validation. + +## Main Migration Targets +- Upgrade Qt5 to Qt6. +- Upgrade C++11/14/17 code to C++23. +- Keep Qt Core, Gui, and Widgets explicitly linked. +- Replace `QRegExp` with `QRegularExpression`. +- Replace `QDesktopWidget` and `QApplication::desktop()` with `QScreen`-based Qt6 APIs. +- Remove legacy `QTextCodec` usage and adopt Qt6-safe text handling. +- Replace old `SIGNAL`/`SLOT` syntax with function-pointer connect syntax. +- Replace `0`/`NULL` pointer literals with `nullptr`. +- Preserve `.ui` and `.qrc` integration. +- Preserve behavior unless Qt6 compatibility requires adaptation. + +## C++23 Modernization Rules +- Preserve semantics first; modernize second. +- Use `auto` when the type is obvious; avoid it when it hides important type information. +- Prefer structured bindings where clearer. +- Replace raw owning pointers/manual `delete` with RAII, usually `std::unique_ptr`. +- Use `std::make_unique` / `std::make_shared`; use `std::shared_ptr` only for real shared ownership. +- Use `std::string_view` only when lifetime safety is clear. +- Prefer `std::span` for non-owning contiguous data; use `std::mdspan` only when multidimensional access clearly benefits. +- Prefer `.contains()` over `find(...) != end()` where available. +- Prefer algorithms and ranges over manual loops when readability improves. +- Use `[[nodiscard]]` when ignoring a result is likely a bug. +- Prefer early returns over deeply nested control flow. +- Use `std::optional` monadic operations (`and_then`, `transform`, `or_else`) when clearer. +- Prefer `constexpr`, `if constexpr`, concepts, and `requires` over legacy `std::enable_if`/SFINAE where practical. +- Add `noexcept`, `override`, `final`, `= default`, and `= delete` where correct and useful. +- Prefer `enum class` over unscoped enums where practical. +- Prefer `std::print` / `std::println` when supported by the toolchain. +- Prefer typed `std::chrono` durations and `std::jthread` where appropriate. + +## Safety Rules +- Do not change business logic unless explicitly requested or required for Qt6 compatibility. +- Do not introduce unsupported Qt6/C++23 features. +- Do not silently change ABI, ownership, lifetime, exception behavior, performance, UI behavior, or event ordering. +- Do not worsen readability for the sake of modernization. +- Avoid dangling references, dangling `std::string_view`, and ownership ambiguity. +- Keep includes minimal and preserve repository-local formatting/style. + +## Tests +- For every code change inside a method, add at least three tests covering the changed behavior. +- Place generated tests in `qt6-after/qt6-migrated-benchmark/tests`. +- Use policy-compatible test filenames such as: + - `test_.cpp` + - `_test.cpp` + - `test.cpp` + - `gtest.cpp` +- Update CMake so the migrated app and all tests build and run with CTest. +- Ensure all tests are registered with CTest. + +## Docker-First Validation +Use `lifemaps/ci-cpp:latest` as the authoritative environment. Do not substitute host tools for missing container tools. Treat `Dockerfile.ci` as the source of truth for CI dependencies. + +### Required validation sequence +1. Configure in Docker +2. Build in Docker +3. Run tests in Docker +4. If tests pass, run `python3 ci/check_pr_policies.py` in Docker + +### Recommended commands +- Configure: + `cmake -S qt6-after/qt6-migrated-benchmark -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug` +- Build: + `cmake --build build --parallel` +- Test: + `ctest --test-dir build --output-on-failure` +- Policy: + `python3 ci/check_pr_policies.py` + +Adapt paths/flags only if repository inspection proves they must differ. + +## Missing-Tool Remediation +If Docker validation fails because a required tool/package is missing: +- identify the exact missing dependency +- update `Dockerfile.ci` minimally +- rebuild `lifemaps/ci-cpp:latest` +- rerun the full validation sequence + +Continue until: +- validation succeeds, or +- the next blocker is a genuine project/code issue + +## Failure Classification +Environment failures: +- command not found +- missing compiler/toolchain utility +- missing Qt dev package +- missing CMake/Ninja/CTest support tool +- missing dependency required by `ci/check_pr_policies.py` + +Project failures: +- compile errors +- linker errors +- failing tests +- formatting/policy failures caused by migration changes + +## Policy Awareness +- `ci/check_pr_policies.py` checks formatting for changed C/C++ files, expects related tests, and verifies commit-signature conditions in its diff range. +- Ensure Docker validation runs with mounted workspace and git metadata available. +- Do not claim success unless the policy script passes. + +## Execution Plan +1. Inspect `${PROJECT_DIR}` and the target tree. +2. Identify Qt5 and legacy C++ constructs to migrate. +3. Migrate incrementally in `qt6-after/qt6-migrated-benchmark`. +4. Add/update tests with each behavior-relevant change. +5. Update CMake/test registration. +6. Validate in Docker. +7. If missing dependencies are found, update `Dockerfile.ci`, rebuild, and rerun. +8. Repeat until success or a real project defect remains. + +## Reporting +Group change explanations by: +- CMake / build-system migration +- Qt API replacements +- C++ modernization +- UI/resource preservation +- tests added +- `Dockerfile.ci` / container updates + +Also provide a concise changed-files summary. + +## Completion Criteria +Success requires: +- migrated project exists under `qt6-after/qt6-migrated-benchmark` +- configure succeeds in Docker +- build succeeds in Docker +- tests succeed in Docker +- `python3 ci/check_pr_policies.py` succeeds in Docker after tests pass + +## Final Response +- State whether migration is fully validated or which blocker remains. +- List the exact Docker commands used for image rebuild, configure, build, test, and policy check. +- For every failed attempt, include: + - exact command + - key error + - environment vs project classification + - fix applied +- End with a short summary of any remaining blocker. \ No newline at end of file diff --git a/scripts/migration-cpp23.prompt b/scripts/migration-cpp23.prompt new file mode 100644 index 0000000..051d94a --- /dev/null +++ b/scripts/migration-cpp23.prompt @@ -0,0 +1,119 @@ +# GitHub Copilot Repository Instructions: C++ Modernization + +## Project Context +- **Language:** C++ +- **Target Standard:** C++23 (Strict enforcement) +- **Migration Goal:** Systematically upgrade legacy C++11/C++14/C++17 code to modern C++23 paradigms. + +## Core Objective +Modernize the codebase incrementally and safely. Preserve existing behavior unless the task explicitly requests functional changes. Prefer small, reviewable refactors that improve correctness, safety, readability, and maintainability. + +## Global Migration Principles +- Preserve semantics first; modernize second. +- Prefer standard C++23 library facilities over custom utilities where equivalent. +- Favor compile-time validation, explicit ownership, and strong type safety. +- Reduce boilerplate only when readability improves. +- Avoid unnecessary churn in code that is already modern and clear. +- Keep ABI-sensitive or externally exposed interfaces stable unless breaking changes are explicitly allowed. +- For larger migrations, refactor file-by-file or subsystem-by-subsystem. + +## Migration Rules + +### 1. Type Inference & Variables +- Replace explicit types with `auto` where the type is obvious from the initializer. +- Do not use `auto` when it obscures important type information or changes value/reference semantics unintentionally. +- Prefer `const auto` and `const auto&` where appropriate. +- Use structured bindings (`auto [x, y] = ...`) instead of `std::tie`, `.first/.second`, or tuple indexing where it improves clarity. +- Prefer uniform initialization where appropriate. + +### 2. Memory & Resource Management +- Replace raw owning pointers and manual `delete` with `std::unique_ptr` or `std::shared_ptr`. +- Prefer `std::unique_ptr` by default; use `std::shared_ptr` only for true shared ownership. +- Use `std::make_unique` and `std::make_shared`. +- Enforce RAII for all resource management. +- Replace manual lifetime management with scoped objects where possible. +- Distinguish clearly between owning and non-owning access; prefer references, `std::span`, or observer-style usage for non-owning views. + +### 3. Containers, Views & Strings +- Use `std::string_view` for read-only string parameters where lifetime safety is guaranteed. +- Never introduce dangling `std::string_view`. +- Replace `if (items.find(key) != items.end())` with `if (items.contains(key))` where supported. +- Prefer `.starts_with()`, `.ends_with()`, and `.contains()` when they improve readability. +- Prefer `std::span` for non-owning contiguous views. +- Use `std::mdspan` for multidimensional indexing only where it meaningfully improves safety or clarity. +- Prefer standard algorithms and ranges over manual loops when they improve readability and maintainability. +- Avoid unnecessary copies; prefer move semantics, `emplace`, and views where safe. + +### 4. Control Flow & Error Handling +- Prefer early returns over deep nesting. +- Use `[[nodiscard]]` for functions whose return values should not be ignored. +- Modernize `std::optional` usage with `.and_then()`, `.transform()`, and `.or_else()` where this makes the logic clearer. +- Replace sentinel values with `std::optional`, strong types, or `std::expected` if supported by the project/toolchain. +- Preserve existing exception guarantees and error behavior unless changes are explicitly requested. + +### 5. Formatting & Output +- Replace `printf` and legacy `` console output with `` where toolchain support exists. +- Use `std::print` and `std::println` for standard console output. +- If `` is unavailable in the project toolchain, note the limitation and prefer the most modern supported alternative. +- Do not mix output styles in the same updated code path without a strong reason. + +### 6. Compile-Time Optimization & Templates +- Maximize appropriate use of `constexpr`. +- Use `consteval` and `constinit` where semantically beneficial. +- Replace legacy SFINAE / `std::enable_if` with Concepts and `requires` clauses. +- Use `if constexpr` to simplify compile-time branching. +- Prefer readable template constraints and diagnostics over complex metaprogramming. + +### 7. API & Interface Modernization +- Add `noexcept` where correct and useful. +- Use `override` consistently for overridden virtual functions. +- Use `final` where appropriate. +- Prefer `= default` and `= delete` for special member functions. +- Prefer `enum class` over unscoped enums where practical. +- Replace output parameters with return values or small result structs where this improves clarity and does not break required interfaces. + +### 8. Concurrency & Time +- Prefer modern standard library concurrency primitives. +- Use `std::jthread` instead of `std::thread` where automatic joining and cancellation semantics are beneficial. +- Prefer typed `std::chrono` durations and literals over raw integer time values. + +## Code Style Enforcement +- Avoid C-style macros where `constexpr`, `const`, enums, or inline functions are better. +- Never introduce deprecated or removed standard library facilities. +- Prefer expressive, self-documenting code over mechanical modernization. +- Keep includes minimal and correct. +- Avoid hidden lifetime bugs, dangling references, dangling views, and ownership ambiguity. +- Preserve repository formatting and local style conventions unless explicitly changing them. + +## Safety Constraints +- Do not change business logic unless explicitly requested. +- Do not silently alter ownership semantics without calling it out. +- Do not replace code with newer constructs if the result is harder to read. +- Do not introduce C++23 features that are unsupported by the project compiler/toolchain. +- Highlight any modernization that may affect ABI, performance, exception behavior, or object lifetime. + +## Review Checklist +For each proposed migration, verify: +- Behavior is preserved. +- Ownership and lifetime are clearer and safer. +- Readability is improved. +- Interface compatibility is maintained unless breaking changes are allowed. +- C++23 features are applied only where beneficial. +- Toolchain compatibility is respected. +- Tests and warnings should still pass after the change. + +## Expected Copilot Behavior +When modernizing code: +1. Start from the existing implementation and refactor incrementally. +2. Prefer minimal, reviewable patches over broad rewrites. +3. Briefly explain non-trivial modernizations. +4. Call out risky or behavior-adjacent changes explicitly. +5. Provide optional follow-up refactors separately when they are useful but non-essential. +6. Avoid touching unrelated code. + +## Preferred Output Format +For each migration task, provide: +- the modernized code, +- a short rationale, +- any compatibility/toolchain caveats, +- and optional next-step improvements.tes diff --git a/scripts/migration.prompt b/scripts/migration.prompt new file mode 100644 index 0000000..7c06c3e --- /dev/null +++ b/scripts/migration.prompt @@ -0,0 +1,152 @@ +Migrate the legacy Qt5/C++11 desktop application to Qt6/C++23 and validate the migration completely using the repository’s Docker-based CI workflow. + +Operating mode: +- Execute the task autonomously from analysis through validation. +- Do not stop after code edits; continue until configure, build, tests, and policy checks have been attempted in the CI container workflow. +- Do not ask for confirmation between normal implementation steps. +- Only stop early if the repository is missing required source material, the task is logically impossible, or a destructive action would be required. + +Project boundaries: +- Read the legacy source project from ${PROJECT_DIR}. +- Write the migrated project into qt6-after/qt6-migrated-benchmark. +- Do not modify the legacy source tree in place. +- Keep the migration isolated to the target tree and related CI/build/test files only when necessary. + +Primary migration goals: +- Update the build system from Qt5 to Qt6. +- Upgrade the language standard from C++11 to C++23. +- Keep Qt Core, Gui, and Widgets explicitly linked. +- Replace QRegExp with QRegularExpression. +- Replace QDesktopWidget and QApplication::desktop() usage with QScreen-based Qt6 APIs. +- Remove legacy QTextCodec usage and adopt modern Qt6-safe text handling. +- Replace old SIGNAL/SLOT syntax with function-pointer connect syntax. +- Replace legacy null pointer literals with nullptr. +- Preserve .ui integration. +- Preserve .qrc integration. +- Preserve application behavior unless a Qt6-compatible adaptation is strictly necessary. + +Testing requirements: +- For every code change inside a method, add at least three tests covering the changed behavior. +- Place all generated tests in qt6-after/qt6-migrated-benchmark/tests. +- Keep test filenames compatible with repository policy checks, for example patterns like: + - test_.cpp + - _test.cpp + - test.cpp + - gtest.cpp +- Update CMake so the migrated application and all tests are buildable and runnable with CTest. +- Ensure tests are actually registered with CTest. + +Container-first build policy: +- Use lifemaps/ci-cpp:latest as the authoritative environment for configure, build, test, and policy validation. +- Do not rely on host-installed build tools as a substitute for missing container tools. +- Execute all validation commands inside Docker using the mounted repository workspace. +- Treat Dockerfile.ci as the source of truth for CI dependencies and container tool availability. + +Execution plan: +1. Inspect the legacy project under ${PROJECT_DIR}. +2. Inspect the target tree qt6-after/qt6-migrated-benchmark. +3. Identify all Qt5/C++11 constructs that must be migrated. +4. Apply the migration incrementally in the target tree. +5. Add or update tests together with each behavior-relevant code change. +6. Update CMake and test registration. +7. Validate inside the Docker container. +8. If validation reveals missing tools inside the container, update Dockerfile.ci, rebuild the image, and rerun validation. +9. Repeat until full success or until a genuine project defect remains. + +Mandatory container validation sequence: +- Run CMake configure inside lifemaps/ci-cpp:latest. +- Run the build inside lifemaps/ci-cpp:latest. +- Run tests with CTest inside lifemaps/ci-cpp:latest. +- Only if tests succeed, run: + python3 ci/check_pr_policies.py + inside the same Docker container against the mounted workspace. + +Missing-tool remediation loop: +- If configure, build, test, or policy validation fails because a required tool or package is missing in the container: + - identify the missing tool precisely + - update Dockerfile.ci to install it + - rebuild the Docker image + - rerun the full validation sequence in the rebuilt image +- Do not stop after rebuilding once if another missing dependency appears. +- Continue until: + - the environment is complete and the next failure is a real project/code issue, or + - the entire validation flow succeeds + +Failure classification rules: +- Treat these as environment failures: + - command not found + - missing compiler/toolchain utility + - missing Qt development package + - missing CMake/Ninja/CTest support tool + - missing formatting or git verification dependency needed by ci/check_pr_policies.py +- Treat these as project failures: + - compile errors in migrated source + - linker errors caused by project configuration or code + - failing tests + - policy check failures caused by formatting, missing tests, or related project issues introduced by the migration + +Policy-check awareness: +- The repository policy script checks changed C/C++ files for formatting via clang-format. +- The policy script also expects related tests for changed C/C++ files. +- The policy script verifies commit signatures in its comparison range. +- When running local validation in the container, ensure the workspace and git metadata are available so the script can evaluate diffs properly. +- If the script fails because of issues caused by your migration, fix them and rerun validation. +- Do not claim policy success unless the script passes. + +Container command expectations: +- Use Docker commands that mount the current repository into /workspace or an equivalent work directory. +- Run commands from the mounted repository root. +- Use explicit configure/build/test commands rather than vague summaries. +- Reuse the same image name lifemaps/ci-cpp:latest unless Dockerfile.ci changes require rebuilding that image. + +Recommended validation shape: +- Configure: + cmake -S qt6-after/qt6-migrated-benchmark -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug +- Build: + cmake --build build --parallel +- Test: + ctest --test-dir build --output-on-failure +- Policy: + python3 ci/check_pr_policies.py +- If the repository uses a different build directory or requires additional flags discovered during inspection, adapt accordingly. + +Dockerfile maintenance rules: +- If you modify Dockerfile.ci, keep changes minimal and focused on missing CI dependencies. +- Do not remove already needed packages without evidence. +- After editing Dockerfile.ci, rebuild the CI image before retrying validation. +- Use the rebuilt image for all subsequent validation attempts. + +Change reporting requirements: +- Briefly explain each migration change. +- Group the explanation by: + - CMake / build-system migration + - Qt API replacements + - C++ modernization + - UI/resource preservation + - tests added + - Dockerfile.ci / container updates +- Include a concise changed-files summary. + +Completion criteria: +- Success requires all of the following: + - migrated project exists under qt6-after/qt6-migrated-benchmark + - configure succeeds in the Docker container + - build succeeds in the Docker container + - tests succeed in the Docker container + - python3 ci/check_pr_policies.py succeeds in the Docker container after tests pass +- If full success is not achieved, continue until the remaining blocker is a genuine project problem rather than a missing CI dependency. + +Final response requirements: +- State whether the migration is fully validated or which blocker remains. +- List the exact Docker commands used for: + - image rebuild + - configure + - build + - test + - policy check +- For every failed attempt, report: + - the exact command + - the key error + - whether it was an environment issue or a project issue + - the fix applied, if any +- End with a short summary of what remains, if anything. diff --git a/scripts/run-entire-copilot-migration-one.sh b/scripts/run-entire-copilot-migration-one.sh new file mode 100755 index 0000000..7323587 --- /dev/null +++ b/scripts/run-entire-copilot-migration-one.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +PROJECT_DIR="${1:-qt5-before/qt5-legacy-migration-benchmark}" +COPILOT_MODEL="${2:-qwen3.5-397b-a17b}" + +need_cmd() { + command -v "$1" >/dev/null 2>&1 || { + echo "ERROR: '$1' not found in PATH." >&2 + exit 1 + } +} + +need_cmd entire +need_cmd copilot +need_cmd git + +if ! git rev-parse --show-toplevel >/dev/null 2>&1; then + echo "ERROR: Dieses Skript muss innerhalb eines bestehenden Git-Repositories gestartet werden." >&2 + echo "Bitte zuerst im Repo-Root 'git init' oder in einem bestehenden Repo arbeiten." >&2 + exit 1 +fi + +REPO_ROOT="$(git rev-parse --show-toplevel)" +cd "$REPO_ROOT" + +if [ ! -d "$PROJECT_DIR" ]; then + echo "ERROR: project directory '$PROJECT_DIR' not found relative to repo root '$REPO_ROOT'." >&2 + exit 1 +fi + +echo "Repo root: $REPO_ROOT" +echo "Legacy project: $PROJECT_DIR" +echo "Copilot model: $COPILOT_MODEL" + +entire agent add copilot-cli +entire status + +git add . +if git diff --cached --quiet; then + git commit --allow-empty -m "baseline: Qt5/C++11 legacy benchmark before Qt6/C++23 migration" +else + git commit -m "baseline: Qt5/C++11 legacy benchmark before Qt6/C++23 migration" +fi + +echo +echo "== Checkpoints vor der Session ==" +entire checkpoint list + +envsubst < scripts/migration.prompt diff --git a/scripts/run-entire-copilot-migration-two.sh b/scripts/run-entire-copilot-migration-two.sh new file mode 100755 index 0000000..33fc5bd --- /dev/null +++ b/scripts/run-entire-copilot-migration-two.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail + +PROJECT_DIR="${1:-qt5-before/qt5-legacy-migration-benchmark}" +COPILOT_MODEL="${2:-qwen3.5-397b-a17b}" + +need_cmd() { + command -v "$1" >/dev/null 2>&1 || { + echo "ERROR: '$1' not found in PATH." >&2 + exit 1 + } +} + +need_cmd entire +need_cmd copilot +need_cmd git + +echo +echo "== Git status after Copilot session ==" +git status --short + +git add . + +if git diff --cached --quiet; then + echo "No changes to commit." + exit 0 +fi + +git commit -m "migrate: Qt5/C++11 app to Qt6/C++23 with tests and modern Qt APIs" + +echo +echo "== Checkpoints nach der Session ==" +entire checkpoint list +entire checkpoint explain HEAD || true diff --git a/scripts/run-entire-copilot-migration-with-optional-rewind-resume.sh b/scripts/run-entire-copilot-migration-with-optional-rewind-resume.sh index 4f1e27f..d2ed0e6 100755 --- a/scripts/run-entire-copilot-migration-with-optional-rewind-resume.sh +++ b/scripts/run-entire-copilot-migration-with-optional-rewind-resume.sh @@ -47,34 +47,7 @@ echo echo "== Checkpoints vor der Session ==" entire checkpoint list -cat <