From 355097d5c89397dcfef18975082d28184da7f362 Mon Sep 17 00:00:00 2001 From: Kostiantyn Dvornik Date: Mon, 31 Aug 2026 14:57:11 +0300 Subject: [PATCH 1/2] fix(SOF-8032): add grace period before deleting non-tip WIP releases Staleness was decided purely by "is this tag's sha still a branch tip" (git ls-remote --heads). That broke job-designer's build: ive's wip-2a8a93e was still pinned in job-designer/package.json, but a later commit on the same ive branch (with no [release] tag of its own) moved the tip past it, so the next Monday's scheduled cleanup deleted it - 404ing job-designer's `npm install`. Add min-age-days (default 14) as a second, independent gate: a non-tip release is only deleted once it's also older than the grace period, giving a pinned-but-superseded tarball time to get noticed and repinned before it's swept. Existing callers pick this up via the default with no changes needed, since all 22 mat3ra/* repos invoke this reusable workflow without overriding the new input. --- .github/workflows/cleanup-wip-releases.yml | 52 ++++++++++++++++------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/.github/workflows/cleanup-wip-releases.yml b/.github/workflows/cleanup-wip-releases.yml index 29fb219..99e3733 100644 --- a/.github/workflows/cleanup-wip-releases.yml +++ b/.github/workflows/cleanup-wip-releases.yml @@ -15,6 +15,15 @@ on: required: false type: boolean default: false + min-age-days: + description: >- + Grace period: only delete a non-tip release once it's at least this many days + old, so a WIP tarball that's still pinned by another repo's package.json + survives a follow-up commit landing on the same branch (which alone makes it + "not the tip") until someone notices and repins it. + required: false + type: number + default: 14 secrets: github-token: description: grants access to list/delete releases and read branch refs @@ -34,30 +43,45 @@ jobs: set -euo pipefail PREFIX="${{ inputs.tag-prefix }}" DRY_RUN="${{ inputs.dry-run }}" + MIN_AGE_DAYS="${{ inputs.min-age-days }}" LIVE_SHAS=$(git ls-remote --heads origin | awk '{print $1}') + NOW_EPOCH=$(date -u +%s) # Hard safety check: never touch a release that isn't marked pre-release, no # matter what its tag looks like. This is a second, independent gate on top of # the tag-prefix filter, not a substitute for it. JQ_FILTER='.[] | select(.isPrerelease == true)' - JQ_FILTER="${JQ_FILTER} | select(.tagName | startswith(\"${PREFIX}\")) | .tagName" - gh release list --limit 1000 --json tagName,isPrerelease -q "${JQ_FILTER}" | - while IFS= read -r tag; do + JQ_FILTER="${JQ_FILTER} | select(.tagName | startswith(\"${PREFIX}\"))" + JQ_FILTER="${JQ_FILTER} | [.tagName, .publishedAt] | @tsv" + gh release list --limit 1000 --json tagName,isPrerelease,publishedAt -q "${JQ_FILTER}" | + while IFS=$'\t' read -r tag published_at; do sha="${tag#"${PREFIX}"}" if echo "${LIVE_SHAS}" | grep -q "^${sha}"; then echo "Keeping ${tag} (${sha} is still a branch tip)" - else - echo "Deleting ${tag} (${sha} is no longer any branch's tip)" - if [[ "${DRY_RUN}" != "true" ]]; then - # Re-check immediately before deleting - never delete anything that isn't - # (still) marked pre-release, even if the listing above was somehow stale. - is_prerelease=$(gh release view "${tag}" --json isPrerelease -q .isPrerelease) - if [[ "${is_prerelease}" != "true" ]]; then - echo "REFUSING to delete ${tag}: not marked pre-release" >&2 - continue - fi - gh release delete "${tag}" --yes --cleanup-tag + continue + fi + + # Not a branch tip alone doesn't mean unused: a follow-up commit on the same + # branch (with no [release] tag of its own) makes the previous WIP tag + # "stale" by that check even while another repo's package.json is still + # pinned to its tarball. Give it MIN_AGE_DAYS to get noticed and repinned + # before treating it as abandoned. + age_days=$(( (NOW_EPOCH - $(date -u -d "${published_at}" +%s)) / 86400 )) + if (( age_days < MIN_AGE_DAYS )); then + echo "Keeping ${tag} (not a tip, ${age_days}d old, grace is ${MIN_AGE_DAYS}d)" + continue + fi + + echo "Deleting ${tag} (${sha} is no longer any branch's tip, ${age_days}d old)" + if [[ "${DRY_RUN}" != "true" ]]; then + # Re-check immediately before deleting - never delete anything that isn't + # (still) marked pre-release, even if the listing above was somehow stale. + is_prerelease=$(gh release view "${tag}" --json isPrerelease -q .isPrerelease) + if [[ "${is_prerelease}" != "true" ]]; then + echo "REFUSING to delete ${tag}: not marked pre-release" >&2 + continue fi + gh release delete "${tag}" --yes --cleanup-tag fi done From afe227bf24583f15b1268ccd8898e8d4521e16ad Mon Sep 17 00:00:00 2001 From: Kostiantyn Dvornik Date: Mon, 31 Aug 2026 15:19:45 +0300 Subject: [PATCH 2/2] chore: trim over-verbose comments in the grace-period fix --- .github/workflows/cleanup-wip-releases.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/workflows/cleanup-wip-releases.yml b/.github/workflows/cleanup-wip-releases.yml index 99e3733..a5fe36d 100644 --- a/.github/workflows/cleanup-wip-releases.yml +++ b/.github/workflows/cleanup-wip-releases.yml @@ -16,11 +16,7 @@ on: type: boolean default: false min-age-days: - description: >- - Grace period: only delete a non-tip release once it's at least this many days - old, so a WIP tarball that's still pinned by another repo's package.json - survives a follow-up commit landing on the same branch (which alone makes it - "not the tip") until someone notices and repins it. + description: Grace period (days) before a non-tip release is eligible for deletion required: false type: number default: 14 @@ -62,11 +58,8 @@ jobs: continue fi - # Not a branch tip alone doesn't mean unused: a follow-up commit on the same - # branch (with no [release] tag of its own) makes the previous WIP tag - # "stale" by that check even while another repo's package.json is still - # pinned to its tarball. Give it MIN_AGE_DAYS to get noticed and repinned - # before treating it as abandoned. + # Not a tip != unused: another repo may still be pinned to this tarball. + # Grace period gives time to notice and repin before deleting it. age_days=$(( (NOW_EPOCH - $(date -u -d "${published_at}" +%s)) / 86400 )) if (( age_days < MIN_AGE_DAYS )); then echo "Keeping ${tag} (not a tip, ${age_days}d old, grace is ${MIN_AGE_DAYS}d)"