Skip to main content

crate-upgrade

Use when upgrading a Rust crate / third-party dependency to a new version — especially non-trivial bumps where the new version removes previously-deprecated APIs, moves modules into separate crates, renames items, or otherwise has a broad blast radius across many crates. Covers reading the changelog, picking the version deliberately, splitting the migration into aspects, and migrating incrementally.

الانتقال إلى التثبيت

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

المستودع
dfinity/ic
آخر نشاط في المصدر
٢٣ يوليو ٢٠٢٦ في ١٦:١١
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١٬٧٩٢
التفرعات
٤١٠

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

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

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

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

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
crate-upgrade
description
Use when upgrading a Rust crate / third-party dependency to a new version — especially non-trivial bumps where the new version removes previously-deprecated APIs, moves modules into separate crates, renames items, or otherwise has a broad blast radius across many crates. Covers reading the changelog, picking the version deliberately, splitting the migration into aspects, and migrating incrementally.
# Upgrading a Rust crate dependency Most version bumps are trivial: edit the version in `Cargo.toml`, mirror it in `bazel/rust.MODULE.bazel`, repin, build. This skill is for the **non-trivial** ones — where the new version removes APIs, splits modules into new crates, renames items, or the change ripples across many crates. Work through the steps in order. Steps 3–6 are the ones that keep a large migration from turning into an unreviewable, half-broken mess. ## 1. Read the release notes first Before touching any code, read the changelog for **every** version between the current and target version. - Classify each change: **deprecated** vs **removed**, and in which version. Note module moves and module→separate-crate splits — those are easy to miss because they aren't "deprecations". - Estimate the blast radius: grep the repo for the affected APIs (paths, macros, type names) to see how many crates/files are involved. ## 2. Pick the version deliberately — don't jump across a removal boundary If the target version **removes** APIs that were only **deprecated** in an earlier version, do not bump straight to it in one leap. - Prefer the highest version where the old and new APIs still **coexist** (typically the last version before the removal). Migrate the code to the new APIs there — while everything still compiles and the old APIs are merely deprecated — and only bump to the target version once the code no longer references anything that version removed. - Example: if `X` was deprecated in 0.18 and removed in 0.20, do the migration on 0.19 first, then bump to 0.20. ## 3. For non-trivial migrations, list the aspects and get human sign-off Most upgrades are straightforward and you can just do them. But when a migration spans several distinct **aspects / areas** — e.g. renamed accessor functions, a new inter-canister call API, a reject/error-type change, a module that became a separate crate — do **not** start coding. - After reading the release notes and understanding the blast radius, enumerate the aspects, and for each note the API involved and the files/crates it touches. - Present that split to a human and get it confirmed before starting. - (A trivial single-aspect upgrade can skip this.) ## 4. Migrate one aspect at a time - Do a single aspect across the codebase, and leave **every other aspect** on the existing (deprecated-but-working) API. - Each step should compile and pass tests on its own — a small, self-contained, reviewable change. - If an aspect's blast radius turns out far larger than expected (e.g. it hits production canisters or needs a brand-new dependency), that's a signal to stop and reassess the approach with a human, not to plow ahead. ## 5. Adopt the new names directly — no aliases or shims Aim for the cleanest end state; the code should read as if it had always been written against the new API. - When a symbol is renamed, update the call sites to the new name. - Do **not** introduce `use new::path::Thing as OldName` aliases, wrapper functions, or other compatibility shims just to avoid touching call sites. They leave the codebase looking backwards instead of forward. ## 6. Don't abstract mid-migration - Favor mechanical, localized edits, even when they produce boilerplate or duplication. Duplicating a small amount of code (e.g. a local type that preserves a Candid interface) is fine when it avoids re-architecting. - Do **not** introduce new helpers/abstractions to smooth the migration while it is in flight. - Only **after** the migration is fully done — it compiles, passes tests, and has been approved by a human — reassess whether the accumulated boilerplate/duplication is worth factoring out. ## 7. Keep Cargo and Bazel in sync - Edit `Cargo.toml` first, then mirror the version in `bazel/rust.MODULE.bazel` (the `crate.spec(...)` for the crate). A new crate must be added to both. - Repin the Bazel crate index: `./bin/bazel-pin.sh`. - Then follow the repo's standard Rust workflow: `rustfmt` → `cargo check` → `cargo clippy` → `bazel build` → `bazel test` (see the project `CLAUDE.md`). - See the **check-bazel-files** skill after editing Bazel files, and **run-in-dev-container** for running builds/tests inside the dev container.
عرض على GitHub