googlefonts / fontc

Where in we pursue oxidizing (context: https://github.com/googlefonts/oxidize) fontmake.
Apache License 2.0
76 stars 13 forks source link

Add release workflow to build and publish source and binary artifacts to Github and PyPI #795

Closed anthrotype closed 4 months ago

anthrotype commented 4 months ago

For the Glyphs.app fontc export plugin (#684) we need to make precompiled binaries of fontc available to download and run without requiring to build from source. Glyphs.app already comes with Python, which in turn comes with an established and secure way to distribute and install binary packages via the Python Package Index (PyPI) and the pip installer. With the help of a tool called maturin (see source and docs) it's super easy to make Python wheels out of any Rust crate, including binary-only ones like fontc. Maturin itself is written in Rust, uses cargo under the hood, and it's primarily used to package up hybrid Python/Rust projects -- which fontc technically is not (but who knows, it may in the future get a python API as well); but that's ok, ours would not be the first project on PyPI that doesn't contain any Python itself but is simply an executable that gets unpacked to the environment's bin/ or Scripts/ directories (e.g. ther's also stuff like ninja or cmake). And we have used maturin in the past to package stuff like resvg or pngquant for nanoemoji, for example. Maturin is great because I don't have to deal with the complications of making sure the binaries works on, e.g., both intel or Apple Silicon macs, or some random linux distro. I'm sure other, more expert Rust devs in here would know how do deal with all that, and may sniff at any snakes creeping in.. but I hope they will accept this as a pragmatic, first-time attempt :)

PS: While this is more of a side effect than the primary goal, allowing one to pip install fontc would increase its reach among font editors (Glyphs.app, Robofont, fontra either expose Python API/Macros or are themselves writtein in it) as well as many font developers who are already accustomed to Python (think fontTools, fontmake, afdko, etc.).

This PR adds a new release.yml Github Actions workflow that is triggered automatically on git tags (actually tags conventionally start with 'v' e.g. v1.0.0) or manually from the Actions interface. It builds the wheels for Mac, Linux and Windows and pushes them to PyPI, where they will be available at https://pypi.org/project/fontc/ It also compresses and publish the same fontc binaries that maturin has built for the Python wheels as simple .tar.gz archives and uploads them to a new Github Release, as downloadable assets. Besides allowing one to just curl, unzip and run, this also makes them ready to be installed with the nifty cargo binstall (https://github.com/cargo-bins/cargo-binstall), which can automatically finds the Github release associated with a given crate on crates.io and download precompiled binaries from it. Finally, I added a block that automatically publishes fontc to crates.io but have not enabled that yet, because I think we first need to check we have all the required metatada and maybe we need to make the first cargo publish manually to reserve our spot and make sure everying works.

EDIT: I removed the automatic upload to crates.io, since we decided to publish source crates manually instead like we do in fontations.

anthrotype commented 4 months ago

testing this workflow from my anthrotype/fontc fork, the Github Releases produced by it look like the following:

https://github.com/anthrotype/fontc/releases

anthrotype commented 4 months ago

Note that the "Build GS" CI failure is because this PR branch sits on my anthrotype fork and as such hasn't access to the token required to download GS from the private repo

rsheeter commented 4 months ago

we need to make the first cargo publish manually to reserve our spot and make sure everying works.

I believe you are right about first manual. We should do that so our names aren't subject to unexpected changes. IIRC we might also have to manually add everyone as owners in the crates web interface.

anthrotype commented 4 months ago

also generate a text file with sha256 and file lengths of the compiler binaries to attach to the release

77677e3 uploads two additional files to the Github release assets:

They will look like this: https://github.com/anthrotype/fontc/releases/tag/v0.0.2a6

respectively,

checksums.txt:

af59d98378cfb0954be5614fad97c5aec4469a1f039de4abb2ef5cca24405ee7  fontc-aarch64-apple-darwin.tar.gz
cce3d24108dacfdd9088f215532c7a3d8526c7bb2fbc586ed7d26dc5bafea7ad  fontc-aarch64-unknown-linux-musl.tar.gz
2d1fab0ca1c406fb0f6337a54ddc26a1a6aeeee95907de4f304906a9d1502735  fontc-x86_64-apple-darwin.tar.gz
5d167f1fb3c17f1d8553aa5b87ef7fa1664af4b154d7af8a661bf7e80e233cae  fontc-x86_64-unknown-linux-musl.tar.gz
5ace6f5ba908d5894d3a8b6e2872109f5e42d17fb564b9622f3303d91d000577  fontc-i686-pc-windows-msvc.zip
784f7af89d109410de61bb7e46b41c10a6b2bc12949cfb4cd4b477652b5f9a81  fontc-x86_64-pc-windows-msvc.zip
dbc01d3ab9b8e1a04102ff5d509cf6511e9e9be6e7023dbcdd88036ed156a46f  requirements.txt

requirements.txt:

--only-binary :all:

fontc==0.0.2a6 \
    --hash=sha256:0107f837cef0aa4b2cec0f540d95ab98e2425e951e5d9c62868c2e4ff8ce644b \
    --hash=sha256:0f0598d1fd636adbb1d3e86134d1e12d5965d667b7554f0e353e8d89da71ef65 \
    --hash=sha256:416834e52ff98c2e8ee7c26157ca9336da2f809eccc254478f89c21f68ce2974 \
    --hash=sha256:8149b65d0d04aee7c74663cb472575ede9985b3a62b870aedc8127b2600160ed \
    --hash=sha256:a9b7aba1d02b4b61f8b22c7adc53b7712b9f8a49c7340d77c66048f3fbc497dc
anthrotype commented 4 months ago

I think this is ready. Copying the release shell scripts from fontations could be done in a separate PR. After we merged this, could one of you publish fontc to crates.io and push a git tag in the form fontc-vX.X.X? the worflow should do the rest (build the wheels, upload them PyPI, create GH release and upload binary assets there)

the GH release should then look like this one: https://github.com/anthrotype/fontc/releases/tag/fontc-v0.0.2a9

(note that the Github's automatically generated release notes will look nicer on the upstream repo because they'll also include a list of merged pull requests and contributors, not just the bare "full changelog" link like it appears on my fork where I was just pushing to main for testing purposes)