Skip to content

An artifact surviving the failed run may defeat the Re-run all jobs recovery D4.5 now prescribes #1216

Description

@ptr727

WORKFLOW.md D4.5, as of #1215, names Re-run all jobs as the recovery for a failed package push whose branch tip has moved. That route re-executes the build leaves, which re-upload their artifacts under fixed names into a run that may still hold artifacts of those names. Whether that succeeds decides whether the documented recovery works, and nothing in the tree settles it.

The collision

Every build leaf uploads under a fixed, branch-suffixed name with actions/upload-artifact pinned at v7.0.1, and none sets overwrite:

  • .github/actions/nuget-build-default/action.yml uploads nuget-build-<branch> and release-asset-<branch>-nuget
  • .github/actions/pypi-build-default/action.yml uploads pypi-build-<branch>
  • .github/actions/dotnet-publish-default/action.yml uploads release-asset-<branch>-dotnet-publish

That action's own README states the default: "If false, the action will fail if an artifact for the given name already exists." Artifacts belong to the run rather than to one attempt, so a re-run of a run that still holds the name would hit it.

Why the recovery reaches that case

D5.2 gates the package-artifact delete on !cancelled() && steps.<download-step-id>.outcome == 'success', so on the ordinary failed-push path the delete runs and the name is free. Two paths leave it occupied:

  1. D5.3 leaves the delete best-effort. continue-on-error: true plus a script that turns a failed DELETE into a ::warning:: means a failed delete is silent, and the artifact survives.
  2. On a re-run replaying a push event with the tag already cut, D4.4's no-op leg skips the release-create, and D5.2 skips the paired release-asset-* delete with it. That one is deterministic rather than a best-effort failure, so a second full re-run meets an occupied name by design.

retention-days: 1 (D5.4) bounds the window to roughly a day, which is exactly when an operator reaches for the recovery.

The contradictory evidence in the tree

.github/workflows/build-release-task.yml's asset-delete step comments "It deletes every matching id, because a rerun can upload duplicates". That asserts a re-run does upload a duplicate name, which reads as pre-v4 upload-artifact behaviour that the pinned v7 no longer has. D5.3's "deletes all matching ids" rule exists for that same older reading. One of the two is stale and the contract now leans on which.

What needs deciding

  1. Set overwrite: true on the build leaves' uploads. Dissolves the collision, makes the recovery unconditional, and retires the "a rerun can upload duplicates" comment and D5.3's all-ids rationale if they are indeed stale.
  2. Leave it and document the bound. D4.5 gains a fourth qualification saying the full re-run reds at the upload where an artifact survived, and that --failed is the route in exactly that case.
  3. The collision does not occur for a reason not yet identified, in which case the comment above is stale and should say so.

Verification owed

GitHub documents nothing about artifact visibility across run attempts, in either the action README or the re-run docs. Settling this needs a real run: fail a package push, let the delete fail or take the skipped-delete path, then Re-run all jobs and observe whether the leaf's upload succeeds. That is a real publish against a real registry, so it is the maintainer's to run rather than an agent's.

Related

Found by the adversarial passes on #1215, which documented the recovery this bears on. Related to #1200 and #1212, which carry the other section 4 and condensed-catalog defects.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions