The store job brings JP's fork of the store up to date before it publishes
czdev starts its branch from the fork's default branch, and the store's check compares the PR branch with the store's main directly. After M5Stack removed every app on 2026-10-12, the fork was 10 commits behind, so the 0.11.0 PR (#176) carried all 40 removed apps as new files, and the check failed on the first of them. store-publish.py now calls GitHub's merge-upstream for the fork first, and publishes nothing if that fails. PR #176 was repaired by hand with "Update branch". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1853e5e603
commit
7209d89911
2 files changed
+45
-4
No files matched your search
@@ -184,7 +184,10 @@ gh pr list -R CardputerZero/packages --author jpmartineau --state all --limit 3
|
||||
If `store` failed, the usual causes are the `CARDPUTER_STORE_TOKEN` secret (missing, or the
|
||||
token revoked) or a change in czdev: the job pins AppBuilder to one commit because
|
||||
`scripts/cardputer-zero/store-publish.py` corrects two of its functions, and the script
|
||||
refuses a czdev without them. A rerun is safe — the script publishes nothing when the store
|
||||
refuses a czdev without them. The script also fast-forwards JP's fork of the store before
|
||||
czdev branches from it; it stops if that fails (the fork has commits of its own), because
|
||||
a stale fork makes the store's check fail on every file the store has removed since. A
|
||||
rerun is safe — the script publishes nothing when the store
|
||||
already has the version or a PR for it is open. While a PR for an **earlier** version is
|
||||
still open (a first release waits for a maintainer and a video), the job only warns: a
|
||||
second PR would add the same files and conflict. The release itself is not held back. Once
|
||||
|
||||
@@ -5,7 +5,8 @@ r"""Publish the Cardputer Zero package to M5Stack's app store, with ``czdev`` an
|
||||
``czdev publish`` (M5Stack's CardputerZero-AppBuilder) uploads the ``.deb`` to a release in
|
||||
the fork of ``CardputerZero/packages``, pushes a branch with the store listing, and opens a
|
||||
pull request. The store merges an update by itself when its checks pass. This script runs
|
||||
``czdev`` in its own process with two corrections, and it sets up ``git`` for it:
|
||||
``czdev`` in its own process with two corrections. It also sets up ``git`` for it, and it
|
||||
brings the fork up to date first:
|
||||
|
||||
* The manifest records the email of the uploader. ``czdev`` takes the public email of the
|
||||
GitHub profile. MeshTerm uses only ``johnputer@meshterm.net`` (JP, 2026-10-07), so the
|
||||
@@ -17,6 +18,13 @@ pull request. The store merges an update by itself when its checks pass. This sc
|
||||
* ``czdev`` pushes to ``git@github.com:``. A CI runner or a Cardputer has no SSH key for
|
||||
GitHub, so the script sends ``git`` over HTTPS with the token, and gives it a name and an
|
||||
email for the commit. These settings are in the environment of this process only.
|
||||
* ``czdev`` starts its branch from the default branch of the fork, and the store's check
|
||||
compares the pull request's branch with the store's ``main`` directly. Thus, if the fork
|
||||
is behind, each file that the store removed since then looks like a new file of the pull
|
||||
request, and the check fails on it. This occurred on 2026-10-12, when M5Stack removed
|
||||
all apps from the store to start the reviews again. The script brings the fork's
|
||||
default branch up to the store's ``main`` before ``czdev`` starts. If it cannot, it
|
||||
publishes nothing.
|
||||
|
||||
The corrections replace two functions of ``czdev``. Thus the release workflow pins
|
||||
AppBuilder to one commit. If a later ``czdev`` does not have these functions, the script
|
||||
@@ -43,6 +51,7 @@ import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
@@ -56,10 +65,11 @@ PUBLISHED_INDEX = "https://cardputerzero.github.io/packages/dists/stable/main/bi
|
||||
TOKEN_ENV = "CARDPUTER_STORE_TOKEN"
|
||||
|
||||
|
||||
def _api(path: str, token: str) -> object:
|
||||
"""GET one GitHub API path, as JSON."""
|
||||
def _api(path: str, token: str, body: dict[str, str] | None = None) -> object:
|
||||
"""Call one GitHub API path, as JSON: a GET, or a POST of ``body``."""
|
||||
request = urllib.request.Request(
|
||||
f"https://api.github.com{path}",
|
||||
data=None if body is None else json.dumps(body).encode(),
|
||||
headers={"Authorization": f"Bearer {token}", "Accept": "application/vnd.github+json"},
|
||||
)
|
||||
with urllib.request.urlopen(request, timeout=30) as response: # noqa: S310 - a fixed https host
|
||||
@@ -98,6 +108,30 @@ def _open_pull_requests(package: str, login: str, token: str) -> dict[str, str]:
|
||||
}
|
||||
|
||||
|
||||
def _sync_fork(login: str, token: str) -> str | None:
|
||||
"""Bring the fork's default branch up to the store's ``main``. Return a problem, or ``None``.
|
||||
|
||||
GitHub's merge-upstream does a fast-forward when the fork has no commits of its own. If
|
||||
it has some and the merge fails, the script must not publish (refer to the module
|
||||
docstring). With no fork, there is nothing to do: ``czdev`` makes one from the store's
|
||||
current ``main``.
|
||||
"""
|
||||
try:
|
||||
fork = _api(f"/repos/{login}/{TARGET.split('/')[1]}", token)
|
||||
except urllib.error.HTTPError as error:
|
||||
if error.code == 404:
|
||||
return None
|
||||
raise
|
||||
if (fork.get("parent") or {}).get("full_name") != TARGET:
|
||||
return f"{fork['full_name']} is not a fork of {TARGET}"
|
||||
branch = fork["default_branch"]
|
||||
try:
|
||||
_api(f"/repos/{fork['full_name']}/merge-upstream", token, {"branch": branch})
|
||||
except urllib.error.HTTPError as error:
|
||||
return f"cannot bring {fork['full_name']} {branch} up to {TARGET} (HTTP {error.code})"
|
||||
return None
|
||||
|
||||
|
||||
def _set_up_git(login: str, token: str) -> None:
|
||||
"""Send ``czdev``'s git over HTTPS with ``token``, as MeshTerm's author."""
|
||||
os.environ["CZDEV_GIT_TOKEN"] = token
|
||||
@@ -181,6 +215,10 @@ def main() -> int:
|
||||
for other, url in pending.items():
|
||||
print(f"{mark}{other} is still open ({url}); {version} waits for its merge")
|
||||
return 0
|
||||
problem = _sync_fork(login, token)
|
||||
if problem:
|
||||
sys.stderr.write(f"store-publish: {problem}\n")
|
||||
return 1
|
||||
|
||||
_correct(publish, GitHubClient)
|
||||
_set_up_git(login, token)
|
||||
|
||||
Reference in new issue
Block a user