mirror of
https://github.com/bitwarden/android.git
synced 2026-05-10 16:45:43 -05:00
Compare commits
4 Commits
BWA-99/sho
...
llm/add-re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86300942de | ||
|
|
b31c448d25 | ||
|
|
90b88067ba | ||
|
|
97bc0d29e9 |
212
.claude/skills/resolving-sdk-updates/SKILL.md
Normal file
212
.claude/skills/resolving-sdk-updates/SKILL.md
Normal file
@@ -0,0 +1,212 @@
|
||||
---
|
||||
name: resolving-sdk-updates
|
||||
description: >
|
||||
Diagnose and resolve build failures from Bitwarden SDK updates (com.bitwarden:sdk-android).
|
||||
Investigates sdk-internal PRs, fixes exhaustive when expressions, and assesses behavioral
|
||||
impact. Use when reviewing SDK update PRs, fixing SDK build errors, encountering "when
|
||||
expression must be exhaustive" after SDK bump, updating sdk-android in libs.versions.toml,
|
||||
or when any PR from the sdlc/sdk-update branch has failing CI. Triggered by "fix the SDK
|
||||
update", "resolve SDK breaking changes", "check the SDK PR", "SDK version bump",
|
||||
"sdk-android", "sdk-internal". Do NOT use for general dependency updates unrelated to the
|
||||
Bitwarden SDK.
|
||||
allowed-tools: Bash(git branch --show-current), Bash(git diff *), Bash(gh run list *), Bash(gh run view *), Bash(gh pr view *), Bash(gh pr diff *)
|
||||
---
|
||||
|
||||
# Resolving SDK Updates
|
||||
|
||||
Sequential five-phase workflow for diagnosing and resolving build failures caused by Bitwarden SDK (`com.bitwarden:sdk-android`) version updates.
|
||||
|
||||
## Important
|
||||
|
||||
- **SDK repo**: `bitwarden/sdk-internal`
|
||||
- **Artifact**: `com.bitwarden:sdk-android` published to GitHub Packages
|
||||
- **Version catalog**: `gradle/libs.versions.toml` (key: `sdk-android`)
|
||||
- **Update branch convention**: `sdlc/sdk-update`
|
||||
|
||||
CRITICAL: Before applying any fix, always read the `sdk-internal` PR diff to understand the author's intent. A compile fix alone may be insufficient if the SDK change introduces new behavior that requires a dedicated code path.
|
||||
|
||||
## Current State (preprocessed)
|
||||
|
||||
- **Current branch**: !`git branch --show-current`
|
||||
- **SDK version diff vs main**: !`git diff main -- gradle/libs.versions.toml | grep sdk-android || echo "No SDK version change detected"`
|
||||
- **Latest CI failure (sdlc/sdk-update)**: !`gh run list --branch sdlc/sdk-update --status failure --limit 1 --json databaseId,event,conclusion -q '.[0]' 2>/dev/null`
|
||||
|
||||
## Proactive Behavior
|
||||
|
||||
- If the preprocessed state above shows CI failures, skip Phase 1 and jump directly to Phase 2.
|
||||
- If no CI failures exist, focus on Phase 1 (changelog review) and Phase 5 (impact assessment).
|
||||
- If the SDK version diff above shows no change, confirm the branch and version catalog before proceeding.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Identify the Update
|
||||
|
||||
Determine what changed in the SDK version bump. The preprocessed SDK version diff above may already provide this; verify and continue.
|
||||
|
||||
1. **Extract version diff** (if not already shown above) from `gradle/libs.versions.toml`:
|
||||
```bash
|
||||
git diff main -- gradle/libs.versions.toml | grep sdk-android
|
||||
```
|
||||
|
||||
2. **Parse PR body** for linked `sdk-internal` PRs and Jira tickets:
|
||||
- SDK PR pattern: `bitwarden/sdk-internal#NNN` or `#NNN` in context of SDK references
|
||||
- Jira ticket pattern: `PM-NNNNN`
|
||||
- If working from a GitHub PR: `gh pr view {PR_NUMBER} --json body -q .body`
|
||||
|
||||
3. **Record findings**: List each `sdk-internal` PR number and Jira ticket for subsequent phases.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Diagnose Build Failures
|
||||
|
||||
Identify and categorize all compiler errors introduced by the SDK change.
|
||||
|
||||
1. **Extract CI errors** (if CI is failing):
|
||||
```bash
|
||||
gh run list --branch {BRANCH} --status failure --limit 1 --json databaseId -q '.[0].databaseId'
|
||||
gh run view {RUN_ID} --log-failed | grep -E "e: |error:" | head -50
|
||||
```
|
||||
|
||||
2. **Or build locally**:
|
||||
```bash
|
||||
./gradlew app:compileStandardDebugKotlin 2>&1 | grep -E "e: " | head -30
|
||||
```
|
||||
|
||||
3. **Categorize each error** — see `references/common-fix-patterns.md` for the full error category table and fix strategies.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Investigate SDK Changes
|
||||
|
||||
Understand the SDK author's intent behind each change. This determines whether a compile fix alone is sufficient or a new code path is needed.
|
||||
|
||||
1. **For each referenced `sdk-internal` PR**, retrieve details:
|
||||
```bash
|
||||
gh pr view {N} --repo bitwarden/sdk-internal --json title,body,files
|
||||
```
|
||||
|
||||
2. **Read the diff** for breaking changes:
|
||||
```bash
|
||||
gh pr diff {N} --repo bitwarden/sdk-internal
|
||||
```
|
||||
|
||||
3. **Focus on**:
|
||||
- New sealed class variants (will cause exhaustive `when` breaks)
|
||||
- Changed function signatures (new/removed/renamed parameters)
|
||||
- New error types in Result sealed classes
|
||||
- Behavioral changes described in PR body or commit messages
|
||||
- Deprecation notices or migration guidance
|
||||
|
||||
4. **Document** each change with: what changed, why it changed (from PR description), and expected Android impact.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Apply Fixes
|
||||
|
||||
Resolve each compiler error using patterns from `references/common-fix-patterns.md`.
|
||||
|
||||
1. **Fix each error** according to its category. For exhaustive `when` expressions, the most common fix:
|
||||
```kotlin
|
||||
is NewSealedVariant -> {
|
||||
// Handle new case appropriately based on SDK PR context
|
||||
}
|
||||
```
|
||||
|
||||
2. **Search for non-exhaustive usages** the compiler won't catch (`when` used as statement not expression, or `when` without `else` on non-sealed types):
|
||||
```bash
|
||||
grep -r "AffectedTypeName\." --include="*.kt" app/src/main/kotlin/
|
||||
grep -r "is AffectedTypeName" --include="*.kt" app/src/main/kotlin/
|
||||
```
|
||||
|
||||
3. **Verify the fix compiles**:
|
||||
```bash
|
||||
./gradlew app:compileStandardDebugKotlin
|
||||
```
|
||||
|
||||
4. **Run affected tests** to ensure no regressions:
|
||||
```bash
|
||||
./gradlew app:testStandardDebugUnitTest --tests "*.AffectedClassTest"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Assess Behavioral Impact
|
||||
|
||||
Classify each SDK change and determine if follow-up work is needed beyond compile fixes.
|
||||
|
||||
1. **For each change, classify**:
|
||||
- **Compile-only fix**: New variant added but no feature work needed (e.g., new error type that maps to existing generic error handling)
|
||||
- **Feature-requiring**: New capability exposed by SDK that needs a new code path, UI, or business logic
|
||||
|
||||
2. **For feature-requiring changes**, trace Jira tickets.
|
||||
|
||||
First, determine if the `bitwarden-atlassian-tools` MCP plugin is available by checking whether any tools starting with `mcp__plugin_bitwarden-atlassian-tools_` are listed in your available tools.
|
||||
|
||||
**If the plugin IS available:**
|
||||
- Search for existing Android tickets: `project = PM AND text ~ "{keyword}" AND text ~ "Android"`
|
||||
- Check linked issues from SDK tickets: `issue in linkedIssues(PM-XXXXX)`
|
||||
- Document: ticket ID, status, assignee, whether Android work is already planned
|
||||
|
||||
**If the plugin is NOT available:**
|
||||
- Inform the user: "Jira ticket tracing requires the `bitwarden-atlassian-tools@bitwarden-marketplace` plugin (github.com/bitwarden/ai-plugins). I can skip ticket tracing or pause for plugin installation."
|
||||
- Document the Jira ticket IDs (from Phase 1) that should be investigated manually
|
||||
- Note: behavioral impact assessment will be incomplete without ticket tracing
|
||||
|
||||
3. **Produce summary**:
|
||||
- What was fixed (files changed, error types resolved)
|
||||
- What needs separate feature work (with Jira ticket references)
|
||||
- Any risks or behavioral changes to call out in PR review
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: SDK update PR with failing CI
|
||||
|
||||
User says: "Fix the build errors on PR #6615"
|
||||
|
||||
Actions:
|
||||
1. Extract CI errors from failing run — identify exhaustive `when` breaks
|
||||
2. Parse PR body for `sdk-internal` PR references
|
||||
3. Read `sdk-internal` PR diff to understand new sealed variants
|
||||
4. Add new branches to affected `when` expressions
|
||||
5. Grep for other usages of affected types across codebase
|
||||
6. Verify fix compiles and tests pass
|
||||
|
||||
Result: Two files fixed with new `when` branches, behavioral impact documented showing compile-only changes.
|
||||
|
||||
### Example 2: SDK update PR review (no failures)
|
||||
|
||||
User says: "Review the SDK changes in this PR"
|
||||
|
||||
Actions:
|
||||
1. Parse PR body for changelog and `sdk-internal` PR numbers
|
||||
2. Read each `sdk-internal` PR diff to understand changes
|
||||
3. Classify each change as compile-only vs feature-requiring
|
||||
4. Search Jira for tracking tickets on feature-requiring changes
|
||||
|
||||
Result: Summary of SDK changes with impact assessment and Jira ticket status.
|
||||
|
||||
---
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Take your time to thoroughly investigate each `sdk-internal` PR diff before applying fixes.
|
||||
- Quality is more important than speed — a hasty compile fix that misses behavioral intent creates harder bugs later.
|
||||
- Do not skip the codebase-wide grep in Phase 4 step 2. The compiler only catches exhaustive `when` expressions, not `when` statements.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Cause | Solution |
|
||||
|---|---|---|
|
||||
| 401 Unauthorized fetching SDK | Missing or expired GitHub token | Check `GITHUB_TOKEN` in `user.properties` or env; needs `read:packages` scope |
|
||||
| Cannot find `sdk-internal` repo | GitHub CLI lacks access | Run `gh auth status` and verify org access; may need `gh auth refresh` |
|
||||
| `sdk-internal` PR not found | PR number parsed incorrectly | Verify PR number from the update PR body; check `bitwarden/sdk-internal` directly |
|
||||
| Build succeeds but tests fail | Behavioral change in SDK | Review SDK PR description for behavioral changes; may need test updates |
|
||||
|
||||
**Cross-references**:
|
||||
- `build-test-verify` skill — build and test commands
|
||||
- `reviewing-changes` skill — general dependency update review checklists
|
||||
- `implementing-android-code` skill — patterns for new code paths
|
||||
@@ -0,0 +1,195 @@
|
||||
# Common Fix Patterns for SDK Updates
|
||||
|
||||
Quick-reference for resolving build failures after `com.bitwarden:sdk-android` version bumps.
|
||||
|
||||
---
|
||||
|
||||
## Error Categories and Fix Strategies
|
||||
|
||||
### 1. Exhaustive `when` Expression
|
||||
|
||||
**Compiler message**: `'when' expression must be exhaustive, add necessary 'X' branch or 'else' branch instead`
|
||||
|
||||
**Fix strategy**:
|
||||
1. Identify the sealed class/enum that gained a new variant from the SDK diff
|
||||
2. Search for ALL `when` usages of that type across the codebase:
|
||||
```bash
|
||||
grep -rn "is ${TypeName}\." --include="*.kt" app/src/main/kotlin/
|
||||
grep -rn "when.*${TypeName}" --include="*.kt" app/src/main/kotlin/
|
||||
```
|
||||
3. Add the new branch to each `when` expression
|
||||
4. Determine handling from SDK PR context — does the new variant map to existing behavior or need new logic?
|
||||
|
||||
**Template**:
|
||||
```kotlin
|
||||
// Before (compiler error)
|
||||
when (value) {
|
||||
is SealedType.VariantA -> handleA()
|
||||
is SealedType.VariantB -> handleB()
|
||||
}
|
||||
|
||||
// After (new variant added)
|
||||
when (value) {
|
||||
is SealedType.VariantA -> handleA()
|
||||
is SealedType.VariantB -> handleB()
|
||||
is SealedType.VariantC -> handleC() // Added in SDK vX.Y.Z
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Removed API
|
||||
|
||||
**Compiler message**: `Unresolved reference: '<functionOrPropertyName>'`
|
||||
|
||||
**Fix strategy**:
|
||||
1. Check SDK diff for what replaced the removed API:
|
||||
```bash
|
||||
gh pr diff <N> --repo bitwarden/sdk-internal | grep -A5 -B5 "<removedName>"
|
||||
```
|
||||
2. Look for deprecation annotations in previous SDK version
|
||||
3. Update call sites to use the replacement API
|
||||
|
||||
**Template**:
|
||||
```kotlin
|
||||
// Before (removed API)
|
||||
sdkClient.oldMethodName(params)
|
||||
|
||||
// After (replacement from SDK changelog)
|
||||
sdkClient.newMethodName(updatedParams)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Renamed Type
|
||||
|
||||
**Compiler message**: `Unresolved reference: '<TypeName>'`
|
||||
|
||||
**Fix strategy**:
|
||||
1. Search SDK diff for the old type name to find the rename:
|
||||
```bash
|
||||
gh pr diff <N> --repo bitwarden/sdk-internal | grep "<OldTypeName>"
|
||||
```
|
||||
2. Update all imports and usages:
|
||||
```bash
|
||||
grep -rn "import.*<OldTypeName>" --include="*.kt" app/src/main/kotlin/
|
||||
grep -rn "<OldTypeName>" --include="*.kt" app/src/main/kotlin/
|
||||
```
|
||||
3. Use find-and-replace across affected files
|
||||
|
||||
---
|
||||
|
||||
### 4. New Required Parameter
|
||||
|
||||
**Compiler message**: `No value passed for parameter '<paramName>'`
|
||||
|
||||
**Fix strategy**:
|
||||
1. Check SDK diff for parameter semantics and default behavior:
|
||||
```bash
|
||||
gh pr diff <N> --repo bitwarden/sdk-internal | grep -A10 "fun.*<functionName>"
|
||||
```
|
||||
2. Determine appropriate value from SDK PR description
|
||||
3. If parameter has a logical default for Android, use it; otherwise surface to user
|
||||
|
||||
**Template**:
|
||||
```kotlin
|
||||
// Before (missing parameter)
|
||||
sdkClient.initializeCrypto(
|
||||
method = method,
|
||||
)
|
||||
|
||||
// After (new required parameter added)
|
||||
sdkClient.initializeCrypto(
|
||||
method = method,
|
||||
newParam = appropriateValue, // Added in SDK vX.Y.Z — see PM-XXXXX
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. New Error Type
|
||||
|
||||
**Compiler message**: `'when' expression must be exhaustive` on Result/Error sealed class
|
||||
|
||||
**Fix strategy**:
|
||||
1. Identify the new error variant from SDK diff
|
||||
2. Determine if it maps to an existing error handling path or needs new UX
|
||||
3. Search for all catch/when sites handling the parent error type:
|
||||
```bash
|
||||
grep -rn "is.*Error\." --include="*.kt" app/src/main/kotlin/
|
||||
```
|
||||
4. Add handling — often maps to existing generic error display
|
||||
|
||||
**Template**:
|
||||
```kotlin
|
||||
// Error handling with new variant
|
||||
when (error) {
|
||||
is SdkError.Network -> showNetworkError()
|
||||
is SdkError.Auth -> showAuthError()
|
||||
is SdkError.NewErrorType -> {
|
||||
// Map to appropriate existing handler or add new handling
|
||||
showGenericError(error.message)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Useful Commands Reference
|
||||
|
||||
### CI Error Extraction
|
||||
```bash
|
||||
# Get failing run ID for a branch
|
||||
gh run list --branch <branch> --status failure --limit 1 --json databaseId -q '.[0].databaseId'
|
||||
|
||||
# Extract compiler errors
|
||||
gh run view <run-id> --log-failed | grep -E "e: |error:" | head -50
|
||||
```
|
||||
|
||||
### SDK Diff Investigation
|
||||
```bash
|
||||
# View sdk-internal PR details
|
||||
gh pr view <N> --repo bitwarden/sdk-internal --json title,body,files
|
||||
|
||||
# Read full diff
|
||||
gh pr diff <N> --repo bitwarden/sdk-internal
|
||||
|
||||
# Search for specific changes in diff
|
||||
gh pr diff <N> --repo bitwarden/sdk-internal | grep -B5 -A10 "<searchTerm>"
|
||||
```
|
||||
|
||||
### Codebase Impact Search
|
||||
```bash
|
||||
# Find all usages of a type
|
||||
grep -rn "<TypeName>" --include="*.kt" app/src/main/kotlin/
|
||||
|
||||
# Find all when expressions over a sealed type
|
||||
grep -rn "is <TypeName>\." --include="*.kt" app/src/main/kotlin/
|
||||
|
||||
# Find imports of SDK types
|
||||
grep -rn "import com.bitwarden.sdk.*<TypeName>" --include="*.kt" app/src/main/kotlin/
|
||||
```
|
||||
|
||||
### Jira Ticket Search (via bitwarden-atlassian-tools MCP)
|
||||
```
|
||||
# Search for Android tickets related to an SDK change
|
||||
project = PM AND text ~ "<keyword>" AND text ~ "Android"
|
||||
|
||||
# Find linked issues from an SDK ticket
|
||||
issue in linkedIssues(PM-XXXXX)
|
||||
|
||||
# Check ticket status
|
||||
project = PM AND key = PM-XXXXX
|
||||
```
|
||||
|
||||
### Build Verification
|
||||
```bash
|
||||
# Compile check (fastest feedback)
|
||||
./gradlew app:compileStandardDebugKotlin
|
||||
|
||||
# Run specific test class
|
||||
./gradlew app:testStandardDebugUnitTest --tests "*.AffectedClassTest"
|
||||
|
||||
# Full test suite
|
||||
./gradlew app:testStandardDebugUnitTest
|
||||
```
|
||||
Reference in New Issue
Block a user