Skip to content

Commit c859a1b

Browse files
committed
Enhance firmware release workflow even more
1 parent 69fc307 commit c859a1b

4 files changed

Lines changed: 80 additions & 19 deletions

File tree

.github/workflows/build-firmware.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,16 @@ on:
88
description: "MicroPython git tag/branch to build from"
99
type: string
1010
default: "v1.28.0"
11-
push:
12-
tags: ["v*.*.*"]
11+
# Version tags come in through publish-stubs.yml, which calls this and only
12+
# publishes if it passes. No `push: tags` trigger of its own -- that would
13+
# build the firmware twice on every tag and cut the release job loose from
14+
# the gate it is supposed to be.
15+
workflow_call:
16+
inputs:
17+
micropython_ref:
18+
description: "MicroPython git tag/branch to build from"
19+
type: string
20+
default: "v1.28.0"
1321

1422
jobs:
1523
build:
Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,52 @@
11
# .github/workflows/publish-stubs.yml
2-
name: Publish stubs to PyPI
2+
#
3+
# Publishes the generated `alpaca-stubs` package to PyPI and anaconda.org.
4+
#
5+
# NOTE: PyPI matches the trusted publisher on THIS file's name.
6+
7+
name: Publish stubs
38

49
on:
510
push:
611
tags: ["v*.*.*"]
12+
pull_request:
13+
workflow_dispatch:
14+
15+
permissions:
16+
contents: read
17+
18+
concurrency:
19+
group: publish-stubs-${{ github.ref }}
20+
cancel-in-progress: false
721

822
jobs:
23+
firmware:
24+
# Release gate. These used to fire on the same tag independently, so a
25+
# firmware failure after the stubs had published burned that version on
26+
# PyPI for good. Tags only: a pull request just dry-runs the stubs.
27+
if: github.ref_type == 'tag'
28+
uses: ./.github/workflows/build-firmware.yml
29+
permissions:
30+
contents: write # the firmware workflow attaches .uf2 files to the release
31+
932
publish:
33+
needs: firmware
34+
# always(), so a deliberately skipped firmware build on a pull request does
35+
# not block the dry run, while a failed one still does.
36+
if: always() && needs.firmware.result != 'failure' && needs.firmware.result != 'cancelled'
1037
runs-on: ubuntu-latest
1138
environment: pypi
1239
permissions:
13-
id-token: write
40+
id-token: write # mints the OIDC token for PyPI; without it, auth fails
1441
contents: read
1542
steps:
16-
- uses: actions/checkout@v4
17-
- uses: astral-sh/setup-uv@v5
18-
19-
- name: Generate stubs
20-
run: uv run alpaca generate-stubs student
21-
22-
- name: Build
23-
working-directory: .alpaca/stubs
24-
run: uv build
43+
- uses: actions/checkout@v5
2544

26-
- name: Publish to PyPI
27-
working-directory: .alpaca/stubs
28-
run: uv publish
45+
- uses: PlohnenSoftware/PyPI-Anaconda-Publish@v2
46+
with:
47+
prepare: uv run alpaca generate-stubs student
48+
project_dir: .alpaca/stubs
49+
tag: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
50+
anaconda_owner: NB_TUDelft
51+
anaconda_api_key: ${{ secrets.ANACONDA_API_KEY }}
52+
dry_run: ${{ github.event_name == 'pull_request' }}

cli/generate_stubs.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,25 @@ def generate_stubs_cmd(pico_name: Annotated[str, typer.Argument(help="Pico name
3636
(stubs_folder / file).unlink(True)
3737

3838

39+
# This package deliberately ships no runtime dependencies. The one it would
40+
# want, micropython-rp2-stubs, exists only on PyPI -- it is on no anaconda.org
41+
# channel, and neither is its own dependency micropython-stdlib-stubs -- so
42+
# declaring it would leave the conda package unsolvable. The isinstance(str)
43+
# filter below drops `dependencies` anyway; this note is here so that stays a
44+
# decision rather than an accident. Users who want stubs for the MicroPython
45+
# builtins install them separately, as the README below explains.
3946
(stubs_folder / "README.md").write_text(
40-
"Stubs for " +
41-
(PROJECT_ROOT / 'README.md').read_text(encoding='utf-8')
47+
"Stubs for "
48+
+ (PROJECT_ROOT / 'README.md').read_text(encoding='utf-8')
49+
+ "\n\n## MicroPython builtins\n\n"
50+
"These stubs cover ALPACA itself. For `machine`, `rp2` and the rest of\n"
51+
"the MicroPython standard library, install those stubs alongside:\n\n"
52+
"```bash\n"
53+
"pip install micropython-rp2-stubs\n"
54+
"```\n\n"
55+
"They are not published on any conda channel, so they are not declared\n"
56+
"as a dependency here. Without them only the MicroPython builtins stay\n"
57+
"unresolved in your editor; the ALPACA stubs themselves work either way.\n"
4258
)
4359

4460
parent = toml.load(PROJECT_ROOT / "pyproject.toml")
@@ -60,6 +76,19 @@ def generate_stubs_cmd(pico_name: Annotated[str, typer.Argument(help="Pico name
6076
"setuptools": {
6177
"packages": packages,
6278
"package-data": dict.fromkeys(packages, ["*.pyi"])
79+
},
80+
# Read by PlohnenSoftware/PyPI-Anaconda-Publish, which renders the conda
81+
# recipe from this file so the conda package cannot drift from the PyPI one.
82+
"conda-recipe": {
83+
# Only .pyi files, so a single noarch build serves every architecture
84+
# and every Python the inherited requires-python allows.
85+
"noarch": True,
86+
"build-channels": ["conda-forge"],
87+
"maintainers": ["NB-TUDelft"],
88+
# Deliberately empty. A PEP 561 stub-only distribution ships no runtime
89+
# module, so importing these packages is *meant* to fail -- listing them
90+
# here would fail the conda test phase.
91+
"test-imports": []
6392
}
6493
}
6594
}, (stubs_folder / "pyproject.toml").open("w+"))

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "alpaca"
3-
version = "0.2.1"
3+
version = "0.2.2"
44
description = "Libraries for ALPACA 2.0 - NB2420 Electronic Instrumentation"
55
readme = "README.md"
66
requires-python = ">=3.14"

0 commit comments

Comments
 (0)