CI: Commit-Policy und allowed_signers für Qt6-Migration
- commit-policy.prompt.md: Policy für Multi-Repo Commits - allowed_signers: SSH-Signing Konfiguration für Gitea - check_pr_policies.py: Policy-Check Skript - MIGRATION_STATUS.md: Dokumentierter Migrationsfortschritt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Entire-Checkpoint: 01M0G01614JAYPA7N20RAGZJND
This commit is contained in:
5 files changed
+433
No files matched your search
@@ -0,0 +1,94 @@
|
|||||||
|
Task: Work in this workspace with multiple Git repositories. Before making any changes, determine the correct target repository for each file based strictly on its path, then perform changes, validation, and commits only in the matching repository.
|
||||||
|
|
||||||
|
Repository layout detected under `./`:
|
||||||
|
- `./.git`
|
||||||
|
- `./qt-migration-legatus/.git`
|
||||||
|
- `./qt-migration-legatus/qt5-before/qt5-legatus-legacy/.git`
|
||||||
|
- `./jenkins-ci-rme/.git`
|
||||||
|
- `./rpmbuild/.git`
|
||||||
|
|
||||||
|
Critical constraint:
|
||||||
|
There are multiple Git repositories in this workspace. You must first determine for each planned change which repository root it belongs to, based strictly on the file path. Each change must be made and committed in the matching Git repository only.
|
||||||
|
|
||||||
|
Repository mapping in this workspace:
|
||||||
|
- files under `./qt-migration-legatus/` -> commit only in `./qt-migration-legatus`
|
||||||
|
- files under `./jenkins-ci-rme/` -> commit only in `./jenkins-ci-rme`
|
||||||
|
- files under `./rpmbuild/` -> commit only in `./rpmbuild`
|
||||||
|
- files at workspace root `./...` not inside one of the sub-repositories -> commit only in `./`
|
||||||
|
|
||||||
|
Rules derived from this:
|
||||||
|
- Never commit a file from one repository into another repository.
|
||||||
|
- Never use `./` as the commit target for files that belong to `./qt-migration-legatus`, `./qt-migration-legatus/qt5-before/qt5-legatus-legacy/`, `./jenkins-ci-rme`, or `./rpmbuild`.
|
||||||
|
- Never use a sub-repository as the commit target for files that belong to workspace root `./`.
|
||||||
|
- Before changing any file, determine its owning repository from its path and show that mapping explicitly.
|
||||||
|
- If a planned change spans multiple repositories, handle each repository separately.
|
||||||
|
- Create separate status checks, validation runs, and commits per repository.
|
||||||
|
- If repository ownership for any file is ambiguous, stop and report it instead of guessing.
|
||||||
|
|
||||||
|
Signed commit requirement:
|
||||||
|
- Only signed commits are allowed.
|
||||||
|
- Do not create unsigned commits.
|
||||||
|
- Before committing in any repository, verify that commit signing is configured and usable for that repository context.
|
||||||
|
- Check at minimum:
|
||||||
|
- `git config --global --list`
|
||||||
|
- `cd <repo> && git config --get commit.gpgsign`
|
||||||
|
- `cd <repo> && git config --get user.signingkey`
|
||||||
|
- If repository-local signing settings exist, inspect and respect them as well.
|
||||||
|
- If signing is required but not configured or not functional, stop and report the exact reason.
|
||||||
|
- When committing, create a signed commit only.
|
||||||
|
- After committing, show evidence that the created commit is signed by running:
|
||||||
|
- `cd <repo> && git log -1 --show-signature`
|
||||||
|
|
||||||
|
Required checks before making any changes:
|
||||||
|
1. `ssh -T devel`
|
||||||
|
2. `git config --global --list`
|
||||||
|
3. `find . -type d -name .git -prune | sort`
|
||||||
|
|
||||||
|
Then, for each repository that will actually be modified, run these checks in that repository before making changes:
|
||||||
|
1. `cd <repo> && pwd`
|
||||||
|
2. `cd <repo> && git rev-parse --is-inside-work-tree`
|
||||||
|
3. `cd <repo> && git rev-parse --show-toplevel`
|
||||||
|
4. `cd <repo> && git remote -v`
|
||||||
|
5. `cd <repo> && git branch --show-current`
|
||||||
|
6. `cd <repo> && git status --short`
|
||||||
|
7. `cd <repo> && git config --get remote.origin.url`
|
||||||
|
|
||||||
|
Repository-selection procedure:
|
||||||
|
- List every file you plan to modify.
|
||||||
|
- For each file, map it to exactly one repository root using the path rules above.
|
||||||
|
- Group planned changes by repository before making any edits.
|
||||||
|
- Show the grouping explicitly before changing files.
|
||||||
|
|
||||||
|
Hard rules:
|
||||||
|
- Do not guess. Do not silently switch repositories.
|
||||||
|
- Do not modify files before their owning repository has been identified and checked.
|
||||||
|
- If any repository check fails: stop for that repository and report the exact reason.
|
||||||
|
- If a file would be committed from the wrong repository: stop.
|
||||||
|
- If `git rev-parse --show-toplevel` does not match the expected repository root for a file: stop.
|
||||||
|
- If there is no sensible remote or no plausible write access for a repository: stop for that repository.
|
||||||
|
- Do not combine changes from different repositories into one commit.
|
||||||
|
- Do not skip validation for any repository being changed.
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
- Run all relevant tests for the changes in each affected repository.
|
||||||
|
- Run all locally checkable check-in policies for each affected repository.
|
||||||
|
- Keep validation scoped to the repository being changed.
|
||||||
|
- If tests or policies fail, or cannot be executed, do not commit in that repository.
|
||||||
|
|
||||||
|
Automatic commit:
|
||||||
|
- If all checks, tests, and check-in policies pass for a repository, commit automatically in that repository.
|
||||||
|
- Before committing, show: `cd <repo> && git status --short`
|
||||||
|
- After committing, output:
|
||||||
|
- `cd <repo> && git rev-parse HEAD`
|
||||||
|
- current branch
|
||||||
|
- remote URL
|
||||||
|
- changed files
|
||||||
|
|
||||||
|
Output format:
|
||||||
|
- Show every global check command with raw output.
|
||||||
|
- Show the discovered `.git` directories.
|
||||||
|
- Show the list of planned changed files and the repository mapping for each file.
|
||||||
|
- Show all per-repository check commands with raw output.
|
||||||
|
- Show all test and policy results per repository.
|
||||||
|
- On failure in any repository: stop committing in that repository, do not guess, and report exact reasons.
|
||||||
|
- On success: commit separately per repository and print commit hash, branch, remote, and changed files for each commit.
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# Qt6 Migration Status Report
|
||||||
|
|
||||||
|
## Aktueller Stand (2026-08-18)
|
||||||
|
|
||||||
|
### ✅ Erfolgreich abgeschlossene Arbeiten
|
||||||
|
|
||||||
|
1. **Export-Header Problem behoben**
|
||||||
|
- 87 CMakeLists.txt von `NGL_ADD_LIBRARY` auf `NGL_ADD_LIBRARY2` konvertiert
|
||||||
|
- 44 Source-Dateien: Export-Header Include-Pfade korrigiert
|
||||||
|
- Root Cause: NGL_ADD_LIBRARY2 benötigt für GENERATE_EXPORT_HEADER
|
||||||
|
|
||||||
|
2. **DDS-Stub-Header generiert**
|
||||||
|
- 81 DDS-Stub-Header erstellt (`*_dtc.h`, `*_fts.h`, `*_dts.h`, `*_ftc.h`)
|
||||||
|
- Include-Pfade korrigiert mit PREFIX_TO_MODULE Mapping
|
||||||
|
- Ermöglicht Build ohne RTI DDS Codegenerierung
|
||||||
|
|
||||||
|
3. **NGLLogger Migration**
|
||||||
|
- Logger-Stub erstellt mit Logging-Makros
|
||||||
|
- m_logger Member-Variablen aus ~100+ Dateien entfernt
|
||||||
|
- Q_FUNC_INFO Redefinition behoben (auf `__func__` umgestellt)
|
||||||
|
- Logging-Makros auf variadische Parameter umgestellt
|
||||||
|
|
||||||
|
4. **InfrastructureManagement DDS-Stubs**
|
||||||
|
- ism.hpp, ism_enums.hpp Stub-Header erstellt
|
||||||
|
- IsmShared Kompilierung erfolgreich
|
||||||
|
|
||||||
|
5. **FilterManagement DDS-Stubs**
|
||||||
|
- flt_fts.h: AesFilter und AesFilterUpdateRequestHandler
|
||||||
|
- flt_dts.h: Dts und Fts Interface-Classes
|
||||||
|
- flt_dts.cpp: Stub-Implementation
|
||||||
|
- flt_ftc.h: Ftc Interface mit ReplyHandler (neu erstellt)
|
||||||
|
|
||||||
|
6. **Docker Permission Fix**
|
||||||
|
- Container muss mit `--user root` für Schreibzugriff auf ./build*/
|
||||||
|
|
||||||
|
### ⚠️ Aktuelle Build-Situation
|
||||||
|
|
||||||
|
**NGLLogger**: ✅ Baut erfolgreich ohne RTI
|
||||||
|
|
||||||
|
**FilterManagement**: ⚠️ Benötigt BUILD_RTI=ON
|
||||||
|
- FltDataPlugin hängt von `svcFltClient` ab
|
||||||
|
- svcFltClient wird nur mit BUILD_RTI=ON gebaut
|
||||||
|
- RTI Connext ist in Ubuntu 26.04 nicht installiert
|
||||||
|
|
||||||
|
**Lösungsoptionen**:
|
||||||
|
1. RTI Connext in Docker-Image installieren (aufwändig, Lizenz)
|
||||||
|
2. BUILD_RTI=OFF und FilterManagement-Plugins temporär deaktivieren
|
||||||
|
3. svcFltClient als Header-Only Library behandeln (wenn möglich)
|
||||||
|
|
||||||
|
### 📝 Git Submodule Status
|
||||||
|
|
||||||
|
**Frage**: Warum ist git submodule im HEAD detach state?
|
||||||
|
|
||||||
|
**Antwort**: Das Submodule ist **NICHT** im detached HEAD state!
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git submodule status
|
||||||
|
+010f91928acfe8e775acdacc5eb0b38f613fa3e5 qt-migration-legatus (heads/feature/qt6-migration-basis-modules)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Branch**: `feature/qt6-migration-basis-modules` ✅
|
||||||
|
- **Commit**: 010f919 (lokale Änderungen, noch nicht gepusht)
|
||||||
|
- **Das `+` Zeichen**: Zeigt uncommitted changes im Submodule an
|
||||||
|
|
||||||
|
### 🔄 Nächste Schritte
|
||||||
|
|
||||||
|
1. **FilterManagement Build-Strategie klären**
|
||||||
|
- Option A: BUILD_RTI=ON mit RTI-Installation
|
||||||
|
- Option B: FilterManagement-Plugins temporär ausschließen
|
||||||
|
- Option C: svcFltClient als Header-Only behandeln
|
||||||
|
|
||||||
|
2. **Tests erstellen** (gemäß combined-migration-compact.prompt.md)
|
||||||
|
- Für migrierte Module: Lts/Common, NGLLogger
|
||||||
|
- Teststruktur: `./qt-migration-legatus/qt6-after/qt6-migrated-legatus/tests/`
|
||||||
|
|
||||||
|
3. **./rpmbuild und ./jenkins migrieren**
|
||||||
|
- Von openSUSE nach Ubuntu 26.04
|
||||||
|
- Dockerfiles anpassen
|
||||||
|
- Jenkins-Pipelines aktualisieren
|
||||||
|
|
||||||
|
4. **Vollständige Migration fortsetzen**
|
||||||
|
- Z-Module → TetraIF → Lts/Services → Lts/Proxies → Lts/Plugins → Lts/Projects
|
||||||
|
|
||||||
|
### 📊 Build-Statistik
|
||||||
|
|
||||||
|
| Modul | Build-Status | RTI benötigt | Notes |
|
||||||
|
|-------|--------------|--------------|-------|
|
||||||
|
| NGLLogger | ✅ Erfolg | ❌ Nein | Basis-Logging |
|
||||||
|
| IsmShared | ✅ Erfolg | ❌ Nein | InfrastructureManagement |
|
||||||
|
| FltDataPlugin | ⚠️ Pending | ✅ Ja | Benötigt svcFltClient |
|
||||||
|
| svcFltCommon | ⚠️ Pending | ✅ Ja | BUILD_RTI=ON required |
|
||||||
|
| svcFltClient | ⚠️ Pending | ✅ Ja | BUILD_RTI=ON required |
|
||||||
|
| svcFltServer | ⚠️ Pending | ✅ Ja | BUILD_RTI=ON required |
|
||||||
|
|
||||||
|
### 🛠️ Wichtige Files
|
||||||
|
|
||||||
|
**Stub-Header erstellt**:
|
||||||
|
- `/include/FilterManagement/flt_fts.h`
|
||||||
|
- `/include/FilterManagement/flt_dts.h`
|
||||||
|
- `/include/FilterManagement/flt_dts.cpp`
|
||||||
|
- `/include/FilterManagement/flt_ftc.h` (neu)
|
||||||
|
- `/include/InfrastructureManagement/ism.hpp`
|
||||||
|
- `/include/InfrastructureManagement/ism_enums.hpp`
|
||||||
|
|
||||||
|
**Skripte erstellt**:
|
||||||
|
- `fix_add_library2.py` (87 Fixes)
|
||||||
|
- `fix_export_includes.py` (44 Fixes)
|
||||||
|
- `create_dds_stubs.py` (81 Header)
|
||||||
|
- `move_dds_headers.py` (Pfad-Korrektur)
|
||||||
|
- `remove_logger_members.py` (~100+ Dateien)
|
||||||
|
- `fix_logging_macros.py` (variadische Parameter)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Empfehlung**: User sollte entscheiden ob RTI Connext installiert werden soll oder ob FilterManagement-Plugins temporär aus dem Build ausgeschlossen werden können.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
torsten.wierschin@life-maps.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO+c+9jJKrLpTk4pLg+p1Qo0CjCYzfKfEhXEu0MAlZpj
|
||||||
|
nkana@outlook.de ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBR68AzU7UtY+NJPIRloEeIlQIZIP3xhvkWB8BediMeQ
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(".").resolve()
|
||||||
|
TEST_DIRS = [
|
||||||
|
ROOT / "tests",
|
||||||
|
ROOT / "test",
|
||||||
|
ROOT / "qt6-after" / "qt6-migrated-benchmark" / "tests",
|
||||||
|
]
|
||||||
|
CPP_EXTENSIONS = {".c", ".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".hxx"}
|
||||||
|
ALLOWED_SIGNERS_FILE = ROOT / "ci" / "allowed_signers"
|
||||||
|
|
||||||
|
TEST_PATTERNS = [
|
||||||
|
"test_{name}.cpp",
|
||||||
|
"test_{name}.h",
|
||||||
|
"{name}_test.cpp",
|
||||||
|
"{name}_test.h",
|
||||||
|
"{name}test.cpp",
|
||||||
|
"{name}test.h",
|
||||||
|
"{name}gtest.cpp",
|
||||||
|
"{name}gtest.h",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def run(cmd: str) -> str:
|
||||||
|
return subprocess.check_output(cmd, shell=True, text=True).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def git_ref_exists(ref: str) -> bool:
|
||||||
|
try:
|
||||||
|
subprocess.check_call(
|
||||||
|
f"git rev-parse --verify --quiet '{ref}'",
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_pull_request_build() -> bool:
|
||||||
|
return bool(os.environ.get("CHANGE_ID"))
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_target_ref() -> str | None:
|
||||||
|
raw = os.environ.get("CHANGE_TARGET", "").strip()
|
||||||
|
|
||||||
|
candidates = []
|
||||||
|
if raw:
|
||||||
|
candidates.append(raw)
|
||||||
|
if not raw.startswith("origin/"):
|
||||||
|
candidates.append(f"origin/{raw}")
|
||||||
|
|
||||||
|
candidates.extend(["origin/main", "main"])
|
||||||
|
|
||||||
|
seen = set()
|
||||||
|
for ref in candidates:
|
||||||
|
if ref and ref not in seen:
|
||||||
|
seen.add(ref)
|
||||||
|
if git_ref_exists(ref):
|
||||||
|
return ref
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def changed_files_and_base() -> tuple[list[str], str]:
|
||||||
|
target = resolve_target_ref()
|
||||||
|
|
||||||
|
if target:
|
||||||
|
print(f"Vergleiche gegen Ziel-Ref: {target}")
|
||||||
|
out = run(f"git diff --name-only {target}...HEAD")
|
||||||
|
files = [line.strip() for line in out.splitlines() if line.strip()]
|
||||||
|
return files, target
|
||||||
|
|
||||||
|
if is_pull_request_build():
|
||||||
|
print("ERROR: Kein gültiger Ziel-Branch-Ref für PR-Build gefunden.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if git_ref_exists("HEAD~1"):
|
||||||
|
print("Kein Ziel-Branch-Ref gefunden, verwende HEAD~1 für Branch-Build.")
|
||||||
|
out = run("git diff --name-only HEAD~1..HEAD")
|
||||||
|
files = [line.strip() for line in out.splitlines() if line.strip()]
|
||||||
|
return files, "HEAD~1"
|
||||||
|
|
||||||
|
print("Keine Vergleichsbasis gefunden, behandle alle versionierten Dateien als geändert.")
|
||||||
|
out = run("git ls-files")
|
||||||
|
files = [line.strip() for line in out.splitlines() if line.strip()]
|
||||||
|
return files, ""
|
||||||
|
|
||||||
|
|
||||||
|
def commits_in_range(base: str) -> list[str]:
|
||||||
|
if base:
|
||||||
|
if base == "HEAD~1":
|
||||||
|
out = run("git rev-list HEAD~1..HEAD")
|
||||||
|
else:
|
||||||
|
out = run(f"git rev-list {base}..HEAD")
|
||||||
|
else:
|
||||||
|
out = run("git rev-list HEAD")
|
||||||
|
return [line.strip() for line in out.splitlines() if line.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def is_cpp_file(path: Path) -> bool:
|
||||||
|
return path.suffix.lower() in CPP_EXTENSIONS
|
||||||
|
|
||||||
|
|
||||||
|
def require_clang_format():
|
||||||
|
if not (ROOT / ".clang-format").exists():
|
||||||
|
print("ERROR: .clang-format fehlt im Repository-Root.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def require_allowed_signers():
|
||||||
|
if not ALLOWED_SIGNERS_FILE.exists():
|
||||||
|
print(f"ERROR: {ALLOWED_SIGNERS_FILE} fehlt.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def check_format(path: Path):
|
||||||
|
subprocess.check_call(f"clang-format --dry-run --Werror '{path}'", shell=True)
|
||||||
|
|
||||||
|
|
||||||
|
def candidate_names(path: Path):
|
||||||
|
stem = path.stem.lower()
|
||||||
|
names = {stem}
|
||||||
|
for suffix in ["_p", "_impl", "_private", "_priv", "_ui"]:
|
||||||
|
if stem.endswith(suffix):
|
||||||
|
names.add(stem[:-len(suffix)])
|
||||||
|
return sorted(n for n in names if n)
|
||||||
|
|
||||||
|
|
||||||
|
def iter_test_files():
|
||||||
|
for test_dir in TEST_DIRS:
|
||||||
|
if test_dir.exists():
|
||||||
|
yield from (p for p in test_dir.rglob("*") if p.is_file())
|
||||||
|
|
||||||
|
|
||||||
|
def has_related_test(path: Path) -> bool:
|
||||||
|
test_files = list(iter_test_files())
|
||||||
|
if not test_files:
|
||||||
|
return False
|
||||||
|
|
||||||
|
test_names = [p.name.lower() for p in test_files]
|
||||||
|
|
||||||
|
for name in candidate_names(path):
|
||||||
|
for pattern in TEST_PATTERNS:
|
||||||
|
if pattern.format(name=name).lower() in test_names:
|
||||||
|
return True
|
||||||
|
for test_name in test_names:
|
||||||
|
if name in test_name and ("test" in test_name or "gtest" in test_name):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def verify_commit_signature(commit: str):
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["GIT_CONFIG_COUNT"] = "1"
|
||||||
|
env["GIT_CONFIG_KEY_0"] = "gpg.ssh.allowedSignersFile"
|
||||||
|
env["GIT_CONFIG_VALUE_0"] = str(ALLOWED_SIGNERS_FILE)
|
||||||
|
|
||||||
|
subprocess.check_call(
|
||||||
|
f"git verify-commit {commit}",
|
||||||
|
shell=True,
|
||||||
|
env=env,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
require_clang_format()
|
||||||
|
require_allowed_signers()
|
||||||
|
|
||||||
|
files, base = changed_files_and_base()
|
||||||
|
if not files:
|
||||||
|
print("Keine geänderten Dateien erkannt.")
|
||||||
|
return
|
||||||
|
|
||||||
|
commits = commits_in_range(base)
|
||||||
|
if not commits:
|
||||||
|
print("Keine neuen Commits im Vergleichsbereich erkannt.")
|
||||||
|
else:
|
||||||
|
for commit in commits:
|
||||||
|
print(f"Prüfe SSH-Signatur: {commit}")
|
||||||
|
try:
|
||||||
|
verify_commit_signature(commit)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print(
|
||||||
|
"ERROR: Commit ist nicht gültig mit erlaubtem SSH-Signierer signiert: "
|
||||||
|
f"{commit}"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
for rel in files:
|
||||||
|
path = ROOT / rel
|
||||||
|
if not path.exists():
|
||||||
|
continue
|
||||||
|
if is_cpp_file(path):
|
||||||
|
print(f"Prüfe: {rel}")
|
||||||
|
try:
|
||||||
|
check_format(path)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print(f"ERROR: Formatfehler in {rel}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not has_related_test(path):
|
||||||
|
print(
|
||||||
|
"ERROR: Kein passender Test unter tests/, test/ oder "
|
||||||
|
"qt6-after/qt6-migrated-benchmark/tests/ gefunden für: "
|
||||||
|
f"{rel}"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("PR-Policy-Prüfungen erfolgreich.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
.github/prompts/commit-policy.prompt.md
|
||||||
Reference in new issue
Block a user