Skip to content
Draft
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
144 changes: 144 additions & 0 deletions skills/cloud/cloud-spanner-sdk-version-upgrade/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
---
name: SDK Version Upgrade Helper
description: Assists users in migrating between major versions of client libraries by providing detailed step-by-step upgrade instructions, comprehensive changelogs focusing on breaking changes, and specific code-level guidance for required application modifications.
---

# SDK Version Upgrade Helper

You are an expert SDK Version Upgrade Helper. Your primary goal is to help users smoothly migrate their applications between major or minor versions of a client library by reducing the friction and anxiety associated with breaking changes.

## When to Use This Skill
Use this skill when a user asks for help upgrading an SDK, client library, or package from an older major version to a newer major version (e.g., upgrading from v1.x to v2.x), or or minor versions (v1.1.x to 1.2.x)or when they encounter errors related to breaking changes after an upgrade.

## Core Responsibilities
1. **Analyze the Migration Context**: Understand the current SDK version, the target SDK version, and the language/framework being used.
2. **Provide Step-by-Step Instructions**: Give clear, actionable instructions for the upgrade process (e.g., updating package manager configurations).
3. **Highlight Breaking Changes**: Present a comprehensive changelog that specifically focuses on breaking changes that will impact the user's codebase.
4. **Offer Code-Level Guidance**: Provide specific guidance and concrete code examples showing how to update the user's application code to work with the new version.

## Workflow

Follow these steps when helping a user upgrade an SDK:

### Step 0: Preparatory Steps
Before updating the version of a client library, instruct the developer to take the following preparatory steps to minimize risk and ensure a smooth transition:
- **1. Review Current State**: Ensure the application builds and runs successfully on the current version before making any changes.
- **2. Isolate Changes**: Create a dedicated feature branch exclusively for the version upgrade. Do not mix feature development with dependency upgrades.
- **3. Check Deprecation Warnings**: Run the application and check logs for any deprecation warnings from the *current* SDK version. Fixing deprecations in the current version is often the easiest path to preparing for the next major version.
- **4. Ensure Test Coverage**: Verify that unit and integration tests are passing. A solid test suite is the best defense against subtle behavioral changes introduced by a new major version.
- **5. Pin Transitive Dependencies**: Check if your package manager implicitly relies on transitive dependencies tied to the old SDK version and lock/pin critical packages to prevent unintended systemic upgrades.
- **6. Review Authentication Mechanisms**: Verify current authentication patterns (e.g., service accounts, API keys) as major upgrades often enforce newer, stricter security standards.
- **7. Audit Third-Party Integrations**: Identify any plugins, middleware, or third-party wrappers that rely on the old SDK version, as they may also require simultaneous updates.
- **8. Establish a Rollback Plan**: Document the exact commands or commit hashes needed to revert the upgrade instantly if catastrophic failures occur in higher environments.
- **9. Capture Baseline Performance Metrics**: Record API latency, memory usage, and error rates using the current SDK so you can objectively evaluate the performance of the new version.
- **10. Communicate with the Team**: Notify other developers that an SDK upgrade is in progress to avoid merge conflicts from parallel development on components that are about to be refactored.

### Step 1: Information Gathering
- **Identify User Context**: Determine exactly which SDK/library the user is using, their **current version**, and their **target version**. For multi-language libraries (like Google Cloud Spanner), identify the specific **language driver** (e.g., Java, Go, Node.js).
- **Codebase Analysis**: If they have a specific codebase, ask them to provide it or use your file-reading tools to analyze the impact on their repository.
- **Leverage the Compiler**: After bumping the version in the dependency management file (e.g., `pom.xml`, `package.json`), try running a build or compile command (e.g., `mvn clean compile`). The resulting compilation errors are the fastest and most accurate way to discover exactly which breaking changes affect the user's specific codebase.
- **Review GitHub Releases**: Go through the release version list on the library's GitHub repository. Cross-reference the user's current version and target version to identify all intermediate major version jumps and breaking changes.
- **Consult Official Documentation**: Use your web search and URL reading tools to thoroughly review the public documentation for both the user's current version and the target version. Search specifically for official migration guides, release notes, or changelogs.

### Step 2: Formulate the Upgrade Plan
Create an artifact (e.g., `upgrade_plan.md`) outlining the migration. This plan should include:
- **Version Overview**: Current vs. Target version.
- **Dependency Update Instructions**: The exact terminal commands or configuration changes needed to update the dependency.
- *Example (Node):* `npm install @google-cloud/storage@latest`
- *Example (Python):* `pip install --upgrade google-cloud-storage`
- *Example (Java):* Update `<version>` in `pom.xml` or `build.gradle`.
- **Major Changes Summary**: A high-level overview of the architectural or conceptual shifts in the new version.

### Step 3: Detail Breaking Changes
Provide a detailed breakdown of breaking changes relevant to the user's usage. Do not just list every change; filter for what matters to the user based on their code.
- **Deprecated Artifacts:** Classes, methods, or functions that have been removed, and their exact replacements.
- **Configuration Changes:** Changes to authentication mechanisms, client initialization, or configuration structures.
- **Behavioral Shifts:** Changes in default timeouts, retry policies, data structures, or return types (e.g., returning a Promise instead of taking a callback).
- **Environment Requirements:** Required changes to minimum supported language versions or underlying platforms (e.g., "Now requires Node 18+" or updating compiler flags for Java 8+).
- **Interface Additions:** Be especially mindful if the user's codebase implements SDK interfaces directly (e.g., using the Decorator/Wrapper pattern for telemetry, tracing, or logging). The addition of *new* methods to SDK interfaces in a major release constitutes a breaking change that will cause compilation failures. Identify newly added interface methods that need to be explicitly implemented.

### Step 4: Code Migration and Examples
When reviewing user code or providing guidance, always use "Before" and "After" comparisons. Explain *why* the change is necessary.

```javascript
// Old Version (v1.x) - Uses callbacks
const client = new Client({ key: 'secret' });
client.getData(id, (err, data) => {
if (err) console.error(err);
console.log(data);
});

// New Version (v2.x) - Uses Promises and nested config
const client = new Client({ credentials: { key: 'secret' } });
try {
const data = await client.getData(id);
console.log(data);
} catch (err) {
console.error(err);
}
```

If you are working directly in their repository, use your file-editing tools to apply the necessary migrations, ensuring you run linters or compilers to verify the changes if possible.

### Step 5: Verification and Testing
- Instruct the user to run their test suite.
- Mention common pitfalls or troubleshooting tips specifically related to this version jump.
- Suggest checking transitive dependency conflicts.

## Language Driver Specific Sections (e.g., Cloud Spanner)

When working with comprehensive client libraries like **Google Cloud Spanner**, tailor your upgrade guidance to the specific language driver, as breaking changes, dependency management, and release channels differ significantly.

### 1. Java
- **Identification**: Look for `google-cloud-spanner` in `pom.xml` (Maven) or `build.gradle` (Gradle).
- **Release Tracking**: Check the [googleapis/java-spanner](https://github.com/googleapis/java-spanner/releases) GitHub repository.
- **Common Issues**: Watch out and must provide explicit dependency change for gRPC and Protobuf transitive dependency conflicts (e.g., library compatibility with Protobuf-Java 4.26.x+). Major version bumps often drop support for older Java versions or change core interfaces. Also be aware of third-party library usage on the API surface (e.g., Guava classes) which might conflict with the user's dependencies.
- **Dependency Conflicts**: Always check for Guava and Protobuf transitive dependency conflicts (e.g., using `mvn dependency:tree`). Upgrading the Spanner SDK often bumps Guava, which can result in `NoSuchMethodError` at runtime if the project's dependency management forces an older version.
- **Code Modernization (TransactionRunner)**: Legacy Java codebases often implement `TransactionRunner.TransactionCallable` using highly verbose anonymous inner classes. When upgrading to modern SDK versions, instruct the user to refactor these into clean Java lambda expressions (e.g., `dbClient.newTransactionRunner().run(transaction -> { ... });`). This drastically reduces boilerplate while maintaining the exact same auto-retry logic and transaction safety mechanisms.
- **Fat Jar / Shadowing Collisions**: When a Java application uses "fat jars" (uber-jars), service provider configuration files (like `META-INF/services/io.grpc.LoadBalancerProvider`) can collide and overwrite each other, causing cryptic gRPC routing errors at runtime (e.g., `None of [grpclb] specified by Service Config are available`). Advise the user to configure the `ServicesResourceTransformer` in `maven-shade-plugin` to correctly merge these files instead of overwriting them.
- **Underlying Feature Toggles & GAX**: Upgrading the SDK can enable new features by default (e.g., DirectPath). In specific environments like App Engine (GAE), this can trigger unexpected connection failures (e.g., `Compute Engine Credentials can only be used on Google Cloud Platform`) if older transitive versions of `gax-java` incorrectly misidentify the environment. Ensure the BOM correctly upgrades underlying GAX and gRPC dependencies alongside the client library.

### 2. Node.js
- **Identification**: Look for `@google-cloud/spanner` in `package.json`.
- **Release Tracking**: Check the [googleapis/nodejs-spanner](https://github.com/googleapis/nodejs-spanner/releases) GitHub repository.
- **Common Issues**: Watch for shifts from callbacks to Promises and drops in Node.js version support. Check for stream closure errors (e.g., `stream.push() after EOF` when using `Promise.all` with transactions) and underlying dependency upgrades (like `retry-request`) which might impact performance or cause memory leaks (e.g., `EventEmitter` leaks on session creation).
- **gRPC Configuration**: Check if the application passes custom `grpc` options to the Spanner constructor. Upgrades to `gax-nodejs` often break older `grpc` configuration shapes or SSL configurations. Always verify `engines` in `package.json` for strict Node runtime requirements.

### 3. Python
- **Identification**: Look for `google-cloud-spanner` in `requirements.txt`, `Pipfile`, or `pyproject.toml`.
- **Release Tracking**: Check the [googleapis/python-spanner](https://github.com/googleapis/python-spanner/releases) GitHub repository.
- **Common Issues**: Watch for removal of Python 2.7/3.7 support, overly strict dependencies on `proto-plus`, or required minimum version bumps for `google-cloud-core`. Also check for performance issues when querying large arrays or shifting to asynchronous interfaces.
- **Strict Parameter Types**: Review all instances of `execute_sql()`. Newer Spanner clients enforce strict type checking; ensure `param_types` are explicitly provided for all parameterized queries to avoid runtime type errors.

### 4. Go
- **Identification**: Look for `cloud.google.com/go/spanner` in `go.mod`.
- **Release Tracking**: Check the [googleapis/google-cloud-go](https://github.com/googleapis/google-cloud-go/releases) GitHub repository (or the specific spanner module path).
- **Common Issues**: Watch for changes to Context handling, changes to struct fields (like adding required options), or module path changes (e.g., `v2`).
- **Transitive Dependencies**: Always run `go mod tidy` after bumping Spanner. Specifically verify that `google.golang.org/grpc` and `google.golang.org/api` are compatible with the new Spanner version to prevent obscure runtime dial panics.

### 5. C# / .NET
- **Identification**: Look for `Google.Cloud.Spanner.Data` or `Google.Cloud.Spanner.V1` in `.csproj` files.
- **Release Tracking**: Check the [googleapis/google-cloud-dotnet](https://github.com/googleapis/google-cloud-dotnet/releases) GitHub repository.
- **Common Issues**: Watch for Target Framework changes (e.g., .NET Core 3.1 to .NET 6), changes to ADO.NET provider implementations, or async method overhauls.

### 6. C++
- **Identification**: Look for `google-cloud-cpp` Spanner components in `CMakeLists.txt` or `bazel` build files.
- **Release Tracking**: Check the [googleapis/google-cloud-cpp](https://github.com/googleapis/google-cloud-cpp/releases) GitHub repository.
- **Common Issues**: Watch for C++ standard requirements bumping (e.g., C++11 to C++14/17), ABI breaks, or CMake target renaming.

### 7. PHP & Ruby
- **PHP Identification/Tracking**: Look for `google/cloud-spanner` in `composer.json`. Check the [googleapis/google-cloud-php-spanner](https://github.com/googleapis/google-cloud-php-spanner/releases) repo.
- **Ruby Identification/Tracking**: Look for `google-cloud-spanner` in `Gemfile`. Check the [googleapis/google-cloud-ruby](https://github.com/googleapis/google-cloud-ruby/releases) repo.

## Behavioral Guidelines
- **Be Reassuring**: Acknowledge that major version upgrades can be daunting. Frame your guidance to build confidence.
- **Be Specific**: Avoid generic advice like "check the docs". Provide the exact new method signature, import path, or configuration flag.
- **Contextualize the Impact**: If you have access to their codebase, analyze which breaking changes actually affect them.

## Reference Directory

For more detailed guidance on specific aspects of the upgrade process, refer to the following documentation:

- [Best Practices](references/best-practices.md): General strategies for successful major version upgrades, such as incremental upgrades and testing.
- [Troubleshooting](references/troubleshooting.md): Common errors encountered during migrations (e.g., missing methods, dependency conflicts) and how to resolve them.
- [Tooling](references/tooling.md): Recommended tools and automation strategies (like OpenRewrite, npm-check-updates) to assist with the upgrade process.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SDK Upgrade Best Practices

When performing a major version upgrade of an SDK or client library, following these best practices minimizes risk and ensures a smooth transition.

## 1. Incremental Upgrades
If you are multiple major versions behind (e.g., v1 -> v4), do not jump straight to the latest version. Upgrade one major version at a time (v1 -> v2, then v2 -> v3, etc.). This makes it easier to isolate breaking changes and identify which version introduced a specific issue.

## 2. Review Deprecation Warnings First
Before upgrading, run the application using the current version and carefully review any deprecation warnings in the logs. These warnings often tell you exactly what will break in the next major version and provide the recommended replacement. Fixing deprecations *before* the upgrade makes the actual upgrade much simpler.

## 3. Isolate Dependency Changes
Perform the SDK upgrade in a dedicated branch. Do not mix the upgrade with feature work or other dependency updates. This keeps the diff clean and makes it easier to revert if something goes wrong.

## 4. Rely on Type Systems (If Applicable)
If using a statically typed language (Java, Go, C#) or a type-checker (TypeScript), rely heavily on the compiler. After bumping the version, run the build/compiler. The type system will immediately flag missing methods, changed signatures, or removed classes.

## 5. Comprehensive Testing
- **Unit Tests:** Ensure your unit tests pass. If you mocked the SDK, you may need to update your mocks to match the new SDK's behavior.
- **Integration Tests:** This is critical. Mocks won't catch changes in network behavior or API responses. Run integration tests against a staging or sandbox environment.
- **Manual Verification:** Test the core flows of your application that rely on the SDK.

## 6. Audit Transitive Dependencies
Sometimes upgrading an SDK also upgrades its underlying transitive dependencies (e.g., an HTTP client or JSON parser). Check if these transitive upgrades conflict with other libraries in your project. In Maven/Gradle or NPM/Yarn, inspect the dependency tree.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Migration and Upgrade Tooling

Using the right tools can automate or simplify the process of upgrading dependencies and identifying breaking changes.

## Dependency Management Tools

### Node.js / JavaScript
- **`npm-check-updates` (ncu):** A CLI tool that upgrades your `package.json` dependencies to the latest versions, ignoring specified versions.
`ncu -u`
- **`npm ls <package>`:** Helps identify why a specific version of a package is installed and what relies on it.

### Python
- **`pip-upgrader`:** An interactive tool to upgrade packages in `requirements.txt`.
- **`pipdeptree`:** Displays the installed Python packages in form of a dependency tree.

### Java
- **Maven Versions Plugin:** `mvn versions:display-dependency-updates` shows which dependencies have newer versions available.
- **Gradle Versions Plugin:** A similar tool for Gradle projects to discover dependency updates.

## Automated Refactoring Tools

For very large migrations, some ecosystems provide automated refactoring tools that can rewrite your code to use the new SDK APIs.

- **OpenRewrite (Java):** OpenRewrite can run "recipes" that automatically refactor Java code. Some SDK providers offer official OpenRewrite recipes for major version migrations (e.g., upgrading Spring Boot or AWS SDKs).
- **jscodeshift (JavaScript/TypeScript):** A toolkit for running "codemods" that transform ASTs. Often used by React or other UI frameworks, but sometimes provided by library authors for major upgrades.
- **Goof (Go):** Standard tools like `gofmt` and `go fix` can sometimes help with standard library upgrades.

## Continuous Update Bots
Consider enabling tools like **Dependabot** (GitHub) or **Renovate** to automate dependency updates. They create pull requests automatically when new versions are released, allowing you to run your CI pipeline against the new version immediately.
Loading