From 4283f488dcf944ac2f026d7d66ebc2506cb68ce3 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 25 Dec 2020 19:15:23 +0000 Subject: [PATCH 1/5] Use WAMR for `carton test` This simplifies our CI scripts, and installation via Homebrew and on Linux. It also allows us to pin the version of WASI runtime we use for CLI test execution. Closes #177. --- .github/workflows/swift.yml | 4 --- Brewfile | 1 - Brewfile.lock.json | 25 ------------------- Dockerfile | 6 ++--- Package.resolved | 11 +++++++- Package.swift | 24 +++++++----------- Sources/CartonCLI/Commands/Test.swift | 21 ++++++++-------- Sources/CartonKit/Helpers/WASI.swift | 11 ++++++++ .../Formula.swift | 1 - .../HashArchive.swift | 0 .../main.swift | 0 11 files changed, 42 insertions(+), 62 deletions(-) create mode 100644 Sources/CartonKit/Helpers/WASI.swift rename Sources/{carton-release => CartonRelease}/Formula.swift (98%) rename Sources/{carton-release => CartonRelease}/HashArchive.swift (100%) rename Sources/{carton-release => CartonRelease}/main.swift (100%) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index c971494e..01e4e35b 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -87,8 +87,6 @@ jobs: swift test -c release --enable-test-discovery swift build -c release sudo ./install_ubuntu_deps.sh - curl https://get.wasmer.io -sSfL | sh - source /home/runner/.wasmer/wasmer.sh cd TestApp && ../.build/release/carton test ../.build/release/carton bundle env: @@ -104,8 +102,6 @@ jobs: swift test -c release --enable-test-discovery swift build -c release sudo ./install_ubuntu_deps.sh - curl https://get.wasmer.io -sSfL | sh - source /home/runner/.wasmer/wasmer.sh cd TestApp && ../.build/release/carton test ../.build/release/carton bundle env: diff --git a/Brewfile b/Brewfile index b42467a9..82e7662d 100644 --- a/Brewfile +++ b/Brewfile @@ -2,4 +2,3 @@ brew "pre-commit" brew "swiftformat" brew "swiftlint" brew "binaryen" -brew "wasmer" diff --git a/Brewfile.lock.json b/Brewfile.lock.json index cd9e369e..14317d48 100644 --- a/Brewfile.lock.json +++ b/Brewfile.lock.json @@ -84,31 +84,6 @@ } } } - }, - "wasmer": { - "version": "0.16.2", - "bottle": { - "cellar": ":any_skip_relocation", - "prefix": "/usr/local", - "files": { - "big_sur": { - "url": "https://homebrew.bintray.com/bottles/wasmer-0.16.2.big_sur.bottle.tar.gz", - "sha256": "63d91bbfece68628e7bb464cd8d3a90a6dc89344c4889ada157f174db62f05da" - }, - "catalina": { - "url": "https://homebrew.bintray.com/bottles/wasmer-0.16.2.catalina.bottle.tar.gz", - "sha256": "751b4b059036dbca254eef935bc03240e1fd559465a376a0cff8f5a41dcd3980" - }, - "mojave": { - "url": "https://homebrew.bintray.com/bottles/wasmer-0.16.2.mojave.bottle.tar.gz", - "sha256": "725d2b857e0954b1e2fd8a01021847e168d5daec33cd76c32f90a0ae12fdf422" - }, - "high_sierra": { - "url": "https://homebrew.bintray.com/bottles/wasmer-0.16.2.high_sierra.bottle.tar.gz", - "sha256": "42ea898c1ebd9c0ac58bf21117c05df6a4726123590444c19173a01586c80c63" - } - } - } } } }, diff --git a/Dockerfile b/Dockerfile index a70a2267..78e6fafb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,7 @@ RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true && ap libsqlite3-0 \ libsqlite3-dev \ curl unzip \ - && export WASMER_DIR=/usr/local && curl https://get.wasmer.io -sSfL | sh && \ - rm -r /var/lib/apt/lists/* + && rm -r /var/lib/apt/lists/* ENV CARTON_ROOT=/root/.carton ENV CARTON_DEFAULT_TOOLCHAIN=wasm-5.3.1-RELEASE @@ -28,8 +27,7 @@ RUN cd carton && \ swift build -c release && \ cd TestApp && ../.build/release/carton test && cd .. && \ mv .build/release/carton /usr/bin && \ - cd .. && \ - rm -rf carton /tmp/wasmer* + cd .. # Set the default command to run CMD ["carton --help"] diff --git a/Package.resolved b/Package.resolved index 90dc1cdc..22f476fa 100644 --- a/Package.resolved +++ b/Package.resolved @@ -163,9 +163,18 @@ "version": "4.36.2" } }, + { + "package": "WAMR", + "repositoryURL": "https://github.com/swiftwasm/wamr-swift.git", + "state": { + "branch": "main", + "revision": "f06c454fd9c16d5a00c8bdece0b0a57e0bb82f43", + "version": null + } + }, { "package": "WasmTransformer", - "repositoryURL": "https://github.com/swiftwasm/WasmTransformer", + "repositoryURL": "https://github.com/swiftwasm/WasmTransformer.git", "state": { "branch": null, "revision": "74bd6559322b43390eb6da5a134f5af7f117bd01", diff --git a/Package.swift b/Package.swift index 482428b3..48f60c6c 100644 --- a/Package.swift +++ b/Package.swift @@ -18,7 +18,7 @@ let package = Package( .library(name: "CartonKit", targets: ["CartonKit"]), .library(name: "CartonCLI", targets: ["CartonCLI"]), .executable(name: "carton", targets: ["Carton"]), - .executable(name: "carton-release", targets: ["carton-release"]), + .executable(name: "carton-release", targets: ["CartonRelease"]), ], dependencies: [ .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.2.2"), @@ -34,7 +34,11 @@ let package = Package( .package(url: "https://github.com/vapor/vapor.git", from: "4.29.3"), .package(url: "https://github.com/apple/swift-crypto.git", from: "1.1.0"), .package(url: "https://github.com/JohnSundell/Splash.git", from: "0.14.0"), - .package(url: "https://github.com/swiftwasm/WasmTransformer", .upToNextMinor(from: "0.0.2")), + .package( + url: "https://github.com/swiftwasm/WasmTransformer.git", + .upToNextMinor(from: "0.0.2") + ), + .package(name: "WAMR", url: "https://github.com/swiftwasm/wamr-swift.git", .branch("main")), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module @@ -42,18 +46,7 @@ let package = Package( // products in packages which this package depends on. .target( name: "Carton", - dependencies: [ - "CartonCLI", - // commented out for now. Will remove once confirmed working -// .product(name: "ArgumentParser", package: "swift-argument-parser"), -// .product(name: "AsyncHTTPClient", package: "async-http-client"), -// .product(name: "Crypto", package: "swift-crypto"), -// .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"), -// .product(name: "Vapor", package: "vapor"), -// "CartonHelpers", -// openCombineProduct, -// "SwiftToolchain", - ] + dependencies: ["CartonCLI"] ), .target( name: "CartonCLI", @@ -70,6 +63,7 @@ let package = Package( "CartonHelpers", openCombineProduct, "SwiftToolchain", + "WAMR", ] ), .target( @@ -94,7 +88,7 @@ let package = Package( // This target is used only for release automation tasks and // should not be installed by `carton` users. .target( - name: "carton-release", + name: "CartonRelease", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), .product(name: "AsyncHTTPClient", package: "async-http-client"), diff --git a/Sources/CartonCLI/Commands/Test.swift b/Sources/CartonCLI/Commands/Test.swift index 499b7f80..d64e4ed1 100644 --- a/Sources/CartonCLI/Commands/Test.swift +++ b/Sources/CartonCLI/Commands/Test.swift @@ -22,16 +22,17 @@ import CartonHelpers import CartonKit import SwiftToolchain import TSCBasic +import WAMR private enum Environment: String, CaseIterable, ExpressibleByArgument { - case wasmer + case wamr case defaultBrowser var destination: DestinationEnvironment { switch self { case .defaultBrowser: return .browser - case .wasmer: + case .wamr: return .other } } @@ -52,7 +53,7 @@ struct Test: ParsableCommand { var testCases = [String]() @Option(help: "Environment used to run the tests, either a browser, or command-line Wasm host.") - private var environment = Environment.wasmer + private var environment = Environment.wamr @Option( name: .shortAndLong, @@ -67,18 +68,16 @@ struct Test: ParsableCommand { let toolchain = try Toolchain(localFileSystem, terminal) let testBundlePath = try toolchain.buildTestBundle(isRelease: release) - if environment == .wasmer { - terminal.write("\nRunning the test bundle with wasmer:\n", inColor: .yellow) - var wasmerArguments = ["wasmer", testBundlePath.pathString] + if environment == .wamr { + terminal.write("\nRunning the test bundle with WAMR:\n", inColor: .yellow) + var arguments = [String]() if list { - wasmerArguments.append(contentsOf: ["--", "-l"]) + arguments.append(contentsOf: ["-l"]) } else if !testCases.isEmpty { - wasmerArguments.append("--") - wasmerArguments.append(contentsOf: testCases) + arguments.append(contentsOf: testCases) } - let runner = ProcessRunner(wasmerArguments, parser: TestsParser(), terminal) - try runner.waitUntilFinished() + try wasiRuntimeExecute(wasmPath: testBundlePath, cmdLineArgs: arguments) } else { try Server( with: .init( diff --git a/Sources/CartonKit/Helpers/WASI.swift b/Sources/CartonKit/Helpers/WASI.swift new file mode 100644 index 00000000..226480af --- /dev/null +++ b/Sources/CartonKit/Helpers/WASI.swift @@ -0,0 +1,11 @@ +import TSCBasic +import WAMR + +public func wasiRuntimeExecute(wasmPath: AbsolutePath, cmdLineArgs: [String]) throws { + WasmRuntime.initialize() + let binary = try localFileSystem.readFileContents(wasmPath) + let module = try WasmModule(binary: binary.contents) + module.setWasiOptions(dirs: [], mapDirs: [], envs: [], args: cmdLineArgs) + let instance = try module.instantiate(stackSize: 256 * 1024) + try instance.executeMain(args: []) +} diff --git a/Sources/carton-release/Formula.swift b/Sources/CartonRelease/Formula.swift similarity index 98% rename from Sources/carton-release/Formula.swift rename to Sources/CartonRelease/Formula.swift index d2e48a6e..41f6ba37 100644 --- a/Sources/carton-release/Formula.swift +++ b/Sources/CartonRelease/Formula.swift @@ -44,7 +44,6 @@ struct Formula: ParsableCommand { head "https://github.com/swiftwasm/carton.git" depends_on :xcode => "11.4" - depends_on "wasmer" depends_on "binaryen" stable do diff --git a/Sources/carton-release/HashArchive.swift b/Sources/CartonRelease/HashArchive.swift similarity index 100% rename from Sources/carton-release/HashArchive.swift rename to Sources/CartonRelease/HashArchive.swift diff --git a/Sources/carton-release/main.swift b/Sources/CartonRelease/main.swift similarity index 100% rename from Sources/carton-release/main.swift rename to Sources/CartonRelease/main.swift From 2eb5323034e9ae5c82979af2726b82415ca8a0e9 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 25 Dec 2020 19:20:43 +0000 Subject: [PATCH 2/5] Tweak CI scripts --- .github/workflows/swift.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 01e4e35b..ee21f2bf 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -15,8 +15,8 @@ jobs: - name: Build on macOS 10.15 with Swift 5.2 run: | sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer + swift build -c release --arch x86_64 --arch arm64 swift test -c release --enable-test-discovery - swift build -c release brew bundle cd TestApp && ../.build/release/carton test ../.build/release/carton test --environment defaultBrowser @@ -33,8 +33,8 @@ jobs: - name: Build on macOS 11.0 with Swift 5.2 run: | sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer + swift build -c release --arch x86_64 --arch arm64 swift test -c release --enable-test-discovery - swift build -c release brew bundle cd TestApp && ../.build/release/carton test ../.build/release/carton test --environment defaultBrowser @@ -49,9 +49,9 @@ jobs: - uses: actions/checkout@v2 - name: Build on macOS 10.15 with Swift 5.3 run: | - sudo xcode-select --switch /Applications/Xcode_12.app/Contents/Developer + sudo xcode-select --switch /Applications/Xcode_12.3.app/Contents/Developer + swift build -c release --arch x86_64 --arch arm64 swift test -c release --enable-test-discovery - swift build -c release brew bundle cd TestApp && ../.build/release/carton test ../.build/release/carton test --environment defaultBrowser @@ -67,8 +67,8 @@ jobs: - name: Build on macOS 11.0 with Swift 5.3 run: | sudo xcode-select --switch /Applications/Xcode_12.2.app/Contents/Developer + swift build -c release --arch x86_64 --arch arm64 swift test -c release --enable-test-discovery - swift build -c release brew bundle cd TestApp && ../.build/release/carton test ../.build/release/carton test --environment defaultBrowser @@ -84,9 +84,8 @@ jobs: - name: Build on Ubuntu 18.04 with Swift 5.3 run: | - swift test -c release --enable-test-discovery - swift build -c release sudo ./install_ubuntu_deps.sh + swift test -c release --enable-test-discovery cd TestApp && ../.build/release/carton test ../.build/release/carton bundle env: @@ -99,9 +98,8 @@ jobs: - uses: actions/checkout@v2 - name: Build on Ubuntu 20.04 with Swift 5.3 run: | - swift test -c release --enable-test-discovery - swift build -c release sudo ./install_ubuntu_deps.sh + swift test -c release --enable-test-discovery cd TestApp && ../.build/release/carton test ../.build/release/carton bundle env: From 358423a789132abaef5a67bfd486997039f766d1 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 25 Dec 2020 19:22:45 +0000 Subject: [PATCH 3/5] Avoid producing fat binaries with Xcode 11 --- .github/workflows/swift.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index ee21f2bf..636f2a09 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -15,7 +15,7 @@ jobs: - name: Build on macOS 10.15 with Swift 5.2 run: | sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer - swift build -c release --arch x86_64 --arch arm64 + swift build -c release swift test -c release --enable-test-discovery brew bundle cd TestApp && ../.build/release/carton test @@ -33,7 +33,7 @@ jobs: - name: Build on macOS 11.0 with Swift 5.2 run: | sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer - swift build -c release --arch x86_64 --arch arm64 + swift build -c release swift test -c release --enable-test-discovery brew bundle cd TestApp && ../.build/release/carton test From 738fb3435ac43c7b495c18304b93305bfa56c709 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 25 Dec 2020 19:38:07 +0000 Subject: [PATCH 4/5] Drop support for Swift 5.2 --- .github/workflows/swift.yml | 35 ----------- .swiftformat | 2 +- Package@swift-5.2.swift | 115 ------------------------------------ README.md | 6 +- 4 files changed, 4 insertions(+), 154 deletions(-) delete mode 100644 Package@swift-5.2.swift diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 636f2a09..949e7f69 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -7,41 +7,6 @@ on: branches: [main] jobs: - catalina-swift5_2: - runs-on: macos-10.15 - - steps: - - uses: actions/checkout@v2 - - name: Build on macOS 10.15 with Swift 5.2 - run: | - sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer - swift build -c release - swift test -c release --enable-test-discovery - brew bundle - cd TestApp && ../.build/release/carton test - ../.build/release/carton test --environment defaultBrowser - ../.build/release/carton bundle - # the token is required to get around GitHub API limits when downloading the toolchain - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - bigsur-swift5_2: - runs-on: macos-11.0 - - steps: - - uses: actions/checkout@v2 - - name: Build on macOS 11.0 with Swift 5.2 - run: | - sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer - swift build -c release - swift test -c release --enable-test-discovery - brew bundle - cd TestApp && ../.build/release/carton test - ../.build/release/carton test --environment defaultBrowser - ../.build/release/carton bundle - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - catalina-swift5_3: runs-on: macos-10.15 diff --git a/.swiftformat b/.swiftformat index a33cd17e..2f2d430e 100644 --- a/.swiftformat +++ b/.swiftformat @@ -6,5 +6,5 @@ --ifdef noindent --stripunusedargs closure-only --disable andOperator ---swiftversion 5.2 +--swiftversion 5.3 --maxwidth 100 diff --git a/Package@swift-5.2.swift b/Package@swift-5.2.swift deleted file mode 100644 index b9a29ab9..00000000 --- a/Package@swift-5.2.swift +++ /dev/null @@ -1,115 +0,0 @@ -// swift-tools-version:5.2 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "carton", - platforms: [.macOS(.v10_15)], - products: [ - .library(name: "SwiftToolchain", targets: ["SwiftToolchain"]), - .library(name: "CartonHelpers", targets: ["CartonHelpers"]), - .library(name: "CartonKit", targets: ["CartonKit"]), - .library(name: "CartonCLI", targets: ["CartonCLI"]), - .executable(name: "carton", targets: ["Carton"]), - .executable(name: "carton-release", targets: ["carton-release"]), - ], - dependencies: [ - .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.1.1"), - .package( - url: "https://github.com/apple/swift-argument-parser.git", - .upToNextMinor(from: "0.3.0") - ), - .package( - url: "https://github.com/apple/swift-tools-support-core.git", - .upToNextMinor(from: "0.1.10") - ), - .package(url: "https://github.com/OpenCombine/OpenCombine.git", from: "0.10.0"), - .package(url: "https://github.com/vapor/vapor.git", from: "4.29.3"), - .package(url: "https://github.com/apple/swift-crypto.git", from: "1.1.0"), - .package(url: "https://github.com/JohnSundell/Splash.git", from: "0.14.0"), - .package(url: "https://github.com/swiftwasm/WasmTransformer", .upToNextMinor(from: "0.0.1")), - ], - targets: [ - // Targets are the basic building blocks of a package. A target can define a module - // or a test suite. Targets can depend on other targets in this package, and on - // products in packages which this package depends on. - .target( - name: "Carton", - dependencies: [ - "CartonCLI", - // commented out for now. Will remove once confirmed working -// .product(name: "ArgumentParser", package: "swift-argument-parser"), -// .product(name: "AsyncHTTPClient", package: "async-http-client"), -// .product(name: "Crypto", package: "swift-crypto"), -// .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"), -// .product(name: "Vapor", package: "vapor"), -// "CartonHelpers", -// openCombineProduct, -// "SwiftToolchain", - ] - ), - .target( - name: "CartonCLI", - dependencies: ["CartonKit"] - ), - .target( - name: "CartonKit", - dependencies: [ - .product(name: "ArgumentParser", package: "swift-argument-parser"), - .product(name: "AsyncHTTPClient", package: "async-http-client"), - .product(name: "Crypto", package: "swift-crypto"), - .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"), - .product(name: "Vapor", package: "vapor"), - "CartonHelpers", - "OpenCombine", - "SwiftToolchain", - ] - ), - .target( - name: "SwiftToolchain", - dependencies: [ - .product(name: "AsyncHTTPClient", package: "async-http-client"), - .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"), - "CartonHelpers", - "OpenCombine", - "WasmTransformer", - ] - ), - .target( - name: "CartonHelpers", - dependencies: [ - .product(name: "AsyncHTTPClient", package: "async-http-client"), - .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"), - "OpenCombine", - "Splash", - ] - ), - // This target is used only for release automation tasks and - // should not be installed by `carton` users. - .target( - name: "carton-release", - dependencies: [ - .product(name: "ArgumentParser", package: "swift-argument-parser"), - .product(name: "AsyncHTTPClient", package: "async-http-client"), - .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"), - "CartonHelpers", - ] - ), - .testTarget( - name: "CartonTests", - dependencies: [ - "Carton", - "CartonHelpers", - .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"), - .product(name: "ArgumentParser", package: "swift-argument-parser"), - ] - ), - .testTarget( - name: "CartonCommandTests", - dependencies: [ - "CartonCLI", - ] - ), - ] -) diff --git a/README.md b/README.md index 655da6a8..2e0f57ea 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ development workflow such as toolchain and SDK installations. ### Requirements -- macOS 10.15 and Xcode 11.4 or later. -- [Swift 5.2 or later](https://swift.org/download/) and Ubuntu 18.04 or 20.04 for Linux users. +- macOS 10.15 and Xcode 12.0 or later. +- [Swift 5.3 or later](https://swift.org/download/) and Ubuntu 18.04 or 20.04 for Linux users. ### Installation @@ -170,7 +170,7 @@ Refer to [the pre-commit documentation page](https://pre-commit.com/) for more d and installation instructions for other platforms. SwiftFormat and SwiftLint also run on CI for every PR and thus a CI build can -fail with incosistent formatting or style. We require CI builds to pass for all +fail with inconsistent formatting or style. We require CI builds to pass for all PRs before merging. ### Code of Conduct From ff803418e54f636a7d6124b87d5e4d180e684155 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 25 Dec 2020 20:15:05 +0000 Subject: [PATCH 5/5] Try building for x86 only --- .github/workflows/swift.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 949e7f69..900c543f 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -15,7 +15,7 @@ jobs: - name: Build on macOS 10.15 with Swift 5.3 run: | sudo xcode-select --switch /Applications/Xcode_12.3.app/Contents/Developer - swift build -c release --arch x86_64 --arch arm64 + swift build -c release swift test -c release --enable-test-discovery brew bundle cd TestApp && ../.build/release/carton test @@ -31,8 +31,8 @@ jobs: - uses: actions/checkout@v2 - name: Build on macOS 11.0 with Swift 5.3 run: | - sudo xcode-select --switch /Applications/Xcode_12.2.app/Contents/Developer - swift build -c release --arch x86_64 --arch arm64 + sudo xcode-select --switch /Applications/Xcode_12.3.app/Contents/Developer + swift build -c release swift test -c release --enable-test-discovery brew bundle cd TestApp && ../.build/release/carton test