Files
TheRock/build_tools/github_actions/publish_rocm_to_release_buckets.py
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

356 lines
14 KiB
Python

#!/usr/bin/env python3
# Copyright Advanced Micro Devices, Inc.
# SPDX-License-Identifier: MIT
"""Publish ROCm release files from an artifacts bucket to release buckets.
These release file types are supported:
- [x] tarballs
- [x] python packages
- [x] native linux packages
- [ ] native windows packages
Example with ``--run-id 12345 --platform linux --release-type dev``:
tarballs:
s3://therock-dev-artifacts/12345-linux/tarballs/therock-dist-linux-gfx94X-dcgpu-7.10.0.tar.gz
-> s3://therock-dev-tarball/v4/tarball/therock-dist-linux-gfx94X-dcgpu-7.10.0.tar.gz
python (kpack split enabled, multi-arch):
s3://therock-dev-artifacts/12345-linux/python/rocm-7.13.0.tar.gz
s3://therock-dev-artifacts/12345-linux/python/rocm_sdk_core-7.13.0-py3-none-linux_x86_64.whl
s3://therock-dev-artifacts/12345-linux/python/rocm_sdk_device_gfx1100-7.13.0-py3-none-linux_x86_64.whl
s3://therock-dev-artifacts/12345-linux/python/rocm_sdk_libraries-7.13.0-py3-none-linux_x86_64.whl
-> s3://therock-dev-python/v4/whl/rocm-7.13.0.tar.gz
-> s3://therock-dev-python/v4/whl/rocm_sdk_core-7.13.0-py3-none-linux_x86_64.whl
-> s3://therock-dev-python/v4/whl/rocm_sdk_device_gfx1100-7.13.0-py3-none-linux_x86_64.whl
-> s3://therock-dev-python/v4/whl/rocm_sdk_libraries-7.13.0-py3-none-linux_x86_64.whl
native linux packages (dev/nightly):
s3://therock-dev-artifacts/12345-linux/packages/deb/
-> s3://therock-dev-packages/v4/deb/20250101-12345/
s3://therock-dev-artifacts/12345-linux/packages/rpm/
-> s3://therock-dev-packages/v4/rpm/20250101-12345/
native linux packages (prerelease):
s3://therock-prerelease-artifacts/12345-linux/packages/deb/
-> s3://therock-prerelease-packages/v4/packages/deb/
s3://therock-prerelease-artifacts/12345-linux/packages/rpm/
-> s3://therock-prerelease-packages/v4/packages/rpm/
ASAN build variant:
For ASAN builds (--build-variant asan), python packages are skipped and
tarballs/native packages are published to separate paths:
s3://therock-dev-artifacts/12345-linux/tarballs/
-> s3://therock-dev-tarball/v4/tarball-asan/
s3://therock-dev-artifacts/12345-linux/packages/deb/
-> s3://therock-dev-packages/v4/packages-asan/deb/20250101-12345/
s3://therock-dev-artifacts/12345-linux/packages/rpm/
-> s3://therock-dev-packages/v4/packages-asan/rpm/20250101-12345/
Test usage:
python build_tools/github_actions/publish_rocm_to_release_buckets.py \\
--run-id 12345 --platform linux --release-type dev --dry-run
"""
import argparse
import datetime
import logging
import platform as platform_module
import sys
from pathlib import Path
_BUILD_TOOLS_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(_BUILD_TOOLS_DIR))
from _therock_utils.s3_buckets import get_release_bucket_config
from _therock_utils.storage_backend import StorageBackend, create_storage_backend
from _therock_utils.storage_location import StorageLocation
from _therock_utils.python_package_paths import plan_key_copies
from _therock_utils.workflow_outputs import WorkflowOutputRoot
logger = logging.getLogger(__name__)
def publish_tarballs(
artifacts_root: WorkflowOutputRoot,
release_type: str,
backend: StorageBackend,
build_variant: str = "release",
) -> int:
"""Copy tarballs from the artifacts bucket to the release tarball bucket.
Example:
s3://therock-dev-artifacts/12345-linux/tarballs/
-> s3://therock-dev-tarball/v4/tarball/
ASAN example:
s3://therock-dev-artifacts/12345-linux/tarballs/
-> s3://therock-dev-tarball/v4/tarball-asan/
Returns:
Number of tarballs copied.
"""
source = artifacts_root.tarballs()
dest_bucket = get_release_bucket_config(release_type, "tarball")
dest_path = "v4/tarball-asan" if build_variant == "asan" else "v4/tarball"
dest = StorageLocation(dest_bucket.name, dest_path)
logger.info("Tarballs: %s -> %s", source.s3_uri, dest.s3_uri)
count = backend.copy_directory(source, dest, include=["*.tar.gz"])
logger.info("Copied %d tarballs", count)
if count == 0:
raise FileNotFoundError(f"No tarballs found at {source.s3_uri}")
def publish_python_packages(
artifacts_root: WorkflowOutputRoot,
release_type: str,
backend: StorageBackend,
kpack_split: bool,
structured: bool = False,
index: str = "whl",
) -> None:
"""Copy python packages from the artifacts bucket to the release python bucket.
The destination layout depends on kpack_split:
- kpack_split=False (per-family): publishes to both v3/whl-staging and
v3/whl. Test-gated promotion may later move wheels from staging to
release separately.
- kpack_split=True (multi-arch): publishes directly to v4/whl (no
staging index — tests run post-publish as a signal, not a gate).
Examples:
kpack split disabled (per-family subdirs):
s3://therock-dev-artifacts/12345-linux/python/gfx110X-all/*.whl
-> s3://therock-dev-python/v3/whl-staging/gfx110X-all/*.whl
-> s3://therock-dev-python/v3/whl/gfx110X-all/*.whl
kpack split enabled (flat):
s3://therock-dev-artifacts/12345-linux/python/*.whl
-> s3://therock-dev-python/v4/whl/*.whl
When ``structured`` is set (multi-arch only), packages are copied into
product-local package directories instead of the flat v4/whl prefix:
s3://therock-dev-artifacts/12345-linux/python/rocm_sdk_core-...whl
-> s3://therock-dev-python/v5/rocm/core/<index>/rocm-sdk-core/rocm_sdk_core-...whl
"""
source = artifacts_root.python_packages()
dest_bucket = get_release_bucket_config(release_type, "python")
if structured:
_publish_python_packages_structured(
source=source,
dest_bucket=dest_bucket.name,
backend=backend,
index=index,
)
return
if kpack_split:
# Multi-arch: publish directly (no staging index).
s3_subdirs = ["v4/whl"]
else:
# Per-family: publish to both staging and release.
s3_subdirs = ["v3/whl-staging", "v3/whl"]
for s3_subdir in s3_subdirs:
dest = StorageLocation(dest_bucket.name, s3_subdir)
logger.info("Python packages: %s -> %s", source.s3_uri, dest.s3_uri)
count = backend.copy_directory(source, dest, include=["*.whl", "*.tar.gz"])
logger.info("Copied %d python package files to %s", count, s3_subdir)
if count == 0:
raise FileNotFoundError(f"No python packages found at {source.s3_uri}")
def _publish_python_packages_structured(
source: StorageLocation,
dest_bucket: str,
backend: StorageBackend,
index: str,
) -> None:
"""Copy python packages into product-local package directories.
Lists the flat source prefix, then copies each accepted artifact into
``v5/rocm/core/<index>/<normalized-package>/<filename>`` so the structured
index generator can discover per-package directories.
"""
source_objects = backend.list_files(source, include=["*.whl", "*.tar.gz", "*.zip"])
plans = plan_key_copies(
source_keys=[obj.relative_path for obj in source_objects],
source_bucket=source.bucket,
dest_bucket=dest_bucket,
product="core",
index=index,
)
if not plans:
raise FileNotFoundError(f"No python packages found at {source.s3_uri}")
for plan in plans:
logger.info("Python package: %s -> %s", plan.source.s3_uri, plan.dest.s3_uri)
backend.copy_file(plan.source, plan.dest)
logger.info("Copied %d python package files (structured)", len(plans))
def publish_native_linux_packages(
artifacts_root: WorkflowOutputRoot,
release_type: str,
backend: StorageBackend,
build_variant: str = "release",
) -> None:
"""Copy native Linux packages from the artifacts bucket to the release packages bucket.
The source packages were uploaded by upload_package_repo.py (called from
multi_arch_build_native_linux_packages.yml) and already include repodata
(Packages/Release files for deb, repodata/ for rpm).
dev/nightly example:
s3://therock-dev-artifacts/12345-linux/packages/deb/
-> s3://therock-dev-packages/v4/deb/20250101-12345/
s3://therock-dev-artifacts/12345-linux/packages/rpm/
-> s3://therock-dev-packages/v4/rpm/20250101-12345/
prerelease example:
s3://therock-prerelease-artifacts/12345-linux/packages/deb/
-> s3://therock-prerelease-packages/v4/packages/deb/
s3://therock-prerelease-artifacts/12345-linux/packages/rpm/
-> s3://therock-prerelease-packages/v4/packages/rpm/
asan example:
s3://therock-dev-artifacts/12345-linux/packages/deb/
-> s3://therock-dev-packages/v4/packages-asan/deb/20250101-12345/
s3://therock-dev-artifacts/12345-linux/packages/rpm/
-> s3://therock-dev-packages/v4/packages-asan/rpm/20250101-12345/
Note (prerelease): This is a plain copy — the repodata already present in the
packages bucket is overwritten with the repodata from this run. If multiple
prerelease runs upload packages to the same fixed prefix, earlier packages
will no longer be referenced by the repodata.
TODO: Implement a proper repodata merge for the prerelease case, similar to
the merge logic in upload_package_repo.py (regenerate_repo_metadata_from_s3).
"""
dest_bucket = get_release_bucket_config(release_type, "packages")
today = datetime.date.today().strftime("%Y%m%d")
is_asan = build_variant == "asan"
for pkg_type in ["deb", "rpm"]:
source = artifacts_root.native_linux_packages(pkg_type)
# Determine base path (asan vs non-asan, prerelease vs dated)
# prerelease: v4/packages/{pkg_type} or v4/packages-asan/{pkg_type}
# non-prerelease: v4/{pkg_type}/{dated} or v4/packages-asan/{pkg_type}/{dated}
if is_asan:
base_path = "v4/packages-asan"
else:
base_path = "v4/packages" if release_type == "prerelease" else "v4"
if release_type == "prerelease":
dest_prefix = f"{base_path}/{pkg_type}"
else:
dest_prefix = f"{base_path}/{pkg_type}/{today}-{artifacts_root.run_id}"
dest = StorageLocation(dest_bucket.name, dest_prefix)
logger.info(
"Native %s packages: %s -> %s", pkg_type, source.s3_uri, dest.s3_uri
)
count = backend.copy_directory(source, dest)
logger.info("Copied %d files for %s packages", count, pkg_type)
if count == 0:
raise FileNotFoundError(f"No {pkg_type} packages found at {source.s3_uri}")
def main(argv: list[str]) -> None:
parser = argparse.ArgumentParser(
description="Publish ROCm release files to release buckets"
)
parser.add_argument("--run-id", required=True, help="Source workflow run ID")
parser.add_argument(
"--platform",
default=platform_module.system().lower(),
choices=["linux", "windows"],
help="Platform (default: current system)",
)
parser.add_argument(
"--release-type",
required=True,
choices=["dev", "nightly", "prerelease"],
help="Release type (determines source and destination buckets)",
)
# String "true"/"false" because GitHub Actions outputs are strings.
parser.add_argument(
"--kpack-split",
default="false",
help='Whether kpack split is enabled ("true" or "false")',
)
parser.add_argument(
"--structured",
action="store_true",
help="Publish python packages into product-local package directories "
"(v5/rocm/core/<index>/<package>/) instead of the flat v4/whl prefix. "
"Multi-arch (--kpack-split true) only.",
)
parser.add_argument(
"--python-index",
default="whl",
choices=["whl", "whl-next"],
help="Product-local index name for structured Python publishing "
"(default: whl). Selects the v5/rocm/core/<index>/ path segment.",
)
parser.add_argument(
"--skip-native-packages",
action="store_true",
help="Skip publishing native Linux packages (deb/rpm)",
)
parser.add_argument(
"--dry-run", action="store_true", help="Print plan without copying"
)
parser.add_argument(
"--build-variant",
default="release",
choices=["release", "asan"],
help="Build variant (default: release). ASAN builds skip python packages "
"and publish native packages to separate paths.",
)
args = parser.parse_args(argv)
kpack_split = args.kpack_split.lower() == "true"
if args.structured and not kpack_split:
parser.error("--structured requires --kpack-split true (multi-arch only)")
artifacts_root = WorkflowOutputRoot.from_workflow_run(
run_id=args.run_id, platform=args.platform, release_type=args.release_type
)
backend = create_storage_backend(dry_run=args.dry_run)
is_asan = args.build_variant == "asan"
publish_tarballs(artifacts_root, args.release_type, backend, args.build_variant)
if not is_asan:
publish_python_packages(
artifacts_root,
args.release_type,
backend,
kpack_split,
structured=args.structured,
index=args.python_index,
)
else:
logger.info("Skipping python packages for ASAN build variant")
if artifacts_root.platform == "linux" and not args.skip_native_packages:
publish_native_linux_packages(
artifacts_root, args.release_type, backend, args.build_variant
)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
main(sys.argv[1:])