Skip to content

IONOS(ci): refresh pr/ artifact slot from branch pushes - #305

Open
printminion-co wants to merge 1 commit into
ionos-dev-v33from
mk/dev/refresh-pr-artifact-on-push
Open

IONOS(ci): refresh pr/ artifact slot from branch pushes#305
printminion-co wants to merge 1 commit into
ionos-dev-v33from
mk/dev/refresh-pr-artifact-on-push

Conversation

@printminion-co

Copy link
Copy Markdown

Problem

ionos-productivity-hdnext-snapshot/pr/hidrive-next-pr-<N>.zip goes silently stale once a PR develops a merge conflict.

The flat pr/ slot is only ever written by the pull_request run. When a PR becomes CONFLICTING (mergeStateStatus: DIRTY), GitHub cannot compute refs/pull/<N>/merge and therefore creates no pull_request run at all — so nothing refreshes the slot, while the push run keeps happily uploading the immutable devs/<prefix>/<version>/<sha>/ artifact.

Observed on #294 (kh/dev/add-simplenavigation-v33, submodule gitlink conflict in IONOS):

Push sha push run pull_request run
2026-08-04, PR mergeable f4bb552 30895496405cancelled 30895503667 — success → pr/…-294.zip
2026-08-13, PR conflicting 491da87 31672429506 — success → devs/kh/… none created

Change

Resolve the open PR for a pushed */dev/* branch, then mirror the freshly uploaded devs/ artifact into the pr/ slot with a server-side jf rt copy (the zip is not re-transferred). The slot now tracks the branch head regardless of PR mergeability.

  • Gated to */dev/*. Protected branches (ionos-dev/ionos-stable/rc/*) use a unique-per-run-id concurrency key, so their push and pull_request runs execute in parallel and would race for the same slot.
  • Non-fatal by design. trigger-remote-dev-workflow gates on needs.upload-to-artifactory.result == 'success'; failing the job over a convenience mirror would block GitLab dev deployments even though the canonical artifact uploaded fine. Reported via ::error:: + step summary instead. One exit 1 flips this if the team prefers hard failure.
  • ARTIFACTORY_LAST_BUILD_PATH unchanged — still the immutable devs/<sha>/ path, since GitLab is handed GITHUB_SHA alongside it and must not receive a mutable slot.
  • actions/github-script for the lookup rather than gh/jq: this job is runs-on: self-hosted, where neither tool is provably installed (every existing jq call in this workflow is in an ubuntu-latest job). Node is already required here by checkout/download-artifact/setup-jfrog-cli.
  • Adds job-level permissions: — note these replace the workflow-level map, so contents: read is repeated for actions/checkout.
  • New artifact properties build.from_merge_ref / build.source_event make the caveat below machine-readable.

Caveat (documented in the workflow)

The pr/ slot now has two possible producers with different content:

  • pull_request run → built from refs/pull/<N>/merge (head merged into base)
  • push/workflow_dispatch run → built from the branch head only, base changes not included

build.from_merge_ref=(true|false) records which produced a given zip, and the step summary warns whoever downloads it.

Verification

actionlint + shellcheck (via podman) against the base as baseline: no new errors or warnings. The only delta is SC2086:info 56 → 60 — unquoted $GITHUB_OUTPUT in redirects, the convention already used 56× in this file.

Runtime check, no merge required (workflow_dispatch ignores the paths: filter and carries no PR number, so it takes the new push path):

gh workflow run "HiDrive Next Build" --ref <a-*/dev/*-branch-with-an-open-PR>
gh run view <run-id> --log --job "Push to artifactory" | grep -A5 "Resolved PR"
jf rt curl -XGET "/api/storage/ionos-productivity-hdnext-snapshot/pr/hidrive-next-pr-<N>.zip?properties"

Expect Resolved PR #<N>, ✅ PR slot refreshed on attempt 1, and pr.number / build.from_merge_ref=false / vcs.revision=<pushed sha> on the slot.

⚠️ First run needs a look at jf rt copy's target semantics. --flat=true is load-bearing — without it the source hierarchy is recreated underneath the target, producing a directory named like the slot. The jf rt s | grep -q check plus the direct-upload fallback cover the failure, but confirm the layout on the first real run.

Not included

The symmetric half — having the pull_request run also publish the devs/<sha>/ artifact — is left out deliberately. Today a push to a */dev/* branch with a healthy PR is cancelled by the PR run, so no devs/<sha>/ artifact exists for that push. Worth a follow-up; it needs github.event.pull_request.head.sha rather than github.sha (the latter is the ephemeral merge commit, which exists on no branch).

The flat `pr/hidrive-next-pr-<N>.zip` slot in JFrog was only ever written by
the pull_request run. When a PR becomes CONFLICTING, GitHub cannot compute
refs/pull/<N>/merge and therefore creates NO pull_request run at all, so the
slot silently went stale on every subsequent push while only the immutable
devs/<prefix>/<version>/<sha>/ artifact kept updating.

Resolve the open PR for a pushed `*/dev/*` branch and mirror the freshly
uploaded devs/ artifact into the pr/ slot with a server-side `jf rt copy`,
so the slot tracks the branch head regardless of PR mergeability.

- gate the lookup to `*/dev/*`: protected branches use a unique-per-run-id
  concurrency key, so their push and pull_request runs would race for the slot
- non-fatal by design; trigger-remote-dev-workflow gates on this job's success
  and must not lose GitLab dev deployments over a convenience mirror
- ARTIFACTORY_LAST_BUILD_PATH keeps pointing at the immutable devs/ path
- record build.from_merge_ref / build.source_event so consumers can tell a
  merge-ref build from a branch-head build of the same slot
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant