blob: 6a89dbfee1ec3e31706d1c3d631d9f4c62413dd7 [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
Dustin J. Mitchellf93a83d2024-09-16 18:56:0123## Avoiding Conflicts
24
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 Anforowicz121edc92024-03-20 18:24:3329## Automated step: `create_update_cl.py`
30
Lukasz Anforowicz561878d2024-03-22 18:30:1231The first actual step of the rotation is running the script:
Lukasz Anforowiczceddb032024-02-21 16:39:2332
Lukasz Anforowicz561878d2024-03-22 18:30:1233```
34$ tools/crates/create_update_cl.py auto
35```
36
Lukasz Anforowicz52258d12024-03-05 20:23:3637`create_update_cl.py` has to be invoked from within a Chromium repo.
Lukasz Anforowiczceddb032024-02-21 16:39:2338The script depends on `depot_tools` and `git` being present in the `PATH`.
Lukasz Anforowicz561878d2024-03-22 18:30:1239
40In `auto` mode `//tools/crates/create_update_cl.py` runs `gnrt update` to
Lukasz Anforowiczcc3a61e2024-10-11 21:20:5041discover crate updates and then for each update creates a
Lukasz Anforowicz561878d2024-03-22 18:30:1242new local git branch (and a Gerrit CL unless invoked with `--no-upload`).
43Each branch contains an update created by `gnrt update <old crate id>`, `gnrt
44vendor`, and `gnrt gen`.
Lukasz Anforowicz121edc92024-03-20 18:24:3345Depending on how many crates are updated, the script may need 10-15 minutes to
46run.
Lukasz Anforowiczceddb032024-02-21 16:39:2347
Lukasz Anforowiczc420fb62025-03-17 23:14:3248The script should Just Work in most cases, but sometimes it may fail when
49dealing with a specific create update. See the "Recovering from script
50failures" section below for what to do when that happens.
51
Lukasz Anforowicze72d5b92025-03-25 17:41:1352Before the auto-generated CLs can be landed, you will need to get an LGTM from
53`//third_party/rust/OWNERS`. See `//third_party/rust/OWNERS-security-review.md`
54for a review checklist.
Lukasz Anforowiczceddb032024-02-21 16:39:2355
danakjeeeb7622024-09-13 06:36:3156## New transitive dependencies
57
Lukasz Anforowicze72d5b92025-03-25 17:41:1358Notes from `//third_party/rust/OWNERS-security-review.md` apply:
danakjeeeb7622024-09-13 06:36:3159
Lukasz Anforowicze72d5b92025-03-25 17:41:1360* The dependency will need to go through security review.
61* An FYI email should be sent to
62 [[email protected]](mailto:[email protected])
63 in order to record the addition.
danakjeeeb7622024-09-13 06:36:3164
65### Optional: Adding the transitive dependency in its own CL.
66
Lukasz Anforowicze72d5b92025-03-25 17:41:1367If the new crate is non-trivial, it's possible to split the
danakjeeeb7622024-09-13 06:36:3168additional crate into its own CL, however then it will default to global
69visibility and allowing non-test use.
70* `gnrt add` and `gnrt vendor` can add the dependency to a fresh checkout.
71* Mark the crate as being for third-party code only by setting
72 `allow_first_party_usage` to `false` for the crate in
73 `third_party/rust/chromium_crates_io/gnrt_config.toml`.
74* If the crates making use of the transitive dependency are only allowed
75 in tests, then set `group = 'test'` for the crate in
76 `third_party/rust/chromium_crates_io/gnrt_config.toml`. This reduces
77 the level of security review required for the library.
78* `gnrt gen` will then generate the GN rules.
79* Rebase the roll CL on top of the changes to make sure the choices made above
80 are correct. `gn gen` will fail in CQ if the crate was placed in the `'test'`
81 group but needs to be visible outside of tests.
82
Lukasz Anforowicz121edc92024-03-20 18:24:3383## Potential additional steps
Lukasz Anforowiczceddb032024-02-21 16:39:2384
danakj7f3a0262024-09-09 15:20:1985* If updating `cxx`, you will also need to update its version in
86 - `build/rust/cxx_version.gni`
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
120```
121$ tools/crates/run_cargo.py -Zunstable-options -C third_party/rust/chromium_crates_io -Zbindeps update --dry-run --verbose
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 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
167```
168[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
Lukasz Anforowiczc420fb62025-03-17 23:14:32224## Recovering from script failures
225
226Sometimes the `create_update_cl.py` script will fail when dealing with
227a specific crate update. The general workflow in this case is to
2281) fix the issue in a separate CL, and 2) restart the tool from the middle
229by using `--upstream-branch` that points to the last successful update branch
230(or to the fix CL) rather than defaulting to `origin/main`.
231
232Examples of a few specific situations that may lead to script failure:
233
234* An update brought in a new crate, but `gnrt` didn't recognize new crate's
235 license kind or license file. In that case a prerequisite CL needs to be
236 landed first, teaching `gnrt` about the new license kinds/files
237 (somewhere around
238 [here](https://source.chromium.org/chromium/chromium/src/+/main:tools/crates/gnrt/lib/readme.rs;l=264-290;drc=c838bc6c6317d4c1ead1f7f0c615af353482f2b3)).
239 Example CL with such a fix: https://crrev.com/c/6219211
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:
246 ```
247 $ 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):
254 ```
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:
262 ```
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:
268 ```
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).