From 0fd134cba644e737ac2f7053ae05ba78004b0f45 Mon Sep 17 00:00:00 2001 From: Kyle Schellen Date: Wed, 20 May 2026 19:30:31 -0400 Subject: [PATCH] Add repo setup orchestration commands --- .env.example | 6 +- .github/CONTRIBUTING.md | 24 +- AGENTS.md | 14 + dev.yml | 369 +++++++++++------- .../samples/MobileBuyIntegration/.env.example | 2 +- .../samples/MobileBuyIntegration/README.md | 23 +- platforms/android/samples/README.md | 6 +- platforms/react-native/CONTRIBUTING.md | 21 +- .../ios/ShopifyCheckoutKit.swift | 8 +- platforms/react-native/sample/.env.example | 2 +- .../Samples/MobileBuyIntegration/README.md | 25 +- .../Storefront.xcconfig.example | 2 +- platforms/swift/Samples/README.md | 38 +- .../Storefront.xcconfig.example | 2 +- platforms/web/.gitignore | 1 + platforms/web/.oxlintrc.json | 1 + platforms/web/package.json | 6 +- scripts/setup_dev_workspace | 281 +++++++++++++ 18 files changed, 632 insertions(+), 199 deletions(-) create mode 100755 scripts/setup_dev_workspace diff --git a/.env.example b/.env.example index 4693ace4..d33347a9 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,9 @@ # Checkout Kit sample storefront configuration. -# Copy this file to .env, fill in local values, then run: +# Copy this file to .env, fill in local values, then run dev bootstrap or: # scripts/setup_storefront_env -# Optional Apple Pay and Customer Account API values can stay blank. +# Direct interactive setup prompts for optional Apple Pay and Customer Account +# API values by default. dev up/dev bootstrap use non-interactive setup, so +# missing optional values can stay blank. # # Do not commit real values from .env or generated platform config files. diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e3282b82..c6966ac6 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,7 +2,7 @@ The following is a set of guidelines for contributing to this project. Please take a moment to read through them before submitting your first PR. -This is a monorepo containing the iOS/Swift, Android, and (forthcoming) React Native implementations of the Shopify Checkout Kit. Each platform has its own conventions, tooling, and release process; the shared guidelines below apply to all of them. +This is a monorepo containing the Swift, Android, React Native, and Web implementations of the Shopify Checkout Kit. Each platform has its own conventions, tooling, and release process; the shared guidelines below apply to all of them. ## Code of Conduct @@ -48,7 +48,25 @@ 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`. +`dev up` performs full DevHub provisioning, then runs Checkout Kit's repo-owned +setup steps. Those repo-owned steps are summarized at the end so a Swift, +Android, React Native, or Web setup failure is visible without hiding later +platform results. If a platform-specific setup step fails, fix it and rerun that +platform directly, for example `dev swift setup`. To rerun the repo-owned setup +summary without DevHub's native provisioning, use `dev bootstrap`. + +Setup creates or syncs sample app storefront configuration from the repo-root +`.env`. If `.env` is missing, setup prompts for required storefront values and +then generates the Android, Swift, and React Native sample config files. +Optional Apple Pay and Customer Account API values are preserved if already set, +but `dev up` leaves missing optional values blank instead of prompting. To fill +optional values interactively, run `dev storefront-env sync --prompt-optional`. + +Platform-scoped commands are available as `dev android `, `dev swift `, `dev react-native ` (or `dev rn`), and `dev web `. Each platform also supports `dev setup` and `dev up` for platform-local setup when the full repo does not need to be reprovisioned. 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`. + +React Native sample apps can be run against local in-repo SDK sources with +`dev rn ios --local` or `dev rn android --local`. The Web sample accepts a +checkout URL directly and does not use the shared storefront credential files. --- @@ -133,7 +151,7 @@ If your change intentionally modifies the public API: 2. Review the diff in `platforms/android/lib/api/lib.api` alongside your code changes. 3. Commit the updated `.api` file in the same PR. -If you did *not* intend to change public API and `apiCheck` is failing, the diff shows what your change inadvertently affected — treat it as a signal that something in your PR has consumer-visible impact. +If you did _not_ intend to change public API and `apiCheck` is failing, the diff shows what your change inadvertently affected — treat it as a signal that something in your PR has consumer-visible impact. ### Releasing a new Android version diff --git a/AGENTS.md b/AGENTS.md index f9ef5375..3259adef 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,6 +5,7 @@ platforms/ swift/ # iOS Swift Package and CocoaPods sources android/ # Android library and sample apps react-native/ # React Native wrapper + web/ # Web component package and sample app protocol/ # cross-platform communication layer based on UCP e2e/ # cross-platform end-to-end tests .github/ # workflows, issue templates, CODEOWNERS @@ -27,6 +28,11 @@ For platform-scoped work, prefer the root `dev.yml` commands: - Android: `dev android ` - Swift: `dev swift ` - React Native: `dev react-native ` or `dev rn ` +- Web: `dev web ` + +Use `dev setup` or `dev up` for platform-local setup when +the full repo has already been provisioned. Use `dev bootstrap` to rerun the +repo-owned setup aggregator without rerunning DevHub's native provisioning. For protocol schema/model work, use `dev protocol `. @@ -34,3 +40,11 @@ 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. + +## Sensitive configuration + +Treat storefront environment and generated sample app configuration values as +sensitive. Never print, commit, paste, or document real values from `.env`, +generated platform config, access tokens, merchant identifiers, shop IDs, +account IDs, or storefront domains. Use synthetic placeholders for docs and +verification. diff --git a/dev.yml b/dev.yml index fe8b3e59..9403533e 100644 --- a/dev.yml +++ b/dev.yml @@ -11,48 +11,6 @@ up: - swiftformat - sccache - ruby - - custom: - name: Install bundle packages - met?: BUNDLE_GEMFILE=platforms/swift/Gemfile bundle check - meet: BUNDLE_GEMFILE=platforms/swift/Gemfile bundle install - # Android - - custom: - name: Ensure Android sample app .env files exist - met?: | - ([ -f "./platforms/android/samples/MobileBuyIntegration/.env" ] || exit 1) - meet: cd platforms/android && ./scripts/setup_env.sh - - - custom: - name: Bootstrap Mint packages - met?: | - set -e - cd platforms/swift - expected_swiftlint="$(sed -n 's#^realm/SwiftLint@##p' Mintfile)" - expected_swiftformat="$(sed -n 's#^nicklockwood/SwiftFormat@##p' Mintfile)" - swiftlint_bin="$(mint which swiftlint)" - swiftformat_bin="$(mint which swiftformat)" - test -n "$expected_swiftlint" - test -n "$expected_swiftformat" - test "$("$swiftlint_bin" version)" = "$expected_swiftlint" - test "$("$swiftformat_bin" --version)" = "$expected_swiftformat" - meet: cd platforms/swift && mint bootstrap - - xcode: - version: "26.2" - runtimes: - ios: - - version: 23C54 # 26.2 - architecture_variant: arm64 - - custom: - name: Ensure Storefront.xcconfig file - met?: | - ([ -f "./platforms/swift/Samples/MobileBuyIntegration/Storefront.xcconfig" ] || exit 1) - meet: cd platforms/swift && ./Scripts/ensure_storefront_config - - custom: - name: Setup entitlements - met?: | - ([ -f "./platforms/swift/Samples/MobileBuyIntegration/MobileBuyIntegration/MobileBuyIntegration.entitlements" ] || exit 1;) - meet: cd platforms/swift && ./Scripts/setup_entitlements - - node: version: v22.14.0 package_manager: pnpm@10.33.1 @@ -60,17 +18,15 @@ up: - platforms/react-native - platforms/web - custom: - name: Install NPM dependencies (React Native) - met?: ls -l platforms/react-native | grep node_modules - meet: cd platforms/react-native && pnpm install - - custom: - name: Install NPM dependencies (Web) - met?: ls -l platforms/web | grep node_modules - meet: cd platforms/web && pnpm install - - custom: - name: Install gems (React Native sample) - met?: (cd platforms/react-native/sample/ios && bundle check) - meet: cd platforms/react-native/sample/ios && bundle install + name: Run Checkout Kit workspace setup + met?: ./scripts/setup_dev_workspace --check --skip-optional-prompts all + meet: ./scripts/setup_dev_workspace --skip-optional-prompts all + - xcode: + version: "26.2" + runtimes: + ios: + - version: 23C54 # 26.2 + architecture_variant: arm64 open: "GitHub": "https://github.com/Shopify/checkout-kit" @@ -78,6 +34,7 @@ open: "PRs": "https://github.com/Shopify/checkout-kit/pulls" check: + storefront-env-tests: ./scripts/test_setup_storefront_env android-license-headers: cd platforms/android && ./scripts/check_license_headers.rb android-detekt: cd platforms/android && ./gradlew detekt android-lint: cd platforms/android && ./gradlew lintRelease @@ -87,11 +44,24 @@ check: 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-license-headers: cd platforms/web && ./scripts/check_license_headers.rb web-lint: cd platforms/web && pnpm lint web-test: cd platforms/web && pnpm test commands: # Repo-wide + bootstrap: + desc: Prepare repo-owned setup steps and summarize platform failures + long_desc: | + Runs Checkout Kit repo-owned setup without rerunning DevHub native + provisioning. Use dev up first if shared tools from packages, ruby, node, + or xcode provisioning are missing. + --prompt-optional only affects storefront configuration setup for + Android, Swift, and React Native; web-only setup has no optional prompts. + syntax: + optional: "[--check] [--prompt-optional] [all|android|swift|react-native|rn|web]" + run: ./scripts/setup_dev_workspace "$@" + build: desc: Build all supported workspaces run: | @@ -110,6 +80,23 @@ commands: *) echo "Usage: dev codegen "; exit 1 ;; esac + storefront-env: + desc: "Sample app storefront configuration commands" + subcommands: + sync: + desc: Create or sync generated sample config from the repo-root .env + long_desc: | + Creates or syncs generated platform sample config from the repo-root + .env. dev up skips optional prompts for automation; run + dev storefront-env sync --prompt-optional to fill optional Apple Pay + and Customer Account API values interactively. + syntax: + optional: "[--skip-optional-prompts|--prompt-optional]" + run: ./scripts/setup_storefront_env "$@" + check: + desc: Verify generated sample config is up to date + run: ./scripts/setup_storefront_env --check + format: desc: Auto-format and apply safe lint autocorrections across supported workspaces aliases: [fix] @@ -140,6 +127,7 @@ commands: /opt/dev/bin/dev web test apollo: + desc: "Apollo GraphQL schema and code generation commands" subcommands: download_schema: desc: "Download GraphQL schema. Usage: dev apollo download_schema [accelerated|mobile-buy|all]" @@ -181,6 +169,17 @@ commands: android: desc: "Android Checkout Kit commands" subcommands: + setup: + desc: Prepare Android sample configuration without running full repo setup + long_desc: | + Runs only Checkout Kit repo-owned Android setup. It does not run + DevHub native provisioning for shared tools. Use dev up first if + base tools are missing. + aliases: [up] + syntax: + optional: "[--check] [--prompt-optional]" + run: ./scripts/setup_dev_workspace android "$@" + build: desc: Build the library run: cd platforms/android && ./gradlew :lib:build @@ -189,10 +188,6 @@ 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 @@ -212,22 +207,6 @@ commands: aliases: [fix] run: cd platforms/android && ./gradlew detekt --auto-correct - api: - desc: Validate or update the public API baseline (lib/api/lib.api) - run: | - echo "Usage: dev android api {check|dump}" - 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 - run: cd platforms/android && ./gradlew :lib:apiCheck - dump: - desc: Regenerate the baseline after intentional public API changes - run: cd platforms/android && ./gradlew :lib:apiDump - check: desc: Run all Android checks (license headers + lint) run: | @@ -245,33 +224,41 @@ commands: desc: Run Android lint run: cd platforms/android && ./gradlew lintRelease + clean: + desc: Clean Android Gradle build outputs + run: cd platforms/android && ./gradlew clean + + api: + desc: Validate or update the public API baseline (lib/api/lib.api) + run: | + echo "Usage: dev android api {check|dump}" + 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 + run: cd platforms/android && ./gradlew :lib:apiCheck + dump: + desc: Regenerate the baseline after intentional public API changes + run: cd platforms/android && ./gradlew :lib:apiDump + # Swift swift: desc: "Swift Checkout Kit commands" subcommands: - lint: - desc: Check format and lint issues using SwiftLint and SwiftFormat - aliases: [style] - run: cd platforms/swift && ./Scripts/lint - 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 + setup: + desc: Prepare Swift sample configuration, gems, Mint tools, and entitlements + long_desc: | + Runs only Checkout Kit repo-owned Swift setup. It does not run DevHub + native provisioning for shared tools or Xcode runtimes. Use dev up + first if base tools are missing. + aliases: [up] + syntax: + optional: "[--check] [--prompt-optional]" + run: ./scripts/setup_dev_workspace swift "$@" + build: desc: Build all Swift packages and sample apps run: | @@ -310,6 +297,17 @@ commands: dump: desc: Regenerate the Swift API baselines after intentional public API changes run: cd platforms/swift && ./Scripts/api dump + + lint: + desc: Check format and lint issues using SwiftLint and SwiftFormat + aliases: [style] + run: cd platforms/swift && ./Scripts/lint + + format: + desc: Auto-format and apply safe lint autocorrections + aliases: [fix] + run: cd platforms/swift && ./Scripts/lint fix + check: desc: Run Swift lint and license header checks run: | @@ -321,59 +319,47 @@ commands: desc: Check MIT license headers in Swift source files run: cd platforms/swift && ./Scripts/ensure_license + 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 + # React Native react-native: desc: "React Native Checkout Kit commands" aliases: [rn] subcommands: + setup: + desc: Prepare React Native packages, sample config, and iOS Ruby gems + long_desc: | + Runs only Checkout Kit repo-owned React Native setup. It does not run + DevHub native provisioning for shared tools or CocoaPods install. Use + dev up first if base tools are missing, and use dev rn pod-install + when iOS pods need to be installed. + aliases: [up] + syntax: + optional: "[--check] [--prompt-optional]" + run: ./scripts/setup_dev_workspace react-native "$@" + 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] - run: cd platforms/react-native && pnpm sample start --reset-cache - ios: - desc: Run the iOS sample app in the simulator. - long_desc: | - Builds and runs the iOS sample app on a simulator. - - --local - Build against in-repo Swift SDK sources (runs pod install first). - syntax: - optional: --local - run: cd platforms/react-native && pnpm sample ios "$@" - android: - desc: Run the Android sample app in the emulator. - long_desc: | - Builds and runs the Android sample app on an emulator. - --local - Build against in-repo SDK sources (publishes a local Maven snapshot first). - syntax: - optional: --local - run: cd platforms/react-native && pnpm sample android "$@" - pod-install: - desc: Install CocoaPods for the iOS sample. - long_desc: | - Runs pod install for the iOS sample app. + test: + desc: Run React Native Jest tests + run: cd platforms/react-native && pnpm test --testPathPatterns="modules/@shopify/checkout-kit-react-native/tests" - --local - Wire the Podfile against in-repo Swift SDK sources. - syntax: - optional: --local - run: cd platforms/react-native && pnpm run pod-install -- "$@" - clean: - desc: Remove generated directories and stop sccache - run: | - cd platforms/react-native - pnpm module clean - pnpm sample clean - pnpm clean - if command -v sccache >/dev/null 2>&1; then - sccache --stop-server 2>/dev/null || true - fi - echo "Cleaned root, module and sample workspaces" lint: desc: Run all React Native lint checks (Swift, module, sample) aliases: [style] @@ -393,6 +379,7 @@ commands: sample: desc: Lint the sample app run: cd platforms/react-native && pnpm sample lint + format: desc: Auto-format and apply safe lint autocorrections (Swift bridge only) aliases: [fix] @@ -412,9 +399,7 @@ 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: | @@ -426,6 +411,56 @@ commands: desc: Check React Native module license headers run: cd platforms/react-native && ./scripts/copy_license --check + clean: + desc: Remove generated directories and stop sccache + run: | + cd platforms/react-native + pnpm module clean + pnpm sample clean + pnpm clean + if command -v sccache >/dev/null 2>&1; then + sccache --stop-server 2>/dev/null || true + fi + echo "Cleaned root, module and sample workspaces" + + server: + desc: Start Metro development server + aliases: [s] + run: cd platforms/react-native && pnpm sample start --reset-cache + + ios: + desc: Run the iOS sample app in the simulator. + long_desc: | + Builds and runs the iOS sample app on a simulator. + + --local + Build against in-repo Swift SDK sources (runs pod install first). + syntax: + optional: --local + run: cd platforms/react-native && pnpm sample ios "$@" + + android: + desc: Run the Android sample app in the emulator. + long_desc: | + Builds and runs the Android sample app on an emulator. + + --local + Build against in-repo SDK sources (publishes a local Maven snapshot first). + syntax: + optional: --local + run: cd platforms/react-native && pnpm sample android "$@" + + pod-install: + desc: Install CocoaPods for the iOS sample. + long_desc: | + Runs pod install for the iOS sample app. + + --local + Wire the Podfile against in-repo Swift SDK sources. + syntax: + optional: --local + run: cd platforms/react-native && pnpm run pod-install -- "$@" + rn: desc: "Alias for React Native Checkout Kit commands" long_desc: | @@ -439,13 +474,21 @@ commands: web: desc: "Web Checkout Kit commands" subcommands: - sample: - desc: Start the sample app dev server - aliases: [s] - run: cd platforms/web && pnpm sample + setup: + desc: Prepare Web package dependencies + long_desc: | + Runs only Checkout Kit repo-owned Web setup. It does not run DevHub + native provisioning for shared tools. Use dev up first if base tools + are missing. + aliases: [up] + syntax: + optional: "[--check]" + run: ./scripts/setup_dev_workspace web "$@" + build: desc: Build the @shopify/checkout-kit package run: cd platforms/web && pnpm build + test: desc: Run unit tests with coverage run: cd platforms/web && pnpm test @@ -453,10 +496,12 @@ commands: watch: desc: Run tests in watch mode run: cd platforms/web && pnpm test:watch + lint: desc: Run typecheck, oxlint, and format checks aliases: [style] run: cd platforms/web && pnpm lint + format: desc: Auto-fix JS lint and formatting issues aliases: [fix] @@ -465,6 +510,38 @@ commands: cd platforms/web pnpm run lint:js:fix pnpm run format + + check: + desc: Run Web license header, lint, unit tests, build, package verification, and sample build checks + run: | + set -e + /opt/dev/bin/dev web check license-headers + /opt/dev/bin/dev web lint + /opt/dev/bin/dev web test + /opt/dev/bin/dev web build + /opt/dev/bin/dev web verify + /opt/dev/bin/dev web sample build + subcommands: + license-headers: + desc: Check MIT license headers in Web source files + run: cd platforms/web && ./scripts/check_license_headers.rb + clean: desc: Remove dist and coverage directories run: cd platforms/web && pnpm clean + + sample: + desc: Start the sample app dev server + aliases: [s] + run: cd platforms/web && pnpm sample + subcommands: + build: + desc: Build the sample app + run: cd platforms/web && pnpm sample:build + preview: + desc: Preview the built sample app + run: cd platforms/web && pnpm sample:preview + + verify: + desc: Run Web package verification + run: cd platforms/web && pnpm verify diff --git a/platforms/android/samples/MobileBuyIntegration/.env.example b/platforms/android/samples/MobileBuyIntegration/.env.example index a3e5d264..a870d036 100644 --- a/platforms/android/samples/MobileBuyIntegration/.env.example +++ b/platforms/android/samples/MobileBuyIntegration/.env.example @@ -1,5 +1,5 @@ # Platform-local example for the Android sample. Prefer the repo-root -# .env.example for shared setup, then run scripts/setup_storefront_env. +# .env.example for shared setup, then run dev up or dev bootstrap. STOREFRONT_DOMAIN= STOREFRONT_ACCESS_TOKEN= API_VERSION=2025-07 diff --git a/platforms/android/samples/MobileBuyIntegration/README.md b/platforms/android/samples/MobileBuyIntegration/README.md index cf054942..94a67d6a 100644 --- a/platforms/android/samples/MobileBuyIntegration/README.md +++ b/platforms/android/samples/MobileBuyIntegration/README.md @@ -48,18 +48,24 @@ app/build/generated/source/apollo/ # Auto-generated — do not edit ## Setup -1. Copy the config template and fill in your store credentials: +1. From the repo root, create or sync the shared sample configuration: ```bash - cp .env.example .env + dev up ``` - Then edit `.env` with your values: + If the repo is already provisioned and you only need Android sample setup, + run: + ```bash + dev android setup ``` - STOREFRONT_DOMAIN=your-store.myshopify.com - STOREFRONT_ACCESS_TOKEN=your-token - API_VERSION=2025-07 + + If you are not using `dev`, copy the repo-root `.env.example` to `.env`, + fill in local values, then run: + + ```bash + scripts/setup_storefront_env ``` 2. Open the project in Android Studio and sync Gradle. @@ -72,7 +78,8 @@ When you want to target a newer Storefront API version (e.g. to access new field ### 1. Update the API version -Edit your `.env` and change the `API_VERSION` value: +Edit the repo-root `.env` and change the `API_VERSION` value, then run +`dev storefront-env sync`: ``` API_VERSION=2025-10 @@ -145,7 +152,7 @@ All commands are run from the **repo root** (`checkout-kit/`): |------|---------| | `app/src/main/graphql/schema.graphqls` | Storefront API schema (downloaded, not hand-written) | | `app/build.gradle` | Apollo plugin config + BuildConfig fields | -| `.env` | Store credentials + API version (not checked into git) | +| `.env` | Generated sample config from the repo-root `.env` (not checked into git) | | `StorefrontApiClient.kt` | Apollo client setup, auth header | | `CartRepository.kt` | Cart state, create/add/update/remove operations | | `ProductRepository.kt` | Product fetching operations | diff --git a/platforms/android/samples/README.md b/platforms/android/samples/README.md index d1efe330..a5fd60bc 100644 --- a/platforms/android/samples/README.md +++ b/platforms/android/samples/README.md @@ -1,7 +1,9 @@ # Sample Projects -The project directory contains a `.env.example` file. -Simply rename it to `.env` and update the contained values to match your Shopify storefront. +Sample app storefront configuration is generated from the repo-root `.env`. +Run `dev up` from the repo root to provision the repo and create or sync the +generated sample config files. If the repo is already provisioned, `dev android +setup` or `dev android up` refreshes the Android sample setup directly. --- diff --git a/platforms/react-native/CONTRIBUTING.md b/platforms/react-native/CONTRIBUTING.md index ac4383df..4fc600ce 100644 --- a/platforms/react-native/CONTRIBUTING.md +++ b/platforms/react-native/CONTRIBUTING.md @@ -18,7 +18,10 @@ specific to each workspace. If you've cloned the repo and want to run the sample app, Shopify employees can run `dev up` and `dev react-native ` from the repo root (`dev rn` is -an alias). The underlying `pnpm` commands below are run from +an alias). If the repo is already provisioned, `dev rn setup` or `dev rn up` +refreshes React Native packages, sample config, and iOS Ruby gems directly. +Run `dev rn pod-install` when iOS pods need to be installed. The underlying +`pnpm` commands below are run from `platforms/react-native`: 1. Install the NPM dependencies @@ -30,7 +33,7 @@ an alias). The underlying `pnpm` commands below are run from 2. Install iOS dependencies. (N.b. Android dependencies are automatically installed by Gradle) ```sh - pnpm pod-install sample/ios + pnpm run pod-install ``` 3. Build the Native Module @@ -179,7 +182,7 @@ pnpm install ### Install Cocoapods ```sh -pnpm pod-install sample/ios +pnpm run pod-install ``` ### Build the local module @@ -190,14 +193,20 @@ pnpm module build ### Update the dotenv file -Replace the details in the `sample/.env.example` file and rename it to -`sample/.env` +From the repo root, run `dev up` to create or sync the sample app dotenv file +from the root `.env`. + +If the repo is already provisioned and you only need React Native setup, run +`dev rn setup` or `dev rn up`. + +If you are not using `dev`, copy `.env.example` from the repo root to `.env`, +fill in local values, then run `scripts/setup_storefront_env`. ``` # Storefront Details STOREFRONT_DOMAIN="YOUR_STORE.myshopify.com" STOREFRONT_ACCESS_TOKEN="YOUR_PUBLIC_STOREFRONT_ACCESS_TOKEN" -STOREFRONT_VERSION="2025-07" +API_VERSION="2025-07" ``` ### Start the sample app diff --git a/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/ShopifyCheckoutKit.swift b/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/ShopifyCheckoutKit.swift index 76ac0da7..14f670ba 100644 --- a/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/ShopifyCheckoutKit.swift +++ b/platforms/react-native/modules/@shopify/checkout-kit-react-native/ios/ShopifyCheckoutKit.swift @@ -265,7 +265,7 @@ class RCTShopifyCheckoutKit: NSObject { return NSNumber(value: available) } - @objc func respondToGeolocationRequest(_ allow: Bool) { + @objc func respondToGeolocationRequest(_: Bool) { // No-op on iOS — geolocation permission is handled natively } @@ -342,12 +342,12 @@ extension RCTShopifyCheckoutKit: CheckoutDelegate { // MARK: - Dispatch envelope helpers -private extension RCTShopifyCheckoutKit { +extension RCTShopifyCheckoutKit { /// Builds a `{ "type": ..., "payload": ... }` envelope and forwards /// it to the pending JS dispatcher. SDK lifecycle envelopes are /// single-shot: the callback is released after emission so the same /// presentation can only fire one terminal event. - func emitDispatchEnvelope(type: DispatchEventType, payload: [String: Any]?) { + private func emitDispatchEnvelope(type: DispatchEventType, payload: [String: Any]?) { guard let dispatch = pendingDispatchCallback else { return } // Single-shot for SDK lifecycle events — release before invoking // so a delegate callback that re-enters this code path (e.g. via @@ -376,7 +376,7 @@ private extension RCTShopifyCheckoutKit { /// shape the JS dispatcher expects. Field names match Android's /// `CustomCheckoutListener.populateErrorDetails` so the JS-side /// `parseCheckoutError` works identically on both platforms. - static func errorPayload(from error: CheckoutError) -> [String: Any] { + fileprivate static func errorPayload(from error: CheckoutError) -> [String: Any] { switch error { case let .sdkError(underlying): return [ diff --git a/platforms/react-native/sample/.env.example b/platforms/react-native/sample/.env.example index f504a949..07f48003 100644 --- a/platforms/react-native/sample/.env.example +++ b/platforms/react-native/sample/.env.example @@ -1,5 +1,5 @@ # Platform-local example for the React Native sample. Prefer the repo-root -# .env.example for shared setup, then run scripts/setup_storefront_env. +# .env.example for shared setup, then run dev up or dev bootstrap. # Storefront details STOREFRONT_DOMAIN="your-store.myshopify.com" diff --git a/platforms/swift/Samples/MobileBuyIntegration/README.md b/platforms/swift/Samples/MobileBuyIntegration/README.md index 81b86597..d236e741 100644 --- a/platforms/swift/Samples/MobileBuyIntegration/README.md +++ b/platforms/swift/Samples/MobileBuyIntegration/README.md @@ -53,18 +53,24 @@ MobileBuyIntegration/ ## Setup -1. Copy the config template and fill in your store credentials: +1. From the repo root, create or sync the shared sample configuration: ```bash - cp Storefront.xcconfig.example Storefront.xcconfig + dev up ``` - Then edit `Storefront.xcconfig` with your values: + If the repo is already provisioned and you only need Swift sample setup, + run: + ```bash + dev swift setup ``` - STOREFRONT_DOMAIN = your-store.myshopify.com - STOREFRONT_ACCESS_TOKEN = your-token - API_VERSION = 2025-07 + + If you are not using `dev`, copy the repo-root `.env.example` to `.env`, + fill in local values, then run: + + ```bash + scripts/setup_storefront_env ``` 2. Open the project in Xcode and let SPM resolve the Apollo dependency. @@ -77,10 +83,11 @@ When you want to target a newer Storefront API version (e.g. to access new field ### 1. Update the API version -Edit your `Storefront.xcconfig` and change the `API_VERSION` value: +Edit the repo-root `.env` and change the `API_VERSION` value, then run +`dev storefront-env sync`: ``` -API_VERSION = 2025-10 +API_VERSION=2025-10 ``` ### 2. Download the new schema @@ -149,6 +156,6 @@ All commands are run from the **repo root** (`checkout-kit/`): | `schema.graphqls` | Storefront API schema (downloaded, not hand-written) | | `apollo-codegen-config.json` | Apollo codegen configuration | | `apollo-ios-cli` | Apollo CLI binary (not checked into git) | -| `Storefront.xcconfig` | Store credentials + API version (not checked into git) | +| `Storefront.xcconfig` | Generated sample config from the repo-root `.env` (not checked into git) | | `Network.swift` | Apollo client setup, auth interceptor | | `CartManager.swift` | Cart state, create/add/update operations | diff --git a/platforms/swift/Samples/MobileBuyIntegration/Storefront.xcconfig.example b/platforms/swift/Samples/MobileBuyIntegration/Storefront.xcconfig.example index dd5a79ca..c5c9a6de 100644 --- a/platforms/swift/Samples/MobileBuyIntegration/Storefront.xcconfig.example +++ b/platforms/swift/Samples/MobileBuyIntegration/Storefront.xcconfig.example @@ -1,7 +1,7 @@ // --- Storefront // --- Find your Storefront API access token under: // ----- https://admin.shopify.com/store/{STOREFRONT}/settings/apps/development/{APP_ID}/api_credentials -// --- Prefer the repo-root .env.example for shared setup, then run scripts/setup_storefront_env. +// --- Prefer the repo-root .env.example for shared setup, then run dev up or dev bootstrap. STOREFRONT_DOMAIN = your-store.myshopify.com STOREFRONT_ACCESS_TOKEN = your-public-storefront-access-token diff --git a/platforms/swift/Samples/README.md b/platforms/swift/Samples/README.md index 0bcd1fa7..7374041b 100644 --- a/platforms/swift/Samples/README.md +++ b/platforms/swift/Samples/README.md @@ -1,8 +1,12 @@ # Sample Project -This directory contains a sample project that implements the `ShopifyCheckoutKit` library. +This directory contains sample projects that implement the `ShopifyCheckoutKit` +library. -The project directory contains a `Storefront.xcconfig.example` file. Simply rename it to `Storefront.xcconfig` and update the contained values to match your Shopify storefront. +The sample apps read generated `Storefront.xcconfig` files. From the repo root, +run `dev up` to provision the repo and create or sync them from the shared +`.env`. If the repo is already provisioned, `dev swift setup` or `dev swift up` +refreshes Swift sample setup directly. --- @@ -12,12 +16,17 @@ This project demonstrates how to use the [Mobile Buy SDK](https://github.com/Sho ### Getting Started -1. Copy the example config file: +1. Create or sync the shared configuration from the repo root: + ```sh -cp Samples/MobileBuyIntegration/Storefront.xcconfig.example Samples/MobileBuyIntegration/Storefront.xcconfig +dev up ``` -2. Fill in `STOREFRONT_DOMAIN` and other keys in `Storefront.xcconfig` with your store values. -3. Build & run — entitlements are auto-generated via a build PreAction (no manual script step needed). + +2. If the repo is already provisioned and you only need Swift setup, run +`dev swift setup`. +3. If you are not using `dev`, copy the repo-root `.env.example` to `.env`, +fill in local values, then run `scripts/setup_storefront_env`. +4. Build & run — entitlements are auto-generated via a build PreAction (no manual script step needed). ### Troubleshooting @@ -25,9 +34,9 @@ If the build PreAction fails, Xcode will show **"exited with status code 1"**. C | Build Log Output | Cause | Fix | |------------------|-------|-----| -| `grep: Storefront.xcconfig: No such file or directory` | `Storefront.xcconfig` file is missing | Copy `.xcconfig.example` to `Storefront.xcconfig` and fill in values | -| `Error: STOREFRONT_DOMAIN is not set in Storefront.xcconfig` | `Storefront.xcconfig` exists but `STOREFRONT_DOMAIN` is blank | Set your store's domain in the config | -| Associated domains not working at runtime | Domain value is incorrect | Verify domain matches your Shopify store (no `https://` prefix) | +| `grep: Storefront.xcconfig: No such file or directory` | `Storefront.xcconfig` file is missing | Run `dev swift setup` from the repo root | +| `Error: STOREFRONT_DOMAIN is not set in Storefront.xcconfig` | `Storefront.xcconfig` exists but `STOREFRONT_DOMAIN` is blank | Update root `.env`, then run `dev storefront-env sync` | +| Associated domains not working at runtime | Domain value is incorrect | Update root `.env`, then run `dev storefront-env sync` | --- @@ -37,8 +46,13 @@ This project demonstrates integrating Shopify's Accelerated Checkouts, an all in To get started: -1. Copy the settings file: +1. Create or sync the shared configuration from the repo root: + ```sh -cp Samples/ShopifyAcceleratedCheckouts/Storefront.xcconfig.example Samples/ShopifyAcceleratedCheckouts/Storefront.xcconfig +dev up ``` -2. Modify each of the keys in `Storefront.xcconfig` to match the value in your store settings. \ No newline at end of file + +2. If the repo is already provisioned and you only need Swift setup, run +`dev swift setup`. +3. If you are not using `dev`, copy the repo-root `.env.example` to `.env`, +fill in local values, then run `scripts/setup_storefront_env`. diff --git a/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig.example b/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig.example index 791e21a2..dab30e4e 100644 --- a/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig.example +++ b/platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig.example @@ -1,7 +1,7 @@ // --- Storefront // --- Find your Storefront API access token under: // ----- https://admin.shopify.com/store/{STOREFRONT}/settings/apps/development/{APP_ID}/api_credentials -// --- Prefer the repo-root .env.example for shared setup, then run scripts/setup_storefront_env. +// --- Prefer the repo-root .env.example for shared setup, then run dev up or dev bootstrap. // Configuration settings file format documentation can be found at: // https://help.apple.com/xcode/#/dev745c5c974 diff --git a/platforms/web/.gitignore b/platforms/web/.gitignore index 5c31f727..427cbdac 100644 --- a/platforms/web/.gitignore +++ b/platforms/web/.gitignore @@ -4,6 +4,7 @@ node_modules/ # Build output dist/ +sample/dist/ build/ coverage/ custom-elements.json diff --git a/platforms/web/.oxlintrc.json b/platforms/web/.oxlintrc.json index 7bf618d7..ff76f55a 100644 --- a/platforms/web/.oxlintrc.json +++ b/platforms/web/.oxlintrc.json @@ -24,6 +24,7 @@ }, "ignorePatterns": [ "dist/**", + "sample/dist/**", "coverage/**", "node_modules/**" ], diff --git a/platforms/web/package.json b/platforms/web/package.json index 04064196..4302bd12 100644 --- a/platforms/web/package.json +++ b/platforms/web/package.json @@ -53,7 +53,7 @@ "ecommerce" ], "scripts": { - "clean": "rm -rf dist coverage", + "clean": "rm -rf dist sample/dist coverage", "build": "vite build && pnpm run build:manifest", "build:manifest": "cem analyze --globs 'src/**/*.ts' --exclude 'src/**/*.test.ts' --outdir dist", "dev": "vite build --watch", @@ -62,8 +62,8 @@ "lint": "pnpm run typecheck && pnpm run sample:typecheck && pnpm run lint:js && pnpm run format:check", "lint:js": "oxlint --report-unused-disable-directives --max-warnings 0 src sample", "lint:js:fix": "oxlint --fix src sample", - "format": "oxfmt src sample", - "format:check": "oxfmt --check src sample", + "format": "oxfmt src sample '!sample/dist/**'", + "format:check": "oxfmt --check src sample '!sample/dist/**'", "typecheck": "tsc --noEmit", "sample": "vite --config sample/vite.config.ts", "sample:build": "vite build --config sample/vite.config.ts", diff --git a/scripts/setup_dev_workspace b/scripts/setup_dev_workspace new file mode 100755 index 00000000..443506f6 --- /dev/null +++ b/scripts/setup_dev_workspace @@ -0,0 +1,281 @@ +#!/usr/bin/env bash + +set -o pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +mode="sync" +storefront_prompt_arg="--skip-optional-prompts" +platforms=() +platform_local_invocation="false" + +step_names=() +step_statuses=() +step_details=() +failure_count=0 +last_status=0 +storefront_ran=0 +storefront_status=0 + +usage() { + cat <&2 + exit 1 + ;; + esac + shift +done + +if [[ "${#platforms[@]}" -eq 0 ]]; then + add_platform all +fi + +record_step() { + local name="$1" + local status="$2" + local detail="$3" + + step_names+=("$name") + step_statuses+=("$status") + step_details+=("$detail") + + if [[ "$status" != "PASS" ]]; then + failure_count=$((failure_count + 1)) + fi +} + +status_icon() { + case "$1" in + PASS) printf '✅' ;; + FAIL) printf '❌' ;; + *) printf '•' ;; + esac +} + +run_shell() { + local name="$1" + local command="$2" + local status + + printf '\n🔧 %s\n' "$name" + (cd "$ROOT_DIR" && bash -c "$command") + status=$? + + if [[ "$status" -eq 0 ]]; then + printf '✅ PASS %s\n' "$name" + record_step "$name" "PASS" "" + else + printf '❌ FAIL %s (exit %s)\n' "$name" "$status" + record_step "$name" "FAIL" "exit $status" + fi + + last_status="$status" + return "$status" +} + +ensure_storefront_env() { + if [[ "$storefront_ran" -eq 1 ]]; then + return "$storefront_status" + fi + + if [[ "$mode" == "check" ]]; then + run_shell "Sample storefront config" './scripts/setup_storefront_env --check' + else + run_shell "Sample storefront config" "./scripts/setup_storefront_env ${storefront_prompt_arg}" + fi + + storefront_status="$last_status" + storefront_ran=1 + return "$storefront_status" +} + +setup_android() { + ensure_storefront_env || true +} + +setup_swift() { + ensure_storefront_env || true + + if [[ "$mode" == "check" ]]; then + run_shell "Swift bundle packages" 'BUNDLE_GEMFILE=platforms/swift/Gemfile bundle check' || true + run_shell "Swift Mint packages" ' + set -e + cd platforms/swift + expected_swiftlint="$(sed -n "s#^realm/SwiftLint@##p" Mintfile)" + expected_swiftformat="$(sed -n "s#^nicklockwood/SwiftFormat@##p" Mintfile)" + swiftlint_bin="$(mint which swiftlint)" + swiftformat_bin="$(mint which swiftformat)" + test -n "$expected_swiftlint" + test -n "$expected_swiftformat" + test "$("$swiftlint_bin" version)" = "$expected_swiftlint" + test "$("$swiftformat_bin" --version)" = "$expected_swiftformat" + ' || true + run_shell "Swift sample entitlements" 'test -f platforms/swift/Samples/MobileBuyIntegration/MobileBuyIntegration/MobileBuyIntegration.entitlements' || true + else + run_shell "Swift bundle packages" 'BUNDLE_GEMFILE=platforms/swift/Gemfile bundle check || BUNDLE_GEMFILE=platforms/swift/Gemfile bundle install' || true + run_shell "Swift Mint packages" ' + set -e + cd platforms/swift + if ( + expected_swiftlint="$(sed -n "s#^realm/SwiftLint@##p" Mintfile)" + expected_swiftformat="$(sed -n "s#^nicklockwood/SwiftFormat@##p" Mintfile)" + swiftlint_bin="$(mint which swiftlint)" + swiftformat_bin="$(mint which swiftformat)" + test -n "$expected_swiftlint" + test -n "$expected_swiftformat" + test "$("$swiftlint_bin" version)" = "$expected_swiftlint" + test "$("$swiftformat_bin" --version)" = "$expected_swiftformat" + ); then + exit 0 + fi + mint bootstrap + ' || true + run_shell "Swift sample entitlements" 'test -f platforms/swift/Samples/MobileBuyIntegration/MobileBuyIntegration/MobileBuyIntegration.entitlements || (cd platforms/swift && ./Scripts/setup_entitlements)' || true + fi +} + +setup_react_native() { + ensure_storefront_env || true + + if [[ "$mode" == "check" ]]; then + run_shell "React Native packages" 'test -d platforms/react-native/node_modules' || true + run_shell "React Native iOS gems" 'cd platforms/react-native/sample/ios && bundle check' || true + else + run_shell "React Native packages" 'test -d platforms/react-native/node_modules || (cd platforms/react-native && pnpm install)' || true + run_shell "React Native iOS gems" 'cd platforms/react-native/sample/ios && (bundle check || bundle install)' || true + fi +} + +setup_web() { + if [[ "$mode" == "check" ]]; then + run_shell "Web packages" 'test -d platforms/web/node_modules' || true + else + run_shell "Web packages" 'test -d platforms/web/node_modules || (cd platforms/web && pnpm install)' || true + fi +} + +print_platform_local_notice() { + if [[ "$platform_local_invocation" != "true" ]]; then + return 0 + fi + + cat < setup\n' + printf 'If a base tool is missing, run dev up first so DevHub can provision shared tools.\n' + else + printf '\n✅ All requested setup steps passed.\n' + fi +} + +print_platform_local_notice + +for platform in "${platforms[@]}"; do + case "$platform" in + android) setup_android ;; + swift) setup_swift ;; + react-native) setup_react_native ;; + web) setup_web ;; + *) + echo "Unknown platform: $platform" >&2 + exit 1 + ;; + esac +done + +print_summary + +if [[ "$failure_count" -gt 0 ]]; then + exit 1 +fi