mirror of
https://github.com/ksyasuda/dotfiles.git
synced 2026-02-28 00:22:41 -08:00
update
This commit is contained in:
310
.agents/skills/ios-simulator-skill/scripts/build_and_test.py
Executable file
310
.agents/skills/ios-simulator-skill/scripts/build_and_test.py
Executable file
@@ -0,0 +1,310 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Build and Test Automation for Xcode Projects
|
||||
|
||||
Ultra token-efficient build automation with progressive disclosure via xcresult bundles.
|
||||
|
||||
Features:
|
||||
- Minimal default output (5-10 tokens)
|
||||
- Progressive disclosure for error/warning/log details
|
||||
- Native xcresult bundle support
|
||||
- Clean modular architecture
|
||||
|
||||
Usage Examples:
|
||||
# Build (minimal output)
|
||||
python scripts/build_and_test.py --project MyApp.xcodeproj
|
||||
# Output: Build: SUCCESS (0 errors, 3 warnings) [xcresult-20251018-143052]
|
||||
|
||||
# Get error details
|
||||
python scripts/build_and_test.py --get-errors xcresult-20251018-143052
|
||||
|
||||
# Get warnings
|
||||
python scripts/build_and_test.py --get-warnings xcresult-20251018-143052
|
||||
|
||||
# Get build log
|
||||
python scripts/build_and_test.py --get-log xcresult-20251018-143052
|
||||
|
||||
# Get everything as JSON
|
||||
python scripts/build_and_test.py --get-all xcresult-20251018-143052 --json
|
||||
|
||||
# List recent builds
|
||||
python scripts/build_and_test.py --list-xcresults
|
||||
|
||||
# Verbose mode (for debugging)
|
||||
python scripts/build_and_test.py --project MyApp.xcodeproj --verbose
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Import our modular components
|
||||
from xcode import BuildRunner, OutputFormatter, XCResultCache, XCResultParser
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Build and test Xcode projects with progressive disclosure",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
# Build project (minimal output)
|
||||
python scripts/build_and_test.py --project MyApp.xcodeproj
|
||||
|
||||
# Run tests
|
||||
python scripts/build_and_test.py --project MyApp.xcodeproj --test
|
||||
|
||||
# Get error details from previous build
|
||||
python scripts/build_and_test.py --get-errors xcresult-20251018-143052
|
||||
|
||||
# Get all details as JSON
|
||||
python scripts/build_and_test.py --get-all xcresult-20251018-143052 --json
|
||||
|
||||
# List recent builds
|
||||
python scripts/build_and_test.py --list-xcresults
|
||||
""",
|
||||
)
|
||||
|
||||
# Build/test mode arguments
|
||||
build_group = parser.add_argument_group("Build/Test Options")
|
||||
project_group = build_group.add_mutually_exclusive_group()
|
||||
project_group.add_argument("--project", help="Path to .xcodeproj file")
|
||||
project_group.add_argument("--workspace", help="Path to .xcworkspace file")
|
||||
|
||||
build_group.add_argument("--scheme", help="Build scheme (auto-detected if not specified)")
|
||||
build_group.add_argument(
|
||||
"--configuration",
|
||||
default="Debug",
|
||||
choices=["Debug", "Release"],
|
||||
help="Build configuration (default: Debug)",
|
||||
)
|
||||
build_group.add_argument("--simulator", help="Simulator name (default: iPhone 15)")
|
||||
build_group.add_argument("--clean", action="store_true", help="Clean before building")
|
||||
build_group.add_argument("--test", action="store_true", help="Run tests")
|
||||
build_group.add_argument("--suite", help="Specific test suite to run")
|
||||
|
||||
# Progressive disclosure arguments
|
||||
disclosure_group = parser.add_argument_group("Progressive Disclosure Options")
|
||||
disclosure_group.add_argument(
|
||||
"--get-errors", metavar="XCRESULT_ID", help="Get error details from xcresult"
|
||||
)
|
||||
disclosure_group.add_argument(
|
||||
"--get-warnings", metavar="XCRESULT_ID", help="Get warning details from xcresult"
|
||||
)
|
||||
disclosure_group.add_argument(
|
||||
"--get-log", metavar="XCRESULT_ID", help="Get build log from xcresult"
|
||||
)
|
||||
disclosure_group.add_argument(
|
||||
"--get-all", metavar="XCRESULT_ID", help="Get all details from xcresult"
|
||||
)
|
||||
disclosure_group.add_argument(
|
||||
"--list-xcresults", action="store_true", help="List recent xcresult bundles"
|
||||
)
|
||||
|
||||
# Output options
|
||||
output_group = parser.add_argument_group("Output Options")
|
||||
output_group.add_argument("--verbose", action="store_true", help="Show detailed output")
|
||||
output_group.add_argument("--json", action="store_true", help="Output as JSON")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Initialize cache
|
||||
cache = XCResultCache()
|
||||
|
||||
# Handle list mode
|
||||
if args.list_xcresults:
|
||||
xcresults = cache.list()
|
||||
if args.json:
|
||||
import json
|
||||
|
||||
print(json.dumps(xcresults, indent=2))
|
||||
elif not xcresults:
|
||||
print("No xcresult bundles found")
|
||||
else:
|
||||
print(f"Recent XCResult bundles ({len(xcresults)}):")
|
||||
print()
|
||||
for xc in xcresults:
|
||||
print(f" {xc['id']}")
|
||||
print(f" Created: {xc['created']}")
|
||||
print(f" Size: {xc['size_mb']} MB")
|
||||
print()
|
||||
return 0
|
||||
|
||||
# Handle retrieval modes
|
||||
xcresult_id = args.get_errors or args.get_warnings or args.get_log or args.get_all
|
||||
|
||||
if xcresult_id:
|
||||
xcresult_path = cache.get_path(xcresult_id)
|
||||
|
||||
if not xcresult_path or not xcresult_path.exists():
|
||||
print(f"Error: XCResult bundle not found: {xcresult_id}", file=sys.stderr)
|
||||
print("Use --list-xcresults to see available bundles", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Load cached stderr for progressive disclosure
|
||||
cached_stderr = cache.get_stderr(xcresult_id)
|
||||
parser = XCResultParser(xcresult_path, stderr=cached_stderr)
|
||||
|
||||
# Get errors
|
||||
if args.get_errors:
|
||||
errors = parser.get_errors()
|
||||
if args.json:
|
||||
import json
|
||||
|
||||
print(json.dumps(errors, indent=2))
|
||||
else:
|
||||
print(OutputFormatter.format_errors(errors))
|
||||
return 0
|
||||
|
||||
# Get warnings
|
||||
if args.get_warnings:
|
||||
warnings = parser.get_warnings()
|
||||
if args.json:
|
||||
import json
|
||||
|
||||
print(json.dumps(warnings, indent=2))
|
||||
else:
|
||||
print(OutputFormatter.format_warnings(warnings))
|
||||
return 0
|
||||
|
||||
# Get log
|
||||
if args.get_log:
|
||||
log = parser.get_build_log()
|
||||
if log:
|
||||
print(OutputFormatter.format_log(log))
|
||||
else:
|
||||
print("No build log available", file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# Get all
|
||||
if args.get_all:
|
||||
error_count, warning_count = parser.count_issues()
|
||||
errors = parser.get_errors()
|
||||
warnings = parser.get_warnings()
|
||||
build_log = parser.get_build_log()
|
||||
|
||||
if args.json:
|
||||
import json
|
||||
|
||||
data = {
|
||||
"xcresult_id": xcresult_id,
|
||||
"error_count": error_count,
|
||||
"warning_count": warning_count,
|
||||
"errors": errors,
|
||||
"warnings": warnings,
|
||||
"log_preview": build_log[:1000] if build_log else None,
|
||||
}
|
||||
print(json.dumps(data, indent=2))
|
||||
else:
|
||||
print(f"XCResult: {xcresult_id}")
|
||||
print(f"Errors: {error_count}, Warnings: {warning_count}")
|
||||
print()
|
||||
if errors:
|
||||
print(OutputFormatter.format_errors(errors, limit=10))
|
||||
print()
|
||||
if warnings:
|
||||
print(OutputFormatter.format_warnings(warnings, limit=10))
|
||||
print()
|
||||
if build_log:
|
||||
print("Build Log (last 30 lines):")
|
||||
print(OutputFormatter.format_log(build_log, lines=30))
|
||||
return 0
|
||||
|
||||
# Build/test mode
|
||||
if not args.project and not args.workspace:
|
||||
# Try to auto-detect in current directory
|
||||
cwd = Path.cwd()
|
||||
projects = list(cwd.glob("*.xcodeproj"))
|
||||
workspaces = list(cwd.glob("*.xcworkspace"))
|
||||
|
||||
if workspaces:
|
||||
args.workspace = str(workspaces[0])
|
||||
elif projects:
|
||||
args.project = str(projects[0])
|
||||
else:
|
||||
parser.error("No project or workspace specified and none found in current directory")
|
||||
|
||||
# Initialize builder
|
||||
builder = BuildRunner(
|
||||
project_path=args.project,
|
||||
workspace_path=args.workspace,
|
||||
scheme=args.scheme,
|
||||
configuration=args.configuration,
|
||||
simulator=args.simulator,
|
||||
cache=cache,
|
||||
)
|
||||
|
||||
# Execute build or test
|
||||
if args.test:
|
||||
success, xcresult_id, stderr = builder.test(test_suite=args.suite)
|
||||
else:
|
||||
success, xcresult_id, stderr = builder.build(clean=args.clean)
|
||||
|
||||
if not xcresult_id and not stderr:
|
||||
print("Error: Build/test failed without creating xcresult or error output", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Save stderr to cache for progressive disclosure
|
||||
if xcresult_id and stderr:
|
||||
cache.save_stderr(xcresult_id, stderr)
|
||||
|
||||
# Parse results
|
||||
xcresult_path = cache.get_path(xcresult_id) if xcresult_id else None
|
||||
parser = XCResultParser(xcresult_path, stderr=stderr)
|
||||
error_count, warning_count = parser.count_issues()
|
||||
|
||||
# Format output
|
||||
status = "SUCCESS" if success else "FAILED"
|
||||
|
||||
# Generate hints for failed builds
|
||||
hints = None
|
||||
if not success:
|
||||
errors = parser.get_errors()
|
||||
hints = OutputFormatter.generate_hints(errors)
|
||||
|
||||
if args.verbose:
|
||||
# Verbose mode with error/warning details
|
||||
errors = parser.get_errors() if error_count > 0 else None
|
||||
warnings = parser.get_warnings() if warning_count > 0 else None
|
||||
|
||||
output = OutputFormatter.format_verbose(
|
||||
status=status,
|
||||
error_count=error_count,
|
||||
warning_count=warning_count,
|
||||
xcresult_id=xcresult_id or "N/A",
|
||||
errors=errors,
|
||||
warnings=warnings,
|
||||
)
|
||||
print(output)
|
||||
elif args.json:
|
||||
# JSON mode
|
||||
data = {
|
||||
"success": success,
|
||||
"xcresult_id": xcresult_id or None,
|
||||
"error_count": error_count,
|
||||
"warning_count": warning_count,
|
||||
}
|
||||
if hints:
|
||||
data["hints"] = hints
|
||||
import json
|
||||
|
||||
print(json.dumps(data, indent=2))
|
||||
else:
|
||||
# Minimal mode (default)
|
||||
output = OutputFormatter.format_minimal(
|
||||
status=status,
|
||||
error_count=error_count,
|
||||
warning_count=warning_count,
|
||||
xcresult_id=xcresult_id or "N/A",
|
||||
hints=hints,
|
||||
)
|
||||
print(output)
|
||||
|
||||
# Exit with appropriate code
|
||||
return 0 if success else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user