Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Auto-configure if unconfigured
run: |
# Detect if this is an unconfigured template
if grep -q "{{PROJECT_NAME}}" project.yml 2>/dev/null; then
if grep -q "TestApp" project.yml 2>/dev/null; then
echo "πŸ”§ Unconfigured template detected - generating minimal test project"
./scripts/setup.sh \
--project-name "CITestApp" \
Expand All @@ -37,7 +37,6 @@ jobs:
--generate-minimal \
--no-git-hooks \
--no-commit \
--skip-brew \
--force
echo "βœ… Template auto-configured for CI testing"
else
Expand Down
6 changes: 0 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,3 @@ iOSInjectionProject/
*.pyo
*.rej
*.swp

# CI Test Projects (prevent accidental commits)
/ci-test-*/
/ci-test-project/
/CITest*/
/TestApp*/
2 changes: 1 addition & 1 deletion .swiftformat
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SwiftFormat configuration for {{PROJECT_NAME}}
# SwiftFormat configuration for TestApp
# For more information: https://github.com/nicklockwood/SwiftFormat

# Version
Expand Down
12 changes: 3 additions & 9 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ opt_in_rules:
- yoda_condition

included:
- {{PROJECT_NAME}}
- {{PROJECT_NAME}}Tests
- {{PROJECT_NAME}}UITests
- TestApp
- TestAppTests
- TestAppUITests

excluded:
- Pods
Expand Down Expand Up @@ -114,12 +114,6 @@ large_tuple:
warning: 3
error: 4

# Allow implicitly unwrapped optionals in UI tests (common pattern for XCUIApplication)
implicitly_unwrapped_optional:
excluded:
- "**/*UITests.swift"
- "**/*UITest.swift"

# Custom rules for better code quality
custom_rules:
no_objcMembers:
Expand Down
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ This is a **Swift iOS project template** that uses:

### Core Components
- **`scripts/` Directory**: Contains all development automation scripts with helper functions in `_helpers.sh`
- **`project.yml`**: XcodeGen configuration with placeholders like `{{PROJECT_NAME}}`
- **`project.yml`**: XcodeGen configuration with placeholders like `TestApp`
- **`simulator.yml`**: Auto-generated simulator configuration for tests
- **`.github/workflows/ci.yml`**: Unified CI workflow that auto-configures if needed
- **Brewfile**: Manages all development tool dependencies (yq, jq, xcodegen, swiftlint, etc.)
Expand Down Expand Up @@ -80,9 +80,9 @@ This is a **Swift iOS project template** that uses:
## Configuration Files

### Critical Files (Pre-configured with Placeholders)
- **`project.yml`** - XcodeGen project definition with `{{PROJECT_NAME}}` placeholders
- **`project.yml`** - XcodeGen project definition with `TestApp` placeholders
- **`simulator.yml`** - Auto-generated during setup with sensible defaults
- **`.swiftlint.yml`** - SwiftLint rules with `{{PROJECT_NAME}}` in paths
- **`.swiftlint.yml`** - SwiftLint rules with `TestApp` in paths
- **`.swiftformat`** - SwiftFormat configuration ready to use

### Development Dependencies
Expand Down Expand Up @@ -151,7 +151,7 @@ All tools installed via Brewfile: yq, jq, xcodegen, swiftlint, swiftformat, xcbe

### CI Workflow
1. Checkout code
2. Detect if project is configured (check for `{{PROJECT_NAME}}` in project.yml)
2. Detect if project is configured (check for `TestApp` in project.yml)
3. If unconfigured: run `./scripts/setup.sh --generate-minimal` with test parameters
4. Install dependencies via Brewfile
5. Generate Xcode project with xcodegen (or use existing in adopt mode)
Expand Down
27 changes: 27 additions & 0 deletions TestApp/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import UIKit

@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
true
}

func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role
)
}

func application(
_ application: UIApplication,
didDiscardSceneSessions sceneSessions: Set<UISceneSession>
) {}
}
Empty file added TestApp/Extensions/.gitkeep
Empty file.
Empty file added TestApp/Helpers/.gitkeep
Empty file.
62 changes: 62 additions & 0 deletions TestApp/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>TestApp</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
Empty file added TestApp/Models/.gitkeep
Empty file.
21 changes: 21 additions & 0 deletions TestApp/SceneDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import UIKit

final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?

func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = (scene as? UIWindowScene) else {
return
}

let window = UIWindow(windowScene: windowScene)
let viewController = ViewController()
window.rootViewController = viewController
window.makeKeyAndVisible()
self.window = window
}
}
Empty file added TestApp/Services/.gitkeep
Empty file.
Empty file added TestApp/ViewModels/.gitkeep
Empty file.
21 changes: 21 additions & 0 deletions TestApp/Views/ViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import UIKit

final class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground

let label = UILabel()
label.text = "Hello, TestApp!"
label.font = .preferredFont(forTextStyle: .largeTitle)
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false

view.addSubview(label)

NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
9 changes: 9 additions & 0 deletions TestAppTests/TestAppTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@testable import TestApp
import Testing

struct TestAppTests {
@Test
func exampleTest() {
#expect(true)
}
}
14 changes: 14 additions & 0 deletions TestAppUITests/TestAppUITests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import XCTest

@MainActor
final class TestAppUITests: XCTestCase {
override func setUpWithError() throws {
continueAfterFailure = false
}

func testExample() {
let app = XCUIApplication()
app.launch()
XCTAssertTrue(app.exists)
}
}
50 changes: 25 additions & 25 deletions project.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: {{PROJECT_NAME}}
name: TestApp
options:
bundleIdPrefix: {{BUNDLE_ID_ROOT}}
bundleIdPrefix: com.yourcompany
developmentLanguage: en
deploymentTarget:
iOS: "{{DEPLOYMENT_TARGET}}"
iOS: "18.0"
xcodeVersion: "15.0"
generateEmptyDirectories: true

Expand All @@ -17,7 +17,7 @@ options:
settings:
base:
# Swift version
SWIFT_VERSION: "{{SWIFT_VERSION}}"
SWIFT_VERSION: "6.2"
# Development settings
DEVELOPMENT_TEAM: ""
CODE_SIGN_IDENTITY: "Apple Development"
Expand All @@ -37,18 +37,18 @@ settings:
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor

targets:
{{PROJECT_NAME}}:
TestApp:
type: application
platform: iOS
deploymentTarget: "{{DEPLOYMENT_TARGET}}"
deploymentTarget: "18.0"
sources:
- {{PROJECT_NAME}}
- TestApp
resources:
- {{PROJECT_NAME}}/Resources
- TestApp/Resources
info:
path: {{PROJECT_NAME}}/Info.plist
path: TestApp/Info.plist
properties:
CFBundleDisplayName: {{PROJECT_NAME}}
CFBundleDisplayName: TestApp
CFBundleVersion: "1"
CFBundleShortVersionString: "1.0"
UILaunchStoryboardName: LaunchScreen
Expand All @@ -71,41 +71,41 @@ targets:
- UISceneConfigurationName: Default Configuration
UISceneDelegateClassName: $(PRODUCT_MODULE_NAME).SceneDelegate

{{PROJECT_NAME}}Tests:
TestAppTests:
type: bundle.unit-test
platform: iOS
deploymentTarget: "{{DEPLOYMENT_TARGET}}"
deploymentTarget: "18.0"
sources:
- {{PROJECT_NAME}}Tests
- TestAppTests
dependencies:
- target: {{PROJECT_NAME}}
- target: TestApp

{{PROJECT_NAME}}UITests:
TestAppUITests:
type: bundle.ui-testing
platform: iOS
deploymentTarget: "{{DEPLOYMENT_TARGET}}"
deploymentTarget: "18.0"
sources:
- {{PROJECT_NAME}}UITests
- TestAppUITests
dependencies:
- target: {{PROJECT_NAME}}
- target: TestApp

schemes:
{{PROJECT_NAME}}:
TestApp:
build:
targets:
{{PROJECT_NAME}}: all
{{PROJECT_NAME}}Tests: [test]
{{PROJECT_NAME}}UITests: [test]
TestApp: all
TestAppTests: [test]
TestAppUITests: [test]
run:
config: Debug
test:
config: Debug
gatherCoverageData: true
coverageTargets:
- {{PROJECT_NAME}}
- TestApp
targets:
- {{PROJECT_NAME}}Tests
- {{PROJECT_NAME}}UITests
- TestAppTests
- TestAppUITests
profile:
config: Release
analyze:
Expand Down
9 changes: 5 additions & 4 deletions scripts/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ source "$(dirname "${BASH_SOURCE[0]}")/_helpers.sh"

# Default values
PROJECT_NAME=""
DEPLOYMENT_TARGET="18.0"
DEPLOYMENT_TARGET="26.0"
SWIFT_VERSION="6.2"
PROJECT_TYPE="private"
BUNDLE_ID_ROOT="com.yourcompany"
Expand Down Expand Up @@ -417,7 +417,7 @@ class ViewController: UIViewController {

NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
}
Expand Down Expand Up @@ -467,6 +467,7 @@ EOF
cat > "${PROJECT_NAME}UITests/${PROJECT_NAME}UITests.swift" <<EOF
import XCTest

@MainActor
final class ${PROJECT_NAME}UITests: XCTestCase {
override func setUpWithError() throws {
continueAfterFailure = false
Expand Down Expand Up @@ -527,10 +528,10 @@ configure_simulators() {
cat > simulator.yml <<EOF
simulators:
tests:
name: iPhone 16 Pro
name: iPhone 17 Pro
os: latest
ui-tests:
name: iPhone 16 Pro
name: iPhone 17 Pro
os: latest
EOF
log_success "Created simulator.yml"
Expand Down
Loading
Loading