Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <command>`, `dev swift <command>`, and `dev react-native <command>` (or `dev rn`). Protocol schema/model commands are available as `dev protocol <command>`. For cross-platform changes, use `dev lint`, `dev test`, `dev check`, `dev format`, and `dev build`.

---

## Swift (`platforms/swift/`)
Expand Down
25 changes: 25 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <repo_root> -- /opt/dev/bin/dev up
> shadowenv exec --dir <repo_root> -- /opt/dev/bin/dev test [ARGS]
> ```

Run `dev` commands from the repo root. Use `dev up` before running commands when
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if you've had success with this locally but I think telling it to use shadoenv and where to get dev from helped with certain ai sandboxing

All commands require `shadowenv exec --` prefix. 
shadowenv exec --dir DIR -- /opt/dev/bin/dev up
shadowenv exec --dir DIR -- /opt/dev/bin/dev test [ARGS]

the environment may not be provisioned.

For platform-scoped work, prefer the root `dev.yml` commands:

- Android: `dev android <command>`
- Swift: `dev swift <command>`
- React Native: `dev react-native <command>` or `dev rn <command>`

For protocol schema/model work, use `dev protocol <command>`.

For cross-platform changes, use the repo-wide aggregates: `dev lint`,
`dev test`, `dev check`, `dev format`, and `dev build`. Use
`dev <platform> format` for formatting; `fix` remains an alias for existing
workflows.
158 changes: 137 additions & 21 deletions dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ up:
- xcbeautify
- jq
- swiftlint
- swiftformat
- sccache
- ruby
- custom:
Expand Down Expand Up @@ -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 <kotlin|swift|typescript>"
syntax: "<kotlin|swift|typescript>"
Expand All @@ -97,6 +109,36 @@ commands:
kotlin|swift|typescript|ts) ./protocol/scripts/generate_models.sh --lang "$1" ;;
*) echo "Usage: dev codegen <kotlin|swift|typescript>"; 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
Comment thread
Juanita-Dash marked this conversation as resolved.
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:
Expand All @@ -118,6 +160,23 @@ commands:
*) echo "Usage: dev apollo codegen <android|swift> [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"
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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
Comment thread
Juanita-Dash marked this conversation as resolved.
subcommands:
check:
desc: Verify public API matches the committed baseline
Expand All @@ -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
Expand All @@ -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
Expand All @@ -220,19 +302,33 @@ 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
run: cd platforms/swift && ./Scripts/api check
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]
Expand Down Expand Up @@ -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]
Expand All @@ -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:
Expand All @@ -311,13 +404,36 @@ 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
run: cd platforms/react-native && pnpm module api:check
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:
Expand Down
4 changes: 2 additions & 2 deletions platforms/android/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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`

Expand Down
5 changes: 4 additions & 1 deletion platforms/android/scripts/check_license_headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ function BuyerIdentityDetails({
if (authenticated) {
return (
<View style={styles.sectionFooter}>
<Text style={[styles.sectionFooterText, {color: '#f5a623'}]}>
<Text style={[styles.sectionFooterText, styles.warningText]}>
Changing Buyer Identity will log you out.
</Text>
<View style={styles.detailRow}>
Expand Down Expand Up @@ -449,6 +449,9 @@ function createStyles(colors: Colors) {
fontSize: 12,
color: colors.textSubdued,
},
warningText: {
color: '#f5a623',
},
detailRow: {
flexDirection: 'row',
alignItems: 'center',
Expand Down
Loading
Loading