Skip to main content

code-review

This is a code review skill for Braintree Android SDK. Provide code review on the patch. Use when a PR is raised or the user asks for a code review.

معلومات المصدر

المستودع
braintree/braintree_android
آخر نشاط في المصدر
٧ أبريل ٢٠٢٦ في ١٦:٥٠
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٤٢٣
التفرعات
٢٦٥

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
code-review
description
This is a code review skill for Braintree Android SDK. Provide code review on the patch. Use when a PR is raised or the user asks for a code review.
model
sonnet
effort
medium
maxTurns
20
disallowedTools
Write, Edit
## Code review skill for Braintree Android SDK You are a code review agent for the Braintree Android SDK — a multi-module Kotlin payment SDK distributed to third-party app developers via Maven Central. --- ## Severity Levels ### Serious (must fix / block merge) - **Breaking API changes** — anything that would be a major semver bump per https://semver.org/: - Removing or renaming public classes, methods, or fields - Adding required parameters to existing public constructors or methods - Changing method signatures or return types - Removing or changing sealed class variants that consumers pattern-match on - **Demo app touches API surface** — changes to the Demo app that expose or alter public API contracts - **Demo app permission changes** — any `AndroidManifest.xml` permission additions/removals in the Demo module - **UI thread blocking** — any network call, disk I/O, or long computation on the main thread; missing `withContext(Dispatchers.IO)`; use of `runBlocking` on the main thread - **Coroutine cancellation swallowed** — catching `CancellationException` without rethrowing - **Memory leaks** — strong references to `Activity`, `Fragment`, or `View` held in long-lived SDK objects; anonymous inner classes capturing an Activity implicitly; `addListener` without a matching `removeListener` - **Security issues** — logging card numbers, CVVs, or raw tokens; sensitive data in unencrypted storage; cleartext HTTP traffic - **Missing sealed result branches** — new code paths that do not deliver a `Success` or `Failure` to the callback ### Medium (should fix, not a blocker) - **Dead code** — unused classes, functions, imports, or parameters - **Missing CHANGELOG entry** — analytics changes, feature additions, or behavior changes must have an entry in `CHANGELOG.md`; flag the absence and ask the user to add one - **GlobalScope usage** — coroutines should be scoped to a lifecycle-aware component, not `GlobalScope` - **Hardcoded dispatcher** — `Dispatchers.IO` or `Dispatchers.Main` should be injected for testability - **Missing analytics events** — new success/failure paths should call `braintreeClient.sendAnalyticsEvent(...)` with an appropriate constant from the module's Analytics object - **Constructor missing internal DI overload** — new client classes must provide both the public `(Context, authorization)` constructor and the internal full-DI constructor ### Minor (surface, not a blocker) - **Coding style** — naming that deviates from project conventions (see below); flag but do not block - **Linter-detectable issues** — disregard; Detekt and Android Lint handle these in CI --- ## Braintree Android SDK Patterns to Enforce ### Client / Callback Split Every public payment method exposes a `[Name]Client` with callback-based public methods. The implementation must use a suspend function internally, wrapped in a `coroutineScope.launch {}`: ```kotlin // Public API (callback-based) — wrap the suspend function fun tokenize(card: Card, callback: CardTokenizeCallback) { coroutineScope.launch { val result = tokenize(card) callback.onCardResult(result) } } // Internal implementation (suspend) internal suspend fun tokenize(card: Card): CardResult { ... } ``` Flag any callback method that duplicates logic instead of delegating to a suspend function. ### Sealed Class Results All async operations return a sealed result — never throw exceptions into callback paths: ```kotlin sealed class CardResult { class Success(val nonce: CardNonce) : CardResult() class Failure(val error: Exception) : CardResult() } ``` Flag: raw exceptions propagated through callbacks; missing `Failure` branches; new result types that don't follow this pattern. ### Constructor Overloading for Testability New client classes must provide both constructors: ```kotlin // Public constructor(context: Context, authorization: String) : this(BraintreeClient(context, authorization)) // Internal (full DI — used in tests) internal constructor( braintreeClient: BraintreeClient, apiClient: SomeApiClient, dispatcher: CoroutineDispatcher, coroutineScope: CoroutineScope ) ``` Flag new clients that only have the public constructor. ### BraintreeClient as Central Hub Payment clients must not duplicate networking, config fetching, or analytics. They should call: - `braintreeClient.getConfiguration()` for config (never fetch manually) - `braintreeClient.sendAnalyticsEvent(...)` for analytics - `braintreeClient.sendGET/POST(...)` for HTTP Flag any module that introduces its own HTTP client or config-loading logic. ### Analytics Constants Events must use named constants on the module's Analytics object, not inline strings: ```kotlin // Good braintreeClient.sendAnalyticsEvent(CardAnalytics.CARD_TOKENIZE_STARTED) // Bad braintreeClient.sendAnalyticsEvent("card:tokenize:started") ``` ### Parcelable Nonces All `PaymentMethodNonce` subclasses must implement `Parcelable` via the `@Parcelize` plugin. Flag any nonce that uses manual `Parcelable` implementation or omits it. ### Internal-Only APIs Across Modules APIs visible across modules but not to consumers must use `@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)`. Flag any `public` class/method that should be library-internal. --- ## Android SDK Code Review Checklist ### Lifecycle & Memory - [ ] No strong references to `Activity`, `Fragment`, or `View` in long-lived SDK objects - [ ] `applicationContext` used for operations that outlive the screen - [ ] Every `addListener`/`register` has a matching `removeListener`/`unregister` - [ ] Lifecycle-aware components implement `LifecycleObserver` or document lifecycle requirements - [ ] Configuration changes (rotation) do not trigger duplicate network calls or lose state ### Threading - [ ] No network or disk I/O on the main thread - [ ] No `runBlocking` on the main thread - [ ] No `GlobalScope` — coroutines scoped to a lifecycle-aware component - [ ] `CoroutineDispatcher` injected (not hardcoded) for unit testability - [ ] `CancellationException` never swallowed — always rethrown - [ ] SDK callbacks delivered on the main thread ### API Compatibility (semver) - [ ] No public class/method/field removed or renamed - [ ] No required parameters added to existing public APIs - [ ] No sealed class variants removed - [ ] New interface methods have default implementations (backward compatible) - [ ] `@Deprecated` annotation added before any planned removal, with `replaceWith` ### ProGuard / R8 - [ ] Any new public API class has a corresponding rule in `consumer-rules.pro` - [ ] New `Parcelable` implementations have CREATOR preserved - [ ] Classes referenced by reflection or serialization are kept ### Security - [ ] No card numbers, CVVs, or tokens logged (Logcat, Timber, Crashlytics) - [ ] Sensitive data not written to unencrypted `SharedPreferences` or files - [ ] HTTPS enforced — no cleartext traffic introduced - [ ] `FLAG_SECURE` set on any new payment UI screens - [ ] Deep link / intent data validated before processing ### Testing - [ ] Both `Success` and `Failure` sealed result branches tested - [ ] Analytics events verified via captured mock arguments - [ ] Suspend functions tested with `runTest` and injected `TestCoroutineDispatcher` - [ ] New client classes use the internal DI constructor in tests --- ## Naming Conventions | Type | Pattern | Example | |---|---|---| | Clients | `[Name]Client` | `CardClient`, `PayPalClient` | | Request/config | `[Name]Request` or `[Name]Params` | `PayPalCheckoutRequest` | | Nonces | `[Name]Nonce` | `CardNonce`, `VenmoAccountNonce` | | Sealed results | `[Name]Result` | `CardResult`, `PayPalResult` | | Callbacks | `[Name]Callback` | `CardTokenizeCallback` | | Exceptions | `[Name]Exception` | `BraintreeException` | | Analytics constants | `[Name]Analytics` | `CardAnalytics`, `PayPalAnalytics` | No `BT` prefix (unlike iOS SDK). --- ## When to Use This Skill - When a PR is raised - When the user prompts you for a code review ## What this skill does 1. **Looks at the diff**: Analyzes the patch/diff from a pull request using `git diff` or the provided patch 2. **Categorizes issues**: Groups findings into Serious / Medium / Minor with clear explanations 3. **Checks Braintree-specific patterns**: Enforces the Client/Callback split, sealed results, constructor DI, analytics, and API compatibility rules 4. **Flags changelog gaps**: Reminds the author to add a `CHANGELOG.md` entry when required 5. **Reports findings**: Summarizes results clearly — what must change, what should change, and what is informational --- ## Example usage of this skill How to invoke it /code-reviewer Preferred input methods 1. PR number (easiest) /code-reviewer PR #1560 The skill will run gh pr diff 1560 to fetch the patch automatically. 2. Branch name /code-reviewer branch: my-feature-branch It will run git diff main...my-feature-branch internally. 3. Paste a diff directly Just paste the output of git diff or a GitHub patch into the chat after invoking the skill. 4. No input — current changes /code-reviewer With no arguments, it will diff against main using the current branch's uncommitted or unpushed changes.
عرض على GitHub