Lukasz Anforowicz | ceddb03 | 2024-02-21 16:39:23 | [diff] [blame] | 1 | # Updating Rust crates used by Chromium |
| 2 | |
| 3 | This document describes how Chromium updates crates.io Rust crates that Chromium |
| 4 | depends on. |
| 5 | |
Matthew Riley | 9afd978 | 2025-03-11 00:07:42 | [diff] [blame] | 6 | ## Staffing |
| 7 | |
| 8 | We have a |
| 9 | [weekly rotation](https://goto.google.com/chromium-crates-update-rotation) of |
| 10 | Google engineers responsible for creating and landing CLs that update Rust |
| 11 | crates. |
| 12 | |
| 13 | Google engineers can join the rotation by emailing |
| 14 | [[email protected]](mailto:[email protected]). |
Lukasz Anforowicz | 121edc9 | 2024-03-20 18:24:33 | [diff] [blame] | 15 | |
| 16 | ## Initial setup |
| 17 | |
| 18 | The "Rust: periodic update of 3rd-party crates" rotation requires access to an |
| 19 | up-to-date Chromium repo. One way to start a shift is to run `git fetch`, |
| 20 | `git checkout origin/main`, and `gclient sync` (but other workflows should also |
| 21 | work - e.g. ones based on `git-new-workdir`). |
| 22 | |
Lukasz Anforowicz | 1fe006b | 2025-06-26 23:07:30 | [diff] [blame] | 23 | ## Checking the state of the world |
Dustin J. Mitchell | f93a83d | 2024-09-16 18:56:01 | [diff] [blame] | 24 | |
| 25 | Before creating a CL stack, check for open CLs with the [`cratesio-autoupdate` |
| 26 | tag](https://chromium-review.googlesource.com/q/hashtag:%22cratesio-autoupdate%22+(status:open%20OR%20status:merged)). |
| 27 | Such CLs tend to conflict, so coordinate with owners of any open CLs. |
| 28 | |
Lukasz Anforowicz | 1fe006b | 2025-06-26 23:07:30 | [diff] [blame] | 29 | You may also check a doc with notes from previous rotations, where we may note |
| 30 | known issues and their workarounds. See (Google-internal, sorry): |
| 31 | https://docs.google.com/document/d/1S7gsrJFsgoU5CH0K7-X_gL55zIIgd6UsFpCGrJqjdAg/edit?usp=sharing |
| 32 | |
Lukasz Anforowicz | 121edc9 | 2024-03-20 18:24:33 | [diff] [blame] | 33 | ## Automated step: `create_update_cl.py` |
| 34 | |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 35 | The first actual step of the rotation is running `create_update_cl.py`. You must |
| 36 | invoke it from within the `src/` directory of a Chromium repository checkout, |
| 37 | and it depends on `depot_tools` and `git` being present in the `PATH`. |
Lukasz Anforowicz | ceddb03 | 2024-02-21 16:39:23 | [diff] [blame] | 38 | |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 39 | ```sh |
| 40 | $ cd ~/chromium/src # or wherever you have your checkout |
Lukasz Anforowicz | 561878d | 2024-03-22 18:30:12 | [diff] [blame] | 41 | $ tools/crates/create_update_cl.py auto |
| 42 | ``` |
| 43 | |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 44 | In `auto` mode, it runs `gnrt update` to discover crate updates and then for |
| 45 | each update creates a new local git branch (and a Gerrit CL unless invoked with |
| 46 | `--no-upload`). Each branch contains an update created by `gnrt update <old |
| 47 | crate id>`, `gnrt vendor`, and `gnrt gen`. Depending on how many crates are |
| 48 | updated, the script may need 10-15 minutes to run. |
Lukasz Anforowicz | ceddb03 | 2024-02-21 16:39:23 | [diff] [blame] | 49 | |
Lukasz Anforowicz | c420fb6 | 2025-03-17 23:14:32 | [diff] [blame] | 50 | The script should Just Work in most cases, but sometimes it may fail when |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 51 | dealing with a specific crate update. See [Recovering from script |
| 52 | failures](#recovering-from-script-failures) below for what to do when that |
| 53 | happens. |
Lukasz Anforowicz | c420fb6 | 2025-03-17 23:14:32 | [diff] [blame] | 54 | |
Lukasz Anforowicz | e72d5b9 | 2025-03-25 17:41:13 | [diff] [blame] | 55 | Before the auto-generated CLs can be landed, you will need to get an LGTM from |
Lukasz Anforowicz | a2e0c8d | 2025-05-13 23:18:35 | [diff] [blame] | 56 | `//third_party/rust/OWNERS`. A review checklist can be found at |
| 57 | `//third_party/rust/OWNERS-review-checklist.md`. |
Lukasz Anforowicz | ceddb03 | 2024-02-21 16:39:23 | [diff] [blame] | 58 | |
danakj | eeeb762 | 2024-09-13 06:36:31 | [diff] [blame] | 59 | ## New transitive dependencies |
| 60 | |
Lukasz Anforowicz | a2e0c8d | 2025-05-13 23:18:35 | [diff] [blame] | 61 | Notes from `//third_party/rust/OWNERS-review-checklist.md` apply: |
danakj | eeeb762 | 2024-09-13 06:36:31 | [diff] [blame] | 62 | |
Lukasz Anforowicz | e72d5b9 | 2025-03-25 17:41:13 | [diff] [blame] | 63 | * The dependency will need to go through security review. |
| 64 | * An FYI email should be sent to |
| 65 | [[email protected]](mailto:[email protected]) |
| 66 | in order to record the addition. |
danakj | eeeb762 | 2024-09-13 06:36:31 | [diff] [blame] | 67 | |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 68 | ### Optional: Adding the transitive dependency in its own CL |
danakj | eeeb762 | 2024-09-13 06:36:31 | [diff] [blame] | 69 | |
Lukasz Anforowicz | e72d5b9 | 2025-03-25 17:41:13 | [diff] [blame] | 70 | If the new crate is non-trivial, it's possible to split the |
danakj | eeeb762 | 2024-09-13 06:36:31 | [diff] [blame] | 71 | additional crate into its own CL, however then it will default to global |
| 72 | visibility and allowing non-test use. |
| 73 | * `gnrt add` and `gnrt vendor` can add the dependency to a fresh checkout. |
| 74 | * Mark the crate as being for third-party code only by setting |
| 75 | `allow_first_party_usage` to `false` for the crate in |
| 76 | `third_party/rust/chromium_crates_io/gnrt_config.toml`. |
| 77 | * If the crates making use of the transitive dependency are only allowed |
| 78 | in tests, then set `group = 'test'` for the crate in |
| 79 | `third_party/rust/chromium_crates_io/gnrt_config.toml`. This reduces |
| 80 | the level of security review required for the library. |
| 81 | * `gnrt gen` will then generate the GN rules. |
| 82 | * Rebase the roll CL on top of the changes to make sure the choices made above |
| 83 | are correct. `gn gen` will fail in CQ if the crate was placed in the `'test'` |
| 84 | group but needs to be visible outside of tests. |
| 85 | |
Lukasz Anforowicz | 121edc9 | 2024-03-20 18:24:33 | [diff] [blame] | 86 | ## Potential additional steps |
Lukasz Anforowicz | ceddb03 | 2024-02-21 16:39:23 | [diff] [blame] | 87 | |
Lukasz Anforowicz | 121edc9 | 2024-03-20 18:24:33 | [diff] [blame] | 88 | * The `create_update_cl.py` script may stop early if it detects that `gnrt |
| 89 | vendor` or `gnrt gen` have reported any warnings or errors (e.g. a "License |
| 90 | file not found for crate foo" warning). In this case, manual intervention is |
| 91 | needed to finish the update CL. It's probably best to finish and land the CLs |
| 92 | created so far before trying to restart the script in order to create the |
| 93 | remaining CLs. |
Lukasz Anforowicz | 52258d1 | 2024-03-05 20:23:36 | [diff] [blame] | 94 | |
Lukasz Anforowicz | 121edc9 | 2024-03-20 18:24:33 | [diff] [blame] | 95 | ## Landing the CL |
Lukasz Anforowicz | ceddb03 | 2024-02-21 16:39:23 | [diff] [blame] | 96 | |
| 97 | Other than the above, the CL can go through the normal, plain-vanilla, manual |
| 98 | review and landing process. |
| 99 | |
| 100 | 1. `git cl upload` |
| 101 | 1. Get a review from one of `//third_party/rust/OWNERS` |
| 102 | 1. Land the CL using CQ+2 |
Lukasz Anforowicz | 6778368 | 2024-03-22 16:24:49 | [diff] [blame] | 103 | |
| 104 | ## Checking for new major versions |
| 105 | |
Lukasz Anforowicz | cc3a61e | 2024-10-11 21:20:50 | [diff] [blame] | 106 | Note that `create_update_cl.py auto` will by default only handle minor version |
| 107 | updates (e.g. 123.1 => 123.2, or 0.123.1 => 0.123.2). Major version changes |
| 108 | (e.g. 1.0 => 2.0, which may include breaking API changes and other breaking |
| 109 | changes) need to be handled separately - this section describes what to do. |
| 110 | |
| 111 | ### Detecting available major version updates |
Lukasz Anforowicz | 6778368 | 2024-03-22 16:24:49 | [diff] [blame] | 112 | |
| 113 | As part of the rotation, one should attempt to check for new major versions of |
Lukasz Anforowicz | cc3a61e | 2024-10-11 21:20:50 | [diff] [blame] | 114 | _direct_ Chromium dependencies (i.e. dependencies directly listed in |
Lukasz Anforowicz | 6778368 | 2024-03-22 16:24:49 | [diff] [blame] | 115 | `third_party/rust/chromium_crates_io/Cargo.toml`). To discover direct _and_ |
| 116 | transitive dependencies with a new major version, you can use the command below |
| 117 | (running it in the final update CL branch - after all the minor version |
| 118 | updates): |
| 119 | |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 120 | ```sh |
Lukasz Anforowicz | 6f8bcd6 | 2025-06-16 18:19:56 | [diff] [blame] | 121 | $ tools/crates/run_gnrt.py update -- --verbose --dry-run |
Lukasz Anforowicz | 6778368 | 2024-03-22 16:24:49 | [diff] [blame] | 122 | ... |
| 123 | Unchanged serde_json_lenient v0.1.8 (latest: v0.2.0) |
| 124 | Unchanged syn v1.0.109 (latest: v2.0.53) |
| 125 | ... |
| 126 | ``` |
| 127 | |
Lukasz Anforowicz | cc3a61e | 2024-10-11 21:20:50 | [diff] [blame] | 128 | ### Major version update: Workflow A: Single update CL |
Lukasz Anforowicz | 6778368 | 2024-03-22 16:24:49 | [diff] [blame] | 129 | |
Lukasz Anforowicz | cc3a61e | 2024-10-11 21:20:50 | [diff] [blame] | 130 | If updating to a new major version doesn't require lots of Chromium changes, |
Lukasz Anforowicz | 6778368 | 2024-03-22 16:24:49 | [diff] [blame] | 131 | then it may be possible to land the update in a single CL. This is typically |
| 132 | possible when the APIs affected by the major version's breaking change either |
| 133 | weren't used by Chromium, or were used only in a handful of places. |
| 134 | |
| 135 | **Warning**: Sometimes a new major version may be API compatible, but may |
| 136 | introduce breaking changes in the _behavior_ of the existing APIs. |
| 137 | |
| 138 | To update: |
| 139 | |
Lukasz Anforowicz | cc3a61e | 2024-10-11 21:20:50 | [diff] [blame] | 140 | 1. `tools/crates/create_update_cl.py auto -- some_crate_name --breaking` |
Lukasz Anforowicz | e72d5b9 | 2025-03-25 17:41:13 | [diff] [blame] | 141 | 1. Follow the manual steps from the minor version update rotation for |
| 142 | review, landing, etc. |
Lukasz Anforowicz | 6778368 | 2024-03-22 16:24:49 | [diff] [blame] | 143 | |
Lukasz Anforowicz | cc3a61e | 2024-10-11 21:20:50 | [diff] [blame] | 144 | ### Major version update: Workflow B: Incremental transition |
Lukasz Anforowicz | 6778368 | 2024-03-22 16:24:49 | [diff] [blame] | 145 | |
| 146 | When lots of first-party code depends on the old major version, then the |
| 147 | transition to the new major version may need to be done incrementally. In this |
| 148 | case the transition can be split into the following steps: |
| 149 | |
| 150 | 1. Open a new bug to track the transition |
| 151 | - TODO: Figure out how to tag/format the bug to make it easy to discover |
| 152 | in future rotations |
| 153 | 1. Land the new major version, so that the old and the new versions coexist. |
| 154 | To do this follow the process for importing a new crate as described in |
| 155 | [`docs/rust.md`](../../docs/rust.md#importing-a-crate-from-crates_io) |
| 156 | (i.e. edit `Cargo.toml` to add the new version, run `gnrt vendor`, and so |
| 157 | forth). |
| 158 | 1. Incrementally transition first-party code to the new major version |
| 159 | 1. Remove the old major version. To do this follow a similar process as above |
| 160 | (i.e. edit `Cargo.toml` to remove the old version, run `gnrt vendor`, and so |
| 161 | forth). Any leftover files in `//third_party/rust/<crate>/<old epoch>` |
| 162 | should also be removed. |
| 163 | |
| 164 | Note that the following `Cargo.toml` syntax allows two versions of a crate to |
| 165 | coexist: |
| 166 | |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 167 | ```toml |
Lukasz Anforowicz | 6778368 | 2024-03-22 16:24:49 | [diff] [blame] | 168 | [dependencies.serde_json_lenient_old_epoch] |
| 169 | package = "serde_json_lenient" |
| 170 | version = "0.1" |
| 171 | |
| 172 | [dependencies.serde_json_lenient] |
| 173 | version = "0.2" |
| 174 | ``` |
Lukasz Anforowicz | cc3a61e | 2024-10-11 21:20:50 | [diff] [blame] | 175 | |
| 176 | ## Other ways to use `create_update_cl.py` |
| 177 | |
| 178 | ### `auto` mode |
| 179 | |
| 180 | Extra arguments passed to `create_update_cl.py auto` end up being passed to |
| 181 | `cargo update`. For a complete list of available options, see |
| 182 | [Cargo documentation here](https://doc.rust-lang.org/cargo/commands/cargo-update.html#update-options)), |
| 183 | but the most common scenarios are covered in the sections below. |
| 184 | |
| 185 | #### Updating all crates during the weekly rotation |
| 186 | |
| 187 | `tools/crates/create_update_cl.py auto` with no extra arguments will attempt to |
| 188 | discover **minor** version updates for **all** crates that Chromium depends on |
| 189 | and for their transitive dependencies. |
| 190 | |
| 191 | #### Updating the minor version of a single crate |
| 192 | |
| 193 | `tools/crates/create_update_cl.py auto -- some_crate_name` can be used to |
| 194 | trigger a **minor** version update of a single crate. |
| 195 | |
| 196 | #### Updating the major version of a single crate |
| 197 | |
| 198 | `tools/crates/create_update_cl.py auto -- some_crate_name --breaking` can be |
| 199 | used to trigger a **major** version update of a single crate |
| 200 | |
| 201 | ### `manual` mode |
| 202 | |
| 203 | For maximal control, the script can be used in `manual` mode: |
| 204 | |
| 205 | 1. Prepare `Cargo.toml` change: |
| 206 | 1. `git checkout origin/main` |
| 207 | 1. `git checkout -b manual-update-of-foo` |
| 208 | 1. Edit `third_party/rust/chromium_crates_io/Cargo.toml` to change the crate |
| 209 | version of the crate (or crates) you want to update. |
| 210 | **Important**: Do not edit `Cargo.lock` (e.g. don't run `gnrt vendor` |
| 211 | etc.). |
| 212 | 1. `git add third_party/rust/chromium_crates_io/Cargo.toml` |
| 213 | 1. `git commit -m "Manual edit of Cargo.toml"` |
| 214 | 1. `git cl upload -m "Manual edit of Cargo.toml" --bypass-hooks --skip-title --force` |
| 215 | 1. Run the helper script as follows: |
| 216 | `tools/crates/create_update_cl.py manual |
| 217 | --title "Roll foo crate to new version X"` |
| 218 | - This will run `gnrt vendor` to discover and execute updates that were |
| 219 | requested by the manual edits of `Cargo.toml` in the previous steps. |
| 220 | - This will automatically add more details to the CL description |
| 221 | - To make the review easier, one of the patchsets covers just the path |
| 222 | changes. For example - see [the delta here](https://crrev.com/c/5445719/2..7). |
| 223 | |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 224 | <a id="recovering-from-script-failures"></a> |
Lukasz Anforowicz | c420fb6 | 2025-03-17 23:14:32 | [diff] [blame] | 225 | ## Recovering from script failures |
| 226 | |
| 227 | Sometimes the `create_update_cl.py` script will fail when dealing with |
| 228 | a specific crate update. The general workflow in this case is to |
| 229 | 1) fix the issue in a separate CL, and 2) restart the tool from the middle |
| 230 | by using `--upstream-branch` that points to the last successful update branch |
| 231 | (or to the fix CL) rather than defaulting to `origin/main`. |
| 232 | |
| 233 | Examples of a few specific situations that may lead to script failure: |
| 234 | |
| 235 | * An update brought in a new crate, but `gnrt` didn't recognize new crate's |
| 236 | license kind or license file. In that case a prerequisite CL needs to be |
| 237 | landed first, teaching `gnrt` about the new license kinds/files |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 238 | ([in readme.rs](https://source.chromium.org/chromium/chromium/src/+/main:tools/crates/gnrt/lib/readme.rs;l=264-290;drc=c838bc6c6317d4c1ead1f7f0c615af353482f2b3)). |
| 239 | You can see [an example CL with such a fix](https://crrev.com/c/6219211). |
Lukasz Anforowicz | c420fb6 | 2025-03-17 23:14:32 | [diff] [blame] | 240 | * Patches from `//third_party/rust/chromium_crates_io/patches/` no longer |
| 241 | apply cleanly to the new version of a crate. In that case the crate update CL |
| 242 | needs to 1) first update the patches, and then 2) update the crate as usual. |
| 243 | This is not very well supported by the script... But something like this |
| 244 | should work: |
| 245 | - Checkout a new branch: |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 246 | ```sh |
Lukasz Anforowicz | c420fb6 | 2025-03-17 23:14:32 | [diff] [blame] | 247 | $ git checkout rust-crates-update--last-successful-update |
| 248 | $ git checkout -b fix-patches-for-foo |
Andrew Paseltiner | 4f4864c | 2025-03-27 18:07:37 | [diff] [blame] | 249 | $ git branch --set-upstream-to=rust-crates-update--last-successful-update |
Lukasz Anforowicz | c420fb6 | 2025-03-17 23:14:32 | [diff] [blame] | 250 | ``` |
| 251 | - Fix the patches and upload as a temporary / throw-away CL |
| 252 | (this CL can't be landed on its own - it needs to be combined |
| 253 | with the actual update CL): |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 254 | ```sh |
Lukasz Anforowicz | c420fb6 | 2025-03-17 23:14:32 | [diff] [blame] | 255 | $ # Fix the patches |
| 256 | $ git commit -a -m ... |
| 257 | $ git cl upload |
| 258 | ``` |
| 259 | - Restart the script (the CL created by the script can't be landed |
| 260 | as-is / on its own - it needs to be combined with the fixed patches |
| 261 | in the step below) with `--upstream-branch` parameter: |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 262 | ```sh |
Andrew Paseltiner | 4f4864c | 2025-03-27 18:07:37 | [diff] [blame] | 263 | $ tools/crates/create_update_cl.py auto \ |
| 264 | --upstream-branch=fix-patches-for-foo \ |
| 265 | -- name-of-failed-crate |
Lukasz Anforowicz | c420fb6 | 2025-03-17 23:14:32 | [diff] [blame] | 266 | ``` |
| 267 | - Combine the branches: |
Chris Palmer | a03c7c6 | 2025-04-30 17:27:52 | [diff] [blame] | 268 | ```sh |
Lukasz Anforowicz | c420fb6 | 2025-03-17 23:14:32 | [diff] [blame] | 269 | $ git map-branches -v # to orient yourself |
| 270 | $ git checkout rust-crates-update--new-successful-update |
| 271 | $ git branch --set-upstream-to=rust-crates-update--last-successful-update |
| 272 | $ git cl upload -m Rebasing... # --bypass-hooks as needed |
| 273 | ``` |
| 274 | * `//third_party/rust/chromium_crates_io/gnrt_config.toml` needs to be updated |
| 275 | to work with a new crate version. The same workflow should work as for fixing |
| 276 | `//third_party/rust/chromium_crates_io/patches/` (see the item above). |