blob: 032d61c9501c60d5b773e8bf69509c9a184e14d1 [file] [log] [blame] [view]
Lukasz Anforowiczceddb032024-02-21 16:39:231# Updating Rust crates used by Chromium
2
3This document describes how Chromium updates crates.io Rust crates that Chromium
4depends on.
5
Matthew Riley9afd9782025-03-11 00:07:426## Staffing
7
8We have a
9[weekly rotation](https://goto.google.com/chromium-crates-update-rotation) of
10Google engineers responsible for creating and landing CLs that update Rust
11crates.
12
13Google engineers can join the rotation by emailing
14[[email protected]](mailto:[email protected]).
Lukasz Anforowicz121edc92024-03-20 18:24:3315
16## Initial setup
17
18The "Rust: periodic update of 3rd-party crates" rotation requires access to an
19up-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
21work - e.g. ones based on `git-new-workdir`).
22
Lukasz Anforowicz1fe006b2025-06-26 23:07:3023## Checking the state of the world
Dustin J. Mitchellf93a83d2024-09-16 18:56:0124
25Before creating a CL stack, check for open CLs with the [`cratesio-autoupdate`
26tag](https://chromium-review.googlesource.com/q/hashtag:%22cratesio-autoupdate%22+(status:open%20OR%20status:merged)).
27Such CLs tend to conflict, so coordinate with owners of any open CLs.
28
Lukasz Anforowicz1fe006b2025-06-26 23:07:3029You may also check a doc with notes from previous rotations, where we may note
30known issues and their workarounds. See (Google-internal, sorry):
31https://docs.google.com/document/d/1S7gsrJFsgoU5CH0K7-X_gL55zIIgd6UsFpCGrJqjdAg/edit?usp=sharing
32
Lukasz Anforowicz121edc92024-03-20 18:24:3333## Automated step: `create_update_cl.py`
34
Chris Palmera03c7c62025-04-30 17:27:5235The first actual step of the rotation is running `create_update_cl.py`. You must
36invoke it from within the `src/` directory of a Chromium repository checkout,
37and it depends on `depot_tools` and `git` being present in the `PATH`.
Lukasz Anforowiczceddb032024-02-21 16:39:2338
Chris Palmera03c7c62025-04-30 17:27:5239```sh
40$ cd ~/chromium/src # or wherever you have your checkout
Lukasz Anforowicz561878d2024-03-22 18:30:1241$ tools/crates/create_update_cl.py auto
42```
43
Chris Palmera03c7c62025-04-30 17:27:5244In `auto` mode, it runs `gnrt update` to discover crate updates and then for
45each 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
47crate id>`, `gnrt vendor`, and `gnrt gen`. Depending on how many crates are
48updated, the script may need 10-15 minutes to run.
Lukasz Anforowiczceddb032024-02-21 16:39:2349
Lukasz Anforowiczc420fb62025-03-17 23:14:3250The script should Just Work in most cases, but sometimes it may fail when
Chris Palmera03c7c62025-04-30 17:27:5251dealing with a specific crate update. See [Recovering from script
52failures](#recovering-from-script-failures) below for what to do when that
53happens.
Lukasz Anforowiczc420fb62025-03-17 23:14:3254
Lukasz Anforowicze72d5b92025-03-25 17:41:1355Before the auto-generated CLs can be landed, you will need to get an LGTM from
Lukasz Anforowicza2e0c8d2025-05-13 23:18:3556`//third_party/rust/OWNERS`. A review checklist can be found at
57`//third_party/rust/OWNERS-review-checklist.md`.
Lukasz Anforowiczceddb032024-02-21 16:39:2358
danakjeeeb7622024-09-13 06:36:3159## New transitive dependencies
60
Lukasz Anforowicza2e0c8d2025-05-13 23:18:3561Notes from `//third_party/rust/OWNERS-review-checklist.md` apply:
danakjeeeb7622024-09-13 06:36:3162
Lukasz Anforowicze72d5b92025-03-25 17:41:1363* 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.
danakjeeeb7622024-09-13 06:36:3167
Chris Palmera03c7c62025-04-30 17:27:5268### Optional: Adding the transitive dependency in its own CL
danakjeeeb7622024-09-13 06:36:3169
Lukasz Anforowicze72d5b92025-03-25 17:41:1370If the new crate is non-trivial, it's possible to split the
danakjeeeb7622024-09-13 06:36:3171additional crate into its own CL, however then it will default to global
72visibility 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 Anforowicz121edc92024-03-20 18:24:3386## Potential additional steps
Lukasz Anforowiczceddb032024-02-21 16:39:2387
Lukasz Anforowicz121edc92024-03-20 18:24:3388* 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 Anforowicz52258d12024-03-05 20:23:3694
Lukasz Anforowicz121edc92024-03-20 18:24:3395## Landing the CL
Lukasz Anforowiczceddb032024-02-21 16:39:2396
97Other than the above, the CL can go through the normal, plain-vanilla, manual
98review and landing process.
99
1001. `git cl upload`
1011. Get a review from one of `//third_party/rust/OWNERS`
1021. Land the CL using CQ+2
Lukasz Anforowicz67783682024-03-22 16:24:49103
104## Checking for new major versions
105
Lukasz Anforowiczcc3a61e2024-10-11 21:20:50106Note that `create_update_cl.py auto` will by default only handle minor version
107updates (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
109changes) need to be handled separately - this section describes what to do.
110
111### Detecting available major version updates
Lukasz Anforowicz67783682024-03-22 16:24:49112
113As part of the rotation, one should attempt to check for new major versions of
Lukasz Anforowiczcc3a61e2024-10-11 21:20:50114_direct_ Chromium dependencies (i.e. dependencies directly listed in
Lukasz Anforowicz67783682024-03-22 16:24:49115`third_party/rust/chromium_crates_io/Cargo.toml`). To discover direct _and_
116transitive 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
118updates):
119
Chris Palmera03c7c62025-04-30 17:27:52120```sh
Lukasz Anforowicz6f8bcd62025-06-16 18:19:56121$ tools/crates/run_gnrt.py update -- --verbose --dry-run
Lukasz Anforowicz67783682024-03-22 16:24:49122...
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 Anforowiczcc3a61e2024-10-11 21:20:50128### Major version update: Workflow A: Single update CL
Lukasz Anforowicz67783682024-03-22 16:24:49129
Lukasz Anforowiczcc3a61e2024-10-11 21:20:50130If updating to a new major version doesn't require lots of Chromium changes,
Lukasz Anforowicz67783682024-03-22 16:24:49131then it may be possible to land the update in a single CL. This is typically
132possible when the APIs affected by the major version's breaking change either
133weren'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
136introduce breaking changes in the _behavior_ of the existing APIs.
137
138To update:
139
Lukasz Anforowiczcc3a61e2024-10-11 21:20:501401. `tools/crates/create_update_cl.py auto -- some_crate_name --breaking`
Lukasz Anforowicze72d5b92025-03-25 17:41:131411. Follow the manual steps from the minor version update rotation for
142 review, landing, etc.
Lukasz Anforowicz67783682024-03-22 16:24:49143
Lukasz Anforowiczcc3a61e2024-10-11 21:20:50144### Major version update: Workflow B: Incremental transition
Lukasz Anforowicz67783682024-03-22 16:24:49145
146When lots of first-party code depends on the old major version, then the
147transition to the new major version may need to be done incrementally. In this
148case the transition can be split into the following steps:
149
1501. 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
1531. 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).
1581. Incrementally transition first-party code to the new major version
1591. 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
164Note that the following `Cargo.toml` syntax allows two versions of a crate to
165coexist:
166
Chris Palmera03c7c62025-04-30 17:27:52167```toml
Lukasz Anforowicz67783682024-03-22 16:24:49168[dependencies.serde_json_lenient_old_epoch]
169package = "serde_json_lenient"
170version = "0.1"
171
172[dependencies.serde_json_lenient]
173version = "0.2"
174```
Lukasz Anforowiczcc3a61e2024-10-11 21:20:50175
176## Other ways to use `create_update_cl.py`
177
178### `auto` mode
179
180Extra 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)),
183but 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
188discover **minor** version updates for **all** crates that Chromium depends on
189and 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
194trigger 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
199used to trigger a **major** version update of a single crate
200
201### `manual` mode
202
203For maximal control, the script can be used in `manual` mode:
204
2051. 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`
2151. 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 Palmera03c7c62025-04-30 17:27:52224<a id="recovering-from-script-failures"></a>
Lukasz Anforowiczc420fb62025-03-17 23:14:32225## Recovering from script failures
226
227Sometimes the `create_update_cl.py` script will fail when dealing with
228a specific crate update. The general workflow in this case is to
2291) fix the issue in a separate CL, and 2) restart the tool from the middle
230by using `--upstream-branch` that points to the last successful update branch
231(or to the fix CL) rather than defaulting to `origin/main`.
232
233Examples 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 Palmera03c7c62025-04-30 17:27:52238 ([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 Anforowiczc420fb62025-03-17 23:14:32240* 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 Palmera03c7c62025-04-30 17:27:52246 ```sh
Lukasz Anforowiczc420fb62025-03-17 23:14:32247 $ git checkout rust-crates-update--last-successful-update
248 $ git checkout -b fix-patches-for-foo
Andrew Paseltiner4f4864c2025-03-27 18:07:37249 $ git branch --set-upstream-to=rust-crates-update--last-successful-update
Lukasz Anforowiczc420fb62025-03-17 23:14:32250 ```
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 Palmera03c7c62025-04-30 17:27:52254 ```sh
Lukasz Anforowiczc420fb62025-03-17 23:14:32255 $ # 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 Palmera03c7c62025-04-30 17:27:52262 ```sh
Andrew Paseltiner4f4864c2025-03-27 18:07:37263 $ tools/crates/create_update_cl.py auto \
264 --upstream-branch=fix-patches-for-foo \
265 -- name-of-failed-crate
Lukasz Anforowiczc420fb62025-03-17 23:14:32266 ```
267 - Combine the branches:
Chris Palmera03c7c62025-04-30 17:27:52268 ```sh
Lukasz Anforowiczc420fb62025-03-17 23:14:32269 $ 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).