Some checks failed
Validate Config / Python Syntax & Import Check (pull_request) Failing after 13s
Validate Config / Shell Script Lint (pull_request) Successful in 19s
Validate Config / Cron Syntax Check (pull_request) Successful in 11s
Validate Config / Deploy Script Dry Run (pull_request) Successful in 10s
Validate Config / Playbook Schema Validation (pull_request) Successful in 10s
Architecture Lint / Lint Repository (pull_request) Failing after 10s
Architecture Lint / Linter Tests (pull_request) Successful in 10s
PR Checklist / pr-checklist (pull_request) Failing after 1m16s
Smoke Test / smoke (pull_request) Failing after 9s
Validate Config / YAML Lint (pull_request) Failing after 11s
Validate Config / JSON Validate (pull_request) Successful in 8s
88 lines
2.8 KiB
Python
88 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
ci_automation_gate.py — Automated Quality Gate for Timmy Foundation CI.
|
|
|
|
Enforces:
|
|
1. The 10-line Rule — functions should ideally be under 10 lines (warn at 20, fail at 50).
|
|
2. Complexity Check — basic cyclomatic complexity check.
|
|
3. Auto-fixable Linting — trailing whitespace, missing final newlines.
|
|
|
|
Used as a pre-merge gate.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import re
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
class QualityGate:
|
|
def __init__(self, fix=False):
|
|
self.fix = fix
|
|
self.failures = 0
|
|
self.warnings = 0
|
|
|
|
def check_file(self, path: Path):
|
|
if path.suffix not in (".js", ".ts", ".py"):
|
|
return
|
|
|
|
with open(path, "r") as f:
|
|
lines = f.readlines()
|
|
|
|
new_lines = []
|
|
changed = False
|
|
|
|
# 1. Basic Linting
|
|
for line in lines:
|
|
cleaned = line.rstrip() + "\n"
|
|
if cleaned != line:
|
|
changed = True
|
|
new_lines.append(cleaned)
|
|
|
|
if lines and not lines[-1].endswith("\n"):
|
|
new_lines[-1] = new_lines[-1] + "\n"
|
|
changed = True
|
|
|
|
if changed and self.fix:
|
|
with open(path, "w") as f:
|
|
f.writelines(new_lines)
|
|
print(f" [FIXED] {path}: Cleaned whitespace and newlines.")
|
|
elif changed:
|
|
print(f" [WARN] {path}: Has trailing whitespace or missing final newline.")
|
|
self.warnings += 1
|
|
|
|
# 2. Function Length Check (Simple regex-based)
|
|
content = "".join(new_lines)
|
|
if path.suffix in (".js", ".ts"):
|
|
# Match function blocks
|
|
functions = re.findall(r"function\s+\w+\s*\(.*?\)\s*\{([\s\S]*?)\}", content)
|
|
for i, func in enumerate(functions):
|
|
length = func.count("\n")
|
|
if length > 50:
|
|
print(f" [FAIL] {path}: Function {i} is too long ({length} lines).")
|
|
self.failures += 1
|
|
elif length > 20:
|
|
print(f" [WARN] {path}: Function {i} is getting long ({length} lines).")
|
|
self.warnings += 1
|
|
|
|
def run(self, directory: str):
|
|
print(f"--- Quality Gate: {directory} ---")
|
|
for root, _, files in os.walk(directory):
|
|
if "node_modules" in root or ".git" in root:
|
|
continue
|
|
for file in files:
|
|
self.check_file(Path(root) / file)
|
|
|
|
print(f"\nGate complete. Failures: {self.failures}, Warnings: {self.warnings}")
|
|
if self.failures > 0:
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("dir", nargs="?", default=".")
|
|
parser.add_argument("--fix", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
gate = QualityGate(fix=args.fix)
|
|
gate.run(args.dir)
|