diff --git a/.env.example b/.env.example index 00f2b847..2674c44d 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 up 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 uses 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 b28d02ed..9fc7dccb 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 @@ -41,14 +41,30 @@ When in doubt about whether we will be interested in including a new feature, pl ### Dev tooling -Shopify employees can use the root `dev.yml` from the repo root: +Shopify employees can use the root `dev.yml` from the repo root or any platform +directory: ```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`. +`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 setup step fails, fix it and rerun `dev up`. + +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. + +Platform-scoped commands are available as `dev android `, `dev swift `, `dev react-native ` (or `dev rn`), and `dev web ` after setup. 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. Sample app storefront configuration is generated from the repo-root `.env`. Shopify employees get this through `dev up`. External contributors can copy @@ -142,7 +158,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 f7eee896..3981f4e9 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 @@ -19,14 +20,17 @@ e2e/ # cross-platform end-to-end tests > 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. +Run `dev` commands from the repo root or any platform directory. 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 ` +- Web: `dev web ` + +Use `dev up` for setup and setup recovery. For protocol schema/model work, use `dev protocol `. @@ -87,3 +91,11 @@ USE_LOCAL_SDK=1 ./scripts/publish_android_snapshot cd sample/android USE_LOCAL_SDK=1 ./gradlew :shopify_checkout-kit-react-native:testDebugUnitTest ``` + +## 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 434b8506..6133bdc7 100644 --- a/dev.yml +++ b/dev.yml @@ -11,48 +11,12 @@ 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 +24,9 @@ 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 + meet: ./scripts/setup_dev_workspace --skip-optional-prompts 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-detekt: cd platforms/android && ./gradlew detekt android-lint: cd platforms/android && ./gradlew lintRelease swift-lint: cd platforms/swift && ./Scripts/lint @@ -137,6 +94,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]" @@ -165,10 +123,10 @@ commands: 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 + desc: Run Swift protocol package tests + run: cd protocol/languages/swift && swift test check: - desc: Build the Swift protocol target and test target + desc: Build and test the Swift protocol package run: | set -e /opt/dev/bin/dev protocol build @@ -192,10 +150,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 @@ -215,6 +169,24 @@ commands: aliases: [fix] run: cd platforms/android && ./gradlew detekt --auto-correct + check: + desc: Run all Android checks (detekt, Android lint) + run: | + set -e + /opt/dev/bin/dev android check detekt + /opt/dev/bin/dev android check android-lint + subcommands: + detekt: + desc: Run detekt static analysis + run: cd platforms/android && ./gradlew detekt + android-lint: + 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: | @@ -231,47 +203,10 @@ commands: desc: Regenerate the baseline after intentional public API changes run: cd platforms/android && ./gradlew :lib:apiDump - check: - desc: Run all Android checks (detekt, Android lint) - run: | - set -e - /opt/dev/bin/dev android check detekt - /opt/dev/bin/dev android check android-lint - subcommands: - detekt: - desc: Run detekt static analysis - run: cd platforms/android && ./gradlew detekt - android-lint: - desc: Run Android lint - run: cd platforms/android && ./gradlew lintRelease - # 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 build: desc: Build all Swift packages and sample apps run: | @@ -310,10 +245,37 @@ 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 checks run: /opt/dev/bin/dev swift lint + 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" @@ -322,56 +284,7 @@ commands: 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: | - Ensures CocoaPods are in sync, then builds and runs the iOS sample app on a simulator. - --local - Build against in-repo Swift SDK sources. - 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 -- "$@" - clean: - desc: Remove generated directories, clean CocoaPods cache, and stop sccache - run: | - cd platforms/react-native - if (cd sample/ios && bundle exec pod --version >/dev/null 2>&1); then - (cd sample/ios && bundle exec pod cache clean --all) - else - echo "Skipping CocoaPods cache clean (pod unavailable; run dev up first)" - fi - 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" test: desc: Run React Native module tests (JS + iOS + Android) long_desc: | @@ -420,6 +333,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] @@ -439,10 +353,66 @@ commands: dump: desc: Regenerate the RN API report after intentional public API changes run: cd platforms/react-native && pnpm module api:dump + check: desc: Run React Native lint checks run: /opt/dev/bin/dev react-native lint + clean: + desc: Remove generated directories, clean CocoaPods cache, and stop sccache + run: | + cd platforms/react-native + if (cd sample/ios && bundle exec pod --version >/dev/null 2>&1); then + (cd sample/ios && bundle exec pod cache clean --all) + else + echo "Skipping CocoaPods cache clean (pod unavailable; run dev up first)" + fi + 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: | + Ensures CocoaPods are in sync, then builds and runs the iOS sample app on a simulator. + + --local + Build against in-repo Swift SDK sources. + 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: | @@ -456,13 +426,10 @@ commands: web: desc: "Web Checkout Kit commands" subcommands: - sample: - desc: Start the sample app dev server - aliases: [s] - run: cd platforms/web && pnpm sample 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 @@ -470,10 +437,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] @@ -482,6 +451,33 @@ commands: cd platforms/web pnpm run lint:js:fix pnpm run format + + check: + desc: Run Web lint, unit tests, build, package verification, and sample build checks + run: | + set -e + /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 + 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/README.md b/platforms/android/samples/MobileBuyIntegration/README.md index 16edb0ed..35988b4c 100644 --- a/platforms/android/samples/MobileBuyIntegration/README.md +++ b/platforms/android/samples/MobileBuyIntegration/README.md @@ -66,20 +66,19 @@ Do not edit files in `app/build/generated/source/apollo/` by hand. Update `.grap ## Setup -From the repo root: +1. From the repo root or this platform directory, create or sync the shared + sample configuration: -```sh -cp .env.example .env -scripts/setup_storefront_env -``` + ```bash + dev up + ``` -Edit the repo-root `.env`: + If you are not using `dev`, copy the repo-root `.env.example` to `.env`, + fill in local values, then run: -```text -STOREFRONT_DOMAIN=your-store.myshopify.com -STOREFRONT_ACCESS_TOKEN=your-token -API_VERSION=2026-04 -``` + ```bash + scripts/setup_storefront_env + ``` Optional values enable Customer Account API and buyer identity demo flows: @@ -98,14 +97,16 @@ Open the project in Android Studio, sync Gradle, then build and run. ## Updating the Storefront API version 1. Update `API_VERSION` in the repo-root `.env`. -2. Run `scripts/setup_storefront_env` from the repo root. -3. Download the schema with Rover. This introspects your store's Storefront API and writes `schema.graphqls` into `app/src/main/graphql/`. +2. Sync the generated platform config: + + ```sh + dev up + ``` + +3. Download the schema. This introspects your store's Storefront API and writes `schema.graphqls` into `app/src/main/graphql/`. ```sh - rover graph introspect \ - "https://$STOREFRONT_DOMAIN/api/$API_VERSION/graphql" \ - --header="X-Shopify-Storefront-Access-Token: $STOREFRONT_ACCESS_TOKEN" \ - --output "app/src/main/graphql/schema.graphqls" + dev apollo download_schema android ``` 4. Update GraphQL operations in `app/src/main/graphql/` if the schema changed. For example, add a product field to `FetchProducts.graphql` before regenerating types: @@ -122,13 +123,13 @@ Open the project in Android Studio, sync Gradle, then build and run. } ``` -4. Regenerate Kotlin types with Apollo Kotlin. This reads the schema and `.graphql` files, then regenerates Kotlin code in `app/build/generated/source/apollo/`. +5. Regenerate Kotlin types with Apollo Kotlin. This reads the schema and `.graphql` files, then regenerates Kotlin code in `app/build/generated/source/apollo/`. ```sh - ./gradlew :app:generateApolloSources + dev apollo codegen android ``` -5. Build and fix any compile errors from schema changes: +6. Build and fix any compile errors from schema changes: ```sh ./gradlew :app:assembleDebug @@ -138,7 +139,7 @@ Open the project in Android Studio, sync Gradle, then build and run. | File | Purpose | | --- | --- | -| `.env` | Store credentials, API version, Customer Account API values, and demo buyer identity. | +| `.env` | Generated sample config from the repo-root `.env` (not checked into git). | | `app/build.gradle` | Apollo plugin configuration and `BuildConfig` values from `.env`. | | `app/src/main/graphql/schema.graphqls` | Storefront API schema. | | `common/client/StorefrontApiClient.kt` | Apollo client setup and Storefront API auth header. | diff --git a/platforms/android/samples/README.md b/platforms/android/samples/README.md index badf78c8..d0e23e55 100644 --- a/platforms/android/samples/README.md +++ b/platforms/android/samples/README.md @@ -2,27 +2,30 @@ This directory contains Android sample apps for Checkout Kit. +Sample app storefront configuration is generated from the repo-root `.env`. +Run `dev up` from the repo root or any platform directory to provision the repo +and create or sync the generated sample config files. + | Sample | Purpose | | --- | --- | | `MobileBuyIntegration` | Storefront API cart flow with Apollo Kotlin, checkout presentation, typed protocol lifecycle events, file chooser handling, geolocation callbacks, buyer identity demo data, and Customer Account API sign-in. | ## Setup -From the repo root: +From the repo root or this platform directory: ```sh -cp .env.example .env -scripts/setup_storefront_env +dev up ``` -Fill `.env` with: +If you are not using `dev`, copy the repo-root `.env.example` to `.env`, fill +in local values, then run: -- `STOREFRONT_DOMAIN` -- `STOREFRONT_ACCESS_TOKEN` -- `API_VERSION` -- Optional Customer Account API values -- Optional demo buyer identity values +```sh +scripts/setup_storefront_env +``` The setup script generates `platforms/android/samples/MobileBuyIntegration/.env`. -Open `MobileBuyIntegration` in Android Studio, sync Gradle, then build and run the `app` target. +Open `MobileBuyIntegration` in Android Studio, sync Gradle, then build and run +the `app` target. diff --git a/platforms/react-native/CONTRIBUTING.md b/platforms/react-native/CONTRIBUTING.md index 70ad6ade..4ef13f1d 100644 --- a/platforms/react-native/CONTRIBUTING.md +++ b/platforms/react-native/CONTRIBUTING.md @@ -17,8 +17,10 @@ specific to each workspace. ## Getting started 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 +run `dev up` and `dev react-native ` from the repo root or any +platform directory (`dev rn` is an alias). 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 +32,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 +181,7 @@ pnpm install ### Install Cocoapods ```sh -pnpm pod-install sample/ios +pnpm run pod-install ``` ### Build the local module @@ -190,14 +192,11 @@ pnpm module build ### Update sample configuration -From the repo root, copy the shared example and generate platform-local config: +From the repo root or this platform directory, run `dev up` to create or sync +the sample app dotenv file from the root `.env`. -```sh -cp .env.example .env -scripts/setup_storefront_env -``` - -Fill `.env` with your local storefront values: +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 diff --git a/platforms/swift/Samples/MobileBuyIntegration/README.md b/platforms/swift/Samples/MobileBuyIntegration/README.md index 3b95a5b1..35aa2508 100644 --- a/platforms/swift/Samples/MobileBuyIntegration/README.md +++ b/platforms/swift/Samples/MobileBuyIntegration/README.md @@ -63,20 +63,19 @@ Do not edit files in `Generated/` by hand. Update `.graphql` files and regenerat ## Setup -From the repo root: +1. From the repo root or this platform directory, create or sync the shared + sample configuration: -```sh -cp .env.example .env -scripts/setup_storefront_env -``` + ```bash + dev up + ``` -Edit `.env`: + If you are not using `dev`, copy the repo-root `.env.example` to `.env`, + fill in local values, then run: -```text -STOREFRONT_DOMAIN=your-store.myshopify.com -STOREFRONT_ACCESS_TOKEN=your-token -API_VERSION=2026-04 -``` + ```bash + scripts/setup_storefront_env + ``` Optional values enable Customer Account API and buyer identity demo flows: @@ -94,14 +93,16 @@ Open the project in Xcode, let Swift Package Manager resolve dependencies, then ## Updating the Storefront API version 1. Update `API_VERSION` in the repo-root `.env`. -2. Run `scripts/setup_storefront_env` from the repo root. -3. Download the schema with Rover. This introspects your store's Storefront API and writes `schema..graphqls` into the sample app directory. +2. Sync the generated platform config: + + ```sh + dev up + ``` + +3. Download the schema. This introspects your store's Storefront API and writes `schema..graphqls` into the sample app directory. ```sh - rover graph introspect \ - "https://$STOREFRONT_DOMAIN/api/$API_VERSION/graphql" \ - --header="X-Shopify-Storefront-Access-Token: $STOREFRONT_ACCESS_TOKEN" \ - --output "schema.$API_VERSION.graphqls" + dev apollo download_schema swift mobile-buy ``` 4. Update `.graphql` operations if the schema changed. For example, add a product field to `MobileBuyIntegration/Sources/Api/Queries/GetProducts.graphql` before regenerating types: @@ -118,13 +119,13 @@ Open the project in Xcode, let Swift Package Manager resolve dependencies, then } ``` -4. Regenerate Swift types with the Apollo iOS CLI and this sample's `apollo-codegen-config.json`. This reads the schema and `.graphql` files, then regenerates Swift code in `MobileBuyIntegration/Sources/Generated/`. +5. Regenerate Swift types with the Apollo iOS CLI and this sample's `apollo-codegen-config.json`. This reads the schema and `.graphql` files, then regenerates Swift code in `MobileBuyIntegration/Sources/Generated/`. ```sh - ./apollo-ios-cli generate --path apollo-codegen-config.json + dev apollo codegen swift mobile-buy ``` -5. Build in Xcode and fix any compile errors from schema changes. +6. Build in Xcode and fix any compile errors from schema changes. ## Dev commands reference @@ -143,7 +144,7 @@ All commands are run from the **repo root** (`checkout-kit/`): | File | Purpose | | --- | --- | -| `Storefront.xcconfig` | Store credentials, API version, Customer Account API values, and demo buyer identity. | +| `Storefront.xcconfig` | Generated sample config from the repo-root `.env` (not checked into git). | | `schema..graphqls` | Storefront API schema downloaded with the Apollo iOS CLI. | | `apollo-codegen-config.json` | Apollo code generation configuration. | | `MobileBuyIntegration/Sources/Api/Network.swift` | Apollo client setup and authentication interceptor. | diff --git a/platforms/swift/Samples/MobileBuyIntegration/Scripts/generate_entitlements.sh b/platforms/swift/Samples/MobileBuyIntegration/Scripts/generate_entitlements.sh index 067f8901..9a4309be 100755 --- a/platforms/swift/Samples/MobileBuyIntegration/Scripts/generate_entitlements.sh +++ b/platforms/swift/Samples/MobileBuyIntegration/Scripts/generate_entitlements.sh @@ -8,11 +8,6 @@ STOREFRONT_DOMAIN=$(grep '^[[:space:]]*STOREFRONT_DOMAIN' "$CONFIG_FILE" | cut - TEMPLATE_FILE="MobileBuyIntegration/MobileBuyIntegration.entitlements.template" OUTPUT_FILE="MobileBuyIntegration/MobileBuyIntegration.entitlements" -if [ -e "$OUTPUT_FILE" ]; then - echo "Warning: $OUTPUT_FILE already exists." - exit 0 -fi - if [ -z "$STOREFRONT_DOMAIN" ]; then echo "Error: STOREFRONT_DOMAIN is not set in Storefront.xcconfig" exit 1 diff --git a/platforms/swift/Samples/README.md b/platforms/swift/Samples/README.md index 1b3c98c9..7a9246c6 100644 --- a/platforms/swift/Samples/README.md +++ b/platforms/swift/Samples/README.md @@ -2,6 +2,10 @@ This directory contains iOS sample apps for Checkout Kit. +The sample apps read generated `Storefront.xcconfig` files. From the repo root +or any platform directory, run `dev up` to provision the repo and create or sync +them from the shared `.env`. + | Sample | Purpose | | --- | --- | | `MobileBuyIntegration` | Storefront API cart flow with Apollo iOS, checkout presentation, buyer identity modes, Customer Account API sign-in, and protocol lifecycle events. | @@ -16,52 +20,54 @@ This directory contains iOS sample apps for Checkout Kit. ## MobileBuyIntegration -From the repo root: +### Getting Started -```sh -cp .env.example .env -scripts/setup_storefront_env -``` +1. Create or sync the shared configuration from the repo root or this platform + directory: -Fill `.env` with: + ```sh + dev up + ``` -- `STOREFRONT_DOMAIN` -- `STOREFRONT_ACCESS_TOKEN` -- `API_VERSION` -- Optional Customer Account API values -- Optional demo buyer identity values +2. If you are not using `dev`, copy the repo-root `.env.example` to `.env`, +fill in local values, then run `scripts/setup_storefront_env`. The setup script generates `platforms/swift/Samples/MobileBuyIntegration/Storefront.xcconfig`. -Open `platforms/swift/Samples/Samples.xcworkspace` or `platforms/swift/Samples/MobileBuyIntegration/MobileBuyIntegration.xcodeproj` in Xcode, then build and run the `MobileBuyIntegration` scheme. +Open `Samples/Samples.xcworkspace` or +`Samples/MobileBuyIntegration/MobileBuyIntegration.xcodeproj` in Xcode, then +build and run the `MobileBuyIntegration` scheme. -The project generates associated-domain entitlements from `Storefront.xcconfig` during the Xcode build pre-action. +The project generates associated-domain entitlements from +`Storefront.xcconfig` during the Xcode build pre-action. ## ShopifyAcceleratedCheckoutsApp -From the repo root: +To get started: -```sh -cp .env.example .env -scripts/setup_storefront_env -``` +1. Create or sync the shared configuration from the repo root or this platform + directory: -Fill `.env` with: + ```sh + dev up + ``` -- `STOREFRONT_DOMAIN` -- `STOREFRONT_ACCESS_TOKEN` -- `API_VERSION` +2. If you are not using `dev`, copy the repo-root `.env.example` to `.env`, +fill in local values, then run `scripts/setup_storefront_env`. The setup script generates `platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/Storefront.xcconfig`. -Open `platforms/swift/Samples/Samples.xcworkspace` or `platforms/swift/Samples/ShopifyAcceleratedCheckoutsApp/ShopifyAcceleratedCheckoutsApp.xcodeproj` in Xcode, then build and run the `ShopifyAcceleratedCheckoutsApp` scheme. +Open `Samples/Samples.xcworkspace` or +`Samples/ShopifyAcceleratedCheckoutsApp/ShopifyAcceleratedCheckoutsApp.xcodeproj` +in Xcode, then build and run the `ShopifyAcceleratedCheckoutsApp` scheme. ## Troubleshooting -If the build pre-action fails, Xcode usually shows `exited with status code 1`. Open the build log and check the script output. +If the build pre-action fails, Xcode usually shows `exited with status code 1`. +Open the build log and check the script output. | Build log output | Cause | Fix | | --- | --- | --- | -| `grep: Storefront.xcconfig: No such file or directory` | The sample config file is missing. | Run `scripts/setup_storefront_env` from the repo root. | -| `Error: STOREFRONT_DOMAIN is not set in Storefront.xcconfig` | `STOREFRONT_DOMAIN` is blank. | Set your shop domain without `https://`. | -| Associated domains do not work at runtime | Domain or app association is wrong. | Verify your custom storefront domain, app ID, and Universal Links setup. | +| `grep: Storefront.xcconfig: No such file or directory` | `Storefront.xcconfig` file is missing. | Run `dev up` from the repo root or any platform directory. | +| `Error: STOREFRONT_DOMAIN is not set in Storefront.xcconfig` | `Storefront.xcconfig` exists but `STOREFRONT_DOMAIN` is blank. | Update root `.env`, then run `dev up`. | +| Associated domains not working at runtime | Domain value is incorrect. | Update root `.env`, then run `dev up`. | diff --git a/platforms/swift/Scripts/setup_entitlements b/platforms/swift/Scripts/setup_entitlements index 04200593..063b3171 100755 --- a/platforms/swift/Scripts/setup_entitlements +++ b/platforms/swift/Scripts/setup_entitlements @@ -1,4 +1,4 @@ - #!/usr/bin/env bash +#!/usr/bin/env bash set -e 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..66402d58 --- /dev/null +++ b/scripts/setup_dev_workspace @@ -0,0 +1,197 @@ +#!/usr/bin/env bash + +set -o pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +mode="sync" +storefront_prompt_arg="--skip-optional-prompts" + +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 + +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" 'cd platforms/swift && ./Scripts/setup_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" 'cd platforms/swift && mint bootstrap' || true + run_shell "Swift sample 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_summary() { + local index + local status + local detail + local icon + + printf '\n📋 Setup summary\n' + for index in "${!step_names[@]}"; do + status="${step_statuses[$index]}" + detail="${step_details[$index]}" + icon="$(status_icon "$status")" + if [[ -n "$detail" ]]; then + printf '%s %-4s %s (%s)\n' "$icon" "$status" "${step_names[$index]}" "$detail" + else + printf '%s %-4s %s\n' "$icon" "$status" "${step_names[$index]}" + fi + done + + if [[ "$failure_count" -gt 0 ]]; then + printf '\n⚠️ %s setup step(s) failed.\n' "$failure_count" + printf 'Fix the failure, then rerun dev up from the repo root.\n' + else + printf '\n✅ All requested setup steps passed.\n' + fi +} + +setup_android +setup_swift +setup_react_native +setup_web + +print_summary + +if [[ "$failure_count" -gt 0 ]]; then + exit 1 +fi