guardian-framework 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +463 -0
- package/dist/cli.js +12958 -0
- package/dist/exports.js +12765 -0
- package/package.json +61 -0
- package/templates/languages/go-patterns.md +411 -0
- package/templates/languages/java-patterns.md +545 -0
- package/templates/languages/python-patterns.md +312 -0
- package/templates/languages/rust-patterns.md +232 -0
- package/templates/languages/typescript-patterns.md +313 -0
- package/templates/pi/INDEX.md +437 -0
- package/templates/pi/agent/AGENTS.md +166 -0
- package/templates/pi/agents/architecture-coordinator.md +40 -0
- package/templates/pi/agents/architecture-validator.md +36 -0
- package/templates/pi/agents/bootstrap-implementer.md +37 -0
- package/templates/pi/agents/issue-factory.md +31 -0
- package/templates/pi/agents/operations-validator.md +32 -0
- package/templates/pi/agents/security-validator.md +33 -0
- package/templates/pi/architecture/CHANGELOG.md +78 -0
- package/templates/pi/architecture/decisions/ADR-template.md +76 -0
- package/templates/pi/architecture/diagrams/system-overview.md +159 -0
- package/templates/pi/architecture/modules/module-template.md +152 -0
- package/templates/pi/context/checklists.md +91 -0
- package/templates/pi/context/domain-workflow.md +180 -0
- package/templates/pi/context/output-formats.md +135 -0
- package/templates/pi/context/patterns-base.md +47 -0
- package/templates/pi/context/patterns.md +38 -0
- package/templates/pi/context/project.md +88 -0
- package/templates/pi/domain/exploration.md +93 -0
- package/templates/pi/domain/ubiquitous-language.md +24 -0
- package/templates/pi/extensions/architect-lib/generators.ts +528 -0
- package/templates/pi/extensions/architect-lib/helpers.ts +344 -0
- package/templates/pi/extensions/architect-lib/types.ts +117 -0
- package/templates/pi/extensions/architect.ts +1425 -0
- package/templates/pi/extensions/ask-user-question.ts +579 -0
- package/templates/pi/extensions/bash-guard.ts +556 -0
- package/templates/pi/extensions/config-reload.ts +115 -0
- package/templates/pi/extensions/coordinator.ts +304 -0
- package/templates/pi/extensions/curator.ts +543 -0
- package/templates/pi/extensions/domain-explorer.ts +990 -0
- package/templates/pi/extensions/filechanges.ts +656 -0
- package/templates/pi/extensions/goal-loop.ts +717 -0
- package/templates/pi/extensions/hooks.ts +452 -0
- package/templates/pi/extensions/kanban.ts +547 -0
- package/templates/pi/extensions/pipeline.ts +1246 -0
- package/templates/pi/extensions/plan-mode.ts +209 -0
- package/templates/pi/extensions/project-scaffolder.ts +284 -0
- package/templates/pi/extensions/read-only-mode.ts +192 -0
- package/templates/pi/extensions/redaction.ts +128 -0
- package/templates/pi/extensions/session-persistence.ts +174 -0
- package/templates/pi/extensions/slash-commands.ts +229 -0
- package/templates/pi/extensions/snippets.ts +201 -0
- package/templates/pi/extensions/validation-runner.ts +100 -0
- package/templates/pi/github/agents/architecture-coordinator.agent.md +27 -0
- package/templates/pi/github/agents/architecture-validator.agent.md +20 -0
- package/templates/pi/github/agents/bootstrap-implementer.agent.md +20 -0
- package/templates/pi/github/agents/epic-planner.agent.md +70 -0
- package/templates/pi/github/agents/issue-factory.agent.md +20 -0
- package/templates/pi/github/agents/operations-validator.agent.md +20 -0
- package/templates/pi/github/agents/security-validator.agent.md +20 -0
- package/templates/pi/github/copilot/settings.json +16 -0
- package/templates/pi/github/copilot-instructions.md +155 -0
- package/templates/pi/github/instructions/architecture.instructions.md +71 -0
- package/templates/pi/github/instructions/validation.instructions.md +69 -0
- package/templates/pi/github/workflows/01-planning-workflow.md +75 -0
- package/templates/pi/github/workflows/02-issue-generation-workflow.md +69 -0
- package/templates/pi/github/workflows/03-implementation-workflow.md +80 -0
- package/templates/pi/github/workflows/04-validation-workflow.md +68 -0
- package/templates/pi/preflight_report.json +99 -0
- package/templates/pi/prompts/blueprint-update.md +262 -0
- package/templates/pi/prompts/blueprint-validate.md +218 -0
- package/templates/pi/prompts/bug-fix.md +50 -0
- package/templates/pi/prompts/ci-blueprint.md +131 -0
- package/templates/pi/prompts/context-refresh.md +258 -0
- package/templates/pi/prompts/epic-plan.md +356 -0
- package/templates/pi/prompts/epic-template.md +186 -0
- package/templates/pi/prompts/feature-development.md +131 -0
- package/templates/pi/prompts/git-issues.md +243 -0
- package/templates/pi/prompts/hotfix.md +71 -0
- package/templates/pi/prompts/issue-closeout.md +342 -0
- package/templates/pi/prompts/issue-draft.md +218 -0
- package/templates/pi/prompts/issue-implementation-series.md +173 -0
- package/templates/pi/prompts/issue-merge.md +372 -0
- package/templates/pi/prompts/issue-template-set.md +392 -0
- package/templates/pi/prompts/issue-template.md +207 -0
- package/templates/pi/prompts/pattern-extract.md +269 -0
- package/templates/pi/prompts/plan-to-issues.md +430 -0
- package/templates/pi/prompts/refactoring.md +82 -0
- package/templates/pi/prompts/scope-analyzer.md +254 -0
- package/templates/pi/prompts/sync-check.md +230 -0
- package/templates/pi/scripts/categorize-issues.sh +171 -0
- package/templates/pi/scripts/ci/check_architecture_conformance.sh +748 -0
- package/templates/pi/scripts/ci/check_planning_packet.py +228 -0
- package/templates/pi/scripts/ci/run_hardening_stages.sh +264 -0
- package/templates/pi/scripts/ci/run_preflight.sh +649 -0
- package/templates/pi/scripts/ci/run_stage.sh +193 -0
- package/templates/pi/scripts/ci/stage_docs_policy.sh +82 -0
- package/templates/pi/scripts/ci/stage_integration.sh +3 -0
- package/templates/pi/scripts/ci/stage_lint.sh +130 -0
- package/templates/pi/scripts/ci/stage_migration_verify.sh +3 -0
- package/templates/pi/scripts/ci/stage_package_build.sh +3 -0
- package/templates/pi/scripts/ci/stage_release_readiness.sh +3 -0
- package/templates/pi/scripts/ci/stage_remaining.sh +242 -0
- package/templates/pi/scripts/ci/stage_security.sh +3 -0
- package/templates/pi/scripts/ci/stage_static_analysis.sh +114 -0
- package/templates/pi/scripts/ci/stage_unit.sh +119 -0
- package/templates/pi/scripts/ci/validate_agent_output.py +181 -0
- package/templates/pi/scripts/ci/validate_agent_output.sh +243 -0
- package/templates/pi/scripts/create-feature-branch.sh +136 -0
- package/templates/pi/scripts/create-mr.sh +117 -0
- package/templates/pi/scripts/fetch-issues.sh +131 -0
- package/templates/pi/scripts/generate-architecture.sh +161 -0
- package/templates/pi/scripts/git/close-epic.sh +69 -0
- package/templates/pi/scripts/git/close-issue.sh +35 -0
- package/templates/pi/scripts/git/create-tracking-issue.sh +174 -0
- package/templates/pi/scripts/git/link-issue-to-epic.sh +51 -0
- package/templates/pi/scripts/git/update-tracking-issue.sh +66 -0
- package/templates/pi/scripts/languages/go/validate-architecture.sh +139 -0
- package/templates/pi/scripts/languages/go/validate-canonical.sh +129 -0
- package/templates/pi/scripts/languages/go/validate-ci.sh +132 -0
- package/templates/pi/scripts/languages/go/validate-integration.sh +156 -0
- package/templates/pi/scripts/languages/go/validate-operations.sh +146 -0
- package/templates/pi/scripts/languages/go/validate-security.sh +135 -0
- package/templates/pi/scripts/languages/go/validate-tests.sh +125 -0
- package/templates/pi/scripts/languages/java/validate-annotations.sh +185 -0
- package/templates/pi/scripts/languages/java/validate-architecture.sh +159 -0
- package/templates/pi/scripts/languages/java/validate-canonical.sh +114 -0
- package/templates/pi/scripts/languages/java/validate-ci.sh +269 -0
- package/templates/pi/scripts/languages/java/validate-integration.sh +149 -0
- package/templates/pi/scripts/languages/java/validate-operations.sh +142 -0
- package/templates/pi/scripts/languages/java/validate-security.sh +174 -0
- package/templates/pi/scripts/languages/java/validate-spring-architecture.sh +227 -0
- package/templates/pi/scripts/languages/java/validate-tests.sh +159 -0
- package/templates/pi/scripts/languages/python/validate-architecture.sh +99 -0
- package/templates/pi/scripts/languages/python/validate-canonical.sh +124 -0
- package/templates/pi/scripts/languages/python/validate-ci.sh +130 -0
- package/templates/pi/scripts/languages/python/validate-integration.sh +119 -0
- package/templates/pi/scripts/languages/python/validate-operations.sh +107 -0
- package/templates/pi/scripts/languages/python/validate-security.sh +68 -0
- package/templates/pi/scripts/languages/python/validate-tests.sh +102 -0
- package/templates/pi/scripts/languages/rust/validate-architecture.sh +188 -0
- package/templates/pi/scripts/languages/rust/validate-canonical.sh +146 -0
- package/templates/pi/scripts/languages/rust/validate-ci.sh +147 -0
- package/templates/pi/scripts/languages/rust/validate-integration.sh +149 -0
- package/templates/pi/scripts/languages/rust/validate-operations.sh +154 -0
- package/templates/pi/scripts/languages/rust/validate-security.sh +153 -0
- package/templates/pi/scripts/languages/rust/validate-tests.sh +150 -0
- package/templates/pi/scripts/languages/typescript/validate-architecture.sh +157 -0
- package/templates/pi/scripts/languages/typescript/validate-canonical.sh +135 -0
- package/templates/pi/scripts/languages/typescript/validate-ci.sh +244 -0
- package/templates/pi/scripts/languages/typescript/validate-integration.sh +166 -0
- package/templates/pi/scripts/languages/typescript/validate-operations.sh +162 -0
- package/templates/pi/scripts/languages/typescript/validate-security.sh +169 -0
- package/templates/pi/scripts/languages/typescript/validate-tests.sh +158 -0
- package/templates/pi/scripts/merge-mr.sh +95 -0
- package/templates/pi/scripts/mr-validation.sh +228 -0
- package/templates/pi/scripts/validate-architecture-readiness.sh +153 -0
- package/templates/pi/scripts/validate-architecture.sh +22 -0
- package/templates/pi/scripts/validate-canonical.sh +22 -0
- package/templates/pi/scripts/validate-ci.sh +37 -0
- package/templates/pi/scripts/validate-integration.sh +22 -0
- package/templates/pi/scripts/validate-operations.sh +22 -0
- package/templates/pi/scripts/validate-security.sh +22 -0
- package/templates/pi/scripts/validate-tests.sh +22 -0
- package/templates/pi/scripts/validate-ubiquitous-language.sh +291 -0
- package/templates/pi/scripts/validation-cache.sh +139 -0
- package/templates/pi/skills/agents/architecture-coordinator.md +178 -0
- package/templates/pi/skills/agents/architecture-generator.md +79 -0
- package/templates/pi/skills/agents/architecture-validator.md +74 -0
- package/templates/pi/skills/agents/ci-mr-validator.md +46 -0
- package/templates/pi/skills/agents/code-developer.md +76 -0
- package/templates/pi/skills/agents/commit.md +46 -0
- package/templates/pi/skills/agents/curator.md +71 -0
- package/templates/pi/skills/agents/debug.md +59 -0
- package/templates/pi/skills/agents/documentation-maintainer.md +36 -0
- package/templates/pi/skills/agents/goal-loop.md +125 -0
- package/templates/pi/skills/agents/hooks.md +122 -0
- package/templates/pi/skills/agents/integration-validator.md +35 -0
- package/templates/pi/skills/agents/issue-creator.md +75 -0
- package/templates/pi/skills/agents/issue-factory.md +143 -0
- package/templates/pi/skills/agents/kanban.md +85 -0
- package/templates/pi/skills/agents/land.md +59 -0
- package/templates/pi/skills/agents/operations-validator.md +43 -0
- package/templates/pi/skills/agents/pipeline.md +113 -0
- package/templates/pi/skills/agents/plan-mode.md +77 -0
- package/templates/pi/skills/agents/pull.md +40 -0
- package/templates/pi/skills/agents/push.md +41 -0
- package/templates/pi/skills/agents/security-validator.md +85 -0
- package/templates/pi/skills/agents/session-persistence.md +119 -0
- package/templates/pi/skills/agents/slash-commands.md +117 -0
- package/templates/pi/skills/agents/snippets.md +99 -0
- package/templates/pi/skills/agents/subagent-registry.md +78 -0
- package/templates/pi/skills/agents/test-validator.md +42 -0
- package/templates/pi/skills/validators/architecture-validator.md +43 -0
- package/templates/pi/skills/validators/ci-validator.md +27 -0
- package/templates/pi/skills/validators/context-compaction.md +73 -0
- package/templates/pi/skills/validators/integration-validator.md +38 -0
- package/templates/pi/skills/validators/model-registry.md +96 -0
- package/templates/pi/skills/validators/operations-validator.md +34 -0
- package/templates/pi/skills/validators/security-guards.md +72 -0
- package/templates/pi/skills/validators/security-validator.md +41 -0
- package/templates/pi/skills/validators/system-prompt-tiers.md +69 -0
- package/templates/pi/skills/validators/test-validator.md +33 -0
- package/templates/pi/types.ts +62 -0
- package/templates/pi/validators/README.md +93 -0
- package/templates/pi/validators/default.toml +209 -0
- package/templates/pi/validators/spring.toml +142 -0
- package/templates/pi/workpad.md +53 -0
- package/templates/project/java/Dockerfile +14 -0
- package/templates/project/java/README.md +40 -0
- package/templates/project/java/pom.xml +132 -0
- package/templates/project/typescript/Dockerfile +15 -0
- package/templates/project/typescript/README.md +29 -0
- package/templates/project/typescript/package.json +23 -0
- package/templates/project/typescript/tsconfig.json +21 -0
- package/templates/workflow.md +123 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# validate-operations.sh — TypeScript
|
|
4
|
+
# ============================================================================
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
PASS_COUNT=0; ERRORS=(); WARNINGS=()
|
|
8
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
9
|
+
pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
10
|
+
fail() { echo -e "${RED}❌ FAIL${NC} $1"; ERRORS+=("$1"); }
|
|
11
|
+
warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARNINGS+=("$1"); }
|
|
12
|
+
|
|
13
|
+
echo "============================================"
|
|
14
|
+
echo " Operations Validation (TypeScript)"
|
|
15
|
+
echo "============================================"
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
SRC_DIR="${1:-src}"
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
# Structured Logging
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
echo "--- Structured Logging ---"
|
|
24
|
+
LOGGING_LIBS=0
|
|
25
|
+
if [ -d "$SRC_DIR" ] || [ -d "." ]; then
|
|
26
|
+
SEARCH_DIRS=""
|
|
27
|
+
if [ -d "$SRC_DIR" ]; then
|
|
28
|
+
SEARCH_DIRS="$SRC_DIR"
|
|
29
|
+
fi
|
|
30
|
+
SEARCH_DIRS="${SEARCH_DIRS} ${SEARCH_DIRS:+.}"
|
|
31
|
+
|
|
32
|
+
for dir in $SEARCH_DIRS; do
|
|
33
|
+
[ -d "$dir" ] || continue
|
|
34
|
+
FOUND=$(find "$dir" -type f \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" \
|
|
35
|
+
-exec grep -lE "(winston|pino|bunyan|console\.(log|info|warn|error))" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
36
|
+
LOGGING_LIBS=$((LOGGING_LIBS + FOUND))
|
|
37
|
+
done
|
|
38
|
+
if [ "$LOGGING_LIBS" -gt 0 ]; then
|
|
39
|
+
pass "Structured logging detected ($LOGGING_LIBS files)"
|
|
40
|
+
else
|
|
41
|
+
warn "No structured logging or console.log patterns found"
|
|
42
|
+
fi
|
|
43
|
+
else
|
|
44
|
+
warn "No source directory found, skipping logging check"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
# Health Checks
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
echo ""
|
|
51
|
+
echo "--- Health Checks ---"
|
|
52
|
+
HEALTH_ROUTES=0
|
|
53
|
+
if [ -d "$SRC_DIR" ]; then
|
|
54
|
+
HEALTH_ROUTES=$(find "$SRC_DIR" -type f \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" \
|
|
55
|
+
-exec grep -lE "(/health[^/]?|/healthz|/ready|/readiness)" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
56
|
+
if [ "$HEALTH_ROUTES" -gt 0 ]; then
|
|
57
|
+
pass "Health check endpoints found ($HEALTH_ROUTES files)"
|
|
58
|
+
else
|
|
59
|
+
warn "No health check endpoints detected (/health, /healthz, /ready)"
|
|
60
|
+
fi
|
|
61
|
+
else
|
|
62
|
+
warn "No source directory found, skipping health check check"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
# Graceful Shutdown
|
|
67
|
+
# ---------------------------------------------------------------------------
|
|
68
|
+
echo ""
|
|
69
|
+
echo "--- Graceful Shutdown ---"
|
|
70
|
+
SHUTDOWN_HANDLERS=0
|
|
71
|
+
if [ -d "$SRC_DIR" ]; then
|
|
72
|
+
SHUTDOWN_HANDLERS=$(find "$SRC_DIR" -type f \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" \
|
|
73
|
+
-exec grep -lE "process\.on\(['\"]SIG(TERM|INT)['\"]" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
74
|
+
if [ "$SHUTDOWN_HANDLERS" -gt 0 ]; then
|
|
75
|
+
pass "Graceful shutdown handlers found ($SHUTDOWN_HANDLERS files)"
|
|
76
|
+
else
|
|
77
|
+
warn "No SIGTERM/SIGINT handlers detected"
|
|
78
|
+
fi
|
|
79
|
+
else
|
|
80
|
+
warn "No source directory found, skipping shutdown check"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# ---------------------------------------------------------------------------
|
|
84
|
+
# Metrics
|
|
85
|
+
# ---------------------------------------------------------------------------
|
|
86
|
+
echo ""
|
|
87
|
+
echo "--- Metrics ---"
|
|
88
|
+
METRICS_LIBS=0
|
|
89
|
+
if [ -d "$SRC_DIR" ]; then
|
|
90
|
+
METRICS_LIBS=$(find "$SRC_DIR" -type f \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" \
|
|
91
|
+
-exec grep -lE "(prom-client|@opentelemetry|statsd|hot-shots|dd-trace)" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
92
|
+
if [ "$METRICS_LIBS" -gt 0 ]; then
|
|
93
|
+
pass "Metrics/observability libraries detected ($METRICS_LIBS files)"
|
|
94
|
+
else
|
|
95
|
+
warn "No metrics libraries (prom-client, OpenTelemetry, statsd) detected"
|
|
96
|
+
fi
|
|
97
|
+
else
|
|
98
|
+
warn "No source directory found, skipping metrics check"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# ---------------------------------------------------------------------------
|
|
102
|
+
# Error Handling
|
|
103
|
+
# ---------------------------------------------------------------------------
|
|
104
|
+
echo ""
|
|
105
|
+
echo "--- Error Handling ---"
|
|
106
|
+
ERROR_PATTERNS=0
|
|
107
|
+
if [ -d "$SRC_DIR" ]; then
|
|
108
|
+
# Check for try/catch blocks
|
|
109
|
+
TRY_CATCH=$(find "$SRC_DIR" -type f \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" \
|
|
110
|
+
-exec grep -lE "try\s*\{" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
111
|
+
# Check for error middleware (Express-style)
|
|
112
|
+
ERROR_MIDDLEWARE=$(find "$SRC_DIR" -type f \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" \
|
|
113
|
+
-exec grep -lE "error.*:.*Error.*req.*res" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
114
|
+
ERROR_PATTERNS=$((TRY_CATCH + ERROR_MIDDLEWARE))
|
|
115
|
+
if [ "$ERROR_PATTERNS" -gt 0 ]; then
|
|
116
|
+
pass "Error handling patterns found ($ERROR_PATTERNS files with try/catch or error middleware)"
|
|
117
|
+
else
|
|
118
|
+
warn "No error handling patterns detected"
|
|
119
|
+
fi
|
|
120
|
+
else
|
|
121
|
+
warn "No source directory found, skipping error handling check"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# ---------------------------------------------------------------------------
|
|
125
|
+
# Configuration
|
|
126
|
+
# ---------------------------------------------------------------------------
|
|
127
|
+
echo ""
|
|
128
|
+
echo "--- Configuration ---"
|
|
129
|
+
CONFIG_FOUND=0
|
|
130
|
+
if [ -d "$SRC_DIR" ]; then
|
|
131
|
+
CONFIG_FOUND=$(find "$SRC_DIR" -type f \( -name "*.ts" -o -name "*.tsx" \) -not -path "*/node_modules/*" \
|
|
132
|
+
-exec grep -lE "(dotenv|require\(['\"]config['\"]\)|process\.env)" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
133
|
+
if [ "$CONFIG_FOUND" -gt 0 ]; then
|
|
134
|
+
pass "Configuration management detected ($CONFIG_FOUND files with dotenv/config/process.env)"
|
|
135
|
+
else
|
|
136
|
+
warn "No configuration management patterns detected (dotenv, config, process.env)"
|
|
137
|
+
fi
|
|
138
|
+
else
|
|
139
|
+
warn "No source directory found, skipping configuration check"
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# ---------------------------------------------------------------------------
|
|
143
|
+
# Summary
|
|
144
|
+
# ---------------------------------------------------------------------------
|
|
145
|
+
echo ""
|
|
146
|
+
echo "============================================"
|
|
147
|
+
echo " Summary"
|
|
148
|
+
echo "============================================"
|
|
149
|
+
echo -e " Passed: ${GREEN}${PASS_COUNT}${NC}"
|
|
150
|
+
echo -e " Failed: ${RED}${#ERRORS[@]}${NC}"
|
|
151
|
+
echo ""
|
|
152
|
+
|
|
153
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
154
|
+
echo "FAILURES:"
|
|
155
|
+
for err in "${ERRORS[@]}"; do
|
|
156
|
+
echo " - $err"
|
|
157
|
+
done
|
|
158
|
+
exit 1
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
echo -e "${GREEN}Operations validation passed.${NC}"
|
|
162
|
+
exit 0
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# validate-security.sh — TypeScript
|
|
4
|
+
# ============================================================================
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
PASS_COUNT=0; ERRORS=(); WARNINGS=()
|
|
8
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
9
|
+
pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
10
|
+
fail() { echo -e "${RED}❌ FAIL${NC} $1"; ERRORS+=("$1"); }
|
|
11
|
+
warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARNINGS+=("$1"); }
|
|
12
|
+
|
|
13
|
+
echo "============================================"
|
|
14
|
+
echo " Security Validation (TypeScript)"
|
|
15
|
+
echo "============================================"
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
# Detect package manager
|
|
19
|
+
PKG_MGR=""
|
|
20
|
+
if [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
|
|
21
|
+
PKG_MGR="bun"
|
|
22
|
+
elif [ -f "yarn.lock" ]; then
|
|
23
|
+
PKG_MGR="yarn"
|
|
24
|
+
elif [ -f "package-lock.json" ]; then
|
|
25
|
+
PKG_MGR="npm"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# Hardcoded Secrets
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
echo "--- Hardcoded Secrets ---"
|
|
32
|
+
SECRET_COUNT=0
|
|
33
|
+
for ext in ts tsx; do
|
|
34
|
+
COUNT=$(find . -name "*.$ext" -not -path "./node_modules/*" -not -path "./.next/*" -not -path "./dist/*" \
|
|
35
|
+
-exec grep -E "(apiKey|api_key|apiKey|secret|password|token|privateKey)\s*[:=]\s*['\"][^'\"]{8,}['\"]" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
36
|
+
SECRET_COUNT=$((SECRET_COUNT + COUNT))
|
|
37
|
+
done
|
|
38
|
+
if [ "$SECRET_COUNT" -eq 0 ]; then
|
|
39
|
+
pass "No hardcoded secrets detected"
|
|
40
|
+
else
|
|
41
|
+
fail "Potential hardcoded secrets found ($SECRET_COUNT occurrences)"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
# SQL/NoSQL Injection
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
echo ""
|
|
48
|
+
echo "--- SQL/NoSQL Injection ---"
|
|
49
|
+
INJECTION_PATTERNS=0
|
|
50
|
+
for ext in ts tsx; do
|
|
51
|
+
# Template literals used with query/exec calls
|
|
52
|
+
COUNT=$(find . -name "*.$ext" -not -path "./node_modules/*" -not -path "./.next/*" -not -path "./dist/*" \
|
|
53
|
+
-exec grep -E "\.(query|exec)\(\s*\`" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
54
|
+
INJECTION_PATTERNS=$((INJECTION_PATTERNS + COUNT))
|
|
55
|
+
done
|
|
56
|
+
if [ "$INJECTION_PATTERNS" -eq 0 ]; then
|
|
57
|
+
pass "No SQL/NoSQL injection patterns detected"
|
|
58
|
+
else
|
|
59
|
+
warn "Potential injection patterns found ($INJECTION_PATTERNS template literal queries — review manually)"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# Dependency Audit
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
echo ""
|
|
66
|
+
echo "--- Dependency Audit ---"
|
|
67
|
+
if [ "$PKG_MGR" = "bun" ] && command -v bun &>/dev/null; then
|
|
68
|
+
AUDIT_OUT=$(bun audit 2>&1 || true)
|
|
69
|
+
CRITICAL=$(echo "$AUDIT_OUT" | grep -ci "critical" 2>/dev/null || echo "0")
|
|
70
|
+
HIGH=$(echo "$AUDIT_OUT" | grep -ci "high" 2>/dev/null || echo "0")
|
|
71
|
+
if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then
|
|
72
|
+
fail "Dependency audit found critical/high vulnerabilities"
|
|
73
|
+
else
|
|
74
|
+
pass "No critical/high vulnerabilities in dependencies"
|
|
75
|
+
fi
|
|
76
|
+
elif command -v npm &>/dev/null; then
|
|
77
|
+
AUDIT_OUT=$(npm audit 2>&1 || true)
|
|
78
|
+
if echo "$AUDIT_OUT" | grep -q "found 0 vulnerabilities" 2>/dev/null; then
|
|
79
|
+
pass "No vulnerabilities in dependencies"
|
|
80
|
+
else
|
|
81
|
+
CRITICAL_HIGH=$(echo "$AUDIT_OUT" | grep -iE "(critical|high).*vulnerab" 2>/dev/null | head -1 || true)
|
|
82
|
+
if [ -n "$CRITICAL_HIGH" ]; then
|
|
83
|
+
fail "Dependency audit found critical/high vulnerabilities"
|
|
84
|
+
else
|
|
85
|
+
pass "No critical/high vulnerabilities in dependencies"
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
else
|
|
89
|
+
warn "No package manager available for dependency audit"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# ---------------------------------------------------------------------------
|
|
93
|
+
# eval / Dangerous Patterns
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
echo ""
|
|
96
|
+
echo "--- eval / Dangerous Patterns ---"
|
|
97
|
+
DANGEROUS_COUNT=0
|
|
98
|
+
for ext in ts tsx; do
|
|
99
|
+
COUNT=$(find . -name "*.$ext" -not -path "./node_modules/*" -not -path "./.next/*" -not -path "./dist/*" \
|
|
100
|
+
-exec grep -E "(eval\(|innerHTML\s*=|dangerouslySetInnerHTML)" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
101
|
+
DANGEROUS_COUNT=$((DANGEROUS_COUNT + COUNT))
|
|
102
|
+
done
|
|
103
|
+
if [ "$DANGEROUS_COUNT" -eq 0 ]; then
|
|
104
|
+
pass "No dangerous patterns (eval/innerHTML/dangerouslySetInnerHTML) found"
|
|
105
|
+
else
|
|
106
|
+
warn "Dangerous patterns detected ($DANGEROUS_COUNT occurrences — review for XSS risk)"
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# XSS Prevention
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
echo ""
|
|
113
|
+
echo "--- XSS Prevention ---"
|
|
114
|
+
SANITIZE_LIBS=0
|
|
115
|
+
for ext in ts tsx; do
|
|
116
|
+
COUNT=$(find . -name "*.$ext" -not -path "./node_modules/*" -not -path "./.next/*" -not -path "./dist/*" \
|
|
117
|
+
-exec grep -lE "(DOMPurify|sanitize-html|xss|sanitize)" {} + 2>/dev/null | wc -l | tr -d ' ')
|
|
118
|
+
SANITIZE_LIBS=$((SANITIZE_LIBS + COUNT))
|
|
119
|
+
done
|
|
120
|
+
if [ "$SANITIZE_LIBS" -gt 0 ]; then
|
|
121
|
+
pass "Sanitization libraries detected ($SANITIZE_LIBS files)"
|
|
122
|
+
else
|
|
123
|
+
# Only warn if there are TSX files (likely has JSX/DOM rendering)
|
|
124
|
+
TSX_COUNT=$(find . -name "*.tsx" -not -path "./node_modules/*" -not -path "./.next/*" -not -path "./dist/*" 2>/dev/null | wc -l | tr -d ' ')
|
|
125
|
+
if [ "$TSX_COUNT" -gt 0 ]; then
|
|
126
|
+
warn "No sanitization library found in TSX files (consider DOMPurify or sanitize-html)"
|
|
127
|
+
else
|
|
128
|
+
pass "No TSX files, sanitization not applicable"
|
|
129
|
+
fi
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# ---------------------------------------------------------------------------
|
|
133
|
+
# HTTPS Enforcement
|
|
134
|
+
# ---------------------------------------------------------------------------
|
|
135
|
+
echo ""
|
|
136
|
+
echo "--- HTTPS Enforcement ---"
|
|
137
|
+
HTTP_ONLY=0
|
|
138
|
+
for ext in ts tsx; do
|
|
139
|
+
COUNT=$(find . -name "*.$ext" -not -path "./node_modules/*" -not -path "./.next/*" -not -path "./dist/*" \
|
|
140
|
+
-exec grep -E "['\"]http://(?!localhost)" {} + 2>/dev/null | grep -ivE "(test|spec|mock|example|dev)" | wc -l | tr -d ' ')
|
|
141
|
+
HTTP_ONLY=$((HTTP_ONLY + COUNT))
|
|
142
|
+
done
|
|
143
|
+
if [ "$HTTP_ONLY" -eq 0 ]; then
|
|
144
|
+
pass "No hardcoded HTTP URLs (non-localhost) found"
|
|
145
|
+
else
|
|
146
|
+
warn "Hardcoded HTTP URLs detected ($HTTP_ONLY occurrences — use HTTPS for production)"
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
# Summary
|
|
151
|
+
# ---------------------------------------------------------------------------
|
|
152
|
+
echo ""
|
|
153
|
+
echo "============================================"
|
|
154
|
+
echo " Summary"
|
|
155
|
+
echo "============================================"
|
|
156
|
+
echo -e " Passed: ${GREEN}${PASS_COUNT}${NC}"
|
|
157
|
+
echo -e " Failed: ${RED}${#ERRORS[@]}${NC}"
|
|
158
|
+
echo ""
|
|
159
|
+
|
|
160
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
161
|
+
echo "FAILURES:"
|
|
162
|
+
for err in "${ERRORS[@]}"; do
|
|
163
|
+
echo " - $err"
|
|
164
|
+
done
|
|
165
|
+
exit 1
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
echo -e "${GREEN}Security validation passed.${NC}"
|
|
169
|
+
exit 0
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# validate-tests.sh — TypeScript
|
|
4
|
+
# ============================================================================
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
PASS_COUNT=0; ERRORS=(); WARNINGS=()
|
|
8
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
9
|
+
pass() { echo -e "${GREEN}✅ PASS${NC} $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
10
|
+
fail() { echo -e "${RED}❌ FAIL${NC} $1"; ERRORS+=("$1"); }
|
|
11
|
+
warn() { echo -e "${YELLOW}⚠️ WARN${NC} $1"; WARNINGS+=("$1"); }
|
|
12
|
+
|
|
13
|
+
echo "============================================"
|
|
14
|
+
echo " Test Validation (TypeScript)"
|
|
15
|
+
echo "============================================"
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
# Detect package manager
|
|
19
|
+
PKG_MGR=""
|
|
20
|
+
if [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
|
|
21
|
+
PKG_MGR="bun"
|
|
22
|
+
elif [ -f "yarn.lock" ]; then
|
|
23
|
+
PKG_MGR="yarn"
|
|
24
|
+
elif [ -f "package-lock.json" ]; then
|
|
25
|
+
PKG_MGR="npm"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# Unit Tests
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
echo "--- Unit Tests ---"
|
|
32
|
+
if [ -d "tests/unit" ] || [ -d "test/unit" ]; then
|
|
33
|
+
UNIT_DIR=""
|
|
34
|
+
if [ -d "tests/unit" ]; then
|
|
35
|
+
UNIT_DIR="tests/unit"
|
|
36
|
+
elif [ -d "test/unit" ]; then
|
|
37
|
+
UNIT_DIR="test/unit"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
if [ "$PKG_MGR" = "bun" ] && command -v bun &>/dev/null; then
|
|
41
|
+
if bun test "$UNIT_DIR" 2>/dev/null; then
|
|
42
|
+
pass "Unit tests passed (bun test)"
|
|
43
|
+
else
|
|
44
|
+
fail "Unit tests failed (bun test)"
|
|
45
|
+
fi
|
|
46
|
+
elif command -v npx &>/dev/null; then
|
|
47
|
+
if npx vitest run "$UNIT_DIR" 2>/dev/null; then
|
|
48
|
+
pass "Unit tests passed (npx vitest)"
|
|
49
|
+
elif npx jest "$UNIT_DIR" 2>/dev/null; then
|
|
50
|
+
pass "Unit tests passed (npx jest)"
|
|
51
|
+
else
|
|
52
|
+
fail "Unit tests failed"
|
|
53
|
+
fi
|
|
54
|
+
else
|
|
55
|
+
warn "No test runner available for unit tests"
|
|
56
|
+
fi
|
|
57
|
+
else
|
|
58
|
+
pass "No unit test directory (skipped)"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# ---------------------------------------------------------------------------
|
|
62
|
+
# Integration Tests
|
|
63
|
+
# ---------------------------------------------------------------------------
|
|
64
|
+
echo ""
|
|
65
|
+
echo "--- Integration Tests ---"
|
|
66
|
+
if [ -d "tests/integration" ] || [ -d "test/integration" ]; then
|
|
67
|
+
INT_DIR=""
|
|
68
|
+
if [ -d "tests/integration" ]; then
|
|
69
|
+
INT_DIR="tests/integration"
|
|
70
|
+
elif [ -d "test/integration" ]; then
|
|
71
|
+
INT_DIR="test/integration"
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
if [ "$PKG_MGR" = "bun" ] && command -v bun &>/dev/null; then
|
|
75
|
+
if bun test "$INT_DIR" 2>/dev/null; then
|
|
76
|
+
pass "Integration tests passed (bun test)"
|
|
77
|
+
else
|
|
78
|
+
fail "Integration tests failed (bun test)"
|
|
79
|
+
fi
|
|
80
|
+
elif command -v npx &>/dev/null; then
|
|
81
|
+
if npx vitest run "$INT_DIR" 2>/dev/null; then
|
|
82
|
+
pass "Integration tests passed (npx vitest)"
|
|
83
|
+
elif npx jest "$INT_DIR" 2>/dev/null; then
|
|
84
|
+
pass "Integration tests passed (npx jest)"
|
|
85
|
+
else
|
|
86
|
+
fail "Integration tests failed"
|
|
87
|
+
fi
|
|
88
|
+
else
|
|
89
|
+
warn "No test runner available for integration tests"
|
|
90
|
+
fi
|
|
91
|
+
else
|
|
92
|
+
pass "No integration test directory (skipped)"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
# Coverage
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
echo ""
|
|
99
|
+
echo "--- Coverage ---"
|
|
100
|
+
if command -v npx &>/dev/null; then
|
|
101
|
+
COVERAGE_OUTPUT=""
|
|
102
|
+
# Try vitest first
|
|
103
|
+
if npx vitest run --coverage 2>&1 | tee /tmp/ts_coverage_output >/dev/null; then
|
|
104
|
+
COVERAGE_OUTPUT=$(cat /tmp/ts_coverage_output)
|
|
105
|
+
fi
|
|
106
|
+
# If vitest didn't produce output, try jest
|
|
107
|
+
if [ -z "$COVERAGE_OUTPUT" ]; then
|
|
108
|
+
npx jest --coverage 2>&1 | tee /tmp/ts_coverage_output >/dev/null || true
|
|
109
|
+
COVERAGE_OUTPUT=$(cat /tmp/ts_coverage_output)
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
if [ -n "$COVERAGE_OUTPUT" ]; then
|
|
113
|
+
# Extract percentage — vitest and jest report differently
|
|
114
|
+
COVERAGE_PCT=$(echo "$COVERAGE_OUTPUT" | grep -iE "(statements|all files).*[0-9]+(\.[0-9]+)?%" | grep -oE '[0-9]+(\.[0-9]+)?%' | head -1 | tr -d '%' || echo "")
|
|
115
|
+
if [ -z "$COVERAGE_PCT" ]; then
|
|
116
|
+
# Fallback: look for any percentage on a TOTAL or All lines
|
|
117
|
+
COVERAGE_PCT=$(echo "$COVERAGE_OUTPUT" | grep -iE "(total|all).*[0-9]+(\.[0-9]+)?%" | grep -oE '[0-9]+(\.[0-9]+)?%' | head -1 | tr -d '%' || echo "")
|
|
118
|
+
fi
|
|
119
|
+
if [ -n "$COVERAGE_PCT" ]; then
|
|
120
|
+
# Compare against 80% threshold
|
|
121
|
+
COVERAGE_INT=$(echo "$COVERAGE_PCT" | cut -d'.' -f1)
|
|
122
|
+
if [ "${COVERAGE_INT:-0}" -ge 80 ]; then
|
|
123
|
+
pass "Coverage: ${COVERAGE_PCT}% (≥ 80%)"
|
|
124
|
+
else
|
|
125
|
+
fail "Coverage: ${COVERAGE_PCT}% (< 80%)"
|
|
126
|
+
fi
|
|
127
|
+
else
|
|
128
|
+
warn "Coverage output parsed but percentage not detected"
|
|
129
|
+
fi
|
|
130
|
+
else
|
|
131
|
+
warn "No coverage tool produced output"
|
|
132
|
+
fi
|
|
133
|
+
rm -f /tmp/ts_coverage_output
|
|
134
|
+
else
|
|
135
|
+
warn "npx not available, skipping coverage"
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
# ---------------------------------------------------------------------------
|
|
139
|
+
# Summary
|
|
140
|
+
# ---------------------------------------------------------------------------
|
|
141
|
+
echo ""
|
|
142
|
+
echo "============================================"
|
|
143
|
+
echo " Summary"
|
|
144
|
+
echo "============================================"
|
|
145
|
+
echo -e " Passed: ${GREEN}${PASS_COUNT}${NC}"
|
|
146
|
+
echo -e " Failed: ${RED}${#ERRORS[@]}${NC}"
|
|
147
|
+
echo ""
|
|
148
|
+
|
|
149
|
+
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
150
|
+
echo "FAILURES:"
|
|
151
|
+
for err in "${ERRORS[@]}"; do
|
|
152
|
+
echo " - $err"
|
|
153
|
+
done
|
|
154
|
+
exit 1
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
echo -e "${GREEN}Test validation passed.${NC}"
|
|
158
|
+
exit 0
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Merge Merge Request / Pull Request
|
|
3
|
+
#
|
|
4
|
+
# Merges the current PR via GitHub CLI when CI checks pass.
|
|
5
|
+
#
|
|
6
|
+
# Usage: bash .pi/scripts/merge-mr.sh --issue-id "issue-github-gitlab-connector"
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
detect_platform() {
|
|
11
|
+
# First: check guardian-manifest.json for repoTool
|
|
12
|
+
if [ -f "guardian-manifest.json" ]; then
|
|
13
|
+
local tool=$(jq -r '.repoTool // ""' guardian-manifest.json 2>/dev/null || echo "")
|
|
14
|
+
if [[ "$tool" == "glab" ]]; then echo "gitlab"; return; fi
|
|
15
|
+
if [[ "$tool" == "gh" ]]; then echo "github"; return; fi
|
|
16
|
+
fi
|
|
17
|
+
# Fallback: check environment or installed CLIs
|
|
18
|
+
if [[ -n "${GIT_PLATFORM:-}" ]]; then
|
|
19
|
+
echo "$GIT_PLATFORM"
|
|
20
|
+
elif command -v gh &>/dev/null && gh auth status &>/dev/null 2>&1; then
|
|
21
|
+
echo "github"
|
|
22
|
+
elif command -v glab &>/dev/null && glab auth status &>/dev/null 2>&1; then
|
|
23
|
+
echo "gitlab"
|
|
24
|
+
else
|
|
25
|
+
echo "none"
|
|
26
|
+
fi
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
ISSUE_ID=""
|
|
30
|
+
|
|
31
|
+
while [[ $# -gt 0 ]]; do
|
|
32
|
+
case $1 in
|
|
33
|
+
--issue-id) ISSUE_ID="$2"; shift 2 ;;
|
|
34
|
+
*) shift ;;
|
|
35
|
+
esac
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
PLATFORM=$(detect_platform)
|
|
39
|
+
BRANCH_NAME="feature/${ISSUE_ID}"
|
|
40
|
+
|
|
41
|
+
if [[ "$PLATFORM" == "none" ]]; then
|
|
42
|
+
echo "No git platform detected. Cannot merge without gh/glab CLI."
|
|
43
|
+
echo "Merge skipped — local only."
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
case "$PLATFORM" in
|
|
48
|
+
github)
|
|
49
|
+
# Find the PR for this branch
|
|
50
|
+
PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --json number -q '.[0].number' 2>/dev/null || echo "")
|
|
51
|
+
|
|
52
|
+
if [[ -z "$PR_NUMBER" ]]; then
|
|
53
|
+
echo "No PR found for branch $BRANCH_NAME"
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Check PR mergeability
|
|
58
|
+
PR_STATE=$(gh pr view "$PR_NUMBER" --json state -q '.state' 2>/dev/null || echo "unknown")
|
|
59
|
+
if [[ "$PR_STATE" == "MERGED" ]]; then
|
|
60
|
+
echo "PR #$PR_NUMBER already merged"
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
if [[ "$PR_STATE" == "CLOSED" ]]; then
|
|
65
|
+
echo "PR #$PR_NUMBER is closed"
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# Attempt merge with squash
|
|
70
|
+
MERGE_RESULT=$(gh pr merge "$PR_NUMBER" --squash --delete-branch 2>&1) || MERGE_RESULT=""
|
|
71
|
+
|
|
72
|
+
if [[ -n "$MERGE_RESULT" ]]; then
|
|
73
|
+
echo "Merged PR #$PR_NUMBER: $MERGE_RESULT"
|
|
74
|
+
# Switch back to main branch
|
|
75
|
+
git checkout main 2>/dev/null || git checkout master 2>/dev/null || true
|
|
76
|
+
git pull origin main 2>/dev/null || git pull origin master 2>/dev/null || true
|
|
77
|
+
else
|
|
78
|
+
echo "Merge failed for PR #$PR_NUMBER" >&2
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
;;
|
|
82
|
+
|
|
83
|
+
gitlab)
|
|
84
|
+
MR_IID=$(glab mr list --source-branch "$BRANCH_NAME" --json iid -q '.[0].iid' 2>/dev/null || echo "")
|
|
85
|
+
|
|
86
|
+
if [[ -z "$MR_IID" ]]; then
|
|
87
|
+
echo "No MR found for branch $BRANCH_NAME"
|
|
88
|
+
exit 0
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
glab mr merge "$MR_IID" --when-pipeline-succeeds 2>&1 || true
|
|
92
|
+
git checkout main 2>/dev/null || git checkout master 2>/dev/null || true
|
|
93
|
+
git pull origin main 2>/dev/null || git pull origin master 2>/dev/null || true
|
|
94
|
+
;;
|
|
95
|
+
esac
|