Skip to content

Commit

Permalink
Bugfix: Do not rely on provisioning profile ordering on disk for `xco…
Browse files Browse the repository at this point in the history
…de-project use-profiles` (#308)
  • Loading branch information
priitlatt authored Feb 6, 2023
1 parent 2592aaa commit 9ed1e93
Showing 4 changed files with 41 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Version 0.38.2
-------------

**Bugfix**
- Improve action `xcode-project use-profiles` stability so that different invocation with the same set of provisioning profiles will always yield the same changeset to Xcode project settings. [PR #308](https://github.com/codemagic-ci-cd/cli-tools/pull/308)

Version 0.38.1
-------------

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "codemagic-cli-tools"
version = "0.38.1"
version = "0.38.2"
description = "CLI tools used in Codemagic builds"
readme = "README.md"
authors = [
2 changes: 1 addition & 1 deletion src/codemagic/__version__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
__title__ = 'codemagic-cli-tools'
__description__ = 'CLI tools used in Codemagic builds'
__version__ = '0.38.1.dev'
__version__ = '0.38.2.dev'
__url__ = 'https://github.com/codemagic-ci-cd/cli-tools'
__licence__ = 'GNU General Public License v3.0'
35 changes: 33 additions & 2 deletions src/codemagic/models/code_signing_settings_manager.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
from __future__ import annotations

import itertools
import json
import pathlib
import shlex
import shutil
import subprocess
from dataclasses import dataclass
from datetime import datetime
from datetime import timedelta
from datetime import timezone
from functools import lru_cache
from tempfile import NamedTemporaryFile
from typing import TYPE_CHECKING
@@ -57,8 +61,35 @@ def __init__(self, profiles: List[ProvisioningProfile], keychain_certificates: L

@lru_cache()
def _get_json_serialized_profiles(self) -> str:
profiles = [self._serialize_profile(p) for p in self.profiles.values()]
return json.dumps(profiles)
# Make sure profiles are serialized in a specific order so that different runs
# with the same profiles will always yield the same changeset to Xcode project settings.

now = datetime.now(timezone.utc)
max_separators = max((p.bundle_id.count('.') for p in self.profiles.values()), default=0)

def sort_key(profile: ProvisioningProfile) -> Tuple[int, str, timedelta]:
"""
Order profiles so that:
- More specific bundle ids come first with higher priority:
- "com.example.app.extension" is more specific than "com.example.app and
- "com.example.app.*" is more specific than "com.example.*".
Detect this by counting namespace separators in bundle identifier.
- Otherwise order them alphabetically by comparing bundle identifiers.
- Finally in case of bundle identifier collision raise priority for more recent profile.
"""
return (
max_separators - profile.bundle_id.count('.'),
profile.bundle_id,
now - profile.creation_date,
)

# Partition profiles into wildcard profiles and strict matching profiles
wildcard_profiles = sorted((p for p in self.profiles.values() if p.is_wildcard), key=sort_key)
specific_profiles = sorted((p for p in self.profiles.values() if not p.is_wildcard), key=sort_key)
# Non-wildcard profiles come first and have higher priority
profiles = itertools.chain(specific_profiles, wildcard_profiles)

return json.dumps([self._serialize_profile(p) for p in profiles])

def _serialize_profile(self, profile):
usable_certificates = profile.get_usable_certificates(self._certificates)

0 comments on commit 9ed1e93

Please sign in to comment.