diff --git a/recipes/README.recipes.md b/recipes/README.recipes.md index 7b3d3a716..2ba15a6a4 100644 --- a/recipes/README.recipes.md +++ b/recipes/README.recipes.md @@ -721,7 +721,7 @@ Args: — **def [upload](/recipes/recipe_modules/gsutil/api.py#98)(self, source, bucket, dest, args=None, link_name='gsutil.upload', metadata=None, unauthenticated_url=False, \*\*kwargs):** ### *recipe_modules* / [osx\_sdk](/recipes/recipe_modules/osx_sdk) -[DEPS](/recipes/recipe_modules/osx_sdk/__init__.py#7): [recipe\_engine/cipd][recipe_engine/recipe_modules/cipd], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/step][recipe_engine/recipe_modules/step], [recipe\_engine/version][recipe_engine/recipe_modules/version] +[DEPS](/recipes/recipe_modules/osx_sdk/__init__.py#7): [recipe\_engine/cipd][recipe_engine/recipe_modules/cipd], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/step][recipe_engine/recipe_modules/step], [recipe\_engine/version][recipe_engine/recipe_modules/version] The `osx_sdk` module provides safe functions to access a semi-hermetic @@ -729,11 +729,11 @@ XCode installation. Available only to Google-run bots. -#### **class [OSXSDKApi](/recipes/recipe_modules/osx_sdk/api.py#40)([RecipeApi][recipe_engine/wkt/RecipeApi]):** +#### **class [OSXSDKApi](/recipes/recipe_modules/osx_sdk/api.py#44)([RecipeApi][recipe_engine/wkt/RecipeApi]):** API for using OS X SDK distributed via CIPD. -  **@contextmanager**
— **def [\_\_call\_\_](/recipes/recipe_modules/osx_sdk/api.py#58)(self, kind):** +  **@contextmanager**
— **def [\_\_call\_\_](/recipes/recipe_modules/osx_sdk/api.py#62)(self, kind):** Sets up the XCode SDK environment. @@ -781,7 +781,7 @@ Args: Raises: StepFailure or InfraFailure. -— **def [initialize](/recipes/recipe_modules/osx_sdk/api.py#51)(self):** +— **def [initialize](/recipes/recipe_modules/osx_sdk/api.py#55)(self):** ### *recipe_modules* / [presubmit](/recipes/recipe_modules/presubmit) [DEPS](/recipes/recipe_modules/presubmit/__init__.py#13): [bot\_update](#recipe_modules-bot_update), [depot\_tools](#recipe_modules-depot_tools), [gclient](#recipe_modules-gclient), [git](#recipe_modules-git), [tryserver](#recipe_modules-tryserver), [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/cq][recipe_engine/recipe_modules/cq], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/resultdb][recipe_engine/recipe_modules/resultdb], [recipe\_engine/step][recipe_engine/recipe_modules/step] diff --git a/recipes/recipe_modules/osx_sdk/__init__.py b/recipes/recipe_modules/osx_sdk/__init__.py index b6920b4b4..57d44e6d2 100644 --- a/recipes/recipe_modules/osx_sdk/__init__.py +++ b/recipes/recipe_modules/osx_sdk/__init__.py @@ -10,6 +10,7 @@ DEPS = [ 'recipe_engine/json', 'recipe_engine/path', 'recipe_engine/platform', + 'recipe_engine/properties', 'recipe_engine/raw_io', 'recipe_engine/step', 'recipe_engine/version', diff --git a/recipes/recipe_modules/osx_sdk/api.py b/recipes/recipe_modules/osx_sdk/api.py index 053bff6ea..b7daed0ad 100644 --- a/recipes/recipe_modules/osx_sdk/api.py +++ b/recipes/recipe_modules/osx_sdk/api.py @@ -22,6 +22,10 @@ _PROPERTY_DEFAULTS = { # # Maps from OS version to the maximum supported version of Xcode for that OS. # +# These correspond to package instance tags for: +# +# https://chrome-infra-packages.appspot.com/p/infra_internal/ios/xcode/xcode_binaries/mac-amd64 +# # Keep this sorted by OS version. _DEFAULT_VERSION_MAP = [ ('10.12.6', '9c40b'), @@ -131,8 +135,8 @@ class OSXSDKApi(recipe_api.RecipeApi): find_os = self.m.step( 'find macOS version', ['sw_vers', '-productVersion'], stdout=self.m.raw_io.output_text(), - step_test_data=( - lambda: self.m.raw_io.test_api.stream_output_text('14.4'))) + step_test_data=(lambda: self.m.raw_io.test_api.stream_output_text( + self.test_api.DEFAULT_MACOS_VERSION))) cur_os = self.m.version.parse(find_os.stdout.strip()) find_os.presentation.step_text = f'Running on {str(cur_os)!r}.' for target_os, xcode in reversed(_DEFAULT_VERSION_MAP): diff --git a/recipes/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json b/recipes/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json index da94fdf10..e9e7e1fcf 100644 --- a/recipes/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json +++ b/recipes/recipe_modules/osx_sdk/examples/full.expected/ancient_version.json @@ -36,7 +36,7 @@ "infra_step": true, "name": "find macOS version", "~followup_annotations": [ - "@@@STEP_TEXT@Running on '10.1.0'.@@@" + "@@@STEP_TEXT@Running on '10.1'.@@@" ] }, { diff --git a/recipes/recipe_modules/osx_sdk/examples/full.py b/recipes/recipe_modules/osx_sdk/examples/full.py index 04388820e..b0bc92dde 100644 --- a/recipes/recipe_modules/osx_sdk/examples/full.py +++ b/recipes/recipe_modules/osx_sdk/examples/full.py @@ -27,21 +27,29 @@ def GenTests(api): yield api.test( 'explicit_version', api.platform.name('mac'), - api.properties(**{'$depot_tools/osx_sdk': { - 'sdk_version': 'deadbeef', - }}) + api.osx_sdk.pick_sdk_version('deadbeef'), ) yield api.test( 'automatic_version', api.platform.name('mac'), - api.step_data('find macOS version', - stdout=api.raw_io.output_text('10.15.6')), + api.osx_sdk.macos_version('10.15.6'), ) yield api.test( 'ancient_version', api.platform.name('mac'), - api.step_data('find macOS version', - stdout=api.raw_io.output_text('10.1.0')), + api.osx_sdk.macos_version('10.1'), ) + + bad_versions = [ + 'meep.morp', + '1.2.3.4', + '10', + ] + for version in bad_versions: + try: + api.osx_sdk.macos_version(version) + assert False, f'macos_version regex failure, allowed {version=}' # pragma: no cover + except ValueError: + pass diff --git a/recipes/recipe_modules/osx_sdk/test_api.py b/recipes/recipe_modules/osx_sdk/test_api.py new file mode 100644 index 000000000..37dd91bf6 --- /dev/null +++ b/recipes/recipe_modules/osx_sdk/test_api.py @@ -0,0 +1,59 @@ +# Copyright 2024 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import re + +from recipe_engine import recipe_test_api + + +class OSXSDKTestApi(recipe_test_api.RecipeTestApi): + # In tests, this will be the version that we simulate macOS to be. + DEFAULT_MACOS_VERSION = '14.4' + + def macos_version( + self, + major_minor: str = DEFAULT_MACOS_VERSION) -> recipe_test_api.TestData: + """Mock the macOS Major.Minor[.Patch] version that osx_sdk will use to pick + the Xcode SDK version from its internal table. + + This will only be used if the recipe does not explicitly select an SDK + version via the osx_sdk properties (which can be mocked via the + `pick_sdk_version` method below). + + Example use: + + yield api.test( + 'my-test-name', + api.osx_sdk.macos_version('13.3'), + ) + """ + if not re.match(r'^\d+(\.\d+){1,2}$', major_minor): + raise ValueError( + f'Expected Major.Minor[.Patch] (e.g. 14.4), got {major_minor=}') + + return self.step_data('find macOS version', + stdout=self.m.raw_io.output_text(major_minor)) + + def pick_sdk_version(self, + sdk_version: str = 'deadbeef' + ) -> recipe_test_api.TestData: + """This should be used to pick a precise SDK version. + + Recipes used on builders which configure the XCode version via properties + should use this to more accurately reflect how these recipes will run in + production. Specifically, when the XCode version is selected via properties, + the osx_sdk module will not need or attempt to discover the current macOS + version (which is mockable with the `macos_version` method above). + + Example use: + + yield api.test( + 'my-test-name', + api.osx_sdk.pick_sdk_version('13c100'), + ) + """ + return self.m.properties( + **{"$depot_tools/osx_sdk": { + "sdk_version": sdk_version, + }})