make-cloudflare
Cloudflare Pages direct upload for mkrun, in
Python: publish a built directory with no Node on the machine and no wrangler
in the pipeline.
# Makefile.py in a consuming repo
# /// script
# requires-python = ">=3.11"
# dependencies = ["mkrun>=0.4", "make-cloudflare>=0.1"]
# ///
from make_cloudflare import cloudflare # importing is what registers the group
$ mk cloudflare.deploy site/dist --project mkrun # production (branch main)
$ mk cloudflare.deploy site/dist --branch try # a preview, on its own URL
$ mk cloudflare.projects # what the account has
$ mk cloudflare.deployments --limit 5 # one project's recent ones
$ mk cloudflare.prune --keep 10 # delete all but the newest ten
$ mk -n cloudflare.deploy site/dist # the plan; nothing is sent
Credentials are the two variables wrangler already reads, so a repository that
deploys from CI needs no new secret: CLOUDFLARE_ACCOUNT_ID and
CLOUDFLARE_API_TOKEN (a token with Cloudflare Pages: Edit). The token's
name ends in TOKEN, so mkrun treats it as a credential — it is withheld from
the environment until a task asks for it, redacted in everything printed, and
readable from the encrypted store. The project can come from --project or from
CLOUDFLARE_PAGES_PROJECT in the repo's env layer.
Every deploy prunes the project to its newest 10 deployments (--keep N
to change it, --keep 0 to keep them all; pages.deploy(..., keep=) from
Python). Pages never deletes one by itself, and each stays reachable on its own
<hash>.<project>.pages.dev URL forever. The live production deployment is
never deleted, however old; a pruned preview that was still its branch's alias
takes that branch URL with it.
Why this exists
wrangler pages deploy is four HTTPS calls and a hash. Reaching them through
npx costs a Node toolchain in repositories that otherwise have none — a Rust
one, a frontage one — and a
node_modules in the deploy image of every one of them.
POST /accounts/<acct>/pages/projects/<p>/upload-token -> a short-lived JWT
POST /pages/assets/check-missing -> what is not stored yet
POST /pages/assets/upload -> the files, batched
POST /pages/assets/upsert-hashes
POST /accounts/<acct>/pages/projects/<p>/deployments -> the manifest
Three things make a naive port wrong, and all three fail silently — every call returns 200 and the site serves the old bytes, or none:
- The hash is BLAKE3 of a strange input: the base64 text of the contents
with the extension (no dot) appended, first 32 hex characters. Not of the
bytes, and not SHA-256.
tests/test_pages.pylocks it with a golden value. _headers,_redirectsand_routes.jsonare not assets. They are fields on the deployment. Walk them in as ordinary files and the deploy reports success while the site's CSP stops applying.check-missing,uploadandupsert-hashestake the JWT, not the account token, and carry no/accounts/<id>prefix — the JWT already names the account.
What it does not do
Pages Functions. A directory holding _worker.js or functions/ is
refused by name rather than half-deployed: bundling a Worker is a build step,
not an upload, and wrangler should keep doing it.
Steps 2 and 3 are undocumented. They exist because wrangler uses them, and
Cloudflare can change them without a changelog; the documented deployments
endpoint alone cannot upload a file. That is the real cost of dropping
wrangler, and it is the reason this is a small module with a golden test rather
than a wrapper nobody reads.
Nothing here is specific to any owner or account. The group name is
cloudflare, and it merges with a repo's own cloudflare.* tasks — groups are
namespaces — so only a same-named task collides; this package claims deploy,
projects, deployments and prune, nothing else. blake3 is the one dependency, and
it lives here rather than in the runner so mkrun itself stays dependency-free.
Metadata
Release files for make-cloudflare 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| make_cloudflare-0.2.0.tar.gz | 14.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| make_cloudflare-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.7 kB
Release files / make_cloudflare-0.2.0.tar.gz
| Download URL | make_cloudflare-0.2.0.tar.gz |
|---|---|
| Size | 14.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
abe6bd296b4594cd46a60ee67a9a3dd7785b6f0062adb75efab901930465b9cb
|
|
BLAKE2b-256 checksum How to use checksums |
cc9162c6fa6ca1d7d6c375dce73b348acfb7ef03ee8116d0b68540ab3bc60e97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / make_cloudflare-0.2.0-py3-none-any.whl
| Download URL | make_cloudflare-0.2.0-py3-none-any.whl |
|---|---|
| Size | 12.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
61014ba93a18963c009d8bfcc86c5ac504edec60c7926aafe9f9995a043fa306
|
|
BLAKE2b-256 checksum How to use checksums |
c8b1efd77dbcbba727922950d962c996984d619443026ff27aa53e3de7aef4e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|