From e99ff2f24fb0a2aaa9cec7def9dfba8e5f2f58ab Mon Sep 17 00:00:00 2001 From: Stuti Ravikiran Wali Date: Thu, 6 Aug 2026 19:31:10 +0530 Subject: [PATCH 1/6] Update create_wheel_wrapper.sh --- gha-script/create_wheel_wrapper.sh | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/gha-script/create_wheel_wrapper.sh b/gha-script/create_wheel_wrapper.sh index b6aa6e7fb5..f9824df24e 100644 --- a/gha-script/create_wheel_wrapper.sh +++ b/gha-script/create_wheel_wrapper.sh @@ -197,7 +197,7 @@ if [ -n "$TEMP_BUILD_SCRIPT_PATH" ]; then package_url=$(grep -oP '(?<=^PACKAGE_URL=).*' "$TEMP_BUILD_SCRIPT_PATH" | tr -d '"') package_name=$(basename "$package_url" .git) - source "$TEMP_BUILD_SCRIPT_PATH" "$EXTRA_ARGS" "$PYTHON_VERSION" + source "$TEMP_BUILD_SCRIPT_PATH" "$EXTRA_ARGS" fi # checking if wheel is generated through script itself @@ -389,31 +389,25 @@ echo echo "=== Post Processing wheel ${wheel_final} with SHA: ${SHA256_VALUE} ===" echo -# In PR builds ENABLE_CVE_SCAN=false and COS credentials are absent. -# Skip post-processing entirely - PRs only verify the wheel builds, not publish them. -if [ "${ENABLE_CVE_SCAN:-true}" = "false" ]; then +# Post-processing: license injection, IBM classifier, version suffix, RECORD update. +# Always runs. When COS credentials are absent (PR builds), post_process_wheel.py +# skips only suffix resolution and uses fallback suffix "ppc64le0" instead. +if python ${POST_PROCESS_SCRIPT_PATH} ${wheel_final} ${SHA256_VALUE}; then echo - echo "===> Skipping post-processing in PR build (ENABLE_CVE_SCAN=false)." + echo "===> SUCCESS: Wheel post-processed successfully." echo else - # post processing of wheels (Suffix addition, license addition, metadata addition) - if python ${POST_PROCESS_SCRIPT_PATH} ${wheel_final} ${SHA256_VALUE}; then - echo - echo "===> SUCCESS: Wheels post process successfully." - echo - else - echo - echo "===> ERROR: Failed to post process wheels." - echo - exit 1 - fi + echo + echo "===> ERROR: Failed to post-process wheel." + echo + exit 1 fi # CVE scan runs after post-processing so the report is named after the final # wheel filename (with +ppc64leN suffix) from the start - no rename needed. +# Controlled by ENABLE_CVE_SCAN (default: true). Set to false in PR builds. wheel_post_processed=(*.whl) -# Call run_cve_scan - comment out this block locally to skip CVE scanning. if [ "${ENABLE_CVE_SCAN:-true}" = "false" ]; then echo echo "===> Skipping CVE scan (ENABLE_CVE_SCAN=false)." From bc52ce74995635dab70bf47b38d721173e602900 Mon Sep 17 00:00:00 2001 From: Stuti Ravikiran Wali Date: Thu, 6 Aug 2026 19:31:42 +0530 Subject: [PATCH 2/6] Improve COS handling for PR builds Refactor COS client creation and suffix resolution logic for better handling of PR builds without credentials. --- gha-script/post_process_wheel.py | 45 ++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/gha-script/post_process_wheel.py b/gha-script/post_process_wheel.py index fc7bf1aa56..c1947bf8d2 100644 --- a/gha-script/post_process_wheel.py +++ b/gha-script/post_process_wheel.py @@ -43,18 +43,20 @@ logger = logging.getLogger(__name__) -# COS configuration -# These are only available in currency builds (not PR builds). -# If missing, post-processing is skipped gracefully. +# COS configuration — only available in currency builds. +# When absent, suffix resolution is skipped and PR_BUILD_FALLBACK_SUFFIX is used; +# all other post-processing steps (license injection, classifier, RECORD) still run. COS_API_KEY = os.environ.get("GHA_CURRENCY_SERVICE_ID_API_KEY", "") COS_SERVICE_INSTANCE_ID = os.environ.get("GHA_CURRENCY_SERVICE_ID", "") - -if not COS_API_KEY or not COS_SERVICE_INSTANCE_ID: - logger.info("COS credentials not set - skipping post-processing (PR build environment)") - sys.exit(0) COS_ENDPOINT = "https://s3.us.cloud-object-storage.appdomain.cloud" COS_BUCKET = "ose-power-artifacts-production" +# Suffix used in PR builds when COS credentials are absent and suffix +# resolution cannot be performed. "ppc64le0" is intentionally distinct +# from published suffixes (ppc64le1, ppc64le2, …) so it is never +# confused with a real release wheel. +PR_BUILD_FALLBACK_SUFFIX = "ppc64le0" + # License extraction utilities LICENSE_PATTERN = re.compile(r"^(LICENSE|COPYING)(\..*)?$") LICENSE_SEPARATOR = "----" # Hardcoded separator for both files @@ -407,7 +409,16 @@ def regenerate_record(extract_path, dist_info_dir): logger.exception(f"Failed to regenerate RECORD file → {e}") def resolve_suffix(client, package, version, wheel_name, wheel_sha256): - # Resolve a unique suffix for the wheel based on its name and local hash + # Resolve a unique suffix for the wheel based on its name and local hash. + # When client is None (PR build — no COS credentials), skip COS lookup + # and return PR_BUILD_FALLBACK_SUFFIX directly. + if client is None: + logger.info( + f"COS client not available (PR build) — skipping suffix resolution, " + f"using fallback suffix '{PR_BUILD_FALLBACK_SUFFIX}'" + ) + return PR_BUILD_FALLBACK_SUFFIX + try: logger.info(f"Resolving suffix for package={package}, version={version}, wheel={wheel_name}") parts = wheel_name[:-4].rsplit("-", 3) @@ -598,16 +609,22 @@ def main(): wheel_path = sys.argv[1] wheel_sha256 = sys.argv[2] - # Resolve suffix using COS wheel_name = os.path.basename(wheel_path) parts = wheel_name.split("-") package = parts[0] version = parts[1] - client = create_cos_client() - if client is None: - logger.error("COS client creation failed") - sys.exit(1) + # Create COS client only when credentials are available (currency builds). + # In PR builds credentials are absent — client stays None and resolve_suffix + # will return PR_BUILD_FALLBACK_SUFFIX without contacting COS. + if COS_API_KEY and COS_SERVICE_INSTANCE_ID: + client = create_cos_client() + if client is None: + logger.error("COS client creation failed") + sys.exit(1) + else: + logger.info("COS credentials not set — running in PR build mode (suffix resolution skipped)") + client = None suffix = resolve_suffix( client, @@ -616,7 +633,7 @@ def main(): wheel_name, wheel_sha256 ) - + new_wheel = process_wheel(wheel_path, suffix) if not new_wheel: logger.error("Wheel processing failed") From 51b4b052603f19f627ffbac9cd282794c3fdd66f Mon Sep 17 00:00:00 2001 From: Stuti Ravikiran Wali Date: Fri, 7 Aug 2026 16:04:15 +0530 Subject: [PATCH 3/6] Update create_wheel_wrapper.sh From cca01e96812b0c2af964143659f0844a5a3f2fba Mon Sep 17 00:00:00 2001 From: Stuti Ravikiran Wali Date: Fri, 7 Aug 2026 16:04:48 +0530 Subject: [PATCH 4/6] feat: run post-processing in PR builds, skip suffix addition without COS creds Updated suffix resolution logic to skip suffix addition in PR builds when COS credentials are absent. Improved logging for clarity on suffix processing. --- gha-script/post_process_wheel.py | 49 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/gha-script/post_process_wheel.py b/gha-script/post_process_wheel.py index c1947bf8d2..df49bf98ea 100644 --- a/gha-script/post_process_wheel.py +++ b/gha-script/post_process_wheel.py @@ -51,11 +51,6 @@ COS_ENDPOINT = "https://s3.us.cloud-object-storage.appdomain.cloud" COS_BUCKET = "ose-power-artifacts-production" -# Suffix used in PR builds when COS credentials are absent and suffix -# resolution cannot be performed. "ppc64le0" is intentionally distinct -# from published suffixes (ppc64le1, ppc64le2, …) so it is never -# confused with a real release wheel. -PR_BUILD_FALLBACK_SUFFIX = "ppc64le0" # License extraction utilities LICENSE_PATTERN = re.compile(r"^(LICENSE|COPYING)(\..*)?$") @@ -411,13 +406,13 @@ def regenerate_record(extract_path, dist_info_dir): def resolve_suffix(client, package, version, wheel_name, wheel_sha256): # Resolve a unique suffix for the wheel based on its name and local hash. # When client is None (PR build — no COS credentials), skip COS lookup - # and return PR_BUILD_FALLBACK_SUFFIX directly. + # and return None to signal that suffix addition should be skipped entirely. if client is None: logger.info( - f"COS client not available (PR build) — skipping suffix resolution, " - f"using fallback suffix '{PR_BUILD_FALLBACK_SUFFIX}'" + "COS client not available (PR build) — skipping suffix resolution, " + "no suffix will be added to the wheel." ) - return PR_BUILD_FALLBACK_SUFFIX + return None try: logger.info(f"Resolving suffix for package={package}, version={version}, wheel={wheel_name}") @@ -557,27 +552,31 @@ def process_wheel(wheel_path, suffix): if existing_license_files: update_record(dist_info, existing_license_files) - # Version suffix processing - old_version = read_version_from_metadata(dist_info) - - if old_version is None: - logger.error("Version not found in METADATA, cannot proceed") - sys.exit(1) - - new_version = build_new_version(old_version, suffix) - update_metadata_version(dist_info, new_version) - dist_info = rename_dist_info_dir(extract_path, old_version, new_version) - regenerate_record(extract_path, dist_info) + # Version suffix processing — skipped in PR builds (suffix is None). + if suffix is not None: + old_version = read_version_from_metadata(dist_info) + + if old_version is None: + logger.error("Version not found in METADATA, cannot proceed") + sys.exit(1) + + new_version = build_new_version(old_version, suffix) + update_metadata_version(dist_info, new_version) + dist_info = rename_dist_info_dir(extract_path, old_version, new_version) + regenerate_record(extract_path, dist_info) + else: + logger.info("Suffix addition skipped (PR build — no COS credentials).") # Pack wheel subprocess.run(["wheel", "pack", extract_path, "-d", wheel_dir], check=True) new_wheel_name = wheel_name - if "+" in old_version: - base, local = old_version.split("+", 1) - new_wheel_name = wheel_name.replace(f"{base}+{local}", f"{base}+{local}{suffix}", 1) - else: - new_wheel_name = wheel_name.replace(old_version, f"{old_version}+{suffix}", 1) + if suffix is not None and old_version is not None: + if "+" in old_version: + base, local = old_version.split("+", 1) + new_wheel_name = wheel_name.replace(f"{base}+{local}", f"{base}+{local}{suffix}", 1) + else: + new_wheel_name = wheel_name.replace(old_version, f"{old_version}+{suffix}", 1) new_wheel_path = os.path.join(wheel_dir, new_wheel_name) os.remove(wheel_path) From 3eef178be96c47bf632685d4d0851232a87ce242 Mon Sep 17 00:00:00 2001 From: Stuti Ravikiran Wali Date: Fri, 7 Aug 2026 17:48:54 +0530 Subject: [PATCH 5/6] Update create_wheel_wrapper.sh From 83100f48c6847ad27b13c484e00018979dda9daf Mon Sep 17 00:00:00 2001 From: Stuti Ravikiran Wali Date: Fri, 7 Aug 2026 17:49:14 +0530 Subject: [PATCH 6/6] Update post_process_wheel.py --- gha-script/post_process_wheel.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gha-script/post_process_wheel.py b/gha-script/post_process_wheel.py index df49bf98ea..0f3796d01a 100644 --- a/gha-script/post_process_wheel.py +++ b/gha-script/post_process_wheel.py @@ -579,7 +579,12 @@ def process_wheel(wheel_path, suffix): new_wheel_name = wheel_name.replace(old_version, f"{old_version}+{suffix}", 1) new_wheel_path = os.path.join(wheel_dir, new_wheel_name) - os.remove(wheel_path) + # Only remove the original when the repacked wheel has a different path + # (i.e. suffix was added). In PR builds the name is unchanged so + # wheel_path == new_wheel_path — the repacked file IS the original + # location and must not be deleted. + if new_wheel_path != wheel_path: + os.remove(wheel_path) logger.info("Processing wheel completed") return new_wheel_path except Exception as e: