Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions FORK.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,25 @@ Consumers install a wheel from a GitHub Release; a `git+https://` install has no
[The `build/` directory](#the-build-directory)).

```bash
git tag -a quadbio-1.1.61.postN -m "<one line>" main
git push origin quadbio-1.1.61.postN
git tag -a quadbio-1.1.61+quadbio.N -m "<one line>" main
git push origin quadbio-1.1.61+quadbio.N
```

`.github/workflows/release.yml` builds the client, runs `scripts/check_wheel.py`, serves the wheel
once, and attaches `cirrocumulus-1.1.61.postN-py3-none-any.whl`. Every push to `main` runs all of
that except the publish, so tag once `main` is green. `workflow_dispatch` reruns it by hand.

`postN` is sequential; restart at `.post1` when upstream releases a new version. The `quadbio-`
prefix keeps our tags out of upstream's namespace and is stripped by setuptools_scm, so the
version is `1.1.61.postN` — after upstream's 1.1.61, before their 1.1.62.
once, and attaches `cirrocumulus-1.1.61+quadbio.N-py3-none-any.whl`. Every push to `main` runs all
of that except the publish, so tag once `main` is green. `workflow_dispatch` reruns it by hand.

`1.1.61` is the upstream version we sit on; `+quadbio.N` is a **PEP 440 local version identifier**,
sequential, restarting at `.1` when upstream releases a new version. Local versions are the
mechanism for "upstream's release plus our patches", and PyPI *must not* accept them — which is
exactly why ours cannot collide with upstream's. That matters here: upstream has 86 `.postN` tags
on PyPI and has already released `1.1.61`, so the old `1.1.61.postN` scheme was claiming version
strings upstream can publish at will.

The `quadbio-` tag prefix keeps our tags out of upstream's namespace. `tag_regex` in
`pyproject.toml` strips it while keeping the local segment, which setuptools_scm's default would
otherwise drop; `check_wheel.py` fails the build if `+quadbio.` ever goes missing. Off-tag builds
keep the marker too — one commit past a tag gives `1.1.62.dev1+quadbio.N.g<sha>`.

**Never delete a release tag.** For `quadbio-1.1.61.post1` and `.post2` this is literal: they were
cut from the old force-pushed `integration` and are reachable from no branch at all, so the tag is
Expand Down
8 changes: 8 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
..

**This is the quadbio fork of cirrocumulus.** It carries fixes for anndata 0.13, zarr 3 and
pandas 3 that upstream does not have. Wheels are versioned ``1.1.61+quadbio.N`` and published
as GitHub Releases on `quadbio/cirrocumulus <https://github.com/quadbio/cirrocumulus>`_, never
to PyPI. Upstream is `lilab-bcb/cirrocumulus <https://github.com/lilab-bcb/cirrocumulus>`_; see
`FORK.md <https://github.com/quadbio/cirrocumulus/blob/main/FORK.md>`_ for what differs.

Cirrocumulus
----------------

Expand Down
14 changes: 12 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ readme = 'README.rst'
authors = [
{ name = 'Joshua Gould', email = 'cirrocumulus@googlegroups.com' },
]
urls.Source = 'https://github.com/lilab-bcb/cirrocumulus'
maintainers = [
{ name = 'Marius Lange' },
]
urls.Homepage = 'https://github.com/quadbio/cirrocumulus'
urls.Source = 'https://github.com/quadbio/cirrocumulus'
urls.Upstream = 'https://github.com/lilab-bcb/cirrocumulus'
urls.Documentation = "https://cirrocumulus.readthedocs.io/"

license = { file = 'LICENSE' }
Expand Down Expand Up @@ -61,7 +66,12 @@ only-include = ["cirrocumulus", "build"]
[tool.hatch.version]
source = 'vcs'

dev = ['pre-commit', 'isort', 'black']
# Our tags are `quadbio-<version>` where <version> carries a PEP 440 local segment,
# e.g. quadbio-1.1.61+quadbio.4. setuptools_scm's default tag_regex captures [^\+]*
# and would silently drop the local part -- which is the half that makes the version
# unforgeable, since PyPI must not accept local versions.
[tool.hatch.version.raw-options]
tag_regex = '^quadbio-(?P<version>.+)$'

[tool.ruff]
line-length = 88
Expand Down
18 changes: 15 additions & 3 deletions scripts/check_wheel.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
#!/usr/bin/env python3
"""Fail unless a built wheel actually ships the web client.
"""Fail unless a built wheel ships the web client and carries the fork's version.

An empty ``build/`` yields a client-less wheel silently -- no error, just a 404 on ``/``
at runtime. See FORK.md.
at runtime. And a wheel without our ``+quadbio.N`` local version claims a version string
upstream is free to publish. See FORK.md.

python scripts/check_wheel.py dist/cirrocumulus-*.whl
"""

from __future__ import annotations

import fnmatch
import os
import sys
import zipfile

INDEX = "cirrocumulus/client/index.html"
BUNDLE = "cirrocumulus/client/static/js/*.js"
LOCAL = "+quadbio."


def main(path: str) -> int:
Expand All @@ -26,7 +29,16 @@ def main(path: str) -> int:
f"({INDEX}: {INDEX in names}, {BUNDLE}: {len(bundles)}).\n"
"Populate build/ with `yarn build` and rebuild -- see FORK.md."
)
print(f"{path}: {len(names)} files, client entry point {bundles[0]}")
# Wheel filenames are name-version-pytag-abitag-platform.whl, and PEP 440 local
# separators are normalised to '.' in the filename, so '+quadbio.' survives intact.
version = os.path.basename(path).split("-")[1]
if LOCAL not in version:
sys.exit(
f"{path} is versioned {version!r}, which has no {LOCAL!r} local segment.\n"
"Either the tag was not `quadbio-<version>+quadbio.N`, or tag_regex in\n"
"pyproject.toml stopped capturing it -- see FORK.md."
)
print(f"{path}: {len(names)} files, version {version}, entry point {bundles[0]}")
return 0


Expand Down
Loading