Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .builders/images/macos/pbs.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Python Build Standalone (PBS) pins for macOS in resolve-build-deps.
# https://astral.sh/blog/python-build-standalone
# Sourced by .github/workflows/resolve-build-deps.yaml (set -a; source ...).
PYTHON_PATCH=13
PBS_RELEASE=20260414
PBS_SHA256__aarch64=874f9931ad40dcce38caf6f408aa7e10ec3d0dfce2184ba7af62a965a66b9cd9
PBS_SHA256__x86_64=d34198cd856fa80ebf3aa821fe329a25fab66eeda44f72ac9576591282e31bb7
6 changes: 3 additions & 3 deletions .deps/builder_inputs.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
# Hash inputs are defined in .builders/inputs_hash.py (SHARED_INPUTS,
# RESOLUTION_INPUTS).
[resolution]
hash = "8c7602cb4a1ade5ad9eefb7f68259196cb602e88e38261963e834a8349582a7e"
hash = "40ceb658e7d65a76d01feb8c9d759dd7b3099d774c6053f324cd1e4568f47f61"

[images]
linux-aarch64 = "9a455bfa1c898dae1a1aa826dbed31b20da25e226a7d66e18782cb5b4bfc6e43"
linux-x86_64 = "0aad766c48c9fbc4efa30fbfe9c7791e41f5477f0fd9f236e4edb79e3bf74868"
macos-aarch64 = "bd20131cfae81eed46998431117e50a724744679c959a6d9648ca63dd4d3bfdc"
macos-x86_64 = "37e8f1ef74292fb9f2df305603aa991121d35162d47eba98fcbd46e458f7dc54"
macos-aarch64 = "9eac354aa84ad8e38ec4f6f1b782d5041f1cde8a348272999f55113432a39630"
macos-x86_64 = "77e0bd14eb2a07aeed9737de46b86eb86cf8e7a90189409d2f13f3566ab306eb"
windows-x86_64 = "41c9c460a4c72a0e48d825f00cfd27f2d1e54598400eb5aa0918e7e8cf646a9c"
50 changes: 25 additions & 25 deletions .deps/resolved/linux-aarch64_3.13.txt

Large diffs are not rendered by default.

44 changes: 22 additions & 22 deletions .deps/resolved/linux-x86_64_3.13.txt

Large diffs are not rendered by default.

38 changes: 19 additions & 19 deletions .deps/resolved/macos-aarch64_3.13.txt

Large diffs are not rendered by default.

38 changes: 19 additions & 19 deletions .deps/resolved/macos-x86_64_3.13.txt

Large diffs are not rendered by default.

42 changes: 21 additions & 21 deletions .deps/resolved/windows-x86_64_3.13.txt

Large diffs are not rendered by default.

29 changes: 14 additions & 15 deletions .github/workflows/resolve-build-deps.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -276,26 +276,26 @@ jobs:
brew remove --force --ignore-dependencies $(brew list --formula)
brew install coreutils

- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Python
# Use PBS as suggested by: https://github.com/DataDog/integrations-core/pull/21692#pullrequestreview-3358660684
# PBS stands for "Python Build Standalone": https://astral.sh/blog/python-build-standalone
env:
PYTHON_PATCH: 13
PBS_RELEASE: 20260414
PBS_SHA256__aarch64: 874f9931ad40dcce38caf6f408aa7e10ec3d0dfce2184ba7af62a965a66b9cd9
PBS_SHA256__x86_64: d34198cd856fa80ebf3aa821fe329a25fab66eeda44f72ac9576591282e31bb7
# PBS pins live in .builders/images/macos/pbs.env so they enter inputs_hash per-target
# digests (images/macos/**/*) and invalidate ~/builder_root cache on bump.
# https://github.com/DataDog/integrations-core/pull/21692#pullrequestreview-3358660684
run: |
set -u
set -euo pipefail
set -a
# shellcheck disable=SC1091
source .builders/images/macos/pbs.env
set +a
curl -fsSL -o pbs.tgz "https://github.com/astral-sh/python-build-standalone/releases/download/$PBS_RELEASE/cpython-$PYTHON_VERSION.$PYTHON_PATCH+$PBS_RELEASE-${{ matrix.job.arch }}-apple-darwin-install_only_stripped.tar.gz"
echo "$PBS_SHA256__${{ matrix.job.arch }} *pbs.tgz" | shasum -a 256 -c -
prefix=$(dirname "$(dirname "$DD_PYTHON3")")
sudo mkdir -p "$prefix"
sudo tar -xzf pbs.tgz -C "$prefix" --strip-components=1
rm pbs.tgz

- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Download dependency constraints
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
Expand All @@ -312,10 +312,9 @@ jobs:
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: ~/builder_root
# The gate already content-hashes every file that influences this build
# (per-target images, shared images, deps, build.py, the workflow file).
# Using its hash as the cache key removes the duplicate hashFiles list
# and makes drift between the gate and the cache key unrepresentable.
# matrix.job.hash content-hashes per-target .builders/ inputs (including
# images/macos/**/*, so pbs.env participates). Using it as the cache key
# keeps the gate and Actions cache aligned.
key: ${{ matrix.job.image }}-deps-builder-root-cache-${{ matrix.job.hash }}

- name: Run the build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/upgrade-python-version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ jobs:
### Changes
- Updated `PYTHON_VERSION_FULL` in `ddev/src/ddev/repo/constants.py`
- Updated Python version in `.builders/images/*/Dockerfile` (Linux and Windows)
- Updated Python version in `.github/workflows/resolve-build-deps.yaml` (macOS)
- Updated PBS pins in `.builders/images/macos/pbs.env` (macOS)
- Updated SHA256 hashes for Python artifacts
### Review checklist (to be filled by reviewers)
Expand Down
30 changes: 16 additions & 14 deletions ddev/src/ddev/cli/meta/scripts/upgrade_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def upgrade_python_version(app: Application):
and updates version references across:
- ddev/src/ddev/repo/constants.py
- .builders/images/*/Dockerfile (Linux and Windows)
- .github/workflows/resolve-build-deps.yaml (macOS)
- .builders/images/macos/pbs.env (macOS PBS / Python patch)

\b
`$ ddev meta scripts upgrade-python-version`
Expand Down Expand Up @@ -255,13 +255,14 @@ def apply_substitution(pattern: re.Pattern, replace_func, error_msg: str, _docke

def upgrade_macos_python_version(app: Application, new_version: str, tracker: ValidationTracker):
"""
Update macOS Python version in the workflow file.
Update macOS PBS pins used by resolve-build-deps.

The workflow uses Python Build Standalone (PBS) from Astral. Updates PYTHON_PATCH,
PBS_RELEASE, and the SHA256 hashes for both macOS architectures.
CI installs Python from Python Build Standalone (PBS) on macOS. Pins live in
``.builders/images/macos/pbs.env`` so they participate in inputs_hash
(``images/macos/**/*``) and invalidate the ``~/builder_root`` cache when bumped.
"""
workflow_file = app.repo.path / '.github' / 'workflows' / 'resolve-build-deps.yaml'
content = read_file_safely(workflow_file, 'macOS workflow', tracker)
pbs_env_file = app.repo.path / '.builders' / 'images' / 'macos' / 'pbs.env'
content = read_file_safely(pbs_env_file, 'macOS pbs.env', tracker)
if content is None:
return

Expand All @@ -271,27 +272,28 @@ def upgrade_macos_python_version(app: Application, new_version: str, tracker: Va
pbs_info = get_pbs_release_info(app, new_version)
if pbs_info is None:
tracker.error(
('macOS workflow',),
('macOS pbs.env',),
message=f'Could not find PBS release with Python {new_version}. '
'A new PBS release may not be available yet.',
)
return

# Define replacements: (label, pattern, new_value)
# Define replacements: (label, pattern, new_value) — KEY=value lines for shell `source`
# Lines may have trailing spaces from editors; \s*$ matches the old YAML patterns' tolerance.
replacements = [
('PYTHON_PATCH', r'^(\s*PYTHON_PATCH:\s*)\d+\s*$', rf'\g<1>{new_patch}'),
('PBS_RELEASE', r'^(\s*PBS_RELEASE:\s*)\d+\s*$', rf"\g<1>{pbs_info['release']}"),
('PBS_SHA256__aarch64', r'^(\s*PBS_SHA256__aarch64:\s*)[0-9a-f]+\s*$', rf"\g<1>{pbs_info['aarch64']}"),
('PBS_SHA256__x86_64', r'^(\s*PBS_SHA256__x86_64:\s*)[0-9a-f]+\s*$', rf"\g<1>{pbs_info['x86_64']}"),
('PYTHON_PATCH', r'^(PYTHON_PATCH=)\d+\s*$', rf'\g<1>{new_patch}'),
('PBS_RELEASE', r'^(PBS_RELEASE=)\d+\s*$', rf"\g<1>{pbs_info['release']}"),
('PBS_SHA256__aarch64', r'^(PBS_SHA256__aarch64=)[0-9a-f]+\s*$', rf"\g<1>{pbs_info['aarch64']}"),
('PBS_SHA256__x86_64', r'^(PBS_SHA256__x86_64=)[0-9a-f]+\s*$', rf"\g<1>{pbs_info['x86_64']}"),
]

for label, pattern, replacement in replacements:
content, count = re.subn(pattern, replacement, content, count=1, flags=re.MULTILINE)
if count == 0:
tracker.error(('macOS workflow',), message=f'Could not find {label} in workflow file')
tracker.error(('macOS pbs.env',), message=f'Could not find {label} in macOS pbs.env')
return

write_file_safely(workflow_file, content, 'macOS workflow', tracker)
write_file_safely(pbs_env_file, content, 'macOS pbs.env', tracker)


def upgrade_python_version_full_constant(app: Application, new_version: str, tracker: ValidationTracker):
Expand Down
23 changes: 13 additions & 10 deletions ddev/tests/cli/meta/scripts/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,18 @@ def fake_repo(tmp_path_factory, config_file, local_repo, ddev, mocker):
""",
)

# Create fake macOS workflow file for Python upgrade tests
# Uses Python Build Standalone (PBS) format
write_file(
repo_path / '.builders' / 'images' / 'macos',
'pbs.env',
"""# test fixture
PYTHON_PATCH=7
PBS_RELEASE=20251202
PBS_SHA256__aarch64=799a3b76240496e4472dd60ed0cd5197e04637bea7fa16af68caeb989fadcb3a
PBS_SHA256__x86_64=705b39dd74490c3e9b4beb1c4f40bf802b50ba40fe085bdca635506a944d5e74
""",
)

# Minimal workflow stub (upgrade script updates macOS PBS via pbs.env only)
write_file(
repo_path / '.github' / 'workflows',
'resolve-build-deps.yaml',
Expand All @@ -215,14 +225,7 @@ def fake_repo(tmp_path_factory, config_file, local_repo, ddev, mocker):
build-macos:
runs-on: macos-latest
steps:
- name: Set up Python
env:
PYTHON_PATCH: 7
PBS_RELEASE: 20251202
PBS_SHA256__aarch64: 799a3b76240496e4472dd60ed0cd5197e04637bea7fa16af68caeb989fadcb3a
PBS_SHA256__x86_64: 705b39dd74490c3e9b4beb1c4f40bf802b50ba40fe085bdca635506a944d5e74
run: |
curl -fsSL -o pbs.tgz "https://github.com/astral-sh/python-build-standalone/releases/download/$PBS_RELEASE/cpython-$PYTHON_VERSION.$PYTHON_PATCH+$PBS_RELEASE-aarch64-apple-darwin-install_only_stripped.tar.gz"
- run: echo stub
""",
)

Expand Down
22 changes: 11 additions & 11 deletions ddev/tests/cli/meta/scripts/test_upgrade_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ def test_update_python_version_success(fake_repo, ddev, mocker, mock_python_vers
assert '-Hash \'200ddff856bbff949d2cc1be42e8807c07538abd6b6966d5113a094cf628c5c5\'' in contents
assert 'ENV PYTHON_VERSION="3.13.7"' not in contents

workflow_file = fake_repo.path / '.github' / 'workflows' / 'resolve-build-deps.yaml'
contents = workflow_file.read_text()
assert 'PYTHON_PATCH: 9' in contents
assert 'PYTHON_PATCH: 7' not in contents
assert 'PBS_RELEASE: 20251210' in contents
assert 'PBS_SHA256__aarch64: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2' in contents
assert 'PBS_SHA256__x86_64: f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5' in contents
pbs_env = fake_repo.path / '.builders' / 'images' / 'macos' / 'pbs.env'
contents = pbs_env.read_text()
assert 'PYTHON_PATCH=9' in contents
assert 'PYTHON_PATCH=7' not in contents
assert 'PBS_RELEASE=20251210' in contents
assert 'PBS_SHA256__aarch64=a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2' in contents
assert 'PBS_SHA256__x86_64=f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5' in contents


def test_update_python_version_already_latest(fake_repo, ddev, mocker, mock_python_version):
Expand Down Expand Up @@ -132,9 +132,9 @@ def test_upgrade_macos_reports_error_on_pattern_mismatch(tmp_path, mocker):
mock_app.repo.path = tmp_path
mock_tracker = mocker.MagicMock()

workflow_dir = tmp_path / '.github' / 'workflows'
workflow_dir.mkdir(parents=True)
(workflow_dir / 'resolve-build-deps.yaml').write_text('name: Resolve build deps\njobs:\n build: {}\n')
macos_dir = tmp_path / '.builders' / 'images' / 'macos'
macos_dir.mkdir(parents=True)
(macos_dir / 'pbs.env').write_text('PBS_RELEASE=1\n')

mocker.patch(
'ddev.cli.meta.scripts.upgrade_python.get_pbs_release_info',
Expand All @@ -144,7 +144,7 @@ def test_upgrade_macos_reports_error_on_pattern_mismatch(tmp_path, mocker):
upgrade_macos_python_version(mock_app, '3.13.9', mock_tracker)

mock_tracker.error.assert_called_once()
assert 'Could not find PYTHON_PATCH in workflow file' in mock_tracker.error.call_args[1]['message']
assert 'Could not find PYTHON_PATCH in macOS pbs.env' in mock_tracker.error.call_args[1]['message']


@pytest.mark.parametrize(
Expand Down
Loading