* ci: give the feedz.io push room and make it retry
The "Publish to feedz.io" step timed out twice recently (on the #7985-era
and #7991-era PRs) and passed on re-run both times. The 300s in those logs
is not the job timeout -- it is `dotnet nuget push`'s own default --timeout,
applied per push. With ~107 packages pushed sequentially from a single
glob, the feed only has to get slow under the burst for one of them to
cross that line, so this reads as the package set growing into the limit
rather than pure network flakiness.
Push four packages at a time with a 900s per-push timeout, and retry each
package up to three times with a backoff. --skip-duplicate was already
there and makes the retries idempotent -- a package that landed before the
failure is skipped on the next attempt.
A push that fails all three attempts still fails the step, and the job
keeps a bounded ceiling: 25 minutes on the step, 30 on the job.
Same package set, same feed, same credentials -- only how the pushes are
issued changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* ci: share the hardened package push with the nuget.org job
The nuget.org publish had the same shape the feedz.io one just outgrew: a
single sequential `dotnet nuget push *.nupkg` over ~107 packages against a
300s per-push default. It has not timed out yet because it only runs on a
published release, but a timeout there is the worse one -- a half-finished
publish to nuget.org is not something a re-run cleanly repairs.
Rather than copy the retry loop into a second job, move it into a composite
action both jobs call with their own feed and key. Same behaviour on both:
four pushes in flight, 900s per push, three attempts with a backoff,
--skip-duplicate making the retries idempotent.
Two details worth calling out:
Composite actions have to be on disk, so both jobs now check out
.github/actions. It is a sparse, depth-1 checkout -- a couple of seconds,
not a clone of the repo.
The action fails when it finds no .nupkg at all. `dotnet nuget push
*.nupkg` used to fail on its own when the glob matched nothing, and moving
to `find | xargs` would have quietly turned a broken artifact upload into a
green publish of zero packages.
Step-level timeout-minutes is deliberately absent: the runner does not
honour it on a step that calls a composite action. The 30-minute job
timeout is the real ceiling on both jobs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* ci: fit the package push retry budget inside the job timeout
Three 900-second attempts plus backoff could run 2790s per package, so a
package that kept failing got the 30-minute job cancelled mid-retry --
taking its three concurrent siblings with it and leaving a release only
partially published. Budget three 420s attempts plus 45s of backoff
instead: 1305s worst case, roughly eight minutes short of the timeout.
Pin the checkout that supplies the composite action to a full commit SHA
as well; that checkout hands the action the feed API key, so a retargeted
tag would be a path to the publishing credentials.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* ci: bound the package push by a step deadline, not a per-package budget
xargs -P 4 puts the packages through in waves, and the job timeout covers
every wave, so budgeting one package's retries still let enough slow waves
run the job out of time -- and a cancelled runner leaves a release half
published with no record of what made it. Give the step a deadline
instead: no attempt starts that cannot finish before it, and running out
of time fails the step naming the packages.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* ci: note the job timeout's relationship to the push deadline
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* ci: pin the artifact download in the publishing jobs too
Both third-party actions in these jobs run before the local composite is
handed a feed API key, in the same writable workspace, so a retargeted tag
on either could substitute the composite ahead of the credential. The
checkout was pinned; the artifact download was not.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>