From 49fbe9f81ef2efc3a6305754261f1304742a7b33 Mon Sep 17 00:00:00 2001 From: Lars Francke Date: Tue, 18 Aug 2026 22:51:53 +0200 Subject: [PATCH] Various fixes and improvements - All scripts now also work when _not_ called from within the bulk-pr directory - pr_status always reported 0, whatever the checks did - it read the exit code of "set -e" instead of the one from gh - pr_close compared strings with -eq, which is an arithmetic comparison, so every PR looked OPEN - All scripts would abort if a repo had no PR - the proper handling of that is moved to a new "common" file - Closing a PR also deletes the old branches --- README.md | 2 +- bulk-pr/README.md | 8 ++++---- bulk-pr/common | 15 +++++++++++++++ bulk-pr/pr_approve | 10 +++++----- bulk-pr/pr_checks | 11 ++++++++--- bulk-pr/pr_close | 10 +++++----- bulk-pr/pr_diffs | 9 ++++++--- bulk-pr/pr_list | 9 ++++----- bulk-pr/pr_status | 23 ++++++++++++++++------- 9 files changed, 64 insertions(+), 33 deletions(-) create mode 100644 bulk-pr/common diff --git a/README.md b/README.md index 70b4a2e..e6b2f00 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ See relevant READMEs: -- [PR Bulk Tools](./bulk-pr/READMEOverview.md) +- [PR Bulk Tools](./bulk-pr/README.md) - [OLM Overview](./olm/README.md) - [Stackable Quickstart](./quickstart/README.md) - [Release Workflow](./release/README.md) diff --git a/bulk-pr/README.md b/bulk-pr/README.md index 5af38f8..734ba99 100644 --- a/bulk-pr/README.md +++ b/bulk-pr/README.md @@ -17,7 +17,8 @@ The recommended workflow for PRs created by the operator templating is: 3. Run `pr_approve` ### Common parameters -With the only exception of the `repos` script all scripts in this repository take the same parameter, which is the name of the branch the PRs you want to operate on was created from. +All scripts in this repository take the same parameter, which is the name of the branch the PRs you want to operate on was created from. +The exceptions are `repos` and `common`, which are sourced rather than run, and `pr_list`, which lists every open PR and so needs no branch. For example for a set of operator templating pull requests this will usually be in the form of `template_abd68ad` which is the fixed prefix `template_` followed by the short commit hash of the commit in the operator templating repo that it was based on. @@ -38,7 +39,7 @@ Shows all checks for all PRs and their current status. Checks are shown per PR, hitting `q` switches to the next PR, Ctrl-C can be used to abort the entire script. ### pr_close -Closes all PRs. +Closes all PRs and deletes their branches. ### pr_diffs Shows the diffs for all PRs, this can be useful to double check that no unexpected changes were queued in any repository by accident. @@ -56,5 +57,4 @@ The displayed status per PR can have the following values: | 1 | One or more checks failed or are still running | ### pr_list -List all open PRs in all `repos`. - +List all open PRs in all `repos`. Takes no parameter. diff --git a/bulk-pr/common b/bulk-pr/common new file mode 100644 index 0000000..f987470 --- /dev/null +++ b/bulk-pr/common @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Utility script. Not meant to be run on its own. + +# Resolve the repository list relative to this file. +BULK_PR_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=./repos +source "${BULK_PR_DIR}/repos" + +# Prints the state of the PR for a branch (OPEN, MERGED or CLOSED), or nothing +# when that repository has no PR for the branch. +# If we used gh pr view directly the whole script would abort when using set -e. +pr_state() { + local product=$1 branch=$2 + gh pr view "$branch" -R "stackabletech/${product}-operator" --json state --jq '.state' 2>/dev/null || true +} diff --git a/bulk-pr/pr_approve b/bulk-pr/pr_approve index 11aee35..c04dd42 100755 --- a/bulk-pr/pr_approve +++ b/bulk-pr/pr_approve @@ -1,14 +1,14 @@ #!/usr/bin/env bash set -euo pipefail PR_BRANCH_NAME=${1:?Must provide name of PR branch to operate on.} -source repos +source "$(dirname -- "$0")/common" for product in "${products[@]}"; do - STATE=$(gh pr view ${PR_BRANCH_NAME} -R stackabletech/${product}-operator --jq '.state' --json state) + STATE=$(pr_state "$product" "$PR_BRANCH_NAME") if [[ "$STATE" == "OPEN" ]]; then echo "Approving ${product}" - gh pr review ${PR_BRANCH_NAME} --approve -R stackabletech/${product}-operator - gh pr merge ${PR_BRANCH_NAME} -R stackabletech/${product}-operator + gh pr review "$PR_BRANCH_NAME" --approve -R "stackabletech/${product}-operator" + gh pr merge "$PR_BRANCH_NAME" -R "stackabletech/${product}-operator" else - echo "Skipping ${product}, PR already closed" + echo "Skipping ${product}, PR is ${STATE:-absent}" fi done diff --git a/bulk-pr/pr_checks b/bulk-pr/pr_checks index a796acc..c704801 100755 --- a/bulk-pr/pr_checks +++ b/bulk-pr/pr_checks @@ -1,8 +1,13 @@ #!/usr/bin/env bash set -euo pipefail PR_BRANCH_NAME=${1:?Must provide name of PR branch to operate on.} -source repos +source "$(dirname -- "$0")/common" for product in "${products[@]}"; do - gh pr checks ${PR_BRANCH_NAME} -R stackabletech/${product}-operator + if [[ -z "$(pr_state "$product" "$PR_BRANCH_NAME")" ]]; then + echo "Skipping ${product}, no PR for ${PR_BRANCH_NAME}" + continue + fi + # Non-zero means checks are failing or still running. + # And that's what we want to see. + gh pr checks "$PR_BRANCH_NAME" -R "stackabletech/${product}-operator" || true done - diff --git a/bulk-pr/pr_close b/bulk-pr/pr_close index 3beb054..ca55adf 100755 --- a/bulk-pr/pr_close +++ b/bulk-pr/pr_close @@ -1,12 +1,12 @@ #!/usr/bin/env bash set -euo pipefail PR_BRANCH_NAME=${1:?Must provide name of PR branch to operate on.} -source repos +source "$(dirname -- "$0")/common" for product in "${products[@]}"; do - STATE=$(gh pr view ${PR_BRANCH_NAME} -R stackabletech/${product}-operator --jq '.state' --json state) - if [[ $STATE -eq "OPEN" ]]; then - gh pr close ${PR_BRANCH_NAME} -R stackabletech/${product}-operator + STATE=$(pr_state "$product" "$PR_BRANCH_NAME") + if [[ "$STATE" == "OPEN" ]]; then + gh pr close "$PR_BRANCH_NAME" --delete-branch -R "stackabletech/${product}-operator" else - echo "Skipping ${product}, PR already closed" + echo "Skipping ${product}, PR is ${STATE:-absent}" fi done diff --git a/bulk-pr/pr_diffs b/bulk-pr/pr_diffs index 2b0472c..481e0f5 100755 --- a/bulk-pr/pr_diffs +++ b/bulk-pr/pr_diffs @@ -1,8 +1,11 @@ #!/usr/bin/env bash set -euo pipefail PR_BRANCH_NAME=${1:?Must provide name of PR branch to operate on.} -source repos +source "$(dirname -- "$0")/common" for product in "${products[@]}"; do - gh pr diff ${PR_BRANCH_NAME} -R stackabletech/${product}-operator + if [[ -z "$(pr_state "$product" "$PR_BRANCH_NAME")" ]]; then + echo "Skipping ${product}, no PR for ${PR_BRANCH_NAME}" + continue + fi + gh pr diff "$PR_BRANCH_NAME" -R "stackabletech/${product}-operator" done - diff --git a/bulk-pr/pr_list b/bulk-pr/pr_list index 8800ad9..b997904 100755 --- a/bulk-pr/pr_list +++ b/bulk-pr/pr_list @@ -1,10 +1,9 @@ #!/usr/bin/env bash set -euo pipefail -PR_BRANCH_NAME=${1:?Must provide name of PR branch to operate on.} -source repos -# Disable gh paging for results. -PAGER= +source "$(dirname -- "$0")/common" +# Disable gh paging for results. Needs exporting to reach gh. +export PAGER= for product in "${products[@]}"; do echo "#### PRs for $product ###" - gh pr list -R stackabletech/${product}-operator + gh pr list -R "stackabletech/${product}-operator" done diff --git a/bulk-pr/pr_status b/bulk-pr/pr_status index 8faab9b..3582010 100755 --- a/bulk-pr/pr_status +++ b/bulk-pr/pr_status @@ -1,13 +1,22 @@ #!/usr/bin/env bash set -euo pipefail PR_BRANCH_NAME=${1:?Must provide name of PR branch to operate on.} -source repos +source "$(dirname -- "$0")/common" for product in "${products[@]}"; do - STATE=$(gh pr view ${PR_BRANCH_NAME} -R stackabletech/${product}-operator --jq '.state' --json state) - # Disable -e option to the "set" command below because it causes the script to stop if checks are in progress. - set +e - gh pr checks ${PR_BRANCH_NAME} -R stackabletech/${product}-operator &>/dev/null - set -e - status=$? + STATE=$(pr_state "$product" "$PR_BRANCH_NAME") + if [[ -z "$STATE" ]]; then + echo "${product}: no PR for ${PR_BRANCH_NAME}" + continue + fi + # gh pr checks returns 0 (success) when the PR is green. + # It returns 8 when the checks are still running. + # Any other return code is a check failure. + # We only report green vs not-green, so all of that collapses into 0 or 1. + # A command used as an if condition is exempt from set -e, so the non-zero returns don't abort us. + if gh pr checks "$PR_BRANCH_NAME" -R "stackabletech/${product}-operator" &>/dev/null; then + status=0 + else + status=1 + fi echo "${product}(${STATE}): ${status}" done