diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index bf512bbe..e3282b82 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -39,6 +39,17 @@ When in doubt about whether we will be interested in including a new feature, pl 7. Ensure all checks (tests, lint) are passing in GitHub. 8. Open a pull request with a detailed description of what is changing and why. +### Dev tooling + +Shopify employees can use the root `dev.yml` from the repo root: + +```bash +dev up +dev check +``` + +Platform-scoped commands are available as `dev android `, `dev swift `, and `dev react-native ` (or `dev rn`). Protocol schema/model commands are available as `dev protocol `. For cross-platform changes, use `dev lint`, `dev test`, `dev check`, `dev format`, and `dev build`. + --- ## Swift (`platforms/swift/`) diff --git a/AGENTS.md b/AGENTS.md index 63a4b7e1..f9ef5375 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,3 +9,28 @@ protocol/ # cross-platform communication layer based on UCP e2e/ # cross-platform end-to-end tests .github/ # workflows, issue templates, CODEOWNERS ``` + +## Dev workflow + +> **AI agents:** All commands require the `shadowenv exec --` prefix to run inside the shadowenv-managed environment. +> +> ``` +> shadowenv exec --dir -- /opt/dev/bin/dev up +> shadowenv exec --dir -- /opt/dev/bin/dev test [ARGS] +> ``` + +Run `dev` commands from the repo root. Use `dev up` before running commands when +the environment may not be provisioned. + +For platform-scoped work, prefer the root `dev.yml` commands: + +- Android: `dev android ` +- Swift: `dev swift ` +- React Native: `dev react-native ` or `dev rn ` + +For protocol schema/model work, use `dev protocol `. + +For cross-platform changes, use the repo-wide aggregates: `dev lint`, +`dev test`, `dev check`, `dev format`, and `dev build`. Use +`dev format` for formatting; `fix` remains an alias for existing +workflows. diff --git a/dev.yml b/dev.yml index b9d9855e..fe8b3e59 100644 --- a/dev.yml +++ b/dev.yml @@ -8,6 +8,7 @@ up: - xcbeautify - jq - swiftlint + - swiftformat - sccache - ruby - custom: @@ -81,14 +82,25 @@ check: android-detekt: cd platforms/android && ./gradlew detekt android-lint: cd platforms/android && ./gradlew lintRelease swift-lint: cd platforms/swift && ./Scripts/lint + swift-license-headers: cd platforms/swift && ./Scripts/ensure_license react-native-lint-swift: cd platforms/react-native && ./scripts/lint_swift react-native-lint-module: cd platforms/react-native && pnpm module lint react-native-lint-sample: cd platforms/react-native && pnpm sample lint + react-native-license-headers: cd platforms/react-native && ./scripts/copy_license --check web-lint: cd platforms/web && pnpm lint web-test: cd platforms/web && pnpm test commands: # Repo-wide + build: + desc: Build all supported workspaces + run: | + set -e + /opt/dev/bin/dev android build + /opt/dev/bin/dev swift build + /opt/dev/bin/dev react-native build + /opt/dev/bin/dev web build + codegen: desc: "Generate UCP models. Usage: dev codegen " syntax: "" @@ -97,6 +109,36 @@ commands: kotlin|swift|typescript|ts) ./protocol/scripts/generate_models.sh --lang "$1" ;; *) echo "Usage: dev codegen "; exit 1 ;; esac + + format: + desc: Auto-format and apply safe lint autocorrections across supported workspaces + aliases: [fix] + run: | + set -e + /opt/dev/bin/dev android format + /opt/dev/bin/dev swift format + /opt/dev/bin/dev react-native format + /opt/dev/bin/dev web format + + lint: + desc: Run lint checks across supported workspaces + aliases: [style] + run: | + set -e + /opt/dev/bin/dev android lint + /opt/dev/bin/dev swift lint + /opt/dev/bin/dev react-native lint + /opt/dev/bin/dev web lint + + test: + desc: Run tests across all supported workspaces + run: | + set -e + /opt/dev/bin/dev android test + /opt/dev/bin/dev swift test + /opt/dev/bin/dev react-native test + /opt/dev/bin/dev web test + apollo: subcommands: download_schema: @@ -118,6 +160,23 @@ commands: *) echo "Usage: dev apollo codegen [accelerated|mobile-buy|all]"; exit 1 ;; esac + # Protocol + protocol: + desc: "Checkout protocol commands" + subcommands: + build: + desc: Build the Swift protocol target + run: cd protocol/languages/swift && swift build + test: + desc: Build the Swift protocol test target + run: cd protocol/languages/swift && swift build --build-tests + check: + desc: Build the Swift protocol target and test target + run: | + set -e + /opt/dev/bin/dev protocol build + /opt/dev/bin/dev protocol test + # Android android: desc: "Android Checkout Kit commands" @@ -130,6 +189,10 @@ commands: desc: Build all sample applications run: cd platforms/android/samples/MobileBuyIntegration && ./gradlew build + clean: + desc: Clean Android Gradle build outputs + run: cd platforms/android && ./gradlew clean + test: desc: Run all tests with clean build run: cd platforms/android && ./gradlew clean test --console=plain @@ -144,8 +207,9 @@ commands: aliases: [style] run: cd platforms/android && ./gradlew detekt lintRelease - fix: - desc: Automatically fix format and lint issues where possible + format: + desc: Auto-format and apply safe lint autocorrections + aliases: [fix] run: cd platforms/android && ./gradlew detekt --auto-correct api: @@ -155,6 +219,7 @@ commands: echo "" echo " check Verify public API matches the committed baseline" echo " dump Regenerate the baseline after intentional public API changes" + exit 1 subcommands: check: desc: Verify public API matches the committed baseline @@ -164,13 +229,11 @@ commands: run: cd platforms/android && ./gradlew :lib:apiDump check: - desc: Run all Android checks (license headers, detekt, android lint) + desc: Run all Android checks (license headers + lint) run: | set -e - cd platforms/android - ./scripts/check_license_headers.rb - ./gradlew detekt - ./gradlew lintRelease + /opt/dev/bin/dev android check license-headers + /opt/dev/bin/dev android lint subcommands: license-headers: desc: Check MIT license headers in source files @@ -190,20 +253,39 @@ commands: desc: Check format and lint issues using SwiftLint and SwiftFormat aliases: [style] run: cd platforms/swift && ./Scripts/lint - fix: - desc: Automatically fix format and lint issues where possible + format: + desc: Auto-format and apply safe lint autocorrections + aliases: [fix] run: cd platforms/swift && ./Scripts/lint fix + clean: + desc: Clean Swift packages and sample app build artifacts + run: | + set -e + cd platforms/swift + # ShopifyCheckoutKit-Package is the SPM-wide scheme: it cleans all + # library targets in Package.swift (ShopifyCheckoutKit, + # ShopifyAcceleratedCheckouts, ShopifyCheckoutProtocol) in one pass. + ./Scripts/xcode_run clean ShopifyCheckoutKit-Package + cd Samples + # Sample apps have a "Run Script" build phase that runs during clean + # and exits non-zero when there is nothing to delete. Tolerate it so + # the second sample still gets cleaned. + ../Scripts/xcode_run clean MobileBuyIntegration || true + ../Scripts/xcode_run clean ShopifyAcceleratedCheckoutsApp || true build: - desc: Build Swift packages or sample apps + desc: Build all Swift packages and sample apps run: | - echo "Usage: dev swift build {packages|samples}" + set -e + cd platforms/swift + # ShopifyCheckoutKit-Package builds every library target in + # Package.swift in one xcodebuild invocation. The sample apps act as + # integration compilation checks against the built libraries. + ./Scripts/xcode_run build ShopifyCheckoutKit-Package + ./Scripts/build_samples subcommands: packages: - desc: Build both ShopifyCheckoutKit and ShopifyAcceleratedCheckouts packages - run: | - cd platforms/swift - ./Scripts/xcode_run build ShopifyCheckoutKit - ./Scripts/xcode_run build ShopifyAcceleratedCheckouts + desc: Build Swift package targets + run: cd platforms/swift && ./Scripts/xcode_run build ShopifyCheckoutKit-Package samples: desc: Build all sample applications to verify integration run: cd platforms/swift && ./Scripts/build_samples @@ -220,6 +302,7 @@ commands: echo "" echo " check Verify public Swift API matches the committed baselines" echo " dump Regenerate the Swift API baselines after intentional public API changes" + exit 1 subcommands: check: desc: Verify public Swift API matches the committed baselines @@ -227,12 +310,25 @@ commands: dump: desc: Regenerate the Swift API baselines after intentional public API changes run: cd platforms/swift && ./Scripts/api dump + check: + desc: Run Swift lint and license header checks + run: | + set -e + /opt/dev/bin/dev swift lint + /opt/dev/bin/dev swift check license-headers + subcommands: + license-headers: + desc: Check MIT license headers in Swift source files + run: cd platforms/swift && ./Scripts/ensure_license # React Native react-native: desc: "React Native Checkout Kit commands" aliases: [rn] subcommands: + build: + desc: Build the @shopify/checkout-kit-react-native module + run: cd platforms/react-native && pnpm module build server: desc: Start Metro development server aliases: [s] @@ -278,9 +374,6 @@ commands: sccache --stop-server 2>/dev/null || true fi echo "Cleaned root, module and sample workspaces" - build: - desc: Build the @shopify/checkout-kit-react-native module - run: cd platforms/react-native && pnpm module build lint: desc: Run all React Native lint checks (Swift, module, sample) aliases: [style] @@ -295,13 +388,13 @@ commands: desc: Lint Swift code via SwiftLint run: cd platforms/react-native && ./scripts/lint_swift module: - desc: Lint the @shopify/checkout-sheet-kit module + desc: Lint the @shopify/checkout-kit-react-native module run: cd platforms/react-native && pnpm module lint sample: desc: Lint the sample app run: cd platforms/react-native && pnpm sample lint format: - desc: Auto-fix Swift lint and format issues + desc: Auto-format and apply safe lint autocorrections (Swift bridge only) aliases: [fix] run: cd platforms/react-native && ./scripts/lint_swift fix api: @@ -311,6 +404,7 @@ commands: echo "" echo " check Verify public RN API matches the committed report" echo " dump Regenerate the RN API report after intentional public API changes" + exit 1 subcommands: check: desc: Verify public RN API matches the committed report @@ -318,6 +412,28 @@ commands: dump: desc: Regenerate the RN API report after intentional public API changes run: cd platforms/react-native && pnpm module api:dump + test: + desc: Run React Native Jest tests + run: cd platforms/react-native && pnpm test --testPathPatterns="modules/@shopify/checkout-kit-react-native/tests" + check: + desc: Run React Native license header and lint checks + run: | + set -e + /opt/dev/bin/dev react-native check license-headers + /opt/dev/bin/dev react-native lint + subcommands: + license-headers: + desc: Check React Native module license headers + run: cd platforms/react-native && ./scripts/copy_license --check + + rn: + desc: "Alias for React Native Checkout Kit commands" + long_desc: | + Alias for `dev react-native ...`. Use `dev help react-native` for the + full subcommand list. + syntax: + optional: "[command] [args]" + run: /opt/dev/bin/dev react-native "$@" # Web web: diff --git a/platforms/android/AGENTS.md b/platforms/android/AGENTS.md index 3cbd7a6c..1b48dd18 100644 --- a/platforms/android/AGENTS.md +++ b/platforms/android/AGENTS.md @@ -42,7 +42,7 @@ The sample is a separate Gradle composite (`samples/MobileBuyIntegration/setting - **`-Xexplicit-api=strict`** is on (`lib/build.gradle`). Every public class, method, field, and property must have an explicit visibility modifier. "Accidentally public" is not a thing here. This is a consumer-protection rule — if you see a public-by-default declaration, it was deliberate. - **Max line length: 140** (detekt-enforced). Detekt config: `lib/detekt.config.yml`. -- **MIT license header required on every new source file.** Format: copy the top comment of any existing `.kt` or `.java` file in `lib/src/main` or `lib/src/test`. Enforced in CI via the repo-root `scripts/check_license_headers.rb`. +- **MIT license header required on every new source file.** Format: copy the top comment of any existing `.kt` or `.java` file in `lib/src/main` or `lib/src/test`. Enforced in CI via `platforms/android/scripts/check_license_headers.rb`; check locally with `dev android check license-headers` from the repo root. - **Library JVM target: 1.8.** Intentional for consumer compatibility; don't raise without a major-version discussion. - **Library Kotlin version is pinned.** The `lib/build.gradle` plugin version and any `apiVersion` / `languageVersion` settings exist to keep consumer compatibility stable. A Kotlin major-version migration is a planned major-version event, not a casual dep bump. - **Prefer generated protocol models.** Before adding hand-written protocol DTOs, check the generated models in `lib/src/main/java/com/shopify/checkoutkit/Models.kt` and the OpenRPC schema. Use generated UCP/ECP types for wire payloads; reserve local DTOs for Android-internal transport helpers that are not represented in the schema. @@ -64,7 +64,7 @@ If `apiCheck` fails and you did *not* intend to change public API, the diff tell - Tests: `./gradlew :lib:test` (or `dev android test`) - API surface: `./gradlew :lib:apiCheck` / `./gradlew :lib:apiDump` (or `dev android api check` / `dev android api dump`) - Lint: `./gradlew detekt lintRelease` (or `dev android lint`) -- Auto-fix lint: `./gradlew detekt --auto-correct` (or `dev android fix`) +- Format: `./gradlew detekt --auto-correct` (or `dev android format`) - Full local verification: `./gradlew :lib:clean :lib:test :lib:detekt :lib:lintRelease :lib:assembleRelease` - Sample app build (from `samples/MobileBuyIntegration/`): `./gradlew assembleDebug` diff --git a/platforms/android/scripts/check_license_headers.rb b/platforms/android/scripts/check_license_headers.rb index 93b52778..12f59f30 100755 --- a/platforms/android/scripts/check_license_headers.rb +++ b/platforms/android/scripts/check_license_headers.rb @@ -4,7 +4,10 @@ files = [] Find.find('.') do |path| - next if path.include?('build/generated') + if File.directory?(path) && ['.gradle', 'build'].include?(File.basename(path)) + Find.prune + end + next unless File.file?(path) && path.end_with?('.kt') lines = File.readlines(path) diff --git a/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/AcceleratedCheckoutButtons.swift b/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/AcceleratedCheckoutButtons.swift index c54943ac..18d4f006 100644 --- a/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/AcceleratedCheckoutButtons.swift +++ b/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/AcceleratedCheckoutButtons.swift @@ -159,8 +159,8 @@ class RCTAcceleratedCheckoutButtonsView: UIView { hostingController?.view.frame = bounds } - // Deprecated in iOS 17 — superseded by registerForTraitChanges in setupView(). - // Remove this override when dropping iOS 16 support. + /// Deprecated in iOS 17 — superseded by registerForTraitChanges in setupView(). + /// Remove this override when dropping iOS 16 support. override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if #unavailable(iOS 17.0) { diff --git a/platforms/react-native/sample/src/screens/SettingsScreen.tsx b/platforms/react-native/sample/src/screens/SettingsScreen.tsx index 4a9ad9c0..cc87bf95 100644 --- a/platforms/react-native/sample/src/screens/SettingsScreen.tsx +++ b/platforms/react-native/sample/src/screens/SettingsScreen.tsx @@ -361,7 +361,7 @@ function BuyerIdentityDetails({ if (authenticated) { return ( - + Changing Buyer Identity will log you out. @@ -449,6 +449,9 @@ function createStyles(colors: Colors) { fontSize: 12, color: colors.textSubdued, }, + warningText: { + color: '#f5a623', + }, detailRow: { flexDirection: 'row', alignItems: 'center', diff --git a/platforms/react-native/scripts/copy_license b/platforms/react-native/scripts/copy_license index af75710e..e1d59d4c 100755 --- a/platforms/react-native/scripts/copy_license +++ b/platforms/react-native/scripts/copy_license @@ -92,6 +92,7 @@ def copy_license(dir, license_block, normalized_license, check_only: false) supported_exts = %w[.swift .h .mm .java .js .ts .tsx] Find.find(dir) do |path| + next if path.include?('/build/generated/') next unless File.file?(path) && supported_exts.any? { |ext| path.end_with?(ext) } changed = process_file(path, license_block, normalized_license, write: !check_only) diff --git a/platforms/react-native/scripts/lint_swift b/platforms/react-native/scripts/lint_swift index d909a495..6490ab24 100755 --- a/platforms/react-native/scripts/lint_swift +++ b/platforms/react-native/scripts/lint_swift @@ -2,6 +2,9 @@ DIR=modules/@shopify/checkout-kit-react-native MODE="${1:-check}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel)" +SWIFT_TOOLS_DIR="$REPO_ROOT/platforms/swift" # Validate the mode if [[ "$MODE" != "check" && "$MODE" != "fix" ]]; then @@ -16,20 +19,33 @@ fi print_install_instructions() { echo "🔧 FIX:" echo " Shopify employee? Run 'dev up'" - echo " Not a Shopify employee? Install via homebrew:" - echo " - SwiftLint: 'brew install swiftlint' / https://github.com/realm/SwiftLint" - echo " - SwiftFormat: 'brew install swiftformat' / https://github.com/nicklockwood/SwiftFormat" + echo " Not a Shopify employee? Install Mint and run 'mint bootstrap' from platforms/swift" + echo " Homebrew also works: 'brew install swiftlint swiftformat'" } -# Check for SwiftLint -if ! which swiftlint >/dev/null; then +resolve_tool() { + local command_name=$1 + + if which "$command_name" >/dev/null; then + which "$command_name" + return 0 + fi + + if command -v mint >/dev/null; then + (cd "$SWIFT_TOOLS_DIR" && mint which "$command_name") + return $? + fi + + return 1 +} + +if ! SWIFTLINT="$(resolve_tool swiftlint)"; then echo "⚠️ WARN: SwiftLint not installed" print_install_instructions exit 1 fi -# Check for SwiftFormat -if ! which swiftformat >/dev/null; then +if ! SWIFTFORMAT="$(resolve_tool swiftformat)"; then echo "⚠️ WARN: SwiftFormat not installed" print_install_instructions exit 1 @@ -38,11 +54,11 @@ fi # Run SwiftLint if [[ "$MODE" == "check" ]]; then echo "🔄 Running SwiftLint in check mode..." - swiftlint lint --strict $DIR --config .swiftlint.yml + "$SWIFTLINT" lint --strict $DIR --config .swiftlint.yml LINT_STATUS=$? else echo "🔄 Running SwiftLint in fix mode..." - swiftlint lint --fix $DIR --config .swiftlint.yml + "$SWIFTLINT" lint --fix $DIR --config .swiftlint.yml LINT_STATUS=$? fi echo "SwiftLint exit status: $LINT_STATUS" @@ -50,11 +66,11 @@ echo "SwiftLint exit status: $LINT_STATUS" # Run SwiftFormat if [[ "$MODE" == "check" ]]; then echo "🔄 Running SwiftFormat in check mode..." - swiftformat $DIR --lint --config .swiftformat + "$SWIFTFORMAT" $DIR --lint --config .swiftformat FORMAT_STATUS=$? else echo "🔄 Running SwiftFormat in fix mode..." - swiftformat $DIR --config .swiftformat + "$SWIFTFORMAT" $DIR --config .swiftformat FORMAT_STATUS=$? fi echo "SwiftFormat exit status: $FORMAT_STATUS" diff --git a/platforms/swift/.cursor/rules/swift-development.mdc b/platforms/swift/.cursor/rules/swift-development.mdc index 5ae1c7d3..ccb49685 100644 --- a/platforms/swift/.cursor/rules/swift-development.mdc +++ b/platforms/swift/.cursor/rules/swift-development.mdc @@ -25,8 +25,8 @@ alwaysApply: true Key commands for verification: - `dev swift lint` (alias: `dev swift style`) - Check format & lint issues -- `dev swift fix` - Auto-fix formatting and linting issues -- `dev swift build packages` - Build both packages +- `dev swift format` - Auto-format and apply safe lint autocorrections +- `dev swift build packages` - Build Swift package targets - `dev swift test` - Run all tests ## Concurrency Best Practices @@ -50,7 +50,7 @@ actor QueryCache { ✅ DO: Run the appropriate dev command to verify ### After making changes: -- ALWAYS run `dev swift fix && dev swift lint` to check your code is formatted and written in our style. +- ALWAYS run `dev swift format && dev swift lint` to check your code is formatted and written in our style. ## Example Workflow @@ -58,7 +58,7 @@ actor QueryCache { # Make your Swift changes... # Fix any auto-fixable issues -dev swift fix +dev swift format # Check for any remaining lint issues dev swift lint diff --git a/platforms/swift/Samples/MobileBuyIntegration/README.md b/platforms/swift/Samples/MobileBuyIntegration/README.md index d6d58343..81b86597 100644 --- a/platforms/swift/Samples/MobileBuyIntegration/README.md +++ b/platforms/swift/Samples/MobileBuyIntegration/README.md @@ -88,7 +88,7 @@ API_VERSION = 2025-10 The schema defines what types and fields are available in the API. Run from the **repo root** (`checkout-kit/`): ```bash -dev apollo download_schema mobile-buy +dev apollo download_schema swift mobile-buy ``` This introspects your store's Storefront API at the configured version and writes a `schema..graphqls` file into the sample app directory. @@ -120,10 +120,10 @@ query GetProducts(...) { From the **repo root**: ```bash -dev apollo codegen mobile-buy +dev apollo codegen swift mobile-buy ``` -This reads the schema + your `.graphql` files and regenerates the Swift code in `Generated/`. The command also runs `dev swift fix` to auto-format the output. +This reads the schema + your `.graphql` files and regenerates the Swift code in `Generated/`. The command also runs `dev swift format` to auto-format the output. ### 5. Build and fix any issues @@ -135,11 +135,11 @@ All commands are run from the **repo root** (`checkout-kit/`): | Command | Description | |---------|-------------| -| `dev apollo download_schema mobile-buy` | Download the Storefront API schema for this sample app | -| `dev apollo codegen mobile-buy` | Regenerate Swift types from `.graphql` files | -| `dev apollo codegen all` | Regenerate for all sample apps | -| `dev swift style` | Run SwiftLint + SwiftFormat checks | -| `dev swift fix` | Auto-fix lint/format issues | +| `dev apollo download_schema swift mobile-buy` | Download the Storefront API schema for this sample app | +| `dev apollo codegen swift mobile-buy` | Regenerate Swift types from `.graphql` files | +| `dev apollo codegen swift all` | Regenerate for all sample apps | +| `dev swift lint` | Run SwiftLint + SwiftFormat checks | +| `dev swift format` | Auto-format and apply safe lint autocorrections | | `dev swift build samples` | Build all sample apps | ## Key files diff --git a/platforms/swift/Scripts/apollo_codegen b/platforms/swift/Scripts/apollo_codegen index 9839c390..489324a3 100755 --- a/platforms/swift/Scripts/apollo_codegen +++ b/platforms/swift/Scripts/apollo_codegen @@ -23,7 +23,7 @@ run_codegen() { local schema_count=$(find "$REPO_ROOT/$dir" -name "*.graphqls" -maxdepth 1 | wc -l | tr -d ' ') if [ "$schema_count" -eq 0 ]; then echo "❌ No .graphqls schema file found in $dir" - echo " Run 'dev apollo download_schema $name' first" + echo " Run 'dev apollo download_schema swift $name' first" return 1 fi @@ -58,4 +58,4 @@ case "$APP" in ;; esac -/opt/dev/bin/dev swift fix +/opt/dev/bin/dev swift format diff --git a/platforms/swift/Scripts/lint b/platforms/swift/Scripts/lint index 22b82d4b..41e38bc5 100755 --- a/platforms/swift/Scripts/lint +++ b/platforms/swift/Scripts/lint @@ -138,7 +138,7 @@ print_linting_error() { echo "❌ $tool_name detected issues that need to be fixed." if [[ "$MODE" == "check" ]]; then echo "🔧 How to fix:" - echo " Shopify employee? Run 'dev swift fix' and resolve remaining issues" + echo " Shopify employee? Run 'dev swift format' and resolve remaining issues" echo " Not a Shopify employee? Run './Scripts/lint fix' and resolve remaining issues" else echo "🔧 These files will need to be fixed manually" @@ -169,6 +169,7 @@ if [[ "$MODE" == "check" && "$SKIP_POD" == "false" ]]; then # platforms/swift/ and protocol/languages/swift/. Run lint from the # repo root. REPO_ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel)" + export BUNDLE_GEMFILE="${BUNDLE_GEMFILE:-$REPO_ROOT/platforms/swift/Gemfile}" POD_LOG="" if [[ "$VERBOSE" == "true" ]]; then (cd "$REPO_ROOT" && bundle exec pod lib lint ShopifyCheckoutKit.podspec --allow-warnings) @@ -188,7 +189,7 @@ if [[ "$MODE" == "check" && "$SKIP_POD" == "false" ]]; then echo "❌ CocoaPods lint exit status: $POD_STATUS" echo "❌ CocoaPods detected issues that need to be fixed." - echo "🔧 Run 'bundle exec pod lib lint ShopifyCheckoutKit.podspec --allow-warnings --verbose' from the repo root for details" + echo "🔧 Run 'BUNDLE_GEMFILE=platforms/swift/Gemfile bundle exec pod lib lint ShopifyCheckoutKit.podspec --allow-warnings --verbose' from the repo root for details" exit 1 fi diff --git a/platforms/swift/Scripts/xcode_run b/platforms/swift/Scripts/xcode_run index 7b45019e..1b9cf030 100755 --- a/platforms/swift/Scripts/xcode_run +++ b/platforms/swift/Scripts/xcode_run @@ -50,12 +50,18 @@ if [[ "$ACTION" == *"test"* && -n "$TEST_FILTER" ]]; then # Find which test target contains this test class (search all test targets automatically) project_root="$(cd "$SCRIPT_DIR/.." && pwd)" test_target="" + target_filter_added="" # Discover all test targets by looking for *Tests directories test_file="" for test_dir in "$project_root/Tests"/*Tests; do if [[ -d "$test_dir" ]]; then target_name=$(basename "$test_dir") + if [[ "$TEST_FILTER" == "$target_name" ]]; then + xcodebuild_cmd="$xcodebuild_cmd -only-testing:$target_name" + target_filter_added="1" + break + fi # Check if TEST_FILTER matches a .swift filename if find "$test_dir" -name "$TEST_FILTER.swift" -type f | grep -q .; then test_target="$target_name" @@ -65,7 +71,9 @@ if [[ "$ACTION" == *"test"* && -n "$TEST_FILTER" ]]; then fi done - if [[ -n "$test_target" && -n "$test_file" ]]; then + if [[ -n "$target_filter_added" ]]; then + : + elif [[ -n "$test_target" && -n "$test_file" ]]; then # Extract all test class names from the file test_classes=$(grep "class.*XCTestCase" "$test_file" | sed 's/.*class \([^:]*\):.*/\1/')