Skip to content

Commit 6dec220

Browse files
add: workflow for dev release
1 parent 726afa8 commit 6dec220

3 files changed

Lines changed: 134 additions & 0 deletions

File tree

.github/workflows/dev-release.yaml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Dev Release
2+
3+
# AutoGluon-style: publish a `.devN` build to PyPI for every successful push
4+
# to `main`. No git tag, no commit, no GitHub Release — the version is
5+
# computed on the runner and exists only on PyPI.
6+
#
7+
# Gated on the Tests workflow succeeding for that commit, so a broken main
8+
# does not get published.
9+
10+
on:
11+
workflow_run:
12+
workflows: ["Tests"]
13+
types: [completed]
14+
branches: [main]
15+
16+
jobs:
17+
publish-dev:
18+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
19+
runs-on: ubuntu-latest
20+
environment: pypi
21+
permissions:
22+
id-token: write # (future) PyPI trusted publishing via OIDC
23+
steps:
24+
- uses: actions/checkout@v4
25+
with:
26+
ref: ${{ github.event.workflow_run.head_sha }}
27+
28+
- name: Install uv
29+
uses: astral-sh/setup-uv@v5
30+
31+
- name: Set up Python
32+
run: uv python install 3.11
33+
34+
- name: Compute .dev version
35+
id: ver
36+
run: |
37+
base="$(uv version --short)"
38+
if [[ ! "$base" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
39+
echo "::error::pyproject version '$base' is not a plain X.Y.Z; refusing to derive a dev version"
40+
exit 1
41+
fi
42+
IFS=. read -r major minor patch <<<"$base"
43+
next="${major}.${minor}.$((patch + 1))"
44+
# PEP 440: <next-release>.dev<UTC timestamp>. Sorts before <next-release>
45+
# and after any prior release. Strictly monotonic across commits.
46+
ts="$(date -u +%Y%m%d%H%M%S)"
47+
version="${next}.dev${ts}"
48+
echo "version=$version" >> "$GITHUB_OUTPUT"
49+
echo "Publishing dev version: $version (base $base, commit ${{ github.event.workflow_run.head_sha }})"
50+
51+
- name: Set version (ephemeral, not committed)
52+
run: uv version "${{ steps.ver.outputs.version }}"
53+
54+
- name: Build sdist + wheel
55+
run: uv build
56+
57+
- name: Publish to PyPI
58+
env:
59+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
60+
run: uv publish

.github/workflows/prerelease.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Prerelease
2+
3+
# Publish a PEP 440 prerelease (alpha/beta/rc/dev) to PyPI WITHOUT creating a
4+
# git tag, commit, or GitHub Release. The version is set on the runner only;
5+
# nothing is pushed back to the repo.
6+
#
7+
# Trigger from the Actions UI:
8+
# Actions -> Prerelease -> Run workflow -> enter version (e.g. 0.0.4a1)
9+
10+
on:
11+
workflow_dispatch:
12+
inputs:
13+
version:
14+
description: "Prerelease version (e.g. 0.0.4a1, 0.0.4b2, 0.0.4rc1, 0.0.4.dev3)"
15+
required: true
16+
type: string
17+
18+
jobs:
19+
build-and-publish:
20+
runs-on: ubuntu-latest
21+
environment: pypi
22+
permissions:
23+
id-token: write # (future) PyPI trusted publishing via OIDC
24+
steps:
25+
- uses: actions/checkout@v4
26+
27+
- name: Install uv
28+
uses: astral-sh/setup-uv@v5
29+
30+
- name: Set up Python
31+
run: uv python install 3.11
32+
33+
- name: Reject stable versions
34+
run: |
35+
v="${{ inputs.version }}"
36+
if [[ ! "$v" =~ [a-z] ]]; then
37+
echo "::error::'$v' has no prerelease segment. Use the Release workflow (push a v$v tag) for stable releases."
38+
exit 1
39+
fi
40+
41+
- name: Set version (ephemeral, not committed)
42+
run: uv version "${{ inputs.version }}"
43+
44+
- name: Build sdist + wheel
45+
run: uv build
46+
47+
- name: Publish to PyPI
48+
env:
49+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
50+
run: uv publish

DEVELOPMENT.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,30 @@ in two situations:
4949
match the version in `pyproject.toml`, so the bump and the tag must
5050
agree.
5151

52+
### Prereleases (no git tag)
53+
54+
Two flavors, both publish to PyPI without creating a git tag, commit, or
55+
GitHub Release. The version is set only on the CI runner.
56+
57+
**Automatic `.dev` builds on every push to `main`**
58+
[`.github/workflows/dev-release.yaml`](.github/workflows/dev-release.yaml).
59+
Triggered via `workflow_run` after the `Tests` workflow succeeds. The
60+
version is computed as `<next-patch>.dev<UTC-timestamp>` (e.g.
61+
`0.0.4.dev20260528170102` when `pyproject.toml` is at `0.0.3`). This is
62+
the AutoGluon-style "every commit is on PyPI" pattern — install with:
63+
64+
```bash
65+
pip install --pre data-foundry # any prerelease
66+
pip install data-foundry==0.0.4.dev* # a specific dev cycle
67+
```
68+
69+
**Manual `alpha`/`beta`/`rc` from the Actions UI**
70+
[`.github/workflows/prerelease.yaml`](.github/workflows/prerelease.yaml).
71+
Go to `Actions → Prerelease → Run workflow`, enter a PEP 440 prerelease
72+
version (e.g. `0.0.4a1`, `0.0.4b2`, `0.0.4rc1`), and it publishes that
73+
exact version. Stable `X.Y.Z` inputs are rejected — use the tag-push
74+
release flow for those.
75+
5276
### One-time setup
5377

5478
* Add a `PYPI_TOKEN` secret in the GitHub `pypi` environment

0 commit comments

Comments
 (0)