From 4a16928bc30b50096169274ed92683d90e459a57 Mon Sep 17 00:00:00 2001 From: dislbenn Date: Fri, 21 Aug 2026 11:55:32 -0400 Subject: [PATCH 1/3] ocm-ci-fastforward-multiple: clean up stale Tekton files <= LAST_RELEASE_VERSION create_tekton_files() and transform_tekton_files() both use the LAST_RELEASE_VERSION Tekton files as a template/fallback when creating new versions, but never removed the old template afterward. This left stale Tekton files (e.g. acm-50-*.yaml) accumulating on branches after new versions (5.1, 5.2, ...) were created or fast-forwarded along. Add three shared helpers: - compare_versions: numeric major.minor comparison - tekton_file_version_compare: compares a Tekton file's embedded version against a target, preferring the semantic version found in the file content (release-X.Y / backplane-X.Y) since compact filename versions (e.g. "217" vs "50") don't sort correctly once a minor version reaches double digits - cleanup_stale_tekton_files: removes (git rm) any Tekton file whose version is <= a given max_version create_tekton_files() now removes files <= LAST_RELEASE_VERSION after creating the requested destination versions. transform_tekton_files() now sweeps up any remaining files <= LAST_RELEASE_VERSION after renaming the exact source version, covering stragglers that rode along via fast-forward. Both functions' early-exit guards and commit/PR messages were updated to account for cleanup-only changes (no new files created, but stale files removed). --- .../ocm-ci-fastforward-multiple-commands.sh | 163 +++++++++++++++++- 1 file changed, 156 insertions(+), 7 deletions(-) diff --git a/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh b/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh index b0b89bef3c685..bd6ecb767882f 100755 --- a/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh +++ b/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh @@ -118,6 +118,112 @@ extract_version_from_branch() { return 1 } +# Compare two X.Y version strings numerically by major then minor. +# Echoes -1, 0, or 1 (a <, ==, > b). +compare_versions() { + local a_major="${1%%.*}" + local a_minor="${1##*.}" + local b_major="${2%%.*}" + local b_minor="${2##*.}" + + if [[ $a_major -lt $b_major ]]; then + echo "-1" + elif [[ $a_major -gt $b_major ]]; then + echo "1" + elif [[ $a_minor -lt $b_minor ]]; then + echo "-1" + elif [[ $a_minor -gt $b_minor ]]; then + echo "1" + else + echo "0" + fi +} + +# Compare a Tekton file's embedded version against a target X.Y version. +# Prefers the semantic version embedded in the file content (e.g. a +# "release-5.0" / "backplane-5.0" branch reference), since compact filename +# versions (e.g. "50", "217") don't sort correctly once a minor version +# reaches double digits (mirrors get_highest_tekton_version's approach). +# Falls back to comparing the compact filename version numerically if no +# semantic version can be extracted from the file content. +# Echoes -1, 0, or 1 (file version <, ==, > target). +tekton_file_version_compare() { + local file=$1 + local branch_prefix=$2 + local file_ver_compact=$3 # e.g. "50" or "5-0" + local target_version=$4 # e.g. "5.0" + + local semantic_version + semantic_version=$(grep -oE "${branch_prefix}-[0-9]+\.[0-9]+" "$file" 2>/dev/null | head -1 | cut -d'-' -f2) + + if [[ -n "$semantic_version" ]]; then + compare_versions "$semantic_version" "$target_version" + return + fi + + # Fallback: compare compact filename version numerically + local target_compact="${target_version//./}" + local file_num="${file_ver_compact//-/}" + local target_num="${target_compact//-/}" + file_num=$((10#${file_num})) + target_num=$((10#${target_num})) + + if [[ $file_num -lt $target_num ]]; then + echo "-1" + elif [[ $file_num -gt $target_num ]]; then + echo "1" + else + echo "0" + fi +} + +# Remove Tekton files whose embedded version is <= max_version (X.Y format). +# Must be called with cwd inside the target git working tree, on the branch +# already checked out. Stages removals with `git rm`. All log output goes to +# stderr; only the count of removed files is written to stdout, so callers +# can safely capture the result via command substitution. +cleanup_stale_tekton_files() { + local product_prefix=$1 + local branch_prefix=$2 + local max_version=$3 # e.g. "5.0" - files at or below this are removed + + local removed=0 + + for old_file in .tekton/*-"${product_prefix}"-*-*.yaml; do + [[ -f "$old_file" ]] || continue + + local old_filename + old_filename=$(basename "$old_file") + + local old_ver_compact="" + if [[ "${product_prefix}" == "globalhub" ]]; then + if [[ "$old_filename" =~ ${product_prefix}-([0-9]+-[0-9]+)- ]]; then + old_ver_compact="${BASH_REMATCH[1]}" + fi + else + if [[ "$old_filename" =~ ${product_prefix}-([0-9]+)- ]]; then + old_ver_compact="${BASH_REMATCH[1]}" + fi + fi + + [[ -n "$old_ver_compact" ]] || continue + + local cmp + cmp=$(tekton_file_version_compare "$old_file" "${branch_prefix}" "${old_ver_compact}" "${max_version}") + + if [[ "$cmp" == "-1" || "$cmp" == "0" ]]; then + echo "INFO: Removing stale Tekton file: ${old_filename} (<= ${max_version})" >&2 + if git rm -q "$old_file" >/dev/null 2>&1; then + removed=$((removed + 1)) + else + echo "WARNING: Could not remove ${old_file}" >&2 + fi + fi + done + + echo "$removed" +} + # Transform Tekton files from source version to destination version # After fast-forward, renames and updates Tekton files for new branch transform_tekton_files() { @@ -246,18 +352,38 @@ transform_tekton_files() { files_transformed=$((files_transformed + 1)) done - if [[ "$files_found" == "false" ]]; then - echo "INFO: No ${source_pattern}*.yaml files found to transform" + # Remove any remaining Tekton files older than or equal to + # LAST_RELEASE_VERSION. The exact source_version files (if any) were + # already renamed above via `git mv`; this sweeps up stragglers from + # earlier release cycles that rode along via fast-forward (e.g. an + # acm-50- template that was never cleaned up on this branch). + local removed_stale=0 + if [[ -n "${last_release_version:-}" ]]; then + removed_stale=$(cleanup_stale_tekton_files "${product_prefix}" "${branch_prefix}" "${last_release_version}") + fi + + if [[ "$files_found" == "false" ]] && [[ "${removed_stale}" -eq 0 ]]; then + echo "INFO: No ${source_pattern}*.yaml files found to transform, nothing stale to clean up" exit 0 fi echo "INFO: Transformed ${files_transformed} files" + if [[ "${removed_stale}" -gt 0 ]]; then + echo "INFO: Removed ${removed_stale} stale Tekton file(s) <= ${last_release_version}" + fi # Commit transformation git config user.email "${GITHUB_USER}@users.noreply.github.com" git config user.name "${GITHUB_USER}" - git commit -m "Transform Tekton files from ${source_version} to ${dest_version} + local commit_message="Transform Tekton files from ${source_version} to ${dest_version}" + if [[ "${removed_stale}" -gt 0 ]]; then + commit_message="${commit_message} + +Remove ${removed_stale} stale Tekton file(s) <= ${last_release_version}" + fi + + git commit -m "${commit_message} Co-Authored-By: Claude Sonnet 4.5 " @@ -781,6 +907,17 @@ create_tekton_files() { fi done + # Remove Tekton files for versions <= LAST_RELEASE_VERSION. + # LAST_RELEASE_VERSION was only kept around as a template for creating + # the versions above; now that those new versions have been created on + # ${default_branch}, the old template is stale and should not persist. + local removed_stale=0 + if [[ -n "${LAST_RELEASE_VERSION:-}" ]]; then + log "INFO Cleaning up Tekton files <= LAST_RELEASE_VERSION (${LAST_RELEASE_VERSION})" + removed_stale=$(cleanup_stale_tekton_files "${product_prefix}" "${branch_prefix}" "${LAST_RELEASE_VERSION}") + log "INFO Removed ${removed_stale} stale Tekton file(s)" + fi + # Check if PR exists for branch (even if no new files) local pr_title pr_title="Add Tekton files for ${product_prefix} versions: ${dest_versions}" @@ -789,6 +926,11 @@ create_tekton_files() { $(for v in ${dest_versions}; do echo "- ${product_prefix}-${v//./}"; done) Generated from existing ${product_prefix}-${highest_version} templates." + if [[ "${removed_stale}" -gt 0 ]]; then + pr_body="${pr_body} + +Also removes ${removed_stale} stale Tekton file(s) for version <= ${LAST_RELEASE_VERSION}, which are no longer needed now that the versions above exist." + fi local pr_exists=false if command -v gh >/dev/null 2>&1; then @@ -801,8 +943,8 @@ Generated from existing ${product_prefix}-${highest_version} templates." fi fi - if [[ "$files_created" == "false" ]]; then - log "INFO No new files to create" + if [[ "$files_created" == "false" ]] && [[ "${removed_stale}" -eq 0 ]]; then + log "INFO No new files to create and nothing stale to clean up" # Create PR if branch existed on remote (has commits) but no PR if [[ "$pr_exists" == "false" ]] && [[ "$branch_existed_on_remote" == "true" ]] && command -v gh >/dev/null 2>&1; then @@ -843,8 +985,15 @@ Generated from existing ${product_prefix}-${highest_version} templates." git config user.name "OpenShift CI Robot" git config user.email "noreply@openshift.io" - log "INFO Committing: Add Tekton files for versions: ${dest_versions}" - git commit -s -m "Add Tekton files for versions: ${dest_versions}" 2>&1 + local commit_message="Add Tekton files for versions: ${dest_versions}" + if [[ "${removed_stale}" -gt 0 ]]; then + commit_message="${commit_message} + +Remove ${removed_stale} stale Tekton file(s) for version <= ${LAST_RELEASE_VERSION}" + fi + + log "INFO Committing: ${commit_message}" + git commit -s -m "${commit_message}" 2>&1 # Push branch (use -u for new branch, --force-with-lease if we reset existing branch) log "INFO Pushing ${pr_branch} to origin" From a121c2717910195e5475085c8d9898c626d0a529 Mon Sep 17 00:00:00 2001 From: dislbenn Date: Fri, 21 Aug 2026 12:55:17 -0400 Subject: [PATCH 2/3] Track and fail on stale Tekton cleanup failures Previously, cleanup_stale_tekton_files() would log a WARNING and continue silently if `git rm` failed for a stale file, potentially reporting cleanup as successful in commit messages and PR bodies even though some files were left behind. Now cleanup_stale_tekton_files() returns both the removed and failed counts (" "), and both callers (transform_tekton_files and create_tekton_files) abort with an error if any removal failed, rather than silently proceeding. Addresses CodeRabbit feedback on PR #83828. --- .../ocm-ci-fastforward-multiple-commands.sh | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh b/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh index bd6ecb767882f..27d0f5d829a57 100755 --- a/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh +++ b/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh @@ -180,14 +180,16 @@ tekton_file_version_compare() { # Remove Tekton files whose embedded version is <= max_version (X.Y format). # Must be called with cwd inside the target git working tree, on the branch # already checked out. Stages removals with `git rm`. All log output goes to -# stderr; only the count of removed files is written to stdout, so callers -# can safely capture the result via command substitution. +# stderr; only the result is written to stdout as " ", so +# callers can safely capture it via command substitution and must treat a +# non-zero count as an error rather than silently proceeding. cleanup_stale_tekton_files() { local product_prefix=$1 local branch_prefix=$2 local max_version=$3 # e.g. "5.0" - files at or below this are removed local removed=0 + local failed=0 for old_file in .tekton/*-"${product_prefix}"-*-*.yaml; do [[ -f "$old_file" ]] || continue @@ -216,12 +218,13 @@ cleanup_stale_tekton_files() { if git rm -q "$old_file" >/dev/null 2>&1; then removed=$((removed + 1)) else - echo "WARNING: Could not remove ${old_file}" >&2 + echo "ERROR: Could not remove ${old_file}" >&2 + failed=$((failed + 1)) fi fi done - echo "$removed" + echo "$removed $failed" } # Transform Tekton files from source version to destination version @@ -358,8 +361,17 @@ transform_tekton_files() { # earlier release cycles that rode along via fast-forward (e.g. an # acm-50- template that was never cleaned up on this branch). local removed_stale=0 + local failed_cleanup=0 if [[ -n "${last_release_version:-}" ]]; then - removed_stale=$(cleanup_stale_tekton_files "${product_prefix}" "${branch_prefix}" "${last_release_version}") + local cleanup_result + cleanup_result=$(cleanup_stale_tekton_files "${product_prefix}" "${branch_prefix}" "${last_release_version}") + removed_stale="${cleanup_result%% *}" + failed_cleanup="${cleanup_result##* }" + fi + + if [[ "${failed_cleanup}" -gt 0 ]]; then + echo "ERROR: Failed to remove ${failed_cleanup} stale Tekton file(s) <= ${last_release_version}, aborting" + exit 1 fi if [[ "$files_found" == "false" ]] && [[ "${removed_stale}" -eq 0 ]]; then @@ -912,10 +924,19 @@ create_tekton_files() { # the versions above; now that those new versions have been created on # ${default_branch}, the old template is stale and should not persist. local removed_stale=0 + local failed_cleanup=0 if [[ -n "${LAST_RELEASE_VERSION:-}" ]]; then log "INFO Cleaning up Tekton files <= LAST_RELEASE_VERSION (${LAST_RELEASE_VERSION})" - removed_stale=$(cleanup_stale_tekton_files "${product_prefix}" "${branch_prefix}" "${LAST_RELEASE_VERSION}") + local cleanup_result + cleanup_result=$(cleanup_stale_tekton_files "${product_prefix}" "${branch_prefix}" "${LAST_RELEASE_VERSION}") + removed_stale="${cleanup_result%% *}" + failed_cleanup="${cleanup_result##* }" log "INFO Removed ${removed_stale} stale Tekton file(s)" + + if [[ "${failed_cleanup}" -gt 0 ]]; then + log "ERROR Failed to remove ${failed_cleanup} stale Tekton file(s) <= LAST_RELEASE_VERSION, aborting" + exit 1 + fi fi # Check if PR exists for branch (even if no new files) From d495913af069124a625ecd669f787a20e41a92b5 Mon Sep 17 00:00:00 2001 From: dislbenn Date: Fri, 21 Aug 2026 13:23:00 -0400 Subject: [PATCH 3/3] Address remaining CodeRabbit findings on Tekton cleanup 1. Run stale-file cleanup even when all requested versions already exist (Moderate risk, flagged as blocking merge) create_tekton_files() had an early-exit guard that returned as soon as every requested destination version already existed on default_branch, only tidying up an obsolete PR branch. This skipped cleanup_stale_tekton_files() entirely, so files <= LAST_RELEASE_VERSION could persist indefinitely as long as no new destination version needed to be created. The per-version file-creation loop already no-ops correctly (via continue) for versions that already exist, and the "no new files" handling after cleanup already closes obsolete PRs/branches based on an actual diff against default_branch. Removing the redundant early-exit lets execution fall through to cleanup and the existing diff-based PR/branch handling, which is simpler and strictly more correct. The PR-closing courtesy message from the removed block was preserved by moving it into the diff-based "branch is identical to default" path, so it now also covers the case where an obsolete PR remains open with a stale branch. 2. Fix compact-filename version comparison in the no-embedded-version fallback path of tekton_file_version_compare() When a Tekton file has no embedded release-X.Y/backplane-X.Y reference, the function fell back to comparing compact filename versions (e.g. "217", "50") as plain concatenated integers. This misorders versions once a minor version reaches double digits: 217 (2.17) > 50 (5.0) numerically, incorrectly treating 2.17 as newer than 5.0. Now the fallback parses major.minor out of the compact form (reusing the digit-count convention already used elsewhere in this script, and the hyphen-delimited globalhub form directly) and compares via the shared compare_versions helper. Also guard the semantic-version grep|head|cut pipeline with "|| true". This script only sets "set -uo pipefail" (no errexit), so a no-match grep exiting 1 does not currently terminate execution here, but the guard makes that explicit and keeps the code correct if errexit is ever added. --- .../ocm-ci-fastforward-multiple-commands.sh | 152 ++++++++---------- 1 file changed, 71 insertions(+), 81 deletions(-) diff --git a/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh b/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh index 27d0f5d829a57..09d16b9786454 100755 --- a/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh +++ b/ci-operator/step-registry/ocm/ci/fastforward-multiple/ocm-ci-fastforward-multiple-commands.sh @@ -154,27 +154,41 @@ tekton_file_version_compare() { local target_version=$4 # e.g. "5.0" local semantic_version - semantic_version=$(grep -oE "${branch_prefix}-[0-9]+\.[0-9]+" "$file" 2>/dev/null | head -1 | cut -d'-' -f2) + # `|| true` guards against `grep` finding no match (exit 1) so the + # fallback below always runs, regardless of any future `set -e` change. + semantic_version=$(grep -oE "${branch_prefix}-[0-9]+\.[0-9]+" "$file" 2>/dev/null | head -1 | cut -d'-' -f2 || true) if [[ -n "$semantic_version" ]]; then compare_versions "$semantic_version" "$target_version" return fi - # Fallback: compare compact filename version numerically - local target_compact="${target_version//./}" - local file_num="${file_ver_compact//-/}" - local target_num="${target_compact//-/}" - file_num=$((10#${file_num})) - target_num=$((10#${target_num})) - - if [[ $file_num -lt $target_num ]]; then - echo "-1" - elif [[ $file_num -gt $target_num ]]; then - echo "1" + # Fallback: parse the compact filename version into major.minor and + # compare with compare_versions, instead of comparing the compact + # representations as plain integers. A plain-integer comparison + # misorders versions once a minor version reaches double digits, e.g. + # compact "217" (2.17) vs "50" (5.0) would read as 217 > 50 and treat + # 2.17 as newer than 5.0. + local file_major file_minor + if [[ "$file_ver_compact" == *-* ]]; then + # globalhub-style compact version, already major-minor delimited (e.g. "5-0") + file_major="${file_ver_compact%%-*}" + file_minor="${file_ver_compact##*-}" else - echo "0" + # acm/mce-style compact version: 3+ digits is MAJOR + 2-digit MINOR + # (e.g. "217" -> 2.17), otherwise MAJOR + 1-digit MINOR (e.g. "50" -> 5.0) + # (mirrors the same convention used in create_tekton_files). + local compact_num=$((10#${file_ver_compact})) + if [[ ${#file_ver_compact} -ge 3 ]]; then + file_major=$((compact_num / 100)) + file_minor=$((compact_num % 100)) + else + file_major=$((compact_num / 10)) + file_minor=$((compact_num % 10)) + fi fi + + compare_versions "${file_major}.${file_minor}" "${target_version}" } # Remove Tekton files whose embedded version is <= max_version (X.Y format). @@ -681,62 +695,18 @@ create_tekton_files() { cd "$repo" || exit 1 - # First check if files already exist on DEFAULT branch - log "INFO Checking if files already exist on ${default_branch}" - local all_versions_exist=true - for dest_version in ${dest_versions}; do - local dest_ver_compact - if [[ "${product}" == "globalhub" ]]; then - dest_ver_compact="${dest_version//./-}" - else - dest_ver_compact="${dest_version//./}" - fi - - if ! compgen -G ".tekton/*-${product_prefix}-${dest_ver_compact}-*.yaml" >/dev/null; then - all_versions_exist=false - log "INFO ${product_prefix}-${dest_ver_compact} files missing on ${default_branch}" - break - else - log "INFO ${product_prefix}-${dest_ver_compact} files already exist on ${default_branch}" - fi - done - - if [[ "$all_versions_exist" == "true" ]]; then - log "INFO All requested versions already exist on ${default_branch}, nothing to do" - - # Clean up stale PR branch if exists - local pr_branch="add-tekton-files-${dest_versions// /-}" - if git ls-remote --heads origin "${pr_branch}" | grep -q "${pr_branch}"; then - log "INFO Stale PR branch ${pr_branch} found, cleaning up" - - # Close PR if exists - if command -v gh >/dev/null 2>&1; then - export GH_TOKEN="${token}" - local pr_num - pr_num=$(gh pr list --repo "${owner}/${repo}" --head "${pr_branch}" --json number --jq '.[0].number' 2>/dev/null || echo "") - - if [[ -n "${pr_num}" ]]; then - log "INFO Closing obsolete PR #${pr_num}" - if gh pr close "${pr_num}" --repo "${owner}/${repo}" \ - --comment "Closing - all Tekton files already merged to ${default_branch}" 2>&1; then - log "INFO Closed PR #${pr_num}" - else - log "WARNING Failed to close PR #${pr_num}" - fi - fi - fi - - # Delete branch - log "INFO Deleting stale branch ${pr_branch}" - if git push origin --delete "${pr_branch}" 2>&1; then - log "INFO Deleted branch ${pr_branch}" - else - log "WARNING Failed to delete branch ${pr_branch}" - fi - fi - - exit 0 - fi + # NOTE: We intentionally do not short-circuit here even when every + # requested version already exists on ${default_branch}. An earlier + # version of this function returned immediately in that case (after + # only tidying up an obsolete PR branch), which skipped the stale + # Tekton file cleanup below entirely - so files <= LAST_RELEASE_VERSION + # could persist indefinitely as long as no new destination version + # needed to be created. The per-version loop further down already + # no-ops correctly (via `continue`) for any version that already + # exists, and the "no new files" handling after cleanup already closes + # obsolete PRs/branches based on an actual diff against + # ${default_branch}, so falling through here is both simpler and + # strictly more correct than special-casing "all versions exist". # Create branch for PR local pr_branch="add-tekton-files-${dest_versions// /-}" @@ -954,22 +924,29 @@ Also removes ${removed_stale} stale Tekton file(s) for version <= ${LAST_RELEASE fi local pr_exists=false + local pr_num="" if command -v gh >/dev/null 2>&1; then export GH_TOKEN="${token}" log "INFO Checking if PR already exists for ${pr_branch}" - if gh pr list --head "${pr_branch}" --json number --jq '.[0].number' 2>&1 | grep -q '^[0-9]'; then + pr_num=$(gh pr list --head "${pr_branch}" --json number --jq '.[0].number' 2>/dev/null || echo "") + if [[ -n "${pr_num}" ]]; then pr_exists=true - log "INFO PR already exists for ${pr_branch}" + log "INFO PR already exists for ${pr_branch} (#${pr_num})" fi fi if [[ "$files_created" == "false" ]] && [[ "${removed_stale}" -eq 0 ]]; then log "INFO No new files to create and nothing stale to clean up" - # Create PR if branch existed on remote (has commits) but no PR - if [[ "$pr_exists" == "false" ]] && [[ "$branch_existed_on_remote" == "true" ]] && command -v gh >/dev/null 2>&1; then - # Check if branch differs from default branch + if [[ "$branch_existed_on_remote" == "true" ]] && command -v gh >/dev/null 2>&1; then + # Check if branch differs from default branch. This covers both: + # - a pre-existing PR branch that turned out to need no changes + # (e.g. all requested versions already existed on default_branch + # and there was nothing stale to remove), which should be closed + # and deleted rather than left open indefinitely + # - a pre-existing PR branch with real, uncommitted-here changes + # from a previous run, which should get its PR (re)created log "INFO Checking if ${pr_branch} differs from ${default_branch}" if ! git fetch origin "${default_branch}" 2>&1; then log "WARNING Could not fetch ${default_branch}" @@ -978,6 +955,17 @@ Also removes ${removed_stale} stale Tekton file(s) for version <= ${LAST_RELEASE if git diff --quiet "origin/${default_branch}" HEAD; then log "INFO Branch ${pr_branch} is identical to ${default_branch}, no PR needed" + + if [[ -n "${pr_num}" ]]; then + log "INFO Closing obsolete PR #${pr_num}" + if gh pr close "${pr_num}" --repo "${owner}/${repo}" \ + --comment "Closing - all Tekton files already merged to ${default_branch}" 2>&1; then + log "INFO Closed PR #${pr_num}" + else + log "WARNING Failed to close PR #${pr_num}" + fi + fi + log "INFO Deleting orphaned branch ${pr_branch}" if git push origin --delete "${pr_branch}" 2>&1; then log "INFO Successfully deleted ${pr_branch}" @@ -987,14 +975,16 @@ Also removes ${removed_stale} stale Tekton file(s) for version <= ${LAST_RELEASE exit 0 fi - log "INFO Creating PR for existing branch with changes" + if [[ "$pr_exists" == "false" ]]; then + log "INFO Creating PR for existing branch with changes" - if ! gh pr create \ - --title "${pr_title}" \ - --body "${pr_body}" \ - --base "${default_branch}" \ - --head "${pr_branch}" 2>&1; then - log "WARNING PR creation failed" + if ! gh pr create \ + --title "${pr_title}" \ + --body "${pr_body}" \ + --base "${default_branch}" \ + --head "${pr_branch}" 2>&1; then + log "WARNING PR creation failed" + fi fi fi