feat(docs): complete P2.6 type safety cleanup and P2.7 system invariants
P2.6: Type Safety Cleanup - Replaced 'any' return types in vite-plugin.ts with concrete types (UserConfig, transform return type) - Documented TypeScript mixin 'any[]' exception in PlatformServiceMixin.ts - Audit confirmed: zero 'any' in codebase except documented TS mixin limitation - All external boundaries use 'unknown', all data payloads use 'Record<string, unknown>' P2.7: System Invariants Documentation - Created SYSTEM_INVARIANTS.md documenting all 6 enforced invariants - Added to docs/00-INDEX.md under Policy & Contracts section - Each invariant includes: What, Why, How, Where Progress Docs Updates: - Updated 00-STATUS.md: marked P2.6/P2.7 complete, added type safety invariant note - Updated 01-CHANGELOG-WORK.md: added 2025-12-22 entries for P2.6/P2.7 - Updated 03-TEST-RUNS.md: added P2.6 type safety audit test run - Updated P2-DESIGN.md: marked P2.6 acceptance criteria complete - Updated SYSTEM_INVARIANTS.md: added Type Safety Notes section Baseline Tag: - Created v1.0.11-p0-p1.4-p1.5-p2.6-p2.7-complete TypeScript compilation: ✅ PASSES Build: ✅ PASSES CI: ✅ All checks pass
This commit is contained in:
569
scripts/verify.sh
Executable file
569
scripts/verify.sh
Executable file
@@ -0,0 +1,569 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Daily Notification Plugin - Verification Script
|
||||
#
|
||||
# Single entrypoint to validate the project state.
|
||||
# Used by CI and local development.
|
||||
#
|
||||
# @author Matthew Raymer
|
||||
# @version 1.0.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# Counters
|
||||
PASSED=0
|
||||
FAILED=0
|
||||
SKIPPED=0
|
||||
|
||||
# Logging functions
|
||||
print_header() {
|
||||
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
echo -e "${BLUE}$1${NC}"
|
||||
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
|
||||
}
|
||||
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✓${NC} $1"
|
||||
((PASSED++))
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}✗${NC} $1"
|
||||
((FAILED++))
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠${NC} $1"
|
||||
((SKIPPED++))
|
||||
}
|
||||
|
||||
# Check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Run command and capture result
|
||||
run_check() {
|
||||
local name="$1"
|
||||
shift
|
||||
print_info "Checking: $name"
|
||||
|
||||
# Capture output for debugging on failure
|
||||
local output
|
||||
output=$("$@" 2>&1)
|
||||
local exit_code=$?
|
||||
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
print_success "$name"
|
||||
return 0
|
||||
else
|
||||
print_error "$name"
|
||||
# Print captured output on failure for debugging
|
||||
echo ""
|
||||
echo "Command output:"
|
||||
echo "$output" | head -20
|
||||
if [ $(echo "$output" | wc -l) -gt 20 ]; then
|
||||
echo "... (truncated, showing first 20 lines)"
|
||||
fi
|
||||
echo ""
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Print environment diagnostics
|
||||
print_environment() {
|
||||
print_header "Environment Diagnostics"
|
||||
|
||||
echo "Project Root: $PROJECT_ROOT"
|
||||
echo "Script Directory: $SCRIPT_DIR"
|
||||
echo ""
|
||||
|
||||
# Node.js
|
||||
if command_exists node; then
|
||||
echo "Node.js: $(node --version)"
|
||||
else
|
||||
echo "Node.js: ❌ Not found"
|
||||
fi
|
||||
|
||||
# npm
|
||||
if command_exists npm; then
|
||||
echo "npm: $(npm --version)"
|
||||
else
|
||||
echo "npm: ❌ Not found"
|
||||
fi
|
||||
|
||||
# Java (for Android)
|
||||
if command_exists java; then
|
||||
echo "Java: $(java -version 2>&1 | head -n 1)"
|
||||
else
|
||||
echo "Java: ⚠ Not found (Android builds may fail)"
|
||||
fi
|
||||
|
||||
# Gradle (for Android)
|
||||
if command_exists gradle; then
|
||||
echo "Gradle: $(gradle --version 2>&1 | grep 'Gradle' | head -n 1 || echo 'Unknown')"
|
||||
else
|
||||
echo "Gradle: ⚠ Not found (using wrapper)"
|
||||
fi
|
||||
|
||||
# Swift (for iOS)
|
||||
if command_exists swift; then
|
||||
echo "Swift: $(swift --version 2>&1 | head -n 1)"
|
||||
else
|
||||
echo "Swift: ⚠ Not found (iOS builds may fail)"
|
||||
fi
|
||||
|
||||
# xcodebuild (for iOS)
|
||||
if command_exists xcodebuild; then
|
||||
echo "xcodebuild: $(xcodebuild -version 2>&1 | head -n 1)"
|
||||
else
|
||||
echo "xcodebuild: ⚠ Not found (iOS builds may fail)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Install dependencies (best effort)
|
||||
install_dependencies() {
|
||||
print_header "Installing Dependencies"
|
||||
|
||||
if [ ! -d "$PROJECT_ROOT/node_modules" ]; then
|
||||
print_info "Installing npm dependencies..."
|
||||
cd "$PROJECT_ROOT"
|
||||
npm install || print_warning "npm install failed (non-blocking)"
|
||||
else
|
||||
print_success "Dependencies already installed"
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
# TypeScript checks
|
||||
check_typescript() {
|
||||
print_header "TypeScript Checks"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Type check
|
||||
if run_check "TypeScript compilation" npm run typecheck; then
|
||||
:
|
||||
else
|
||||
print_error "TypeScript type checking failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Lint
|
||||
if run_check "ESLint" npm run lint; then
|
||||
:
|
||||
else
|
||||
print_warning "ESLint found issues (non-blocking)"
|
||||
fi
|
||||
|
||||
# Unit tests (if present)
|
||||
if [ -f "$PROJECT_ROOT/package.json" ] && grep -q '"test"' "$PROJECT_ROOT/package.json"; then
|
||||
if run_check "Unit tests" npm test; then
|
||||
:
|
||||
else
|
||||
print_warning "Unit tests failed (non-blocking)"
|
||||
fi
|
||||
else
|
||||
print_warning "No unit tests configured"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Build checks
|
||||
check_build() {
|
||||
print_header "Build Checks"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Run build
|
||||
if run_check "npm run build" npm run build; then
|
||||
:
|
||||
else
|
||||
print_error "Build failed - this will break publish"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify dist/ exists
|
||||
if [ ! -d "$PROJECT_ROOT/dist" ]; then
|
||||
print_error "dist/ directory not found after build"
|
||||
return 1
|
||||
else
|
||||
print_success "dist/ directory exists"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Package checks
|
||||
check_package() {
|
||||
print_header "Package Checks"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Run npm pack --dry-run
|
||||
print_info "Running npm pack --dry-run..."
|
||||
PACK_OUTPUT=$(npm pack --dry-run 2>&1)
|
||||
PACK_EXIT=$?
|
||||
|
||||
if [ $PACK_EXIT -ne 0 ]; then
|
||||
print_error "npm pack --dry-run failed"
|
||||
echo "$PACK_OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract file list from pack output (handle both "===" and plain "Tarball Contents" formats)
|
||||
# Only include actual file entries (lines starting with size like "556B", "1.1kB", etc.)
|
||||
# This excludes metadata lines like "filename: ... .tgz" from Tarball Details section
|
||||
PACK_FILES=$(echo "$PACK_OUTPUT" | grep -A 10000 -E "npm notice === Tarball Contents ===|npm notice Tarball Contents" | grep "npm notice" | sed 's/npm notice //' | grep -v "^===" | grep -v "^Tarball Contents$" | grep -E '^[0-9]')
|
||||
|
||||
# If still empty, try alternative format (without "===" header)
|
||||
if [ -z "$PACK_FILES" ]; then
|
||||
# Extract only file entries (lines starting with size pattern)
|
||||
PACK_FILES=$(echo "$PACK_OUTPUT" | grep "npm notice" | sed 's/npm notice //' | grep -E '^[0-9]' | grep -v "^package size:" | grep -v "^$")
|
||||
fi
|
||||
|
||||
# If still empty, fallback to all npm notice lines (but exclude known metadata)
|
||||
if [ -z "$PACK_FILES" ]; then
|
||||
PACK_FILES=$(echo "$PACK_OUTPUT" | grep "npm notice" | sed 's/npm notice //' | grep -v "^package size:" | grep -v "^name:" | grep -v "^version:" | grep -v "^filename:" | grep -v "^shasum:" | grep -v "^integrity:" | grep -v "^total files:" | grep -v "^$")
|
||||
fi
|
||||
|
||||
# Check for required files
|
||||
if echo "$PACK_FILES" | grep -q "CapacitorDailyNotification.podspec"; then
|
||||
print_success "Podspec included in package"
|
||||
else
|
||||
print_error "Podspec missing from package (check package.json 'files' field)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if echo "$PACK_FILES" | grep -q "dist/"; then
|
||||
print_success "dist/ included in package"
|
||||
else
|
||||
print_error "dist/ missing from package"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if echo "$PACK_FILES" | grep -q "android/"; then
|
||||
print_success "android/ included in package"
|
||||
else
|
||||
print_warning "android/ not in package (may be intentional)"
|
||||
fi
|
||||
|
||||
if echo "$PACK_FILES" | grep -q "ios/"; then
|
||||
print_success "ios/ included in package"
|
||||
else
|
||||
print_warning "ios/ not in package (may be intentional)"
|
||||
fi
|
||||
|
||||
# Check for forbidden files (hard fail)
|
||||
# Patterns: Xcode user state, build artifacts, test apps, editor temp files, macOS junk
|
||||
FORBIDDEN_PATTERNS="xcuserdata/|\.xcuserstate|DerivedData/|\.tgz|ios/App/|\.DS_Store|\.swp|\.swo|\.orig|\.rej"
|
||||
FORBIDDEN_FOUND=$(echo "$PACK_FILES" | grep -E "$FORBIDDEN_PATTERNS" || true)
|
||||
|
||||
if [ -n "$FORBIDDEN_FOUND" ]; then
|
||||
print_error "Forbidden files found in package (update package.json 'files' field):"
|
||||
echo "$FORBIDDEN_FOUND" | while read -r line; do
|
||||
echo " - $line"
|
||||
done
|
||||
print_info "Fix: Tighten package.json 'files' field to exclude ios/App/ and Xcode user state files"
|
||||
print_info "Or add to .npmignore: **/xcuserdata/**, **/*.xcuserstate, **/DerivedData/**, ios/App/**, .DS_Store, *.swp, *.swo, *.orig, *.rej"
|
||||
return 1
|
||||
else
|
||||
print_success "No forbidden files (xcuserdata, xcuserstate, DerivedData, ios/App/, .DS_Store, editor temp files) in package"
|
||||
fi
|
||||
|
||||
# Check for unwanted files (warnings)
|
||||
if echo "$PACK_FILES" | grep -q "test-apps/"; then
|
||||
print_warning "test-apps/ found in package (should be excluded)"
|
||||
fi
|
||||
|
||||
if echo "$PACK_FILES" | grep -q "docs/"; then
|
||||
print_warning "docs/ found in package (should be excluded)"
|
||||
fi
|
||||
|
||||
if echo "$PACK_FILES" | grep -q "node_modules/"; then
|
||||
print_warning "node_modules/ found in package (should be excluded)"
|
||||
fi
|
||||
|
||||
# Print package manifest summary (first 20 lines)
|
||||
print_info "Package manifest summary (showing first 20 of $(echo "$PACK_FILES" | wc -l) files):"
|
||||
echo "$PACK_FILES" | head -20 | while read -r line; do
|
||||
echo " $line"
|
||||
done
|
||||
TOTAL_FILES=$(echo "$PACK_FILES" | wc -l)
|
||||
if [ "$TOTAL_FILES" -gt 20 ]; then
|
||||
print_info "... and $((TOTAL_FILES - 20)) more files"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Android checks (best effort)
|
||||
check_android() {
|
||||
print_header "Android Checks"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
if [ ! -d "$PROJECT_ROOT/android" ]; then
|
||||
print_warning "Android directory not found, skipping Android checks"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! command_exists java; then
|
||||
print_warning "Java not found, skipping Android build checks"
|
||||
return 0
|
||||
fi
|
||||
|
||||
cd "$PROJECT_ROOT/android"
|
||||
|
||||
# Check if gradlew exists
|
||||
if [ ! -f "$PROJECT_ROOT/android/gradlew" ]; then
|
||||
print_warning "gradlew not found, skipping Android build"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Try to run a minimal gradle task
|
||||
if run_check "Android build (compile)" ./gradlew compileDebugJavaWithJavac --no-daemon; then
|
||||
:
|
||||
else
|
||||
print_warning "Android build check failed (non-blocking)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# iOS checks (best effort)
|
||||
check_ios() {
|
||||
print_header "iOS Checks"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
if [ ! -d "$PROJECT_ROOT/ios" ]; then
|
||||
print_warning "iOS directory not found, skipping iOS checks"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! command_exists xcodebuild; then
|
||||
print_warning "xcodebuild not found, skipping iOS build checks"
|
||||
print_info "Manual iOS build command: cd ios && xcodebuild -workspace DailyNotificationPlugin.xcworkspace -scheme DailyNotificationPlugin -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15' build"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if Podfile exists
|
||||
if [ ! -f "$PROJECT_ROOT/ios/Podfile" ]; then
|
||||
print_warning "Podfile not found, skipping iOS build"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Try to build (best effort, may fail in CI)
|
||||
# Note: Don't use pipe in run_check - it won't work. Capture output separately.
|
||||
cd "$PROJECT_ROOT/ios"
|
||||
BUILD_OUTPUT=$(xcodebuild -workspace DailyNotificationPlugin.xcworkspace -scheme DailyNotificationPlugin -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15' build 2>&1)
|
||||
BUILD_EXIT=$?
|
||||
|
||||
if [ $BUILD_EXIT -eq 0 ]; then
|
||||
print_success "iOS build (compile)"
|
||||
# Show first 10 lines of output for context
|
||||
echo "$BUILD_OUTPUT" | head -10 | while read -r line; do
|
||||
echo " $line"
|
||||
done
|
||||
else
|
||||
print_warning "iOS build check failed (non-blocking - may require manual setup)"
|
||||
print_info "Manual iOS build command: cd ios && xcodebuild -workspace DailyNotificationPlugin.xcworkspace -scheme DailyNotificationPlugin -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15' build"
|
||||
fi
|
||||
|
||||
# Try to run tests (best effort)
|
||||
print_info "Running iOS tests..."
|
||||
TEST_OUTPUT=$(xcodebuild test -workspace DailyNotificationPlugin.xcworkspace -scheme DailyNotificationPlugin -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15' -only-testing:DailyNotificationPluginTests/DailyNotificationRecoveryTests 2>&1)
|
||||
TEST_EXIT=$?
|
||||
|
||||
if [ $TEST_EXIT -eq 0 ]; then
|
||||
print_success "iOS recovery tests passed"
|
||||
# Show test summary if available
|
||||
echo "$TEST_OUTPUT" | grep -E "Test Suite|Test Case|passed|failed" | head -10 | while read -r line; do
|
||||
echo " $line"
|
||||
done
|
||||
else
|
||||
print_warning "iOS tests failed or not available (non-blocking)"
|
||||
print_info "Manual iOS test command: cd ios && xcodebuild test -workspace DailyNotificationPlugin.xcworkspace -scheme DailyNotificationPlugin -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15'"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Check for native code in src/
|
||||
# Check core module source (can run before build)
|
||||
check_core_source() {
|
||||
print_header "Core Module (Source) Checks"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Require core source dir + expected files
|
||||
if [ ! -d "src/core" ]; then
|
||||
print_error "Missing src/core/"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local required=(
|
||||
"src/core/index.ts"
|
||||
"src/core/errors.ts"
|
||||
"src/core/enums.ts"
|
||||
"src/core/events.ts"
|
||||
"src/core/contracts.ts"
|
||||
"src/core/guards.ts"
|
||||
)
|
||||
|
||||
local missing=0
|
||||
for f in "${required[@]}"; do
|
||||
if [ ! -f "$f" ]; then
|
||||
print_error "Missing core file: $f"
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
if [ $missing -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# No platform imports inside core
|
||||
# Block Node builtins, React, Capacitor, and other platform-specific modules
|
||||
local NODE_BUILTINS="(fs|path|os|child_process|crypto|http|https|net|tls|zlib|stream|util|url|worker_threads|perf_hooks|vm)"
|
||||
local bad
|
||||
bad=$(grep -RInE \
|
||||
"(from\s+['\"]|require\s*\(\s*['\"]|import\s*\(\s*['\"])(${NODE_BUILTINS}|react|@capacitor/|capacitor)['\"]" \
|
||||
src/core 2>/dev/null || true)
|
||||
|
||||
if [ -n "$bad" ]; then
|
||||
print_error "Core module contains forbidden platform imports:"
|
||||
echo "$bad" | head -50 | while read -r line; do
|
||||
echo " $line"
|
||||
done
|
||||
echo ""
|
||||
echo "Policy: src/core must not import platform, Node, or framework-specific modules."
|
||||
echo "Move platform-dependent code to src/web/ or platform adapters."
|
||||
return 1
|
||||
fi
|
||||
|
||||
print_success "Core source checks passed"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Check core module build artifacts (must run after build)
|
||||
check_core_artifacts() {
|
||||
print_header "Core Module (Build Artifacts) Checks"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Require build outputs for core
|
||||
local required=(
|
||||
"dist/esm/core/index.js"
|
||||
"dist/esm/core/index.d.ts"
|
||||
)
|
||||
|
||||
local missing=0
|
||||
for f in "${required[@]}"; do
|
||||
if [ ! -f "$f" ]; then
|
||||
print_error "Missing build artifact: $f (did build run?)"
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
if [ $missing -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Require package.json export for ./core
|
||||
if ! node -e "const p=require('./package.json'); if(!p.exports||!p.exports['./core']) process.exit(1);" 2>/dev/null; then
|
||||
print_error "package.json missing exports['./core']"
|
||||
return 1
|
||||
fi
|
||||
|
||||
print_success "Core artifact checks passed"
|
||||
echo ""
|
||||
}
|
||||
|
||||
check_native_code_in_src() {
|
||||
print_header "Checking for Native Code in src/"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Check for Java files
|
||||
if find src/android -name "*.java" -type f 2>/dev/null | grep -q .; then
|
||||
print_error "Found Java files in src/android/ (should be removed)"
|
||||
find src/android -name "*.java" -type f 2>/dev/null | while read -r file; do
|
||||
echo " - $file"
|
||||
done
|
||||
return 1
|
||||
else
|
||||
print_success "No Java files in src/android/"
|
||||
fi
|
||||
|
||||
# Check for Swift/Objective-C files
|
||||
if find src/ios -name "*.swift" -o -name "*.m" -o -name "*.mm" -o -name "*.h" 2>/dev/null | grep -q .; then
|
||||
print_error "Found native code files in src/ios/ (should be removed)"
|
||||
find src/ios -name "*.swift" -o -name "*.m" -o -name "*.mm" -o -name "*.h" 2>/dev/null | while read -r file; do
|
||||
echo " - $file"
|
||||
done
|
||||
return 1
|
||||
else
|
||||
print_success "No native code files in src/ios/"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
print_header "Daily Notification Plugin - Verification"
|
||||
|
||||
print_environment
|
||||
install_dependencies
|
||||
|
||||
run_check "Native code not in src/" check_native_code_in_src
|
||||
|
||||
# Core source checks must be before build
|
||||
run_check "Core module source checks" check_core_source
|
||||
|
||||
run_check "TypeScript typecheck" check_typescript
|
||||
run_check "Build" check_build
|
||||
|
||||
# Core artifacts checks must be after build
|
||||
run_check "Core module artifact checks" check_core_artifacts
|
||||
|
||||
run_check "Package checks" check_package
|
||||
|
||||
check_android
|
||||
check_ios
|
||||
|
||||
# Summary
|
||||
print_header "Verification Summary"
|
||||
echo "Passed: $PASSED"
|
||||
echo "Failed: $FAILED"
|
||||
echo "Skipped: $SKIPPED"
|
||||
echo ""
|
||||
|
||||
if [ $FAILED -eq 0 ]; then
|
||||
print_success "All critical checks passed!"
|
||||
exit 0
|
||||
else
|
||||
print_error "Some checks failed. Review output above."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user