Skip to content

Commit 7a9e2b3

Browse files
committed
ci: use one automation branch per package
Nightly declarations and publication metadata currently use separate branch strategies, which can leave overlapping changes in different PRs or combine unrelated package updates on the shared documentation branch. Use `package/<pkg>` for both sources and preserve existing branch changes by rebasing them onto main and pushing with force-with-lease. Serialize nightly and publication branch mutations with the shared `publish-wheel` concurrency group while allowing package builds to continue in parallel. Remove the obsolete documentation-branch build guard and update the workflow and porting documentation to describe the unified package lifecycle.
1 parent ba022a0 commit 7a9e2b3

8 files changed

Lines changed: 462 additions & 186 deletions

File tree

‎.github/workflows/_publish-wheel.yml‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,13 @@ on:
3232
documentation PR is opened with GITHUB_TOKEN and gets no checks.
3333
required: false
3434

35-
concurrency:
36-
group: publish-wheel
37-
cancel-in-progress: false
38-
queue: max
39-
4035
jobs:
4136
publish:
4237
runs-on: ubuntu-latest
38+
concurrency:
39+
group: publish-wheel
40+
cancel-in-progress: false
41+
queue: max
4342
steps:
4443
# A branch pushed or a PR opened with GITHUB_TOKEN raises no events, so
4544
# the documentation PR would sit there with no checks. Push and open it

‎.github/workflows/_setup.yml‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,7 @@ jobs:
4343
env:
4444
PACKAGE: ${{ inputs.package }}
4545
VERSION_GLOB: ${{ inputs.version }}
46-
BRANCH: ${{ github.head_ref || github.ref_name }}
4746
run: |
48-
# The docs branch only records what was just published, so building
49-
# anything from it would rebuild versions that are already released.
50-
if [ "$BRANCH" = "github-actions/update-doc" ]; then
51-
echo "versions=[]" >> "$GITHUB_OUTPUT"
52-
echo "Versions to build: [] (documentation branch)"
53-
exit 0
54-
fi
5547
versions=$(uv run --quiet ci_scripts/pending_versions.py ${VERSION_GLOB:+--glob "$VERSION_GLOB"} "$PACKAGE")
5648
echo "versions=$versions" >> "$GITHUB_OUTPUT"
5749
echo "Versions to build: $versions"

‎.github/workflows/nightly.yml‎

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ env:
2424
jobs:
2525
check_versions:
2626
runs-on: ubuntu-latest
27+
concurrency:
28+
group: publish-wheel
29+
cancel-in-progress: false
30+
queue: max
2731
steps:
2832
# A branch pushed or a PR opened with GITHUB_TOKEN raises no events, so
2933
# the per-package PRs would sit there with no checks at all. Push and open
@@ -71,45 +75,52 @@ jobs:
7175
base=$(git rev-parse HEAD)
7276
ci_scripts/git-identity.sh
7377
74-
# Branch off main and re-declare this package alone, so the PR only
75-
# ever touches its own docs/packages/<pkg>.yaml (plus packages.txt and
76-
# deprecated.txt for a deprecation).
78+
# Re-declare each package on the same package-specific branch used by
79+
# wheel publication. This preserves publication metadata already
80+
# waiting for review while keeping unrelated packages isolated.
7781
open_pr() {
7882
local package="$1" slug="$2" title="$3"
79-
local branch="github-actions/nightly-upgrade/$slug" pr
80-
81-
git switch --force-create "$branch" "$base" || return 1
82-
git reset --hard --quiet "$base" || return 1
83+
local branch="package/$slug" pr pr_title="$slug: update packages" remote_sha=""
84+
85+
if git fetch --quiet origin "$branch" 2>/dev/null; then
86+
remote_sha=$(git rev-parse FETCH_HEAD) || return 1
87+
git switch --force-create "$branch" "$remote_sha" || return 1
88+
if ! git rebase "$base"; then
89+
git rebase --abort || true
90+
return 1
91+
fi
92+
else
93+
git switch --force-create "$branch" "$base" || return 1
94+
fi
8395
8496
uv run --with-requirements ci_scripts/requirements.txt python3 \
8597
ci_scripts/check_versions.py --declare "$package" || return 1
8698
8799
if git diff --quiet -- docs/packages ci_scripts/packages.txt ci_scripts/deprecated.txt; then
100+
if [ -n "$remote_sha" ] && [ "$(git rev-parse HEAD)" != "$remote_sha" ]; then
101+
git push --force-with-lease="$branch:$remote_sha" origin "$branch" || return 1
102+
fi
88103
echo "$package: nothing to declare"
89104
return 0
90105
fi
91106
92107
git add docs/packages ci_scripts/packages.txt ci_scripts/deprecated.txt || return 1
93108
git commit -s -m "$title" || return 1
94109
95-
# Leave an open PR alone when it already declares the same thing:
96-
# a nightly force-push would restart its build for nothing.
97-
if git fetch --quiet origin "$branch" 2>/dev/null &&
98-
git diff --quiet FETCH_HEAD HEAD -- "docs/packages/$slug.yaml"; then
99-
echo "$package: $branch is already up to date"
100-
return 0
110+
if [ -n "$remote_sha" ]; then
111+
git push --force-with-lease="$branch:$remote_sha" origin "$branch" || return 1
112+
else
113+
git push origin "$branch" || return 1
101114
fi
102115
103-
git push --force origin "$branch" || return 1
104-
105116
pr=$(gh pr list --repo "$GITHUB_REPOSITORY" --head "$branch" --state open --json url --jq '.[0].url') || return 1
106117
if [ -n "$pr" ]; then
107-
gh pr edit "$pr" --title "$title" --body-file "$REPORTS/$slug.md" || return 1
118+
gh pr edit "$pr" --title "$pr_title" --body-file "$REPORTS/$slug.md" || return 1
108119
echo "Updated $pr"
109120
else
110121
gh pr create --draft --repo "$GITHUB_REPOSITORY" --base main --head "$branch" \
111122
--reviewer luhenry \
112-
--title "$title" --body-file "$REPORTS/$slug.md" || return 1
123+
--title "$pr_title" --body-file "$REPORTS/$slug.md" || return 1
113124
fi
114125
}
115126

‎ci_scripts/update_doc.py‎

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -278,16 +278,17 @@ def push_remote():
278278
return f"https://x-access-token:{GH_TOKEN}@github.com/{REPO}"
279279

280280

281-
def checkout_shared_branch(branch):
281+
def checkout_package_branch(branch):
282282
"""
283-
Check out the shared docs branch as a local worktree HEAD, based on
283+
Check out the package's branch as a local worktree HEAD, based on
284284
origin/<branch> if it already exists, otherwise on origin/main, and replay
285285
its pending commits on top of origin/main.
286286
287-
All docs updates are pushed to this single branch, so a run needs to build
288-
on whatever is already there rather than starting from main each time. main
289-
keeps moving under it while it waits for review, so without the rebase the
290-
branch carries an ever older tree and the PR ends up conflicting.
287+
Nightly declarations and publication metadata share this package-specific
288+
branch, so a run needs to build on whatever is already there rather than
289+
starting from main each time. main keeps moving under it while it waits for
290+
review, so without the rebase the branch carries an ever older tree and the
291+
PR ends up conflicting.
291292
292293
Returns the origin/<branch> commit the checkout started from, or None when
293294
the branch is new, so the push can lease against it.
@@ -377,8 +378,8 @@ def main():
377378
comment = None
378379
yaml_path = DOCS_DIR / f"{slug}.yaml"
379380

380-
branch = "github-actions/update-doc"
381-
pr_title = "docs: Update projects"
381+
branch = f"package/{slug}"
382+
pr_title = f"{slug}: update packages"
382383

383384
def compute_content():
384385
"""Read the current YAML and return (is_new, old_content, new_content)."""
@@ -425,10 +426,10 @@ def compute_content():
425426
return
426427

427428
configure_git_identity()
428-
remote_sha = checkout_shared_branch(branch)
429+
remote_sha = checkout_package_branch(branch)
429430

430-
# Compute the change against the shared branch's contents, so a package
431-
# already documented there by an earlier run in this batch is seen.
431+
# Compute the change against the package branch's contents, so a version
432+
# declared by the nightly workflow is retained and filled in here.
432433
is_new, _old_content, new_content = compute_content()
433434
if new_content is None:
434435
print(f"{slug} {version} is already documented; nothing to do")

‎docs/development.md‎

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,10 @@ declared is a bug in the build, not something to document.
8282
To **upgrade** an existing package, append a `- version: <new version>` line to
8383
its YAML and open a PR; no workflow change is needed unless the new version
8484
needs one. The nightly `check_versions.py --declare` run opens one draft PR
85-
per package (`github-actions/nightly-upgrade/<package>`), so each upgrade is
86-
built, reviewed and merged on its own.
85+
per package from `package/<package>`, so each upgrade is built, reviewed and merged on its
86+
own. Publication uses the same package-specific branch, allowing a nightly
87+
version declaration and its release metadata to share one PR without mixing
88+
unrelated packages.
8789

8890
## Workflow Customizations for riscv64
8991

@@ -328,19 +330,19 @@ run:
328330
3. uploads all selected wheels and any required `gpl-sources.tar` asset;
329331
4. publishes the release, at which point repository-level immutable releases
330332
freeze its tag and assets; and
331-
5. opens or updates the shared documentation pull request, filling in the
332-
version's entry with the release tag, wheel filenames, SHA-256 hashes, and
333-
`Requires-Python` metadata.
333+
5. opens or updates the package-specific `package/<package>` pull request,
334+
titled `<package>: update packages`, filling in the version's entry with the
335+
release tag, wheel filenames, SHA-256 hashes, and `Requires-Python` metadata.
334336
335337
Every `main` run creates a new release; existing releases are never reused or
336338
modified. Its description links back to the workflow run that produced it.
337339
Publishing fails if immutable releases are disabled, or if the wheel's version
338340
is not declared in the package YAML.
339341
340-
Merging the documentation pull request pushes the now-released entry to `main`
341-
and triggers the workflow once more; with nothing left pending, that run skips
342-
every job. Until then the version is still pending, so any other push touching
343-
the workflow or its YAML rebuilds and re-releases it.
342+
Merging the package pull request pushes the now-released entry to `main` and
343+
triggers the workflow once more; with nothing left pending, that run skips every
344+
guarded job. Until then the version is still pending on `main`, so any other
345+
push touching the workflow or its YAML rebuilds and re-releases it.
344346
345347
The generated `/simple/` package index reads only `docs/packages/*.yaml`. The
346348
new release does not become discoverable through pip until the generated

0 commit comments

Comments
 (0)