Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUMM-2054 Build xcframework with tvos slices #783

Merged
merged 1 commit into from
Mar 28, 2022
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
6 changes: 3 additions & 3 deletions tools/distribution/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@

# Publish GH Release asset:
if publish_to_gh:
gh_asset = GHAsset(add_xcode_version=add_xcode_version_to_github_asset)
gh_asset.validate(git_tag=git_tag)
gh_asset.publish(git_tag=git_tag, overwrite_existing=overwrite_github, dry_run=dry_run)
gh_asset = GHAsset(add_xcode_version=add_xcode_version_to_github_asset,git_tag=git_tag)
gh_asset.validate()
gh_asset.publish(overwrite_existing=overwrite_github, dry_run=dry_run)

# Publish CP podspecs:
if publish_to_cp:
Expand Down
156 changes: 114 additions & 42 deletions tools/distribution/src/release/assets/gh_asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@
from src.release.directory_matcher import DirectoryMatcher
from src.release.semver import Version

min_cr_version = Version.parse('1.7.0')
min_tvos_version = Version.parse('1.10.0')

class XCFrameworkValidator:
name: str

def should_be_included(self, in_version: Version) -> bool:
pass

def validate(self, zip_directory: DirectoryMatcher):
def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool:
pass


class DatadogXCFrameworkValidator(XCFrameworkValidator):
name = 'Datadog.xcframework'

def should_be_included(self, in_version: Version):
return True # always expect `Datadog.xcframework`
def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool:
# always expect `Datadog.xcframework`

dir = zip_directory.get('Datadog.xcframework')

def validate(self, zip_directory: DirectoryMatcher):
zip_directory.get('Datadog.xcframework').assert_it_has_files([
dir.assert_it_has_files([
'ios-arm64',
'ios-arm64/BCSymbolMaps/*.bcsymbolmap',
'ios-arm64/dSYMs/*.dSYM',
Expand All @@ -47,15 +47,35 @@ def validate(self, zip_directory: DirectoryMatcher):
'ios-arm64_x86_64-simulator/**/x86_64-apple-ios-simulator.swiftinterface',
])

if in_version.is_older_than(min_tvos_version):
return True # Stop here: tvOS support was introduced in `1.10.0`

dir.assert_it_has_files([
'tvos-arm64',
'tvos-arm64/BCSymbolMaps/*.bcsymbolmap',
'tvos-arm64/dSYMs/*.dSYM',
'tvos-arm64/**/arm64.swiftinterface',
'tvos-arm64/**/arm64-apple-ios.swiftinterface',

'tvos-arm64_x86_64-simulator',
'tvos-arm64_x86_64-simulator/dSYMs/*.dSYM',
'tvos-arm64_x86_64-simulator/**/arm64.swiftinterface',
'tvos-arm64_x86_64-simulator/**/arm64-apple-tvos-simulator.swiftinterface',
'tvos-arm64_x86_64-simulator/**/x86_64.swiftinterface',
'tvos-arm64_x86_64-simulator/**/x86_64-apple-tvos-simulator.swiftinterface',
])

return True


class DatadogObjcXCFrameworkValidator(XCFrameworkValidator):
name = 'DatadogObjc.xcframework'

def should_be_included(self, in_version: Version):
return True # always expect `DatadogObjc.xcframework`
def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool:
# always expect `DatadogObjc.xcframework`

def validate(self, zip_directory: DirectoryMatcher):
zip_directory.get('DatadogObjc.xcframework').assert_it_has_files([
dir = zip_directory.get('DatadogObjc.xcframework')
dir.assert_it_has_files([
'ios-arm64',
'ios-arm64/BCSymbolMaps/*.bcsymbolmap',
'ios-arm64/dSYMs/*.dSYM',
Expand All @@ -69,16 +89,35 @@ def validate(self, zip_directory: DirectoryMatcher):
'ios-arm64_x86_64-simulator/**/x86_64-apple-ios-simulator.swiftinterface',
])

if in_version.is_older_than(min_tvos_version):
return True # Stop here: tvOS support was introduced in `1.10.0`

dir.assert_it_has_files([
'tvos-arm64',
'tvos-arm64/BCSymbolMaps/*.bcsymbolmap',
'tvos-arm64/dSYMs/*.dSYM',
'tvos-arm64/**/arm64.swiftinterface',
'tvos-arm64/**/arm64-apple-ios.swiftinterface',

'tvos-arm64_x86_64-simulator',
'tvos-arm64_x86_64-simulator/**/arm64.swiftinterface',
'tvos-arm64_x86_64-simulator/**/arm64-apple-tvos-simulator.swiftinterface',
'tvos-arm64_x86_64-simulator/**/x86_64.swiftinterface',
'tvos-arm64_x86_64-simulator/**/x86_64-apple-tvos-simulator.swiftinterface',
])

return True


class DatadogCrashReportingXCFrameworkValidator(XCFrameworkValidator):
name = 'DatadogCrashReporting.xcframework'

def should_be_included(self, in_version: Version):
min_version = Version.parse('1.7.0') # Datadog Crash Reporting.xcframework was introduced in `1.7.0`
return in_version.is_newer_than_or_equal(min_version)
def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool:
if in_version.is_older_than(min_cr_version):
return False # Datadog Crash Reporting.xcframework was introduced in `1.7.0`

def validate(self, zip_directory: DirectoryMatcher):
zip_directory.get('DatadogCrashReporting.xcframework').assert_it_has_files([
dir = zip_directory.get('DatadogCrashReporting.xcframework')
dir.assert_it_has_files([
'ios-arm64',
'ios-arm64/BCSymbolMaps/*.bcsymbolmap',
'ios-arm64/**/arm64.swiftinterface',
Expand All @@ -89,31 +128,58 @@ def validate(self, zip_directory: DirectoryMatcher):
'ios-arm64_x86_64-simulator/**/x86_64.swiftinterface',
'ios-arm64_x86_64-simulator/**/x86_64-apple-ios-simulator.swiftinterface',
])

if in_version.is_older_than(min_tvos_version):
return True # Stop here: tvOS support was introduced in `1.10.0`

dir.assert_it_has_files([
'tvos-arm64',
'tvos-arm64/BCSymbolMaps/*.bcsymbolmap',
'tvos-arm64/**/arm64.swiftinterface',
'tvos-arm64/**/arm64-apple-ios.swiftinterface',

'tvos-arm64_x86_64-simulator',
'tvos-arm64_x86_64-simulator/dSYMs/*.dSYM',
'tvos-arm64_x86_64-simulator/**/x86_64.swiftinterface',
'tvos-arm64_x86_64-simulator/**/x86_64-apple-tvos-simulator.swiftinterface',
])

return True


class CrashReporterXCFrameworkValidator(XCFrameworkValidator):
name = 'CrashReporter.xcframework'

def should_be_included(self, in_version: Version):
min_version = Version.parse('1.7.0') # Datadog Crash Reporting.xcframework was introduced in `1.7.0`
return in_version.is_newer_than_or_equal(min_version)
def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool:
if in_version.is_older_than(min_cr_version):
return False # Datadog Crash Reporting.xcframework was introduced in `1.7.0`

def validate(self, zip_directory: DirectoryMatcher):
zip_directory.get('CrashReporter.xcframework').assert_it_has_files([
dir = zip_directory.get('CrashReporter.xcframework')
dir.assert_it_has_files([
'ios-arm64_arm64e_armv7_armv7s',
'ios-arm64_i386_x86_64-simulator',
])

if in_version.is_older_than(min_tvos_version):
return True # Stop here: tvOS support was introduced in `1.10.0`

dir.assert_it_has_files([
'tvos-arm64',
'tvos-arm64_x86_64-simulator',
])

return True


class KronosXCFrameworkValidator(XCFrameworkValidator):
name = 'Kronos.xcframework'

def should_be_included(self, in_version: Version):
def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool:
min_version = Version.parse('1.5.0') # First version that depends on Kronos
max_version = Version.parse('1.8.99') # Last version that depends on Kronos
return in_version.is_newer_than_or_equal(min_version) and max_version.is_newer_than_or_equal(in_version)

def validate(self, zip_directory: DirectoryMatcher):
max_version = Version.parse('1.9.0') # Version where Kronos dependency was removed
if in_version.is_older_than(min_version) or in_version.is_newer_than_or_equal(max_version):
return False
zip_directory.get('Kronos.xcframework').assert_it_has_files([
'ios-arm64_armv7',
'ios-arm64_armv7/BCSymbolMaps/*.bcsymbolmap',
Expand All @@ -132,6 +198,8 @@ def validate(self, zip_directory: DirectoryMatcher):
'ios-arm64_i386_x86_64-simulator/**/x86_64.swiftinterface',
])

return True


xcframeworks_validators: [XCFrameworkValidator] = [
DatadogXCFrameworkValidator(),
Expand All @@ -148,21 +216,25 @@ class GHAsset:
It uses Carthage for building the actual `.xcframework` bundles (by recursively searching for their Xcode schemes).
"""

__git_tag: str # The git tag to build assets for
__path: str # The path to the asset `.zip` archive

def __init__(self, add_xcode_version: bool):
def __init__(self, add_xcode_version: bool, git_tag: str):
print(f'⌛️️️ Creating the GH release asset from {os.getcwd()}')

with NamedTemporaryFile(mode='w+', prefix='dd-gh-distro-', suffix='.xcconfig') as xcconfig:
xcconfig.write('BUILD_LIBRARY_FOR_DISTRIBUTION = YES\n')
xcconfig.seek(0) # without this line, content isn't actually written
os.environ['XCODE_XCCONFIG_FILE'] = xcconfig.name

this_version = Version.parse(git_tag)
platform = 'iOS' if this_version.is_older_than(min_tvos_version) else 'iOS,tvOS'

# Produce XCFrameworks with carthage:
# - only checkout and `--no-build` as it will build in the next command:
shell('carthage bootstrap --platform iOS --no-build')
shell(f'carthage bootstrap --platform {platform} --no-build')
# - `--no-build` as it will build in the next command:
shell('carthage build --platform iOS --use-xcframeworks --no-use-binaries --no-skip-current')
shell(f'carthage build --platform {platform} --use-xcframeworks --no-use-binaries --no-skip-current')

# Create `.zip` archive:
zip_archive_name = f'Datadog-{read_sdk_version()}.zip'
Expand All @@ -177,22 +249,23 @@ def __init__(self, add_xcode_version: bool):
shell(f'zip -q --symlinks -r {zip_archive_name} *.xcframework')

self.__path = f'{os.getcwd()}/Carthage/Build/{zip_archive_name}'
self.__git_tag = git_tag
print(' → GH asset created')

def __repr__(self):
return f'[GHAsset: path = {self.__path}]'

def validate(self, git_tag: str): # 1.5.0
def validate(self):
"""
Checks the `.zip` archive integrity with given `git_tag`.
"""
print(f'🔎️️ Validating {self} against: {git_tag}')
print(f'🔎️️ Validating {self} against: {self.__git_tag}')

# Check if `sdk_version` matches the git tag name:
sdk_version = read_sdk_version()
if sdk_version != git_tag:
raise Exception(f'The `sdk_version` ({sdk_version}) does not match git tag ({git_tag})')
print(f' → `sdk_version` ({sdk_version}) matches git tag ({git_tag})')
if sdk_version != self.__git_tag:
raise Exception(f'The `sdk_version` ({sdk_version}) does not match git tag ({self.__git_tag})')
print(f' → `sdk_version` ({sdk_version}) matches git tag ({self.__git_tag})')

# Inspect the content of zip archive:
with TemporaryDirectory() as unzip_dir:
Expand All @@ -203,13 +276,12 @@ def validate(self, git_tag: str): # 1.5.0
print(f' - {file_path.removeprefix(unzip_dir)}')

dm = DirectoryMatcher(path=unzip_dir)
this_version = Version.parse(git_tag)
this_version = Version.parse(self.__git_tag)

print(f' → Validating each `XCFramework`:')
validated_count = 0
for validator in xcframeworks_validators:
if validator.should_be_included(in_version=this_version):
validator.validate(zip_directory=dm)
if validator.validate(zip_directory=dm, in_version=this_version):
print(f' → {validator.name} - OK')
validated_count += 1
else:
Expand All @@ -219,15 +291,15 @@ def validate(self, git_tag: str): # 1.5.0

print(f' → the content of `.zip` archive is correct')

def publish(self, git_tag: str, overwrite_existing: bool, dry_run: bool):
def publish(self, overwrite_existing: bool, dry_run: bool):
"""
Uploads the `.zip` archive to GH Release for given `git_tag`.
"""
print(f'📦️️ Publishing {self} to GH Release tag {git_tag}')
print(f'📦️️ Publishing {self} to GH Release tag {self.__git_tag}')

if overwrite_existing:
shell(f'gh release upload {git_tag} {self.__path} --repo DataDog/dd-sdk-ios --clobber', skip=dry_run)
shell(f'gh release upload {self.__git_tag} {self.__path} --repo DataDog/dd-sdk-ios --clobber', skip=dry_run)
else:
shell(f'gh release upload {git_tag} {self.__path} --repo DataDog/dd-sdk-ios', skip=dry_run)
shell(f'gh release upload {self.__git_tag} {self.__path} --repo DataDog/dd-sdk-ios', skip=dry_run)

print(f' → succeeded')
3 changes: 3 additions & 0 deletions tools/distribution/src/release/semver.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,6 @@ def is_newer_than(self, other_version: 'Version'):

def is_newer_than_or_equal(self, other_version: 'Version'):
return self.is_newer_than(other_version=other_version) or self == other_version

def is_older_than(self, other_version: 'Version'):
return not self.is_newer_than_or_equal(other_version)