diff --git a/.github/workflows/claim-pypi-name.yaml b/.github/workflows/claim-pypi-name.yaml new file mode 100644 index 0000000000000..052fb8a2d1137 --- /dev/null +++ b/.github/workflows/claim-pypi-name.yaml @@ -0,0 +1,49 @@ +# This workflow claims package names on PyPI for our integrations by publishing empty packages. +# The working packages can be found here: +# https://dd-integrations-core-wheels-build-stable.datadoghq.com/targets/simple/index.html +# This is a work-around until PyPI adds support for namespaces and we claim an entire namespace for Datadog. +name: Build Placeholder PyPI Packages + +on: + workflow_dispatch: + schedule: + # At 3AM UTC + # Running this every night strikes a good balance between claiming names fast without spamming PyPI with requests. + - cron: "0 3 * * *" + +defaults: + run: + shell: bash + + +jobs: + python-artifacts: + name: Build wheel + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + + - name: Install Build Deps + run: pip install -U build[virtualenv] hatchling + + - name: Build Packages + run: | + bash .github/workflows/scripts/build_placeholders.sh + + - name: Push Python artifacts to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + # We don't mind invalid metadata, we only want to claim the package name. + verify-metadata: false + verbose: true + # Only uploading the missing wheels makes this job idempotent and reduces its complexity. + skip-existing: true + user: __token__ + password: ${{ secrets.INTEGRATIONS_PYPI_NAME_CLAIM }} diff --git a/.github/workflows/scripts/build_placeholders.sh b/.github/workflows/scripts/build_placeholders.sh new file mode 100755 index 0000000000000..0ca5c907bb3c5 --- /dev/null +++ b/.github/workflows/scripts/build_placeholders.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +# Requires python 3.11+ (for tomllib) and the `build` package. +# Run this script from the root of the repo. +# The TL;DR of this script is: for every subdirectory with a pyproject.toml file we build an empty Python wheel. + +mkdir -p dist +mkdir -p pkg_placeholder +for file_or_subdir in *; do + if [[ -d "${file_or_subdir}" ]]; then + pyproject="${file_or_subdir}/pyproject.toml" + if [[ -f "${pyproject}" ]]; then + pypi_pkg_name=$(python -c "import tomllib, pathlib; contents = pathlib.Path('${pyproject}').read_text(); data = tomllib.loads(contents); print(data['project']['name'])") + # multiline strings are sensitive to indentation, so we must unindent the following command +cat < pkg_placeholder/pyproject.toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" +[project] +name = "${pypi_pkg_name}" +version = "0.0.1" +[tool.hatch.build.targets.wheel] +bypass-selection = true +EOF + # We only want wheels. + # We don't need build isolation because we'll trash the env anyway in CI. + # Skipping isolation speeds up the job. + python -m build --no-isolation --wheel pkg_placeholder + mv pkg_placeholder/dist/* dist/ + fi + fi +done