Previously on #rust:
- Self-hosted CI for Rust and C++ using Laminar
- Things I learned writing an SSDP implementation in Rust
- Rust crate release checklist
- System-testing embedded code in Rust 1: Infrastructure
- System-testing embedded code in Rust 2: Testing SSDP
- System-testing embedded code in Rust 3: A CI test-runner
- Rustifying Lakos: Avoiding circular dependencies in Rust
- Things I learned writing a USB host stack in Rust for RP2040
![]() |
Cotton, the collection of low-level Rust crates I started mostly for my own use, had previously seen a couple of small patches supplied by other contributors – but for the first time, I got a pull request for an actual fairly major feature that I knew had to be done, that was on my to-do list, but that I hadn’t yet started.
This is of course very cool, not just because it saves me the effort, but also because it proves that these crates are actually useful to someone, that it’s worth it to them putting in actual work to improve them.
The feature in question was updating the smoltcp dependency from 0.11 to 0.12, which doesn’t sound like a big job, but sort-of is, because the fundamental types used for IPv4 and IPv6 addresses have changed. (Those types are now in the “core”, usable-on-embedded, part of the standard library, whereas previously smoltcp had needed to invent their own ones.) All of this is a Good Thing, because it means that the crate APIs are exactly the same in embedded and host builds, and it cuts out a needless dependency (no-std-net), but it meant a certain amount of churn (and an MSRV update).
The interesting question was, how do I test this pull request before merging it? “Because Rust”, it’s actually pretty likely that if it compiles, it’s going to work. And it certainly compiles. But this is, in part, a blog about taking software testing seriously, so I want to run these changes past the system-test hardware rig – actual Raspberry Pi Picos and STM32s running actual firmware with the code in – because that’s the quality bar for “ready to merge to main”.
Because the system-tests use real embedded hardware, real devboards for RP2040 and STM32, they can’t run in Github’s cloud. (Nor do I really want them run automatically – a malicious PR could overclock the boards or permanently damage them in other ways.) So I need to run them locally. But my local CI runs on my local repo, and Github works by the contributor forking my repository, doing the work, and then asking me to merge their repository’s main back into my repository’s main. But I rather need their work to be in a branch in my repository, not on main in a different one. And I certainly don’t want main in my own repository changed to match theirs, at least until the tests have run.
But fortunately, Github is slightly fictionalising the actual situation here. “My” repository and “their” repository are, in some sense, still actually the same one behind the scenes at Github: it’s just that Github’s UI shows my branches to me when I log in, and their branches to them when they log in. I can still do a one-off git fetch of “their” repository and git (not -hub) just does the Right Thing.
Concretely, my generous contributor’s Github name is tshakah. To fetch the changes on their main to a new branch in my repository, I can just do a one-off fetch (which doesn’t even set the default upstream for that branch):
and then I can push the new, local, tshakah-smoltcp-0.12 branch to my local CI and run it through all the tests.git fetch git@github.com:tshakah/cotton.git main:tshakah-smoltcp-0.12
And the tests passed! So I can just merge the branch to main locally in the usual way (i.e., rebased and with a no-fast-forward merge), and when I push main to github
then the pull request is automatically closed completed. (Or at least, it is if I haven’t needed to rebase – which I’d need to do, for instance if Github main was behind local main. If I rebase the contribution branch, Github doesn’t always recognise it when I push the merge, so in that case I have to close the PR manually, while making it clear to the contributor that I’ve taken their changes and appreciate their efforts.)git push github main
And once everything’s done and dusted, I can delete my local tshakah-smoltcp-0.12 branch from my local git server in the usual way:
because “origin” is still my local git server and not my Github account (nor tshakah’s).git push origin --delete tshakah-smoltcp-0.12