├── .bazelignore
├── .bazelrc
├── .bazelversion
├── .github
└── workflows
│ ├── tests.yml
│ └── xcode_select.sh
├── .gitignore
├── BUILD.bazel
├── LICENSE
├── MODULE.bazel
├── README.md
├── WORKSPACE
├── app
├── Assets
│ └── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ └── Contents.json
│ │ └── Contents.json
├── BUILD.bazel
├── Info.plist
├── PreviewContent
│ └── PreviewAssets.xcassets
│ │ └── Contents.json
├── ios app.entitlements
└── source
│ ├── ContentView.swift
│ └── MainApp.swift
├── modules
├── API
│ ├── API
│ │ └── API.swift
│ ├── BUILD.bazel
│ └── Tests
│ │ └── APITests.swift
├── BUILD.bazel
└── Models
│ ├── BUILD.bazel
│ ├── Models
│ └── Models.swift
│ └── Tests
│ └── ModelsTests.swift
└── tools
├── BUILD.bazel
├── extensions.bzl
├── repositories.bzl
└── shared.bzl
/.bazelignore:
--------------------------------------------------------------------------------
1 | .git
2 |
--------------------------------------------------------------------------------
/.bazelrc:
--------------------------------------------------------------------------------
1 | # Enable Bzlmod for every Bazel command
2 | common --enable_bzlmod
3 |
4 | ## BUILD
5 |
6 | build --macos_minimum_os=13
7 | build --host_macos_minimum_os=13
8 |
9 | # https://bazel.build/reference/command-line-reference#flag--incompatible_strict_action_env
10 | build --incompatible_strict_action_env
11 |
12 | # Disable the worker, which has sandboxing disabled by default, which can hide
13 | # issues with non-hermetic bugs.
14 | build --spawn_strategy=sandboxed,local
15 | build --worker_sandboxing=true
16 |
17 | build --incompatible_disallow_empty_glob
18 |
19 | build --features=swift.use_global_module_cache
20 |
21 | # Enable indexing while building.
22 | build --features swift.use_global_index_store
23 | build --features swift.index_while_building
24 |
25 | # Since there's no way to set the deployment version for swift_{binary,test},
26 | # this forces all targets' minimum macOS to Github Actions macOS version.
27 | build --macos_minimum_os=12.6
28 |
29 | ## TEST
30 |
31 | # `bazel test` tries to build everything also by default, so skip that so the
32 | # *_library targets in examples/... aren't built (and fail since they are
33 | # platform specific).
34 | test --build_tests_only
35 |
36 | # Show detailed errors for test failures
37 | test --test_output=errors
38 |
39 | # Use llvm-cov instead of gcov (default).
40 | coverage --experimental_use_llvm_covmap
41 |
42 | ## REMOTE CACHE
43 |
44 | # Do actions locally when it makes sense.
45 | build --modify_execution_info=^(BitcodeSymbolsCopy|BundleApp|BundleTreeApp|DsymDwarf|DsymLipo|GenerateAppleSymbolsFile|ObjcBinarySymbolStrip|CppLink|ObjcLink|ProcessAndSign|SignBinary|SwiftArchive|SwiftStdlibCopy)$=+no-remote,^(BundleResources|ImportedDynamicFrameworkProcessor)$=+no-remote-exec
46 |
47 | build:remote_cache --bes_results_url=https://app.buildbuddy.io/invocation/
48 | build:remote_cache --bes_backend=grpcs://remote.buildbuddy.io
49 | build:remote_cache --remote_cache=grpcs://remote.buildbuddy.io
50 | # https://bazel.build/reference/command-line-reference#flag--remote_download_toplevel
51 | build:remote_cache --remote_download_toplevel
52 | # https://bazel.build/reference/command-line-reference#flag--remote_timeout
53 | build:remote_cache --remote_timeout=3600
54 | # https://bazel.build/reference/command-line-reference#flag--experimental_remote_cache_compression
55 | build:remote_cache --experimental_remote_cache_compression
56 | # https://bazel.build/reference/command-line-reference#flag--experimental_remote_cache_compression_threshold
57 | build:remote_cache --experimental_remote_cache_compression_threshold=100
58 | # https://bazel.build/reference/command-line-reference#flag--legacy_important_outputs
59 | build:remote_cache --nolegacy_important_outputs
60 |
61 | # Only wait for BES upload in CI builds but not dev builds.
62 | #
63 | # https://bazel.build/reference/command-line-reference#flag--bes_upload_mode
64 | build:remote_cache --bes_upload_mode=nowait_for_upload_complete
65 |
66 | # By default don't upload local results to remote cache, only CI does this.
67 | build --noremote_upload_local_results
68 | build:ci --remote_upload_local_results
69 |
70 | ## LOCAL CONFIG
71 |
72 | # Load a user.bazelrc
73 | try-import %workspace%/user.bazelrc
74 |
--------------------------------------------------------------------------------
/.bazelversion:
--------------------------------------------------------------------------------
1 | 7.6.0
2 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches:
7 | - main
8 |
9 | # One active job per PR, cancel older ones on push
10 | concurrency:
11 | group: ${{ github.head_ref || github.run_id }}
12 | cancel-in-progress: true
13 |
14 | jobs:
15 | tests:
16 | name: Build and Test
17 | runs-on: macos-15
18 | steps:
19 | - uses: actions/checkout@v3
20 | - name: Set Up CI
21 | run: .github/workflows/xcode_select.sh
22 | env:
23 | BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
24 | - name: Lint
25 | run: bazelisk run :lint && git diff --exit-code
26 | - name: Build and Test
27 | run: |
28 | # Build the app
29 | bazelisk build -- //app
30 |
31 | # Run the tests
32 | bazelisk test --local_test_jobs=1 -- //...
33 | - name: Generate Xcode Project
34 | run: |
35 | # Generate Xcode project
36 | bazelisk run -- //:xcodeproj
37 | - uses: actions/upload-artifact@v4
38 | if: failure()
39 | with:
40 | name: bazel-testlogs
41 | path: bazel-testlogs
42 |
--------------------------------------------------------------------------------
/.github/workflows/xcode_select.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | echo "Selecting Xcode for environment"
4 |
5 | printenv
6 |
7 | sudo xcode-select -p
8 | sudo xcode-select -s /Applications/Xcode_16.2.app
9 |
10 | echo "Printing available simulators"
11 |
12 | xcrun simctl list devices
13 |
14 | echo "Generating bazelrc"
15 |
16 | # Enable remote cache for all Github Action builds
17 | echo "build --config=remote_cache" > user.bazelrc
18 | echo "build --config=ci" >> user.bazelrc
19 | echo "build --remote_header=x-buildbuddy-api-key=$BUILDBUDDY_API_KEY" >> user.bazelrc
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Bazel
2 |
3 | /bazel-*
4 | /user.bazelrc
5 | /MODULE.bazel.lock
6 |
7 | # macOS
8 |
9 | .DS_Store
10 |
11 | # Xcode
12 | #
13 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
14 |
15 | /*.xcodeproj
16 |
17 | ## User settings
18 | xcuserdata/
19 |
20 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
21 | *.xcscmblueprint
22 | *.xccheckout
23 |
24 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
25 | build/
26 | DerivedData/
27 | *.moved-aside
28 | *.pbxuser
29 | !default.pbxuser
30 | *.mode1v3
31 | !default.mode1v3
32 | *.mode2v3
33 | !default.mode2v3
34 | *.perspectivev3
35 | !default.perspectivev3
36 |
37 | ## Obj-C/Swift specific
38 | *.hmap
39 |
40 | ## App packaging
41 | *.ipa
42 | *.dSYM.zip
43 | *.dSYM
44 |
45 | ## Playgrounds
46 | timeline.xctimeline
47 | playground.xcworkspace
48 |
49 | # Swift Package Manager
50 | #
51 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
52 | # Packages/
53 | # Package.pins
54 | # Package.resolved
55 | # *.xcodeproj
56 | #
57 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
58 | # hence it is not needed unless you have added a package configuration file to your project
59 | # .swiftpm
60 |
61 | .build/
62 |
63 | # CocoaPods
64 | #
65 | # We recommend against adding the Pods directory to your .gitignore. However
66 | # you should judge for yourself, the pros and cons are mentioned at:
67 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
68 | #
69 | # Pods/
70 | #
71 | # Add this line if you want to avoid checking in source code from the Xcode workspace
72 | # *.xcworkspace
73 |
74 | # Carthage
75 | #
76 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
77 | # Carthage/Checkouts
78 |
79 | Carthage/Build/
80 |
81 | # Accio dependency management
82 | Dependencies/
83 | .accio/
84 |
85 | # fastlane
86 | #
87 | # It is recommended to not store the screenshots in the git repo.
88 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
89 | # For more information about the recommended setup visit:
90 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
91 |
92 | fastlane/report.xml
93 | fastlane/Preview.html
94 | fastlane/screenshots/**/*.png
95 | fastlane/test_output
96 |
97 | # Code Injection
98 | #
99 | # After new code Injection tools there's a generated folder /iOSInjectionProject
100 | # https://github.com/johnno1962/injectionforxcode
101 |
102 | iOSInjectionProject/
103 |
--------------------------------------------------------------------------------
/BUILD.bazel:
--------------------------------------------------------------------------------
1 | load(
2 | "@rules_xcodeproj//xcodeproj:defs.bzl",
3 | "top_level_target",
4 | "xcodeproj",
5 | )
6 |
7 | # Xcode
8 |
9 | xcodeproj(
10 | name = "xcodeproj",
11 | project_name = "App",
12 | top_level_targets = [
13 | top_level_target(
14 | "//app",
15 | target_environments = ["simulator"],
16 | ),
17 | top_level_target(
18 | "//modules/API:APITests",
19 | target_environments = ["simulator"],
20 | ),
21 | top_level_target(
22 | "//modules/Models:ModelsTests",
23 | target_environments = ["simulator"],
24 | ),
25 | ],
26 | )
27 |
28 | # tools
29 |
30 | genrule(
31 | name = "lint",
32 | srcs = [],
33 | outs = ["lint.sh"],
34 | cmd = """
35 | echo "set -e" > "$@"
36 | echo "./$(location @buildifier_prebuilt//:buildifier) -lint fix -mode fix -r \\$$BUILD_WORKSPACE_DIRECTORY" >> "$@"
37 | echo "./$(location @SwiftLint//:swiftlint) --fix \\$$BUILD_WORKSPACE_DIRECTORY" >> "$@"
38 | """,
39 | executable = True,
40 | tools = [
41 | "@SwiftLint//:swiftlint",
42 | "@buildifier_prebuilt//:buildifier",
43 | ],
44 | )
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Matt Robinson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MODULE.bazel:
--------------------------------------------------------------------------------
1 | bazel_dep(name = "bazel_skylib", version = "1.7.1")
2 | bazel_dep(name = "rules_xcodeproj", version = "2.10.0")
3 | bazel_dep(
4 | name = "apple_support",
5 | version = "1.21.1",
6 | repo_name = "build_bazel_apple_support",
7 | )
8 | bazel_dep(
9 | name = "rules_swift",
10 | version = "2.8.1",
11 | repo_name = "build_bazel_rules_swift",
12 | )
13 | bazel_dep(
14 | name = "rules_apple",
15 | version = "3.20.1",
16 | repo_name = "build_bazel_rules_apple",
17 | )
18 |
19 | bazel_dep(
20 | name = "buildifier_prebuilt",
21 | version = "6.4.0",
22 | dev_dependency = True,
23 | )
24 |
25 | non_module_dependencies = use_extension("//tools:extensions.bzl", "non_module_dependencies")
26 | use_repo(non_module_dependencies, "SwiftLint")
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwiftUI iOS App with Bazel
2 |
3 | This is an iOS application written in SwiftUI and built via Bazel. This is a starting place similar to creating a new project in Xcode and choosing SwiftUI as the starting place.
4 |
5 | ## Getting Started
6 |
7 | Install Bazelisk via `brew install bazelisk`. `bazel` & `bazelisk` will now use the `.bazelversion` file to download and run the chosen Bazel version.
8 |
9 | ### Generate/Open Project
10 |
11 | ```bash
12 | $ bazel run :xcodeproj
13 | $ open App.xcodeproj
14 | ```
15 |
16 | ### Build Application (CLI)
17 |
18 | ```bash
19 | $ bazel build //app
20 | ```
21 |
22 | ### Run All Tests (CLI)
23 |
24 | ```bash
25 | $ bazel test $(bazel query 'kind(ios_unit_test,//...)')
26 | ```
27 |
28 | If the tests fail, run `xcrun simctl list devices` to check what devices and OS versions are locally available. iOS version is set in [`shared.bzl`](/tools/shared.bzl).
29 |
30 | ## Underlying Tools
31 |
32 | - [`rules_apple`](https://github.com/bazelbuild/rules_apple)
33 | - [`rules_swift`](https://github.com/bazelbuild/rules_swift)
34 | - [`rules_xcodeproj`](https://github.com/buildbuddy-io/rules_xcodeproj)
35 |
36 | ## Making It Your Own
37 |
38 | `tools/shared.bzl` contains a handful of definitions to define the name of the application, bundle identifier, and similar things. Update these values to change the application's name.
39 |
--------------------------------------------------------------------------------
/WORKSPACE:
--------------------------------------------------------------------------------
1 | workspace(name = "bazel_ios_swiftui_template")
2 |
--------------------------------------------------------------------------------
/app/Assets/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | }
8 | ],
9 | "info" : {
10 | "author" : "xcode",
11 | "version" : 1
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/Assets/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/app/BUILD.bazel:
--------------------------------------------------------------------------------
1 | load("@build_bazel_rules_apple//apple:ios.bzl", "ios_application")
2 | load("@build_bazel_rules_apple//apple:versioning.bzl", "apple_bundle_version")
3 | load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
4 | load("//tools:shared.bzl", "app_info", "versions")
5 |
6 | # Version
7 |
8 | apple_bundle_version(
9 | name = "Version",
10 | build_version = "0.0.1",
11 | short_version_string = "1.0",
12 | )
13 |
14 | # Code
15 |
16 | swift_library(
17 | name = "app.library",
18 | srcs = glob(["source/**/*.swift"]),
19 | data = [":PreviewContent"],
20 | module_name = "app",
21 | deps = [
22 | "//modules/API:APILib",
23 | ],
24 | )
25 |
26 | # Packaging
27 |
28 | filegroup(
29 | name = "PreviewContent",
30 | srcs = glob(["PreviewContent/**"]),
31 | )
32 |
33 | ios_application(
34 | name = "app",
35 | app_icons = glob(["Assets/Assets.xcassets/AppIcon.appiconset/**"]),
36 | bundle_id = app_info.bundle_id,
37 | bundle_name = app_info.bundle_name,
38 | entitlements = "ios app.entitlements",
39 | executable_name = app_info.executable_name,
40 | families = [
41 | "iphone",
42 | "ipad",
43 | ],
44 | infoplists = [":Info.plist"],
45 | minimum_os_version = versions.minimum_ios_version,
46 | resources = glob(
47 | [
48 | "Assets/Assets.xcassets/**",
49 | ],
50 | exclude = ["Assets/Assets.xcassets/AppIcon.appiconset/**"],
51 | ),
52 | # Add localizable assets here.
53 | # strings = glob(["*.lproj/Localizable.strings"]),
54 | version = ":Version",
55 | visibility = [
56 | "//:__subpackages__",
57 | "@rules_xcodeproj//xcodeproj:generated",
58 | ],
59 | deps = [
60 | ":app.library",
61 | ],
62 | )
63 |
--------------------------------------------------------------------------------
/app/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UILaunchScreen
6 |
7 | CFBundleName
8 | $(PRODUCT_NAME)
9 | CFBundleVersion
10 | 1.0
11 | CFBundleShortVersionString
12 | 1.0
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/PreviewContent/PreviewAssets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/app/ios app.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/source/ContentView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct ContentView: View {
4 | var body: some View {
5 | VStack {
6 | Image(systemName: "globe")
7 | .imageScale(.large)
8 | .foregroundColor(.accentColor)
9 | Text("iOS application in SwiftUI!")
10 | }
11 | .padding()
12 | }
13 | }
14 |
15 | struct ContentView_Previews: PreviewProvider {
16 | static var previews: some View {
17 | ContentView()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/source/MainApp.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @main
4 | struct MainApp: App {
5 | var body: some Scene {
6 | WindowGroup {
7 | ContentView()
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/modules/API/API/API.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Models
3 |
4 | public struct API {
5 | public static func returnTrue() -> Bool {
6 | _ = ModelA()
7 | _ = ModelB()
8 | return true
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/modules/API/BUILD.bazel:
--------------------------------------------------------------------------------
1 | load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
2 | load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
3 | load("//tools:shared.bzl", "versions")
4 |
5 | # Code
6 |
7 | swift_library(
8 | name = "APILib",
9 | srcs = [
10 | "API/API.swift",
11 | ],
12 | module_name = "API",
13 | visibility = ["//modules:default_library_visibility"],
14 | deps = [
15 | "//modules/Models:ModelsLib",
16 | ],
17 | )
18 |
19 | # Tests
20 |
21 | swift_library(
22 | name = "APITestsLib",
23 | testonly = True,
24 | srcs = [
25 | "Tests/APITests.swift",
26 | ],
27 | module_name = "APITests",
28 | deps = [
29 | ":APILib",
30 | ],
31 | )
32 |
33 | ios_unit_test(
34 | name = "APITests",
35 | minimum_os_version = versions.minimum_ios_version,
36 | runner = "//tools:default_test_runner",
37 | visibility = ["//modules:default_test_visibility"],
38 | deps = [":APITestsLib"],
39 | )
40 |
--------------------------------------------------------------------------------
/modules/API/Tests/APITests.swift:
--------------------------------------------------------------------------------
1 | import API
2 | import XCTest
3 |
4 | final class APITests: XCTestCase {
5 | func test_success() {
6 | XCTAssertTrue(API.returnTrue())
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/modules/BUILD.bazel:
--------------------------------------------------------------------------------
1 | package_group(
2 | name = "default_library_visibility",
3 | includes = [
4 | # Project generation.
5 | "@rules_xcodeproj//xcodeproj:generated",
6 | ],
7 | packages = [
8 | # The application package.
9 | "//app",
10 | # All other modules.
11 | "//modules/...",
12 | ],
13 | )
14 |
15 | package_group(
16 | name = "default_test_visibility",
17 | includes = [
18 | # Project generation.
19 | "@rules_xcodeproj//xcodeproj:generated",
20 | ],
21 | )
22 |
--------------------------------------------------------------------------------
/modules/Models/BUILD.bazel:
--------------------------------------------------------------------------------
1 | load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
2 | load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
3 | load("//tools:shared.bzl", "versions")
4 |
5 | # Code
6 |
7 | swift_library(
8 | name = "ModelsLib",
9 | srcs = [
10 | "Models/Models.swift",
11 | ],
12 | module_name = "Models",
13 | visibility = ["//modules:default_library_visibility"],
14 | )
15 |
16 | # Tests
17 |
18 | swift_library(
19 | name = "ModelsTestsLib",
20 | testonly = True,
21 | srcs = [
22 | "Tests/ModelsTests.swift",
23 | ],
24 | module_name = "ModelsTests",
25 | deps = [
26 | ":ModelsLib",
27 | ],
28 | )
29 |
30 | ios_unit_test(
31 | name = "ModelsTests",
32 | minimum_os_version = versions.minimum_ios_version,
33 | runner = "//tools:default_test_runner",
34 | visibility = ["//modules:default_test_visibility"],
35 | deps = [":ModelsTestsLib"],
36 | )
37 |
--------------------------------------------------------------------------------
/modules/Models/Models/Models.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct ModelA {
4 | public init() {}
5 |
6 | func internalBoolFunction() -> Bool {
7 | return true
8 | }
9 | }
10 |
11 | public struct ModelB {
12 | public init() {}
13 | }
14 |
--------------------------------------------------------------------------------
/modules/Models/Tests/ModelsTests.swift:
--------------------------------------------------------------------------------
1 | @testable import Models
2 | import XCTest
3 |
4 | final class ModelsTests: XCTestCase {
5 | func test_success() {
6 | XCTAssertTrue(ModelA().internalBoolFunction())
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tools/BUILD.bazel:
--------------------------------------------------------------------------------
1 | load(
2 | "@build_bazel_rules_apple//apple/testing/default_runner:ios_xctestrun_runner.bzl",
3 | "ios_xctestrun_runner",
4 | )
5 |
6 | ios_xctestrun_runner(
7 | name = "default_test_runner",
8 | device_type = "iPhone 16",
9 | random = True,
10 | visibility = ["//visibility:public"],
11 | )
12 |
--------------------------------------------------------------------------------
/tools/extensions.bzl:
--------------------------------------------------------------------------------
1 | load("//tools:repositories.bzl", "swiftlint_dependency")
2 |
3 | def _non_module_dependencies_impl(_ctx):
4 | swiftlint_dependency()
5 |
6 | non_module_dependencies = module_extension(
7 | implementation = _non_module_dependencies_impl,
8 | )
9 |
--------------------------------------------------------------------------------
/tools/repositories.bzl:
--------------------------------------------------------------------------------
1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
2 |
3 | def swiftlint_dependency():
4 | http_archive(
5 | name = "SwiftLint",
6 | build_file_content = """
7 | load("@bazel_skylib//rules:native_binary.bzl", "native_binary")
8 | native_binary(
9 | name = "swiftlint",
10 | src = "bin/swiftlint",
11 | out = "swiftlint",
12 | visibility = ["//visibility:public"],
13 | )
14 | """,
15 | sha256 = "03416a4f75f023e10f9a76945806ddfe70ca06129b895455cc773c5c7d86b73e",
16 | strip_prefix = "SwiftLintBinary.artifactbundle/swiftlint-0.53.0-macos",
17 | url = "https://github.com/realm/SwiftLint/releases/download/0.53.0/SwiftLintBinary-macos.artifactbundle.zip",
18 | )
19 |
--------------------------------------------------------------------------------
/tools/shared.bzl:
--------------------------------------------------------------------------------
1 | app_info = struct(
2 | bundle_name = "SwiftUIApp",
3 | bundle_id = "com.example.SwiftUIApp",
4 | executable_name = "SwiftUIAppBinary",
5 | )
6 |
7 | versions = struct(
8 | minimum_ios_version = "18.0",
9 | )
10 |
--------------------------------------------------------------------------------