Skip to content

Conversation

@ducbm051291
Copy link
Contributor

@ducbm051291 ducbm051291 commented Dec 3, 2025

What happened 👀

This PR represents a major architectural overhaul of the iOS Template. It migrates the tooling from Tuist 3 to Tuist 4, completely removes CocoaPods in favor of Swift Package Manager (SPM), and deprecates the UIKit interface to focus exclusively on SwiftUI.

Key Changes:

  • Tuist 4 Migration: Updated .tuist-version to 4.110.3 and refactored Project.swift to use the latest ProjectDescription syntax.
  • Dependency Management:
    • Removed Podfile and CocoaPods integration.
    • Introduced Package.swift to manage dependencies (Alamofire, Kingfisher, Firebase, etc.) via SPM.
    • Updated Arkana configuration to use SPM logic.
  • Interface:
    • Deleted all UIKit templates, ViewControllers, and Storyboard logic.
    • Refactored the iOSTemplateMaker script to default to SwiftUI and remove the interface selection prompt.
  • CI/CD:
    • Updated GitHub Actions versions (checkout@v6, cache@v4) to support Node 20.
    • Removed pod install steps from workflows (Bitrise, CodeMagic, GitHub Actions).
    • Added caching strategies for .build (SPM) directories.
  • Cleanup: Removed unused scripts (test_uikit_install_script), extensions, and helpers related to the legacy setup.

Insight 📝

Why this solution?
The iOS ecosystem has shifted significantly. UIKit is now considered legacy for new greenfield projects, and CocoaPods is in maintenance mode. By moving to a SwiftUI + SPM + Tuist 4 stack, we ensure the template generates modern, future-proof projects that are faster to build and easier to maintain.

Architecture Shift:
Previously, Tuist generated a project that relied on a separate pod install step to link binary frameworks. Now, Tuist manages the SPM graph directly, integrating dependencies as native targets within the Xcode project structure.

Refactoring Highlights:

  • Project.swift: Now defines dependencies using .package(url: ...) syntax.
  • Fastlane: Updated to invoke tools like xcbeautify directly from the local environment or Mint/SPM, rather than relying on a Pod-installed binary.

Proof Of Work 📹

Screenshot 2025-12-03 at 14 07 36

Test upload build to firebase successfully now Result

Screenshot 2025-12-03 at 16 42 15

Summary by CodeRabbit

Release Notes

  • New Features

    • Migrated dependency management from CocoaPods to Swift Package Manager (SPM).
    • Upgraded Tuist to version 4.110.3 with updated project generation workflow.
    • SwiftUI-only interface; UIKit scaffolding removed.
  • Improvements

    • Updated Xcode minimum requirement to 15+.
    • Enhanced CI/CD workflows with latest GitHub Actions versions.
    • Simplified project setup using tuist generate instead of CocoaPods installation.

✏️ Tip: You can customize this high-level summary in your review settings.

@ducbm051291 ducbm051291 added this to the 4.12.0 milestone Dec 3, 2025
@ducbm051291 ducbm051291 self-assigned this Dec 3, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 3, 2025

Walkthrough

This pull request upgrades Tuist from version 3.2.0 to 4.110.3 and migrates the project from CocoaPods to Swift Package Manager (SPM). UIKit interface support has been removed entirely, leaving only SwiftUI. GitHub Actions workflows are updated to newer action versions, Firebase Crashlytics integration is removed, and build configuration is adjusted for the new dependency management approach.

Changes

Cohort / File(s) Summary
Tuist Version Upgrade
.tuist-version, .mise.toml
Updated Tuist from 3.2.0 to 4.110.3; introduced mise configuration file to pin Tuist version.
Package Manager Migration: Dependency Declarations
Package.swift, Package.resolved, Project.swift
Added new Package.swift manifest declaring SPM dependencies (Alamofire, Kingfisher, Firebase, etc.); generated Package.resolved with resolved versions; updated Project.swift to reference packages array instead of CocoaPods.
Package Manager Migration: Removed CocoaPods Configuration
Podfile, Tuist/Interfaces/*/Project/Podfile, .arkana.yml, Gemfile
Removed all Podfiles and CocoaPods-related build configuration; updated .arkana.yml package_manager from cocoapods to spm; removed cocoapods gem from Gemfile.
GitHub Actions Workflow Version Updates
.github/project_workflows/*.yml, .github/self_hosted_project_workflows/*.yml, .github/workflows/cleanup_cache.yml
Systematically upgraded GitHub Actions versions: actions/checkout v3→v6, actions/cache v2/v3→v4, actions/upload-artifact v3→v4 across multiple workflows.
GitHub Actions Specific Workflow Updates
.github/workflows/test_upload_build_to_firebase.yml, .github/workflows/test_upload_build_to_test_flight.yml
Added mise-action setup, replaced Pod caching with SPM caching, added environment variables for Fastlane xcodebuild settings.
GitHub Actions Workflow Removals
.github/workflows/test_swiftui_install_script.yml, .github/workflows/test_uikit_install_script.yml
Deleted template test workflows for SwiftUI and UIKit install scripts.
UIKit Interface Removal
Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpInterface.swift, Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/iOSTemplateMaker.swift, Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift
Removed interface parameter and UIKit option; hard-coded interface setup to SwiftUI; enhanced Tuist installation and project generation diagnostics.
UIKit Source Code Removal
Tuist/Interfaces/UIKit/Sources/Application/AppDelegate.swift, Tuist/Interfaces/UIKit/Sources/Presentation/Modules/HomeViewController.swift, Tuist/Interfaces/UIKit/Sources/Presentation/Navigator/Navigator*.swift
Removed entire UIKit application bootstrap logic, view controllers, and navigation protocol/implementation.
Tuist Project Helpers: Dependency & Target Updates
Tuist/ProjectDescriptionHelpers/Target+Initializing.swift, Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift
Replaced module-based targets with direct SPM package products; updated destinations and deploymentTargets syntax; removed framework targets and KIFUITests target generation; simplified test target references.
Tuist Project Helpers: Script & Configuration Removal
Tuist/ProjectDescriptionHelpers/TargetScript+Initializing.swift, Tuist/ProjectDescriptionHelpers/Constant.swift, Tuist/ProjectDescriptionHelpers/Module.swift, Workspace.swift
Removed build scripts for Sourcery, R.swift, SwiftLint, SwiftFormat, Firebase; removed Module enum and Constant path helpers; deleted Workspace helper.
Tuist Project Helpers: Minor Formatting
Tuist/ProjectDescriptionHelpers/BuildConfiguration.swift
Reformatted indentation in path switch without functional changes.
Fastlane Configuration Updates
fastlane/Helpers/Build.swift, fastlane/Helpers/Test.swift
Added project parameter to buildApp; updated xcodebuildFormatter from Pods path to direct xcbeautify reference.
Fastlane Crashlytics Removal
fastlane/Fastfile.swift, fastlane/Helpers/Symbol.swift, fastlane/Constants/Constant.swift
Removed Symbol.uploadToCrashlytics calls from all build lanes; deleted Symbol enum and uploadToCrashlytics function; removed uploadSymbolsBinaryPath constant.
Build System Configuration Migration
.gitignore, Dangerfile
Removed Pods/ ignore rule; added *.xcworkspace ignore rule; replaced workspace references with xcodeproj; updated Dangerfile to use direct tool executables and project configuration.
CI/CD Platform Configuration
bitrise.yml, codemagic.yaml
Removed cocoapods-install steps and Pod cache mappings; updated BITRISE_PROJECT_PATH from xcworkspace to xcodeproj across workflows.
Code Generators & Extensions Cleanup
tools/sourcery/templates/AutoMockable.stencil, {PROJECT_NAME}/Sources/Supports/Extensions/UIKit/*, {PROJECT_NAME}/Sources/Supports/Helpers/Typealiases/Typealiases.swift, {PROJECT_NAME}/Sources/Constants/Constants+API.swift
Removed OS-specific conditional imports from Sourcery template; deleted UIKit color and view utility extensions; removed UIAlertAction typealias; removed ArkanaKeys import.
Documentation & Wiki Updates
README.md, PROJECT_README.md, .github/wiki/Bitrise.md, .github/wiki/CodeMagic.md, .github/wiki/Github-Actions.md, .github/wiki/Project-Dependencies.md
Updated project description to highlight SPM/Tuist 4; increased Xcode requirement to 15+; replaced CocoaPods install step with SPM dependency resolution; updated wiki tables and dependency documentation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • Package.swift and Package.resolved correctness: Verify all dependencies are correctly declared with proper versions and compatible with the project's target architecture and deployment target.
  • Tuist helper logic changes (Target+Initializing.swift, Scheme+Initializing.swift): Confirm the simplified target structure generates valid build configuration and that all necessary targets are created.
  • Build system integration (fastlane/Helpers/Build.swift, xcodebuild formatter changes): Ensure project parameter and formatter changes produce expected build output and don't break existing CI/CD logging.
  • Migration completeness: Verify all CocoaPods/Pods references have been removed from build scripts, CI configurations, and source code (search for remaining "Pods/" or cocoapods references).
  • GitHub Actions workflow correctness: Cross-check all workflow YAML syntax, especially cache paths (now .build instead of Pods) and conditional logic.
  • UIKit removal impact: Confirm no remaining UIKit dependencies or references in SwiftUI templates or configuration helpers.

Poem

🐰 From Pods to Packages, we hopped away,
Tuist 4 guides our SwiftUI day,
Gone is UIKit, workspaces disappear,
SPM dependencies crystal clear! 🌿

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes significant scope creep beyond the Tuist version update: migration from CocoaPods to SPM, removal of UIKit templates, elimination of legacy scripts, and CI/CD workflow updates are substantial architectural changes not directly required by issue #581. Consider splitting this into multiple PRs: one for Tuist version update, one for CocoaPods-to-SPM migration, and one for template simplification, to isolate changes and facilitate focused review.
Docstring Coverage ⚠️ Warning Docstring coverage is 5.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[#581] Update the Tuist to the latest version' directly and specifically summarizes the main objective of this changeset.
Linked Issues check ✅ Passed The PR successfully implements the primary objective from issue #581 by upgrading Tuist from 3.2.0 to 4.110.3, ensuring template stability and enabling Tuist 4 features.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/581-update-tuist-to-latest-version

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ducbm051291 ducbm051291 force-pushed the feature/581-update-tuist-to-latest-version branch 2 times, most recently from 54d9c5c to 2c1de03 Compare December 3, 2025 07:33
- Update other gems
- Finish SwiftUI/SPM migration and cleanup
- drop leftover UIKit helpers and simplify Sourcery template
- move Tuist packages into Project.swift and switch targets to `.package`
- remove workspace deletion; open project directly; add documentation for dependencies
- clean README/wiki/CI configs to reflect SwiftUI + SPM-only setup
- delete CocoaPods gems/steps, adjust Danger/Fastlane scripts, update Fastlane constants
- remove Podfiles, UIKit files, and add guidance for Crashlytics upload script
Remove interface
- Add a step to use mise (jdx/mise-action@v3) to install tuist 4.110.3 in all GitHub Actions workflows
Set the project path to Fastlane build
Remove test_install_script
Configure Fastlane setting timeour and retries
Remove upload symbol
@ducbm051291 ducbm051291 force-pushed the feature/581-update-tuist-to-latest-version branch from 165843e to a3bef6a Compare December 3, 2025 08:58
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
.github/self_hosted_project_workflows/automatic_pull_request_review.yml (1)

41-51: Remove CocoaPods caching and installation steps—incompatible with SPM project.

Lines 41–51 contain CocoaPods cache and pod install steps that reference a non-existent Podfile.lock. The repository uses SPM (Package.swift exists) and has no CocoaPods configuration. These steps will fail on self-hosted runners and should be removed or replaced with SPM-appropriate alternatives (e.g., caching the .build directory).

This issue also exists in .github/project_workflows/automatic_pull_request_review.yml and should be removed from both files.

Remove the CocoaPods steps:

-    - name: Cache Pods
-      uses: actions/cache@v4
-      id: cocoapodCache
-      with:
-        path: Pods
-        key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-pods-
-
-    - name: Install Pods Dependencies
-      run: bundle exec pod install
.github/project_workflows/automatic_pull_request_review.yml (1)

41-51: Remove CocoaPods caching and installation steps—incompatible with Tuist/SPM project setup.

The project documentation (PROJECT_README.md) shows dependencies are now managed via tuist generate, not CocoaPods. Lines 41–51 reference outdated CocoaPods workflows (Podfile.lock and pod install) that no longer exist in this Tuist-based project. The workflow will fail attempting to cache and install non-existent Pod dependencies.

Remove these steps:

-    - name: Cache Pods
-      uses: actions/cache@v4
-      id: cocoapodCache
-      with:
-        path: Pods
-        key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-pods-
-
-    - name: Install Pods Dependencies
-      run: bundle exec pod install

If Tuist build caching is needed, add a .build directory cache step instead.

Minor: Line 21 has a typo—bunlderCache should be bundlerCache.

.github/self_hosted_project_workflows/deploy_staging_firebase.yml (1)

23-39: Remove CocoaPods caching and installation from staging Firebase workflow

This workflow retains CocoaPods cache and install steps (lines 72–82) despite the template now generating SPM-only projects. With Podfile.lock no longer present, the cache key will not resolve and bundle exec pod install will fail. Remove:

  • Lines 72–80: Cache Pods step
  • Lines 81–82: Install Pods Dependencies step
.github/self_hosted_project_workflows/deploy_production_firebase.yml (1)

23-39: Self-hosted production workflow still depends on CocoaPods while template is SPM-only

The action version bumps are correct, but this workflow still caches Pods using Podfile.lock (lines 66-73) and runs bundle exec pod install (line 76).

Since the template no longer generates Podfiles and is documented as SPM-only, these steps will break for new projects—the cache will always miss due to missing Podfile.lock, and pod install will fail. Replace these with SPM-aware caching (e.g., .build or DerivedData) or remove them entirely if Fastlane lanes already handle SPM resolution.

This issue appears in all self-hosted workflows: deploy_staging_firebase.yml, deploy_app_store.yml, and automatic_pull_request_review.yml.

.github/self_hosted_project_workflows/deploy_app_store.yml (1)

25-43: App Store self‑hosted workflow still contains CocoaPods assumptions

This workflow caches Pods based on Podfile.lock (lines 62–70) and runs bundle exec pod install (line 72). Once projects are generated as SPM-only, these steps will fail or be redundant since there will be no Podfile to operate on. Align this workflow with the SPM setup by removing CocoaPods steps and replacing with SPM/DerivedData caching if needed.

The same issue appears across multiple workflows: deploy_staging_firebase.yml:82, deploy_production_firebase.yml:76, and automatic_pull_request_review.yml:51.

.github/project_workflows/deploy_production_firebase.yml (1)

72-83: Remove CocoaPods steps from all workflows.

The "Cache Pods" (lines 72-73) and "Install Pods Dependencies" (lines 82-83) steps will fail because Podfile and the Pods directory have been removed. These steps also appear in deploy_staging_firebase.yml, deploy_app_store.yml, automatic_pull_request_review.yml, and their self_hosted_project_workflows equivalents—all require removal to complete the CocoaPods-to-SPM migration.

🧹 Nitpick comments (9)
fastlane/Helpers/Symbol.swift (1)

9-11: Empty file does not preserve API; consider a deprecated stub Symbol helper

Right now the file only contains comments, so any existing Symbol.uploadToCrashlytics usages in customized Fastlane Swift code will fail to compile. If you truly want to “avoid breaking existing references”, consider re‑adding a minimal deprecated stub:

+enum Symbol {
+    @available(*, deprecated, message: "Crashlytics symbol upload is handled by Firebase’s SPM run script. Remove this call.")
+    static func uploadToCrashlytics(environment: Constant.Environment) {
+        // Intentionally left blank (no-op) or call fatalError to surface misuse.
+    }
+}

This keeps the API surface while steering users toward the new Crashlytics integration.

.github/project_workflows/automatic_pull_request_review.yml (1)

20-20: Typo in cache step ID: "bunlderCache" should be "bundlerCache".

This does not affect functionality but inconsistent naming. Consider fixing for consistency.

-      id: bunlderCache
+      id: bundlerCache
.github/self_hosted_project_workflows/automatic_pull_request_review.yml (1)

20-20: Typo in cache step ID: "bunlderCache" should be "bundlerCache".

Identical to the public-facing workflow. Consider fixing for consistency across workflows.

-      id: bunlderCache
+      id: bundlerCache
Project.swift (1)

15-31: SPM package list looks good; consider guarding against drift with root Package.swift

The packages list and Target.makeTargets wiring are consistent with the SPM migration, but the same dependencies (and versions) are now declared in three places: this file, Package.swift, and Package.resolved. It’s easy for one of them to diverge during future bumps.

I’d suggest at least adding a small note here (or a helper) to make that coupling explicit and reduce surprises when updating dependencies later.

-            packages: [
+            packages: [
+                // NOTE: Keep this list in sync with root `Package.swift` and `Package.resolved`.
                 // Backend
                 .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.8.0"),

Also applies to: 36-40

Package.swift (1)

1-37: Root Package.swift is well-structured; monitor NimbleExtension for future tag releases

This manifest cleanly centralizes your SPM dependencies and follows the Tuist integration pattern. The NimbleExtension dependency is currently pinned to the master branch with a specific revision, which provides reasonable stability. However, if this package eventually publishes version tags, consider migrating from branch-based pinning to a semver requirement for more predictable dependency resolution.

.github/workflows/test_upload_build_to_firebase.yml (1)

58-59: Consider adding SPM cache for build performance.

The test_upload_build_to_test_flight.yml workflow includes a "Cache SPM Packages" step caching .build with key based on Package.resolved. This workflow would benefit from the same caching strategy for consistency and faster builds.

     - name: Install tools with mise
       uses: jdx/mise-action@v3

+    - name: Cache SPM Packages
+      uses: actions/cache@v4
+      id: spmCache
+      with:
+        path: .build
+        key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
+        restore-keys: |
+          ${{ runner.os }}-spm-
+
     - name: Start Install Script for Template App
Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpInterface.swift (1)

5-22: Consider simplifying or removing the Interface enum.

With only .swiftUI remaining and the init accepting empty strings as valid, the enum provides limited value. The validation logic (returning nil for unrecognized input) is defensive but may be unnecessary if the interface is always hardcoded to .swiftUI in callers.

If you want to retain extensibility for future interfaces, keep the current structure. Otherwise, consider inlining the folder name directly in perform():

-    enum Interface: Titlable, CaseIterable {
-        case swiftUI
-
-        init?(_ name: String) {
-            let name = name.lowercased()
-            if name == "s" || name == "swiftui" || name.isEmpty {
-                self = .swiftUI
-            } else {
-                return nil
-            }
-        }
-
-        var folderName: String {
-            return "SwiftUI"
-        }
-
-        var title: String { folderName }
-    }
+    private let interfaceFolderName = "SwiftUI"
.github/wiki/Project-Dependencies.md (1)

30-30: Minor style improvement for sentence variety.

The static analysis tool flagged three successive sentences beginning with the same word. Consider rewording for better flow.

-[SwiftLint](https://github.com/realm/SwiftLint) is used to enforce our team's code convention. SwiftLint is the perfect tool for this task as it is customizable, lightweight, and automate-able. CI installs SwiftLint via Homebrew, and Danger runs it directly (no Pods required).
+[SwiftLint](https://github.com/realm/SwiftLint) enforces our team's code convention. This tool is perfect for the task as it is customizable, lightweight, and automate-able. CI installs it via Homebrew, and Danger runs it directly (no Pods required).
Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift (1)

188-245: Consider reducing verbose debug output for cleaner logs.

The extensive debug logging is helpful during development but may be excessive for normal usage. Consider:

  1. Guarding verbose output behind a --verbose flag, or
  2. Reducing to essential status messages only.

For example, the pre/post-generation file existence checks (lines 195-199, 224-228) and ProjectDescriptionHelpers file listing (lines 206-213) could be removed or made conditional:

-        // Check files before generation
-        let projectSwiftExists = fileManager.fileExists(atPath: "Project.swift")
-        let tuistHelpersExists = fileManager.fileExists(atPath: "Tuist/ProjectDescriptionHelpers")
-        print("🔍 Pre-generation check:")
-        print("   Project.swift exists: \(projectSwiftExists)")
-        print("   Tuist/ProjectDescriptionHelpers exists: \(tuistHelpersExists)")
-        
-        // Clean Tuist cache if it exists (might help with compilation issues)
-        print("🧹 Cleaning Tuist cache...")
-        let _ = try? safeShell("tuist clean")
-        
-        // List ProjectDescriptionHelpers files for debugging
-        if tuistHelpersExists {
-            print("📁 ProjectDescriptionHelpers files:")
-            if let helpersFiles = try? fileManager.contentsOfDirectory(atPath: "Tuist/ProjectDescriptionHelpers") {
-                for file in helpersFiles.sorted() {
-                    print("   - \(file)")
-                }
-            }
-        }
+        let _ = try? safeShell("tuist clean")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62edade and 4f45f72.

⛔ Files ignored due to path filters (1)
  • Gemfile.lock is excluded by !**/*.lock
📒 Files selected for processing (60)
  • .arkana.yml (1 hunks)
  • .github/project_workflows/add_device_profile.yml (1 hunks)
  • .github/project_workflows/automatic_pull_request_review.yml (2 hunks)
  • .github/project_workflows/create_release_pull_request_and_bump_version.yml (2 hunks)
  • .github/project_workflows/deploy_app_store.yml (4 hunks)
  • .github/project_workflows/deploy_production_firebase.yml (4 hunks)
  • .github/project_workflows/deploy_staging_firebase.yml (4 hunks)
  • .github/self_hosted_project_workflows/automatic_pull_request_review.yml (2 hunks)
  • .github/self_hosted_project_workflows/deploy_app_store.yml (4 hunks)
  • .github/self_hosted_project_workflows/deploy_production_firebase.yml (4 hunks)
  • .github/self_hosted_project_workflows/deploy_staging_firebase.yml (4 hunks)
  • .github/wiki/Bitrise.md (3 hunks)
  • .github/wiki/CodeMagic.md (2 hunks)
  • .github/wiki/Github-Actions.md (1 hunks)
  • .github/wiki/Project-Dependencies.md (2 hunks)
  • .github/workflows/cleanup_cache.yml (1 hunks)
  • .github/workflows/test_swiftui_install_script.yml (0 hunks)
  • .github/workflows/test_uikit_install_script.yml (0 hunks)
  • .github/workflows/test_upload_build_to_firebase.yml (3 hunks)
  • .github/workflows/test_upload_build_to_test_flight.yml (3 hunks)
  • .gitignore (1 hunks)
  • .mise.toml (1 hunks)
  • .tuist-version (1 hunks)
  • Dangerfile (3 hunks)
  • Gemfile (0 hunks)
  • PROJECT_README.md (1 hunks)
  • Package.resolved (1 hunks)
  • Package.swift (1 hunks)
  • Project.swift (1 hunks)
  • README.md (2 hunks)
  • Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpInterface.swift (2 hunks)
  • Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift (5 hunks)
  • Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/iOSTemplateMaker.swift (1 hunks)
  • Tuist/Interfaces/SwiftUI/Project/Podfile (0 hunks)
  • Tuist/Interfaces/UIKit/Project/.sourcery.yml (0 hunks)
  • Tuist/Interfaces/UIKit/Project/Podfile (0 hunks)
  • Tuist/Interfaces/UIKit/Sources/Application/AppDelegate.swift (0 hunks)
  • Tuist/Interfaces/UIKit/Sources/Presentation/Modules/HomeViewController.swift (0 hunks)
  • Tuist/Interfaces/UIKit/Sources/Presentation/Navigator/Navigator+Scene.swift (0 hunks)
  • Tuist/Interfaces/UIKit/Sources/Presentation/Navigator/Navigator+Transition.swift (0 hunks)
  • Tuist/Interfaces/UIKit/Sources/Presentation/Navigator/Navigator.swift (0 hunks)
  • Tuist/ProjectDescriptionHelpers/BuildConfiguration.swift (1 hunks)
  • Tuist/ProjectDescriptionHelpers/Constant.swift (0 hunks)
  • Tuist/ProjectDescriptionHelpers/Module.swift (0 hunks)
  • Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift (1 hunks)
  • Tuist/ProjectDescriptionHelpers/Target+Initializing.swift (1 hunks)
  • Tuist/ProjectDescriptionHelpers/TargetScript+Initializing.swift (0 hunks)
  • Workspace.swift (0 hunks)
  • bitrise.yml (1 hunks)
  • codemagic.yaml (0 hunks)
  • fastlane/Constants/Constant.swift (1 hunks)
  • fastlane/Fastfile.swift (0 hunks)
  • fastlane/Helpers/Build.swift (2 hunks)
  • fastlane/Helpers/Symbol.swift (1 hunks)
  • fastlane/Helpers/Test.swift (1 hunks)
  • tools/sourcery/templates/AutoMockable.stencil (0 hunks)
  • {PROJECT_NAME}/Sources/Constants/Constants+API.swift (0 hunks)
  • {PROJECT_NAME}/Sources/Supports/Extensions/UIKit/Color+Application.swift (0 hunks)
  • {PROJECT_NAME}/Sources/Supports/Extensions/UIKit/UIView+Subviews.swift (0 hunks)
  • {PROJECT_NAME}/Sources/Supports/Helpers/Typealiases/Typealiases.swift (0 hunks)
💤 Files with no reviewable changes (22)
  • Tuist/Interfaces/UIKit/Sources/Presentation/Navigator/Navigator+Transition.swift
  • .github/workflows/test_uikit_install_script.yml
  • Tuist/Interfaces/UIKit/Sources/Presentation/Modules/HomeViewController.swift
  • Tuist/Interfaces/UIKit/Project/.sourcery.yml
  • Tuist/ProjectDescriptionHelpers/Constant.swift
  • fastlane/Fastfile.swift
  • {PROJECT_NAME}/Sources/Supports/Extensions/UIKit/Color+Application.swift
  • tools/sourcery/templates/AutoMockable.stencil
  • Tuist/ProjectDescriptionHelpers/TargetScript+Initializing.swift
  • {PROJECT_NAME}/Sources/Supports/Helpers/Typealiases/Typealiases.swift
  • .github/workflows/test_swiftui_install_script.yml
  • codemagic.yaml
  • Tuist/Interfaces/SwiftUI/Project/Podfile
  • Gemfile
  • {PROJECT_NAME}/Sources/Constants/Constants+API.swift
  • {PROJECT_NAME}/Sources/Supports/Extensions/UIKit/UIView+Subviews.swift
  • Tuist/Interfaces/UIKit/Sources/Presentation/Navigator/Navigator+Scene.swift
  • Tuist/Interfaces/UIKit/Sources/Application/AppDelegate.swift
  • Tuist/Interfaces/UIKit/Project/Podfile
  • Workspace.swift
  • Tuist/Interfaces/UIKit/Sources/Presentation/Navigator/Navigator.swift
  • Tuist/ProjectDescriptionHelpers/Module.swift
🧰 Additional context used
🧬 Code graph analysis (4)
Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/iOSTemplateMaker.swift (1)
fastlane/Helpers/EnvironmentParser.swift (1)
  • string (17-19)
Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpInterface.swift (1)
Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/FileManager+Utils.swift (3)
  • rename (21-27)
  • moveFiles (5-19)
  • removeItems (48-51)
Project.swift (3)
Tuist/ProjectDescriptionHelpers/BuildConfiguration.swift (1)
  • createConfiguration (32-40)
Tuist/ProjectDescriptionHelpers/Target+Initializing.swift (1)
  • makeTargets (4-9)
Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift (2)
  • productionScheme (4-16)
  • stagingScheme (18-30)
Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift (2)
Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpInterface.swift (1)
  • perform (26-35)
Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/Extensions/FileManager+Utils.swift (1)
  • removeItems (48-51)
🪛 LanguageTool
.github/wiki/Project-Dependencies.md

[style] ~30-~30: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... to enforce our team's code convention. SwiftLint is the perfect tool for this task as it...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (39)
bitrise.yml (1)

186-186: BITRISE_PROJECT_PATH is correctly set to .xcodeproj for SPM integration.

The change from .xcworkspace to .xcodeproj is appropriate for the SPM-only migration. The [email protected] step natively supports SPM package resolution through Xcode's integration, so no additional configuration is needed. This is the correct path for building with SPM dependencies.

The current cache configuration at lines 48, 91, 134, and 170 caching $BITRISE_CACHE_DIR and $GEM_CACHE_PATH is sufficient; Bitrise's cache directory handles derived data and build artifacts.

Dangerfile (2)

44-44: LGTM! Correct migration from workspace to project.

The change from workspace: to project: correctly reflects the migration from CocoaPods (which requires a workspace) to SPM and Tuist 4 (which uses the project directly).


24-24: The {PROJECT_NAME} placeholder will be properly substituted by the iOSTemplateMaker tool. The replaceAllOccurrences() method in FileManager+Utils.swift recursively processes all text files in the project root (excluding .build and .png files), replacing the placeholder across all occurrences including the Dangerfile.

Tuist/ProjectDescriptionHelpers/BuildConfiguration.swift (1)

21-28: Nice formatting improvement.

The switch statement is now properly formatted with consistent multi-line indentation, which improves readability and aligns with modern Swift conventions. The file already uses Tuist 4-compatible API patterns (static factory methods for ConfigurationName.configuration(), Configuration.debug(), and Configuration.release()), so no API breaking changes are present. No behavioral changes.

fastlane/Helpers/Test.swift (1)

16-25: xcbeautify formatter path change is appropriate post‑CocoaPods removal

Using "xcbeautify" directly instead of the Pods path matches the move away from CocoaPods; behavior is fine as long as xcbeautify is installed and on PATH in all CI environments (GitHub Actions, Bitrise, CodeMagic).

fastlane/Constants/Constant.swift (1)

74-82: Constants remain consistent; doc comment is helpful

projectName remains the same placeholder, and the new dSYMSuffix comment correctly documents how dsymPath is formed. No functional issues here.

fastlane/Helpers/Build.swift (1)

42-62: Explicit project path + formatter change look good; verify alignment with generated project

Adding project: .userDefined(Constant.projectPath) is a good move now that Pods/xcworkspace are gone, assuming Tuist/SPM consistently generates ./{PROJECT_NAME}.xcodeproj. The formatter change to "xcbeautify" matches the test helper.

Please double‑check:

  • The actual generated Xcode file name/extension matches Constant.projectPath.
  • xcbeautify is installed and available on PATH in all CI providers you support.
.arkana.yml (1)

1-1: LGTM – Arkana configuration correctly updated for SPM.

The package manager migration from CocoaPods to SPM aligns with the PR's dependency management overhaul.

.gitignore (1)

69-69: LGTM – Gitignore updated appropriately for Tuist 4 and SPM.

The addition of *.xcworkspace in the Tuist section is correct; Tuist 4 generates these files and they should not be committed. The implicit removal of the Pods directory from gitignore aligns with the SPM migration.

.github/project_workflows/add_device_profile.yml (1)

33-33: LGTM – GitHub Actions version upgrade is safe and current.

Checkout@v6 maintains backward compatibility with fetch-depth: 0 and other parameters. No workflow logic changes needed.

.github/project_workflows/create_release_pull_request_and_bump_version.yml (1)

22-22: LGTM – GitHub Actions version upgrades are safe and current.

Checkout@v6 maintains backward compatibility with all existing parameters including fetch-depth: 0 and branch refs. No workflow logic adjustments needed.

Also applies to: 59-59

PROJECT_README.md (1)

18-18: LGTM – README correctly documents the new setup flow.

The documentation update from pod install to tuist generate reflects the SPM migration and Tuist 4's project generation model. Developers will now run the correct command to set up dependencies.

.github/workflows/cleanup_cache.yml (1)

12-12: LGTM – GitHub Actions version upgrade is safe and current.

Checkout@v6 maintains backward compatibility. No workflow logic changes needed.

README.md (1)

14-30: README messaging for Tuist 4 + SwiftUI + SPM looks coherent

The new intro, requirements, “What’s inside” section, and the extra step about opening the generated .xcodeproj all align with the SwiftUI‑only / SPM‑only direction of the template. No changes needed from my side here.

Also applies to: 39-40

Package.resolved (1)

1-248: Pinned SPM dependencies look fine

The resolved versions are consistent with the declared constraints and having this file checked in makes sense for deterministic template builds. No issues from my side.

Tuist/ProjectDescriptionHelpers/Target+Initializing.swift (1)

4-8: Verify JSONAPIMapper product name export; test bundle ID is unconventional

The new makeTargets and target configuration align well with Tuist 4 and SPM setup. Two points to confirm:

  • JSONAPIMapper product name: The main target depends on .package(product: "JSONAPIMapper") (line 26), but the package repository is nimblehq/JSONMapper. Confirm that "JSONAPIMapper" is the correct product name exported by that package in its Package.swift; if it exports a different product name (e.g., "JSONMapper"), this will cause resolution failures during tuist generate or build time.

  • Test bundle identifier (line 47): testsTarget currently passes the same bundleId parameter as the app target. It's more conventional to give the test bundle its own ID, e.g. \(bundleId).tests, for clarity in build logs and tooling. Optional improvement:

     fileprivate static func testsTarget(name: String, bundleId: String) -> Target {
         let targetName = "\(name)Tests"
+        let testsBundleId = "\(bundleId).tests"
         return .target(
             name: targetName,
             destinations: .iOS,
             product: .unitTests,
-            bundleId: bundleId,
+            bundleId: testsBundleId,
Tuist/ProjectDescriptionHelpers/Scheme+Initializing.swift (2)

8-15: LGTM! Scheme generation simplified.

The refactored scheme generation directly references test targets and streamlines the action configuration, making the code more maintainable.


22-29: LGTM! Consistent simplification.

The staging scheme follows the same simplified pattern as the production scheme, ensuring consistency across build configurations.

.mise.toml (1)

1-4: LGTM! Mise configuration added.

The Tuist version pin (4.110.3) correctly aligns with the updated .tuist-version file and the PR's upgrade objective.

.tuist-version (1)

1-1: LGTM! Tuist upgraded to 4.110.3.

The version upgrade from 3.2.0 to 4.110.3 fulfills the primary objective of this PR.

.github/wiki/CodeMagic.md (2)

12-12: LGTM! Documentation updated for SPM migration.

The workflow step description correctly reflects the migration from CocoaPods to Swift Package Manager.


55-55: LGTM! Project structure updated.

The change from .xcworkspace to .xcodeproj aligns with the SPM migration, as SPM doesn't require a workspace file.

.github/project_workflows/deploy_production_firebase.yml (3)

23-23: LGTM! GitHub Actions checkout upgraded.

The upgrade to actions/checkout@v6 ensures compatibility with the latest GitHub Actions features.

Also applies to: 42-42


73-73: LGTM! Cache action upgraded.

The upgrade to actions/cache@v4 is appropriate for improved caching performance.


99-99: LGTM! Artifact upload action upgraded.

The upgrade to actions/upload-artifact@v4 ensures compatibility with the latest artifact handling features.

.github/wiki/Bitrise.md (2)

12-12: LGTM! Bitrise workflow documentation updated.

The workflow step description correctly reflects the migration from CocoaPods to Swift Package Manager.


29-29: LGTM! Project structure documentation updated.

The changes from .xcworkspace to .xcodeproj align with the SPM migration and correctly document the new project structure.

Also applies to: 65-65

.github/wiki/Github-Actions.md (1)

33-33: LGTM! Dependency installation documentation updated.

The updated descriptions correctly reflect the migration from CocoaPods to SPM and the new dependency resolution workflow using Bundler and Tuist/Xcode.

Also applies to: 40-40

Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/iOSTemplateMaker.swift (1)

31-38: Interface parameter successfully removed; SwiftUI now hardcoded as default.

The SetUpIOSProject initializer has been correctly updated to remove the interface parameter. The current signature accepts only bundleIdProduction, bundleIdStaging, projectName, and minimumVersion. SwiftUI is now hardcoded as the default interface in the SetUpInterface().perform(.swiftUI, projectName) call, aligning with the PR's objective to deprecate UIKit templates.

.github/workflows/test_upload_build_to_firebase.yml (1)

21-23: LGTM! Good addition of Fastlane timeout settings.

These environment variables help prevent flaky builds by allowing xcodebuild settings retrieval to retry on transient failures.

.github/project_workflows/deploy_staging_firebase.yml (1)

78-89: CocoaPods steps remain while PR migrates to SPM.

This workflow still caches Pods and runs pod install, but the PR is migrating from CocoaPods to Swift Package Manager. If this template is intended for new projects using SPM, these steps should be replaced with SPM caching similar to test_upload_build_to_test_flight.yml.

If this is intentional (e.g., template for legacy CocoaPods projects), please clarify. Otherwise, consider applying this diff:

-    - name: Cache Pods
+    - name: Cache SPM Packages
       uses: actions/cache@v4
-      id: cocoapodCache
+      id: spmCache
       with:
-        path: Pods
-        key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
+        path: .build
+        key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
         restore-keys: |
-          ${{ runner.os }}-pods-
-
-    - name: Install Pods Dependencies
-      run: bundle exec pod install
-      shell: bash
+          ${{ runner.os }}-spm-
.github/project_workflows/deploy_app_store.yml (2)

62-73: CocoaPods steps remain while PR migrates to SPM.

Same concern as deploy_staging_firebase.yml — this workflow still uses Pods caching and pod install. If the template is moving to SPM, these should be updated accordingly. See the suggested diff in the review comment for deploy_staging_firebase.yml.


24-27: Action version upgrades look good.

Checkout action upgraded to v6 consistently across both jobs.

Also applies to: 38-42

Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpInterface.swift (1)

26-35: LGTM! Clean file operations for SwiftUI setup.

The flow correctly renames the app file, moves sources to the project directory, and cleans up the Interfaces directory.

.github/workflows/test_upload_build_to_test_flight.yml (2)

44-51: LGTM! Proper SPM caching implementation.

The cache configuration correctly targets .build directory and uses Package.resolved for the cache key, which will properly invalidate when dependencies change.


13-14: Good decision to make TestFlight uploads manual-only.

Disabling automatic triggers and requiring workflow_dispatch prevents accidental TestFlight uploads on every PR, which could exhaust review quotas or cause confusion.

.github/wiki/Project-Dependencies.md (1)

6-6: LGTM! Documentation accurately reflects the SPM migration.

The description correctly notes that SPM is now the single source of truth for runtime dependencies.

Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift (2)

45-47: LGTM! Clean hardcoding of SwiftUI interface.

With UIKit support removed, hardcoding .swiftUI is the correct approach.


277-283: LGTM! Correctly opens .xcodeproj for SPM-integrated projects.

With Tuist 4's native SPM integration, opening the project file directly is correct since there's no separate workspace for Pods.

Comment on lines +10 to +11
swiftformat.binary_path = 'swiftformat'
swiftformat.exclude = %w(**/*generated.swift)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find CI configuration files
fd -e yaml -e yml -e sh | grep -E '(\.github|\.circleci|bitrise|codemagic)' | head -20

Repository: nimblehq/ios-templates

Length of output: 92


🏁 Script executed:

# Search for CI workflow patterns
rg -l 'workflow|jobs|steps|script' --type=yaml | head -20

Repository: nimblehq/ios-templates

Length of output: 212


🏁 Script executed:

# Read the Dangerfile to understand the context
cat -n Dangerfile | head -50

Repository: nimblehq/ios-templates

Length of output: 1909


🏁 Script executed:

# Search for swiftformat and swiftlint references in CI/workflow files
rg 'swiftformat|swiftlint' --type=yaml -B2 -A2

Repository: nimblehq/ios-templates

Length of output: 168


🏁 Script executed:

# Search for tool installation patterns (mint, brew, etc.)
rg 'mint install|brew install|setup.*swift|SPM|cocoapods' --type=yaml -B2 -A2

Repository: nimblehq/ios-templates

Length of output: 168


🏁 Script executed:

# Read bitrise.yml to check tool installation
cat -n bitrise.yml | head -100

Repository: nimblehq/ios-templates

Length of output: 3572


🏁 Script executed:

# Read codemagic.yaml to check tool installation
cat -n codemagic.yaml | head -100

Repository: nimblehq/ios-templates

Length of output: 3819


🏁 Script executed:

# Check if Dangerfile is a template file (cookiecutter patterns)
rg 'cookiecutter|PROJECT_NAME' Dangerfile

Repository: nimblehq/ios-templates

Length of output: 212


🏁 Script executed:

# Check for Gemfile or other dependency files that might install Danger plugins
cat Gemfile 2>/dev/null || echo "No Gemfile found"

Repository: nimblehq/ios-templates

Length of output: 373


🏁 Script executed:

# Check if there are any installation instructions in README or docs
fd -e md | xargs rg -l 'swiftformat|swiftlint|setup|install' 2>/dev/null | head -5

Repository: nimblehq/ios-templates

Length of output: 93


🏁 Script executed:

# Check full bitrise.yml for bundle install or gem installation
rg 'bundle|gem' bitrise.yml -B2 -A2

Repository: nimblehq/ios-templates

Length of output: 48


🏁 Script executed:

# Check README for tool setup instructions
cat README.md | grep -A20 -B2 'setup\|install\|swift' | head -50

Repository: nimblehq/ios-templates

Length of output: 1569


🏁 Script executed:

# Verify if Dangerfile is indeed a template file
file Dangerfile && head -5 Dangerfile

Repository: nimblehq/ios-templates

Length of output: 110


Verify swiftformat and swiftlint are installed in CI environments.

The binary paths for SwiftFormat and SwiftLint (lines 10, 15) reference external CLI tools that must be available in the system PATH. The Gemfile includes the Danger wrapper gems (danger-swiftformat, danger-swiftlint), but these gems require the actual swiftformat and swiftlint binaries to be pre-installed. Ensure these tools are installed as part of your CI setup—neither bitrise.yml nor codemagic.yaml shows explicit installation steps for these binaries. Consider adding installation commands (e.g., via Homebrew, mint, or direct download) to your CI workflows.

🤖 Prompt for AI Agents
In Dangerfile around lines 10 to 11, the Danger config references external
swiftformat and swiftlint binaries but the CI configs do not install those
tools; update the CI pipelines (bitrise.yml and codemagic.yaml) to install and
put swiftformat and swiftlint on PATH before running Danger (examples: install
via Homebrew, mint, or download and place in PATH), pin desired versions, verify
installation with a quick --version check, and fail the build early with a clear
message if the binaries are missing so Danger’s swiftformat/swiftlint wrappers
will run reliably.

Comment on lines 260 to 261
try fileManager.removeItems(in: ".tuist-version")
try fileManager.removeItems(in: "tuist")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if tuist or Tuist directory exists in the template
fd -t d -d 1 '^[Tt]uist$'

Repository: nimblehq/ios-templates

Length of output: 72


🏁 Script executed:

#!/bin/bash
# Search for references to tuist or Tuist in Swift files to understand expected paths
rg -i 'tuist' --type swift -A 2 -B 2 | head -100

Repository: nimblehq/ios-templates

Length of output: 10683


🏁 Script executed:

#!/bin/bash
# Check the SetUpiOSProject.swift file to see the context around lines 260-261
sed -n '250,270p' Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift

Repository: nimblehq/ios-templates

Length of output: 948


Change tuist to Tuist on line 261 to match the actual directory structure.

The repository uses Tuist/ (capitalized) throughout the codebase, as confirmed by the actual directory structure and all other references in SetUpInterface.swift and SetUpiOSProject.swift. Line 261 should remove Tuist instead of tuist to properly clean up the template files.

🤖 Prompt for AI Agents
In Scripts/Swift/iOSTemplateMaker/Sources/iOSTemplateMaker/SetUpiOSProject.swift
around lines 260 to 261, the cleanup currently attempts to remove "tuist"
(lowercase) but the actual directory is "Tuist" (capitalized); update the second
removeItems call to target "Tuist" instead of "tuist" so the correct directory
is removed (and ensure casing matches other references in the repo).

@ducbm051291 ducbm051291 changed the base branch from develop to bug/587-ci-cd-workflows-failed-due-to-deprecated-github-actions December 3, 2025 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update the Tuist to the latest version

2 participants