From 03405c6589130775bc468fb512f61f59d56ebf71 Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 10:10:02 -0700 Subject: [PATCH 01/14] use serverless-specific wheel in layer --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ab1f603159c..6f17d6aa458 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -121,7 +121,7 @@ serverless lambda tests: trigger: project: DataDog/datadog-lambda-python strategy: depend - branch: main + branch: emmett.butler/serverless-wheels needs: - job: "upload manylinux2014" rules: From c3e21bacdbbd4ccb35089947bba8a17c8f5eaf78 Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 10:47:11 -0700 Subject: [PATCH 02/14] validate serverless wheels --- .gitlab/validate-ddtrace-package.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index c5613abac79..60a68a284bf 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -47,6 +47,8 @@ def build_expected_set(version: str) -> set[tuple[str, str, str]]: for py_tag in PYTHON_TAGS: for platform in BASE_PLATFORMS: expected.add((version, py_tag, platform, "")) + for platform in SERVERLESS_PLATFORMS: + expected.add((version, py_tag, platform, "_serverless")) # Add win_arm64 for Python 3.11+ if py_tag in WIN_ARM64_PYTHON_TAGS: expected.add((version, py_tag, "win_arm64", "")) @@ -55,7 +57,7 @@ def build_expected_set(version: str) -> set[tuple[str, str, str]]: def reconstruct_wheel_filename(version: str, python_tag: str, platform: str, flavor: str) -> str: """Reconstruct wheel filename from components.""" - package_name = f"ddtrace{flavor.replace('-', '_')}" + package_name = f"ddtrace{flavor}" return f"{package_name}-{version}-{python_tag}-{python_tag}-{platform}.whl" @@ -101,7 +103,7 @@ def parse_actual_wheels(wheels_dir: str) -> tuple[set[tuple[str, str, str, str]] for wheel_file in sorted(Path(wheels_dir).glob("*.whl")): try: name, version, build, tags = parse_wheel_filename(wheel_file.name) - flavor = name.replace("ddtrace", "").replace("_", "-") + flavor = name.replace("ddtrace", "") # Extract python tag - all tags should have the same interpreter py_tag = next(iter(tags)).interpreter From 1f834ad19a30cf916df0a81fce45b6d1bfd46379 Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 11:20:49 -0700 Subject: [PATCH 03/14] dont rm --- .gitlab/release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab/release.yml b/.gitlab/release.yml index 47d5b4702d6..7f5957ab287 100644 --- a/.gitlab/release.yml +++ b/.gitlab/release.yml @@ -26,8 +26,7 @@ variables: - pip install -r ci/requirements/ci.txt - python -m twine check --strict pywheels/* script: - - rm -rf pywheels/ddtrace_serverless* - - python -m twine upload --repository ${PYPI_REPOSITORY} pywheels/* + - python -m twine upload --repository ${PYPI_REPOSITORY} pywheels/ddtrace-* artifacts: paths: - pywheels/*.whl From acd9d6a59308300acb4c1f50c772bdf85dcd2688 Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 11:59:24 -0700 Subject: [PATCH 04/14] depend on build linux serverless --- .gitlab/package.yml | 1 + .gitlab/scripts/build-wheel-helpers.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitlab/package.yml b/.gitlab/package.yml index 406d786eb3f..d3d7474fbfe 100644 --- a/.gitlab/package.yml +++ b/.gitlab/package.yml @@ -384,6 +384,7 @@ download_dependency_wheels: stage: package needs: - "build linux" + - "build linux serverless" - "build macos" - "build sdist" - "collect windows wheels" diff --git a/.gitlab/scripts/build-wheel-helpers.sh b/.gitlab/scripts/build-wheel-helpers.sh index e4676c8c9b8..dc3bee8017f 100755 --- a/.gitlab/scripts/build-wheel-helpers.sh +++ b/.gitlab/scripts/build-wheel-helpers.sh @@ -136,6 +136,7 @@ finalize() { export TMP_WHEEL_FILE=$(ls ${TMP_WHEEL_DIR}/*.whl | head -n 1) WHEEL_BASENAME=$(basename "${TMP_WHEEL_FILE}") mv "${TMP_WHEEL_FILE}" "${FINAL_WHEEL_DIR}/" + ls -al "${FINAL_WHEEL_DIR}" export FINAL_WHEEL_FILE="${FINAL_WHEEL_DIR}/${WHEEL_BASENAME}" section_end "finalize_wheel" } From e1d47ddabfc4092ed714e31c6b92051e021137d1 Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 13:23:50 -0700 Subject: [PATCH 05/14] separate jobs to avoid size limit --- .gitlab/package.yml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/.gitlab/package.yml b/.gitlab/package.yml index d3d7474fbfe..f0635e3c886 100644 --- a/.gitlab/package.yml +++ b/.gitlab/package.yml @@ -378,17 +378,10 @@ download_dependency_wheels: - "pywheels/*.whl" # Aggregate and validate all built wheels -"ddtrace package": +.package_base: image: registry.ddbuild.io/images/mirror/python:3.14.0 tags: [ "arch:amd64" ] stage: package - needs: - - "build linux" - - "build linux serverless" - - "build macos" - - "build sdist" - - "collect windows wheels" - - "package version" script: - pip install 'packaging>=24.0,<26' # ci-deps: allow - .gitlab/validate-ddtrace-package.py pywheels @@ -396,3 +389,18 @@ download_dependency_wheels: paths: - "pywheels/*.whl" - "pywheels/*.tar.gz" + +"ddtrace package": + extends: .package_base + needs: + - "build linux" + - "build macos" + - "build sdist" + - "collect windows wheels" + - "package version" + +"ddtrace package serverless": + extends: .package_base + needs: + - "build linux serverless" + - "package version" From c95a8d5ea88d7fb8fa21320f9163e306fbcc71cd Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 13:39:37 -0700 Subject: [PATCH 06/14] debug output --- .gitlab/validate-ddtrace-package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index 60a68a284bf..bca1b3d2e6c 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -116,7 +116,7 @@ def parse_actual_wheels(wheels_dir: str) -> tuple[set[tuple[str, str, str, str]] if marker in wheel_base: platform = wheel_base.split(marker)[1] else: - raise ValueError(f"Cannot parse platform from {wheel_file.name}") + raise ValueError(f"Cannot parse platform from {wheel_file.name} - searched for marker {marker}") actual.add((str(version), py_tag, platform, flavor)) except Exception as e: From 40d9399defa70c7ccb64c1ad006a004110a5ac1c Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 13:59:42 -0700 Subject: [PATCH 07/14] underscore issue --- .gitlab/validate-ddtrace-package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index bca1b3d2e6c..d58d5d10783 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -112,7 +112,7 @@ def parse_actual_wheels(wheels_dir: str) -> tuple[set[tuple[str, str, str, str]] # We know: name=ddtrace, abi=python tag (e.g., cp310) # So platform is everything after: ddtrace-{version}-{python}-{python}- wheel_base = wheel_file.name.replace(".whl", "") - marker = f"{name}-{version}-{py_tag}-{py_tag}-" + marker = f"{name.replace('-', '_')}-{version}-{py_tag}-{py_tag}-" if marker in wheel_base: platform = wheel_base.split(marker)[1] else: From 19f665cf70b46bde93acdd913f7797e232fd6e9f Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 14:30:58 -0700 Subject: [PATCH 08/14] another hyphen thing --- .gitlab/validate-ddtrace-package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index d58d5d10783..42ab0e740f5 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -48,7 +48,7 @@ def build_expected_set(version: str) -> set[tuple[str, str, str]]: for platform in BASE_PLATFORMS: expected.add((version, py_tag, platform, "")) for platform in SERVERLESS_PLATFORMS: - expected.add((version, py_tag, platform, "_serverless")) + expected.add((version, py_tag, platform, "-serverless")) # Add win_arm64 for Python 3.11+ if py_tag in WIN_ARM64_PYTHON_TAGS: expected.add((version, py_tag, "win_arm64", "")) @@ -112,7 +112,7 @@ def parse_actual_wheels(wheels_dir: str) -> tuple[set[tuple[str, str, str, str]] # We know: name=ddtrace, abi=python tag (e.g., cp310) # So platform is everything after: ddtrace-{version}-{python}-{python}- wheel_base = wheel_file.name.replace(".whl", "") - marker = f"{name.replace('-', '_')}-{version}-{py_tag}-{py_tag}-" + marker = f"{name}-{version}-{py_tag}-{py_tag}-" if marker in wheel_base: platform = wheel_base.split(marker)[1] else: From ac29319ddc562fcd23f3f3454c537f802e3d39ab Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 14:45:33 -0700 Subject: [PATCH 09/14] ugh --- .gitlab/validate-ddtrace-package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index 42ab0e740f5..d58d5d10783 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -48,7 +48,7 @@ def build_expected_set(version: str) -> set[tuple[str, str, str]]: for platform in BASE_PLATFORMS: expected.add((version, py_tag, platform, "")) for platform in SERVERLESS_PLATFORMS: - expected.add((version, py_tag, platform, "-serverless")) + expected.add((version, py_tag, platform, "_serverless")) # Add win_arm64 for Python 3.11+ if py_tag in WIN_ARM64_PYTHON_TAGS: expected.add((version, py_tag, "win_arm64", "")) @@ -112,7 +112,7 @@ def parse_actual_wheels(wheels_dir: str) -> tuple[set[tuple[str, str, str, str]] # We know: name=ddtrace, abi=python tag (e.g., cp310) # So platform is everything after: ddtrace-{version}-{python}-{python}- wheel_base = wheel_file.name.replace(".whl", "") - marker = f"{name}-{version}-{py_tag}-{py_tag}-" + marker = f"{name.replace('-', '_')}-{version}-{py_tag}-{py_tag}-" if marker in wheel_base: platform = wheel_base.split(marker)[1] else: From d3903dfb4ea9af4b42cd5c15965f7edaafad4a01 Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 15:00:02 -0700 Subject: [PATCH 10/14] only serverless, for testing --- .gitlab/validate-ddtrace-package.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index d58d5d10783..08fef05fe1a 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -45,13 +45,13 @@ def build_expected_set(version: str) -> set[tuple[str, str, str]]: """Build set of expected (version, python_tag, platform, flavor) tuples.""" expected: set[tuple[str, str, str, str]] = set() for py_tag in PYTHON_TAGS: - for platform in BASE_PLATFORMS: - expected.add((version, py_tag, platform, "")) + #for platform in BASE_PLATFORMS: + # expected.add((version, py_tag, platform, "")) for platform in SERVERLESS_PLATFORMS: expected.add((version, py_tag, platform, "_serverless")) # Add win_arm64 for Python 3.11+ - if py_tag in WIN_ARM64_PYTHON_TAGS: - expected.add((version, py_tag, "win_arm64", "")) + #if py_tag in WIN_ARM64_PYTHON_TAGS: + # expected.add((version, py_tag, "win_arm64", "")) return expected @@ -103,7 +103,6 @@ def parse_actual_wheels(wheels_dir: str) -> tuple[set[tuple[str, str, str, str]] for wheel_file in sorted(Path(wheels_dir).glob("*.whl")): try: name, version, build, tags = parse_wheel_filename(wheel_file.name) - flavor = name.replace("ddtrace", "") # Extract python tag - all tags should have the same interpreter py_tag = next(iter(tags)).interpreter @@ -118,6 +117,7 @@ def parse_actual_wheels(wheels_dir: str) -> tuple[set[tuple[str, str, str, str]] else: raise ValueError(f"Cannot parse platform from {wheel_file.name} - searched for marker {marker}") + flavor = name.replace("ddtrace", "").replace("-", "_") actual.add((str(version), py_tag, platform, flavor)) except Exception as e: errors.append(f"{wheel_file.name}: {e}") From de4be0dca1ba117ddd703681f34cf17047577ec4 Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 15:10:39 -0700 Subject: [PATCH 11/14] lint --- .gitlab/validate-ddtrace-package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index 08fef05fe1a..a1b53454b30 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -45,12 +45,12 @@ def build_expected_set(version: str) -> set[tuple[str, str, str]]: """Build set of expected (version, python_tag, platform, flavor) tuples.""" expected: set[tuple[str, str, str, str]] = set() for py_tag in PYTHON_TAGS: - #for platform in BASE_PLATFORMS: + # for platform in BASE_PLATFORMS: # expected.add((version, py_tag, platform, "")) for platform in SERVERLESS_PLATFORMS: expected.add((version, py_tag, platform, "_serverless")) # Add win_arm64 for Python 3.11+ - #if py_tag in WIN_ARM64_PYTHON_TAGS: + # if py_tag in WIN_ARM64_PYTHON_TAGS: # expected.add((version, py_tag, "win_arm64", "")) return expected From a52ee165a8729268106cb1ae7f5b89f32e7f9a4d Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 15:46:23 -0700 Subject: [PATCH 12/14] make a serverless validation mode --- .gitlab/package.yml | 7 +++- .gitlab/validate-ddtrace-package.py | 53 ++++++++++++++++------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/.gitlab/package.yml b/.gitlab/package.yml index f0635e3c886..e19bb8257fd 100644 --- a/.gitlab/package.yml +++ b/.gitlab/package.yml @@ -384,7 +384,6 @@ download_dependency_wheels: stage: package script: - pip install 'packaging>=24.0,<26' # ci-deps: allow - - .gitlab/validate-ddtrace-package.py pywheels artifacts: paths: - "pywheels/*.whl" @@ -398,9 +397,15 @@ download_dependency_wheels: - "build sdist" - "collect windows wheels" - "package version" + script: + - !reference [.package_base, script] + - .gitlab/validate-ddtrace-package.py pywheels "ddtrace package serverless": extends: .package_base needs: - "build linux serverless" - "package version" + script: + - !reference [.package_base, script] + - .gitlab/validate-ddtrace-package.py pywheels --mode=serverless diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index a1b53454b30..fb21cd14fb9 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -20,6 +20,7 @@ from pathlib import Path import sys +import argparse from packaging.utils import parse_sdist_filename from packaging.utils import parse_wheel_filename @@ -41,17 +42,19 @@ SERVERLESS_PLATFORMS = [p for p in BASE_PLATFORMS if "linux" in p] -def build_expected_set(version: str) -> set[tuple[str, str, str]]: +def build_expected_set(version: str, args: argparse.Namespace) -> set[tuple[str, str, str]]: """Build set of expected (version, python_tag, platform, flavor) tuples.""" expected: set[tuple[str, str, str, str]] = set() for py_tag in PYTHON_TAGS: - # for platform in BASE_PLATFORMS: - # expected.add((version, py_tag, platform, "")) - for platform in SERVERLESS_PLATFORMS: - expected.add((version, py_tag, platform, "_serverless")) - # Add win_arm64 for Python 3.11+ - # if py_tag in WIN_ARM64_PYTHON_TAGS: - # expected.add((version, py_tag, "win_arm64", "")) + if args.mode == "serverless": + for platform in SERVERLESS_PLATFORMS: + expected.add((version, py_tag, platform, "_serverless")) + else: + for platform in BASE_PLATFORMS: + expected.add((version, py_tag, platform, "")) + # Add win_arm64 for Python 3.11+ + if py_tag in WIN_ARM64_PYTHON_TAGS: + expected.add((version, py_tag, "win_arm64", "")) return expected @@ -137,12 +140,9 @@ def identify_version_mismatches( return mismatches -def main() -> None: - """Main validation function.""" - # Get arguments - wheels_dir = sys.argv[1] if len(sys.argv) > 1 else "pywheels" +def main(args: argparse.Namespace) -> None: + wheels_dir = args.wheels_dir - # Get version from environment package_version: str | None = os.environ.get("PACKAGE_VERSION") if not package_version: print("[ERROR] PACKAGE_VERSION not set. Ensure 'package version' job ran.") @@ -169,15 +169,16 @@ def main() -> None: print() # Phase 2: SDist Validation - print("[Phase 2] SDist Validation") - sdist_ok, sdist_msg, sdist_name = validate_sdist(wheels_dir, package_version) - if not sdist_ok: - print(f"✗ {sdist_msg}") - errors.append(f"SDist validation: {sdist_msg}") - else: - print(f"✓ Found sdist: {sdist_name}") - print(f"✓ {sdist_msg}") - print() + if mode != "serverless": + print("[Phase 2] SDist Validation") + sdist_ok, sdist_msg, sdist_name = validate_sdist(wheels_dir, package_version) + if not sdist_ok: + print(f"✗ {sdist_msg}") + errors.append(f"SDist validation: {sdist_msg}") + else: + print(f"✓ Found sdist: {sdist_name}") + print(f"✓ {sdist_msg}") + print() # Phase 3: Parse Actual Wheels print("[Phase 3] Parsing Actual Wheels") @@ -196,7 +197,7 @@ def main() -> None: # Phase 4: Build Expected Set print("[Phase 4] Building Expected Set") - expected_set = build_expected_set(package_version) + expected_set = build_expected_set(package_version, args) print(f"Expected {len(expected_set)} wheels:") print(f" - {len(PYTHON_TAGS)} Python versions (cp39-cp314)") print(f" - {len(BASE_PLATFORMS)} base platforms") @@ -283,4 +284,8 @@ def main() -> None: if __name__ == "__main__": - main() + parser = argparse.ArgumentParser(prog="Validate DDTrace Package") + parser.add_argument("--mode", choices=["main", "serverless"], default="main") + parser.add_argument("wheels_dir", nargs="?", default="pywheels") + args = parser.parse_args() + main(args) From 3fb712c990ec9e9e2716a47c2611a15b447d1cf3 Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 15:52:04 -0700 Subject: [PATCH 13/14] lint --- .gitlab/validate-ddtrace-package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index fb21cd14fb9..bb072055cc5 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -16,11 +16,11 @@ PACKAGE_VERSION: Version from pyproject.toml (set by "package version" job) """ +import argparse import os from pathlib import Path import sys -import argparse from packaging.utils import parse_sdist_filename from packaging.utils import parse_wheel_filename @@ -169,7 +169,7 @@ def main(args: argparse.Namespace) -> None: print() # Phase 2: SDist Validation - if mode != "serverless": + if args.mode != "serverless": print("[Phase 2] SDist Validation") sdist_ok, sdist_msg, sdist_name = validate_sdist(wheels_dir, package_version) if not sdist_ok: From b667d1e88afd7ed3a4285e95aa2b77b7776982df Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Mon, 30 Mar 2026 16:03:05 -0700 Subject: [PATCH 14/14] missing variable --- .gitlab/validate-ddtrace-package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab/validate-ddtrace-package.py b/.gitlab/validate-ddtrace-package.py index bb072055cc5..6ef5c304963 100755 --- a/.gitlab/validate-ddtrace-package.py +++ b/.gitlab/validate-ddtrace-package.py @@ -169,6 +169,7 @@ def main(args: argparse.Namespace) -> None: print() # Phase 2: SDist Validation + sdist_ok = False if args.mode != "serverless": print("[Phase 2] SDist Validation") sdist_ok, sdist_msg, sdist_name = validate_sdist(wheels_dir, package_version)