Merge pull request 'Migrate Qt5/C++11 app to Qt6/C++23 and stabilize CI/pipeline setup' (#1) from bugfix/ci-pipeline-commissioning into main
qt-migration-copilot-demo/pipeline/head This commit looks good

Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
twi-devel committed 2026-08-13 08:49:52 +00:00
commit 9e3c6eef2e
32 files changed
+1594 -64

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
tmp/
settings.local.json
metadata/
logs/
redactors/local/
+9
View File
@@ -0,0 +1,9 @@
{
"enabled": true,
"telemetry": true,
"checkpoints": {
"primary": {
"type": "git-branch"
}
}
}
+5 -1
View File
@@ -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"
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
+56
View File
@@ -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
+61
View File
@@ -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
}
@@ -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_<name>.cpp`
- `<name>_test.cpp`
- `<name>test.cpp`
- `<name>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.
+4
View File
@@ -0,0 +1,4 @@
.envrc
.*~
*~
build
Vendored
+7 -1
View File
@@ -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'
}
}
}
+6
View File
@@ -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
+2 -1
View File
@@ -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
+10 -1
View File
@@ -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()
+32 -4
View File
@@ -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'
```
---
+336
View File
@@ -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/<user>/.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 <project-id>
```
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 <project-id>
```
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 <name>
```
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 <project-id>
entire repo get <repo> --project <project-id>
entire repo create <name> --project <project-id>
```
### 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 <project-id>` 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 <project-id>
```
Danach prüfen:
```bash
entire repo list <project-id>
```
### 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 <project-id>
entire enable
entire status
entire agent list
entire doctor
```
File renamed without changes.
File renamed without changes.
@@ -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)
@@ -0,0 +1,55 @@
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QApplication>
#include <QPixmap>
#include <QScreen>
#include <QString>
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);
}
}
@@ -0,0 +1,31 @@
#pragma once
#include <QMainWindow>
#include <QRegularExpression>
#include <QString>
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;
};
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>420</width>
<height>240</height>
</rect>
</property>
<property name="windowTitle">
<string>Qt5 Legacy App</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Initial text</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="placeholderText">
<string>Enter value like Test123</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="iconLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="buttonLayout">
<item>
<widget class="QPushButton" name="validateButton">
<property name="text">
<string>Validate</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="screenButton">
<property name="text">
<string>Screen Info</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="resultLabel">
<property name="text">
<string>Result appears here</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

+19
View File
@@ -0,0 +1,19 @@
#include "MainWindow.h"
#include <QApplication>
#include <QScreen>
#if __has_include(<print>)
#include <print>
#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();
}
@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/icons">
<file>app.png</file>
</qresource>
</RCC>
@@ -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)
@@ -0,0 +1,75 @@
#include <QRect>
#include <QRegularExpression>
#include <QScreen>
#include <QString>
#include <QTest>
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"
@@ -0,0 +1,63 @@
#include <QRegularExpression>
#include <QString>
#include <QTest>
class MainTest : public QObject
{
Q_OBJECT
private slots:
void testRegularExpressionValidation_data();
void testRegularExpressionValidation();
void testQStringUtf8Conversion();
void testRegularExpressionPattern();
};
void MainTest::testRegularExpressionValidation_data()
{
QTest::addColumn<QString>("input");
QTest::addColumn<bool>("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"
+157
View File
@@ -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_<name>.cpp`
- `<name>_test.cpp`
- `<name>test.cpp`
- `<name>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.
+119
View File
@@ -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 `<iostream>` console output with `<print>` where toolchain support exists.
- Use `std::print` and `std::println` for standard console output.
- If `<print>` 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
+152
View File
@@ -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_<name>.cpp
- <name>_test.cpp
- <name>test.cpp
- <name>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.
+50
View File
@@ -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
+34
View File
@@ -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
@@ -47,34 +47,7 @@ echo
echo "== Checkpoints vor der Session =="
entire checkpoint list
cat <<PROMPT
Use this prompt in Copilot CLI:
Migrate the legacy Qt5/C++11 desktop application to Qt6/C++23.
Requirements:
- 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
- Update CMake from Qt5 to Qt6
- Keep Core, Gui, and Widgets explicitly linked
- Replace QRegExp with QRegularExpression
- Replace QDesktopWidget / QApplication::desktop() usage with QScreen-based Qt6 APIs
- Remove legacy QTextCodec usage and use modern Qt6-safe text handling
- Modernize old SIGNAL/SLOT syntax to function-pointer connect syntax
- Replace legacy null pointer literals with nullptr
- Preserve the .ui and .qrc integration
- Preserve application behavior
- Upgrade the project from C++11 to C++23
- 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
- Update CMake so the migrated application and all tests build successfully with CTest
- Keep the test file naming compatible with repository policy checks
- Briefly explain each migration change
PROMPT
copilot --model "${COPILOT_MODEL}"
envsubst < scripts/migration.prompt | copilot --model "${COPILOT_MODEL}"
echo
echo "== Git status after Copilot session =="
+1 -28
View File
@@ -47,34 +47,7 @@ echo
echo "== Checkpoints vor der Session =="
entire checkpoint list
cat <<PROMPT
Use this prompt in Copilot CLI:
Migrate the legacy Qt5/C++11 desktop application to Qt6/C++23.
Requirements:
- 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
- Update CMake from Qt5 to Qt6
- Keep Core, Gui, and Widgets explicitly linked
- Replace QRegExp with QRegularExpression
- Replace QDesktopWidget / QApplication::desktop() usage with QScreen-based Qt6 APIs
- Remove legacy QTextCodec usage and use modern Qt6-safe text handling
- Modernize old SIGNAL/SLOT syntax to function-pointer connect syntax
- Replace legacy null pointer literals with nullptr
- Preserve the .ui and .qrc integration
- Preserve application behavior
- Upgrade the project from C++11 to C++23
- 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
- Update CMake so the migrated application and all tests build successfully with CTest
- Keep the test file naming compatible with repository policy checks
- Briefly explain each migration change
PROMPT
copilot --model "${COPILOT_MODEL}"
envsubst < scripts/migration.prompt | copilot --model "${COPILOT_MODEL}"
echo
echo "== Git status after Copilot session =="