This is an automated email from the ASF dual-hosted git repository.

yihua pushed a commit to branch release-1.2.0
in repository https://gitbox.apache.org/repos/asf/hudi.git

commit 0b90200e4312aeb4f271617bfe82a2413bd9e3c3
Author: Y Ethan Guo <[email protected]>
AuthorDate: Fri May 15 12:34:47 2026 -0700

    chore: Enhance validate_staged_bundles.sh to validate bundles before 
closing the staging repo (#18749)
    
    * chore: Enhance the script of validating staged bundles
    
    * Update release guide to run validate_staged_bundles.sh --auth before 
closing the staging repo
---
 release/release_guide.md                   |  15 ++++-
 scripts/release/validate_staged_bundles.sh | 103 ++++++++++++++++++++++++-----
 2 files changed, 98 insertions(+), 20 deletions(-)

diff --git a/release/release_guide.md b/release/release_guide.md
index 4978f116e685..49c5c2eefe50 100644
--- a/release/release_guide.md
+++ b/release/release_guide.md
@@ -433,16 +433,25 @@ Set up a few environment variables to simplify Maven 
commands that follow. This
       hudi-spark3-bundle-2.12/2.13, hudi-spark-2.12/2.13, 
hudi-spark3-2.12/2.13, hudi-utilities-bundle_2.12/2.13 and
       hudi-utilities_2.12/2.13.
       > With 0.10.1, we had 4 bundles. spark2 with scala11, spark2 with 
scala12, spark3.0.x bundles and spark3.1.x bundles. Ensure each spark bundle 
reflects the version correctly. hudi-spark3.1.2-bundle_2.12-0.10.1.jar and 
hudi-spark3.0.3-bundle_2.12-0.10.1.jar are the respective bundle names for 
spark3 bundles.
-   8. Once you have ensured everything is good and validation of step 7 
succeeds, you can close the staging repo. Until
+   8. Before closing the staging repo, run the validate script against the 
private staging URL to programmatically
+      confirm all expected bundle artifacts are present. The `--auth` flag 
reads Nexus credentials from
+      `~/.m2/settings.xml` (server id `apache.releases.https`), which is 
required because the public URL is not
+      populated until the repo is closed.
+      ```shell
+      ./scripts/release/validate_staged_bundles.sh --auth 
orgapachehudi-<stage_repo_number> ${RELEASE_VERSION}-rc${RC_NUM} 2>&1 | tee -a 
/tmp/validate_staged_bundles_output.txt
+      ```
+      If the script reports any missing artifacts, re-run the relevant 
`deploy_staging_jars*.sh` step rather than
+      closing the repo, since once closed it cannot be re-deployed to.
+   9. Once you have ensured everything is good and validation of step 8 
succeeds, you can close the staging repo. Until
       you close, you can re-run deploying to staging multiple times. But once 
closed, it will create a new staging repo.
       So ensure you close this, so that the next RC (if need be) is on a new 
repo. So, once everything is good, close
       the staging repository on Apache Nexus. When prompted for a description, 
enter
       > Apache Hudi, version `${RELEASE_VERSION}`, release candidate 
`${RC_NUM}`.
-   9. After closing, run the script to validate the staged bundles again:
+   10. After closing, run the script to validate the staged bundles again 
against the public URL:
       ```shell
       ./scripts/release/validate_staged_bundles.sh 
orgapachehudi-<stage_repo_number> ${RELEASE_VERSION}-rc${RC_NUM} 2>&1 | tee -a 
/tmp/validate_staged_bundles_output.txt
       ```
-   10. Run the release candidate bundle validation in GitHub Action by 
following the instruction in
+   11. Run the release candidate bundle validation in GitHub Action by 
following the instruction in
       ["Running Bundle Validation on a Release 
Candidate"](../packaging/bundle-validation/README.md#running-bundle-validation-on-a-release-candidate).
 
 ## Checklist to proceed to the next step
diff --git a/scripts/release/validate_staged_bundles.sh 
b/scripts/release/validate_staged_bundles.sh
index 06763dc27e37..36e25ca6aea5 100755
--- a/scripts/release/validate_staged_bundles.sh
+++ b/scripts/release/validate_staged_bundles.sh
@@ -23,41 +23,92 @@
 set -o errexit
 set -o nounset
 
+USE_AUTH=false
+if [[ "${1:-}" == "--auth" ]]; then
+  USE_AUTH=true
+  shift
+fi
+
+if [[ $# -ne 2 ]]; then
+  echo "Usage: $(basename "$0") [--auth] <repo-id> <version>"
+  echo ""
+  echo "  Default:  uses public URL (repo must be closed)"
+  echo "  --auth:   uses private staging URL with ~/.m2/settings.xml 
credentials"
+  echo ""
+  echo "Examples:"
+  echo "  $(basename "$0") orgapachehudi-1176 1.2.0-rc1"
+  echo "  $(basename "$0") --auth orgapachehudi-1177 1.2.0-rc1"
+  exit 1
+fi
+
 REPO=$1
 VERSION=$2
 
-STAGING_REPO="https://repository.apache.org/content/repositories/${REPO}/org/apache/hudi";
+if [[ "$USE_AUTH" == true ]]; then
+  
STAGING_REPO="https://repository.apache.org/service/local/repositories/${REPO}/content/org/apache/hudi";
+
+  SETTINGS_XML="$HOME/.m2/settings.xml"
+  if [[ ! -f "$SETTINGS_XML" ]]; then
+    echo "ERROR: $SETTINGS_XML not found"
+    exit 1
+  fi
+
+  if command -v xmllint &>/dev/null; then
+    NEXUS_USER=$(xmllint --xpath \
+      "string(//server[id='apache.releases.https']/username)" "$SETTINGS_XML")
+    NEXUS_PASS=$(xmllint --xpath \
+      "string(//server[id='apache.releases.https']/password)" "$SETTINGS_XML")
+  else
+    NEXUS_USER=$(sed -n '/<server>/,/<\/server>/{ 
/<id>apache.releases.https<\/id>/,/<\/server>/{ 
s/.*<username>\(.*\)<\/username>.*/\1/p; }; }' "$SETTINGS_XML" | head -1 | 
xargs)
+    NEXUS_PASS=$(sed -n '/<server>/,/<\/server>/{ 
/<id>apache.releases.https<\/id>/,/<\/server>/{ 
s/.*<password>\(.*\)<\/password>.*/\1/p; }; }' "$SETTINGS_XML" | head -1 | 
xargs)
+  fi
+
+  if [[ -z "$NEXUS_USER" || -z "$NEXUS_PASS" ]]; then
+    echo "ERROR: Could not extract credentials for 'apache.releases.https' 
from $SETTINGS_XML"
+    exit 1
+  fi
+
+  export NEXUS_USER NEXUS_PASS
+  CURL_AUTH="-u ${NEXUS_USER}:${NEXUS_PASS}"
+  echo "==> Using private staging URL with authentication (user: $NEXUS_USER)"
+else
+  
STAGING_REPO="https://repository.apache.org/content/repositories/${REPO}/org/apache/hudi";
+  CURL_AUTH=""
+  echo "==> Using public URL (no authentication)"
+fi
+
+export CURL_AUTH
 
 declare -a extensions=("-javadoc.jar" "-javadoc.jar.asc" "-javadoc.jar.md5" 
"-javadoc.jar.sha1" "-sources.jar"
 "-sources.jar.asc" "-sources.jar.md5" "-sources.jar.sha1" ".jar" ".jar.asc" 
".jar.md5" ".jar.sha1" ".pom" ".pom.asc"
 ".pom.md5" ".pom.sha1")
 
-declare -a bundles=("hudi-aws-bundle" "hudi-cli-bundle_2.12" 
"hudi-cli-bundle_2.13" "hudi-datahub-sync-bundle"
+declare -a bundles=("hudi-aws-bundle" "hudi-azure-bundle" 
"hudi-cli-bundle_2.12" "hudi-cli-bundle_2.13" "hudi-datahub-sync-bundle"
 "hudi-flink1.17-bundle" "hudi-flink1.18-bundle" "hudi-flink1.19-bundle" 
"hudi-flink1.20-bundle"
-"hudi-flink2.0-bundle" "hudi-gcp-bundle" "hudi-hadoop-mr-bundle" 
"hudi-hive-sync-bundle" "hudi-integ-test-bundle"
+"hudi-flink2.0-bundle" "hudi-flink2.1-bundle" "hudi-gcp-bundle" 
"hudi-hadoop-mr-bundle" "hudi-hive-sync-bundle" "hudi-integ-test-bundle"
 "hudi-kafka-connect-bundle" "hudi-metaserver-server-bundle" 
"hudi-presto-bundle"
 "hudi-spark3.3-bundle_2.12" "hudi-spark3.4-bundle_2.12" 
"hudi-spark3.5-bundle_2.12"
 "hudi-spark3.5-bundle_2.13" "hudi-spark4.0-bundle_2.13" 
"hudi-spark4.1-bundle_2.13" "hudi-timeline-server-bundle" "hudi-trino-bundle"
 "hudi-utilities-bundle_2.12" "hudi-utilities-bundle_2.13"
 "hudi-utilities-slim-bundle_2.12" "hudi-utilities-slim-bundle_2.13")
 
+MISSING_FILE=$(mktemp)
+export MISSING_FILE
+
 curl_with_url() {
     local url="$1"
-    if curl -s -o /dev/null --head --fail "$url"; then
-      echo "Artifact exists: $url"
+    if curl -s -o /dev/null --head --fail $CURL_AUTH "$url"; then
+      echo "  OK: $url"
     else
-      echo "Artifact missing: $url"
-      exit 1
+      echo "  MISSING: $url"
+      echo "$url" >> "$MISSING_FILE"
     fi
 }
 
 export -f curl_with_url
 
-NOW=$(date +%s)
-TMP_DIR_FOR_BUNDLES=/tmp/${NOW}
-mkdir "$TMP_DIR_FOR_BUNDLES"
-
 ALL_URLS=""
+TOTAL=0
 
 for bundle in "${bundles[@]}"
 do
@@ -65,15 +116,33 @@ do
    do
        url=${STAGING_REPO}/$bundle/${VERSION}/$bundle-${VERSION}$extension
        ALL_URLS+="$url\n"
+       TOTAL=$((TOTAL + 1))
    done
 done
 
-echo "-- All bundles to check:"
-echo -e "$ALL_URLS"
+echo "-- Checking $TOTAL artifacts ..."
+echo ""
+echo -e "$ALL_URLS" | xargs -n 1 -P 16 -I {} bash -c 'curl_with_url "{}"'
 
-if echo -e "$ALL_URLS" | xargs -n 1 -P 16 -I {} bash -c 'curl_with_url "{}"'; 
then
-  echo "All artifacts exist. Validation succeeds."
-else
-  echo "Some artifact(s) missing."
+MISSING_COUNT=0
+if [[ -s "$MISSING_FILE" ]]; then
+  MISSING_COUNT=$(wc -l < "$MISSING_FILE" | xargs)
+fi
+
+echo ""
+echo "==========================================="
+echo "Total: $TOTAL | Present: $((TOTAL - MISSING_COUNT)) | Missing: 
$MISSING_COUNT"
+echo "==========================================="
+
+if [[ "$MISSING_COUNT" -gt 0 ]]; then
+  echo ""
+  echo "Missing artifacts:"
+  sort "$MISSING_FILE" | while read -r url; do
+    echo "  $url"
+  done
+  rm -f "$MISSING_FILE"
   exit 1
+else
+  rm -f "$MISSING_FILE"
+  echo "All artifacts exist. Validation succeeds."
 fi

Reply via email to