Add Strategy Pattern for module integration#8
Merged
Conversation
Introduce a polymorphic module system that supports switching between SPM local packages and framework targets via a single typealias. - Add ModuleContract protocol with FrameworkModule and SPMModule implementations - Extract ProjectConfig struct replacing scattered globals in Config.swift - Auto-generate Package.swift files per module (PackageSwiftGenerator) - Auto-generate .xctestplan from module data (TestPlanGenerator) - Enable Tuist bundle accessors (disableBundleAccessors: false) - Enrich ModuleDependency.external with ExternalPackage (URL/version) - Delete 10 manual Package.swift, manual xctestplan, and Bundle+Module files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow per-module strategy selection (SPM or Framework) instead of a global typealias. Restructure helpers into ModuleKit/ for reusability, centralize external package definitions in ExternalPackages.swift, and derive Package.swift productTypes/dependencies from ExternalPackage instances. Add SPM→Framework dependency validation and mixed test aggregation support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…entation Mixed SPM+Framework modules are not viable with Tuist 4.x, so the global typealias Module approach is restored to enforce a single strategy at the type level. Force unwraps in generators are replaced with do/catch for better error messages. All documentation is updated to reflect the current Strategy Pattern architecture. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move SwiftLint script out of ModuleKit (app-specific, not reusable infra) into a TargetScript extension with a sourceTargetScripts() function that both App and FrameworkModule use. Adding a new build phase now requires changing a single function. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Declaring Equatable on imported types in test extensions causes compiler warnings with the FrameworkModule strategy. Moving the conformance to the enum declaration uses synthesized Equatable, which is compatible with both Framework and SPM strategies. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Include ActiveStrategy.swift in the DerivedData cache hash so switching module strategy (Framework ↔ SPM) automatically invalidates stale build artifacts. Add a manual workflow_dispatch to clear CI caches by scope. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Periphery — Dead code detection✅ No unused code detected. |
Code Coverage
Minimum required: 80% |
ModuleAggregation now always uses .testPlans(...) with an auto-generated test plan regardless of the active strategy. This makes the xcodebuild test command strategy-agnostic — CI never needs to change when switching between FrameworkModule and SPMModule. Key fixes: - Add required configurations section to TestPlanGenerator output (xcodebuild silently rejects test plans without it) - Use Path(stringLiteral:) for dynamic string-to-Path conversion - Always return .relevant for coverage mode (driven by test plan) - Update all documentation to reflect SPMModule as current strategy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Periphery — Dead code detection✅ No unused code detected. |
Code Coverage
Minimum required: 80% |
Replace direct FileSystemMock property reads with actor-mediated assertions to eliminate potential data races on @unchecked Sendable mock. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Periphery — Dead code detection✅ No unused code detected. |
The JS template literal broke when the body contained Markdown backticks (e.g. `TestName`), causing SyntaxError. Pass body via process.env instead, matching the pattern used by Periphery and coverage comment steps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Unit & Snapshot Test Results❌ Tests failed.
|
…dition The actor's await suspension point in withCheckedContinuation allowed complete() to fire before the continuation was stored, causing tests to hang indefinitely. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the static `typealias Module = SPMModule` with a runtime-resolved `ModuleStrategy` enum (reads `TUIST_MODULE_STRATEGY` env var) and `ModuleFactory.create(...)` factory method. This allows switching between SPM and Framework strategies at generation time without editing source. - Add `ModuleStrategy.swift` with env var resolution (default: spm) - Add `ModuleFactory` caseless enum as single creation entry point - Update all module declarations to use `ModuleFactory.create(...)` - Update `App` to use `any ModuleContract` instead of concrete `Module` - Fix `TestPlanGenerator` coverage format (`codeCoverage.targets`) - Fix `FrameworkModule.containerPath` to include xcodeproj name - Update `generate.sh` with `--strategy` flag and argument parsing - Update CI workflows to pass module strategy through setup action - Update documentation (Tuist.md, Scripts.md, tuist skill) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Periphery — Dead code detection✅ No unused code detected. |
UI Test Results
These tests failed initially and were retried via |
xcresulttool merge crashes on CI with "unexpected divergence in object put" (Apple CAS database bug). Keep the merge as primary path for a single xcresult artifact, but fall back to independent coverage extraction when it fails: - Try xcresulttool merge first, output merge_ok flag - On success: upload merged xcresult, extract coverage from it - On failure: extract coverage JSON from each xcresult independently, merge at file level (max coveredLines per file), upload both xcresults as separate artifacts with individual download links Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Periphery — Dead code detection✅ No unused code detected. |
Code Coverage
Minimum required: 80% |
Replace untyped [String: Any] dictionaries and JSONSerialization with Encodable structs (TestPlan, TestPlanConfiguration, TestPlanCoverageTarget, etc.) and JSONEncoder with prettyPrinted + sortedKeys. Configuration ID is now auto-generated via UUID. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Framework strategy provides per-module schemes, code coverage in
workspace, and individual module compilation — capabilities not
available with SPM local packages due to Xcode limitations.
Also fixes the app target containerPath in TestPlanGenerator which
was empty ("container:") for SPM, causing a "missing" target in the
test plan coverage configuration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previous references were captured with the simulator set to Spanish, causing localized text mismatches on CI (English-only). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UI Test Results❌ Tests failed.
|
Periphery — Dead code detection✅ No unused code detected. |
Code Coverage
Minimum required: 80% |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ModuleContractprotocol with two implementations —FrameworkModule(framework targets) andSPMModule(SPM local packages with auto-generatedPackage.swift). A globaltypealias ModuleinActiveStrategy.swiftselects the active strategy for all modules. Currently set toSPMModule.ModuleAggregationalways uses.testPlans(...)with an auto-generated.xctestplan, regardless of the active strategy. CI never needs to change when switching strategies.ModuleFileSystem(auto-detects folder structure),ModuleDependency(dependency specification),ModuleAggregation(unified test plan generation),ExternalPackage(external SPM wrapper).PackageSwiftGeneratorandTestPlanGeneratorfor SPM modules, executed at manifest-time duringtuist generate.TargetScript+BuildPhases.swiftextension — single point of change for all source target build phases.ActiveStrategy.swiftto auto-invalidate on strategy change. Addedclear-cachesworkflow for manual cache cleanup. Test command now uses-testPlan Challenge.Test plan
tuist generatesucceeds with SPMModule strategyxcodebuild test -testPlan Challenge)-testPlanflag🤖 Generated with Claude Code