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)." diff --git a/gha-script/post_process_wheel.py b/gha-script/post_process_wheel.py index fc7bf1aa56..d78a2d6840 100644 --- a/gha-script/post_process_wheel.py +++ b/gha-script/post_process_wheel.py @@ -43,18 +43,15 @@ 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" + # License extraction utilities LICENSE_PATTERN = re.compile(r"^(LICENSE|COPYING)(\..*)?$") LICENSE_SEPARATOR = "----" # Hardcoded separator for both files @@ -407,7 +404,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 None to signal that suffix addition should be skipped entirely. + if client is None: + logger.info( + "COS client not available (PR build) — skipping suffix resolution, " + "no suffix will be added to the wheel." + ) + return None + try: logger.info(f"Resolving suffix for package={package}, version={version}, wheel={wheel_name}") parts = wheel_name[:-4].rsplit("-", 3) @@ -498,7 +504,9 @@ def inject_classifier(dist_info): def process_wheel(wheel_path, suffix): try: logger.info(f"Processing wheel: {wheel_path} with suffix: {suffix}") - wheel_dir = os.path.dirname(wheel_path) + # os.path.dirname of a bare filename returns ""; normalise to "." so + # that "wheel pack -d " and os.path.join produce consistent paths. + wheel_dir = os.path.dirname(wheel_path) or "." wheel_name = os.path.basename(wheel_path) with tempfile.TemporaryDirectory() as tmpdir: @@ -546,30 +554,39 @@ 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) + # Only remove the original when the repacked wheel is a genuinely + # different file (suffix was added → new filename). Use abspath so + # that "foo.whl" and "./foo.whl" compare as equal and we never + # accidentally delete the freshly repacked wheel in PR builds. + if os.path.abspath(new_wheel_path) != os.path.abspath(wheel_path): + os.remove(wheel_path) logger.info("Processing wheel completed") return new_wheel_path except Exception as e: @@ -598,16 +615,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 +639,7 @@ def main(): wheel_name, wheel_sha256 ) - + new_wheel = process_wheel(wheel_path, suffix) if not new_wheel: logger.error("Wheel processing failed")