From 6f58c77418fd81413dab1226d4352e92868870ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bala=CC=81zs=20Hajagos?= Date: Tue, 16 Sep 2025 11:59:35 +0200 Subject: [PATCH 1/7] Add non-user-facing options to platform This will support build-for-simulator code sharing --- step/platform.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/step/platform.go b/step/platform.go index d664ae68..4464d72f 100644 --- a/step/platform.go +++ b/step/platform.go @@ -21,6 +21,11 @@ const ( tvOS Platform = "tvOS" watchOS Platform = "watchOS" visionOS Platform = "visionOS" + + // Not permitted on this steps UI, but may come from build-for-simulator + iOSSimulator Platform = "generic/platform=iOS Simulator" + watchOSSimulator Platform = "generic/platform=watchOS Simulator" + tvOSSimulator Platform = "generic/platform=tvOS Simulator" ) func parsePlatform(platform string) (Platform, error) { @@ -35,6 +40,12 @@ func parsePlatform(platform string) (Platform, error) { return watchOS, nil case "visionos": return visionOS, nil + case "generic/platform=iOS Simulator": + return iOSSimulator, nil + case "generic/platform=watchOS Simulator": + return watchOSSimulator, nil + case "generic/platform=tvOS Simulator": + return tvOSSimulator, nil default: return "", fmt.Errorf("unknown platform: %s", platform) } From 5a8713f1115d9e0da1c850b502f1ff1ff4beec23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bala=CC=81zs=20Hajagos?= Date: Tue, 16 Sep 2025 12:32:12 +0200 Subject: [PATCH 2/7] Delegate archive work to steps-xcode-archive --- step/platform.go | 274 +++++++++++++++++++++++------------------------ 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/step/platform.go b/step/platform.go index 4464d72f..2a3a436b 100644 --- a/step/platform.go +++ b/step/platform.go @@ -1,174 +1,174 @@ package step import ( - "fmt" - "path/filepath" - "strings" - - "github.com/bitrise-io/go-utils/v2/log" - "github.com/bitrise-io/go-xcode/xcodeproject/schemeint" - "github.com/bitrise-io/go-xcode/xcodeproject/serialized" - "github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj" - "github.com/bitrise-io/go-xcode/xcodeproject/xcscheme" + "fmt" + "path/filepath" + "strings" + + "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-xcode/xcodeproject/schemeint" + "github.com/bitrise-io/go-xcode/xcodeproject/serialized" + "github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj" + "github.com/bitrise-io/go-xcode/xcodeproject/xcscheme" ) type Platform string const ( - detectPlatform Platform = "detect" - iOS Platform = "iOS" - osX Platform = "OS X" - tvOS Platform = "tvOS" - watchOS Platform = "watchOS" - visionOS Platform = "visionOS" - - // Not permitted on this steps UI, but may come from build-for-simulator - iOSSimulator Platform = "generic/platform=iOS Simulator" - watchOSSimulator Platform = "generic/platform=watchOS Simulator" - tvOSSimulator Platform = "generic/platform=tvOS Simulator" + detectPlatform Platform = "detect" + iOS Platform = "iOS" + osX Platform = "OS X" + tvOS Platform = "tvOS" + watchOS Platform = "watchOS" + visionOS Platform = "visionOS" + + // Not permitted on this steps UI, but may come from build-for-simulator + iOSSimulator Platform = "iOS Simulator" + watchOSSimulator Platform = "watchOS Simulator" + tvOSSimulator Platform = "tvOS Simulator" ) func parsePlatform(platform string) (Platform, error) { - switch strings.ToLower(platform) { - case "detect": - return detectPlatform, nil - case "ios": - return iOS, nil - case "tvos": - return tvOS, nil - case "watchos": - return watchOS, nil - case "visionos": - return visionOS, nil - case "generic/platform=iOS Simulator": - return iOSSimulator, nil - case "generic/platform=watchOS Simulator": - return watchOSSimulator, nil - case "generic/platform=tvOS Simulator": - return tvOSSimulator, nil - default: - return "", fmt.Errorf("unknown platform: %s", platform) - } + switch strings.ToLower(platform) { + case "detect": + return detectPlatform, nil + case "ios": + return iOS, nil + case "tvos": + return tvOS, nil + case "watchos": + return watchOS, nil + case "visionos": + return visionOS, nil + case "generic/platform=iOS Simulator": + return iOSSimulator, nil + case "generic/platform=watchOS Simulator": + return watchOSSimulator, nil + case "generic/platform=tvOS Simulator": + return tvOSSimulator, nil + default: + return "", fmt.Errorf("unknown platform: %s", platform) + } } func OpenArchivableProject(pth, schemeName, configurationName string) (*xcodeproj.XcodeProj, *xcscheme.Scheme, string, error) { - scheme, schemeContainerDir, err := schemeint.Scheme(pth, schemeName) - if err != nil { - return nil, nil, "", fmt.Errorf("could not get scheme (%s) from path (%s): %s", schemeName, pth, err) - } - if configurationName == "" { - configurationName = scheme.ArchiveAction.BuildConfiguration - } - - if configurationName == "" { - return nil, nil, "", fmt.Errorf("no configuration provided nor default defined for the scheme's (%s) archive action", schemeName) - } - - archiveEntry, ok := scheme.AppBuildActionEntry() - if !ok { - return nil, nil, "", fmt.Errorf("archivable entry not found") - } - - projectPth, err := archiveEntry.BuildableReference.ReferencedContainerAbsPath(filepath.Dir(schemeContainerDir)) - if err != nil { - return nil, nil, "", err - } - - xcodeProj, err := xcodeproj.Open(projectPth) - if err != nil { - return nil, nil, "", err - } - return &xcodeProj, scheme, configurationName, nil + scheme, schemeContainerDir, err := schemeint.Scheme(pth, schemeName) + if err != nil { + return nil, nil, "", fmt.Errorf("could not get scheme (%s) from path (%s): %s", schemeName, pth, err) + } + if configurationName == "" { + configurationName = scheme.ArchiveAction.BuildConfiguration + } + + if configurationName == "" { + return nil, nil, "", fmt.Errorf("no configuration provided nor default defined for the scheme's (%s) archive action", schemeName) + } + + archiveEntry, ok := scheme.AppBuildActionEntry() + if !ok { + return nil, nil, "", fmt.Errorf("archivable entry not found") + } + + projectPth, err := archiveEntry.BuildableReference.ReferencedContainerAbsPath(filepath.Dir(schemeContainerDir)) + if err != nil { + return nil, nil, "", err + } + + xcodeProj, err := xcodeproj.Open(projectPth) + if err != nil { + return nil, nil, "", err + } + return &xcodeProj, scheme, configurationName, nil } type TargetBuildSettingsProvider interface { - TargetBuildSettings(xcodeProj *xcodeproj.XcodeProj, target, configuration string, customOptions ...string) (serialized.Object, error) + TargetBuildSettings(xcodeProj *xcodeproj.XcodeProj, target, configuration string, customOptions ...string) (serialized.Object, error) } type XcodeBuild struct { } func (x XcodeBuild) TargetBuildSettings(xcodeProj *xcodeproj.XcodeProj, target, configuration string, customOptions ...string) (serialized.Object, error) { - return xcodeProj.TargetBuildSettings(target, configuration, customOptions...) + return xcodeProj.TargetBuildSettings(target, configuration, customOptions...) } func BuildableTargetPlatform( - xcodeProj *xcodeproj.XcodeProj, - scheme *xcscheme.Scheme, - configurationName string, - additionalOptions []string, - provider TargetBuildSettingsProvider, - logger log.Logger, + xcodeProj *xcodeproj.XcodeProj, + scheme *xcscheme.Scheme, + configurationName string, + additionalOptions []string, + provider TargetBuildSettingsProvider, + logger log.Logger, ) (Platform, error) { - logger.Printf("Finding platform type") + logger.Printf("Finding platform type") - archiveEntry, ok := scheme.AppBuildActionEntry() - if !ok { - return "", fmt.Errorf("archivable entry not found in project: %s, scheme: %s", xcodeProj.Path, scheme.Name) - } + archiveEntry, ok := scheme.AppBuildActionEntry() + if !ok { + return "", fmt.Errorf("archivable entry not found in project: %s, scheme: %s", xcodeProj.Path, scheme.Name) + } - mainTarget, ok := xcodeProj.Proj.Target(archiveEntry.BuildableReference.BlueprintIdentifier) - if !ok { - return "", fmt.Errorf("target not found: %s", archiveEntry.BuildableReference.BlueprintIdentifier) - } + mainTarget, ok := xcodeProj.Proj.Target(archiveEntry.BuildableReference.BlueprintIdentifier) + if !ok { + return "", fmt.Errorf("target not found: %s", archiveEntry.BuildableReference.BlueprintIdentifier) + } - settings, err := provider.TargetBuildSettings(xcodeProj, mainTarget.Name, configurationName, additionalOptions...) - if err != nil { - return "", fmt.Errorf("failed to get target (%s) build settings: %s", mainTarget.Name, err) - } + settings, err := provider.TargetBuildSettings(xcodeProj, mainTarget.Name, configurationName, additionalOptions...) + if err != nil { + return "", fmt.Errorf("failed to get target (%s) build settings: %s", mainTarget.Name, err) + } - platform, err := getPlatform(settings) + platform, err := getPlatform(settings) - logger.Printf("Platform type: %s", platform) + logger.Printf("Platform type: %s", platform) - return platform, err + return platform, err } func getPlatform(buildSettings serialized.Object) (Platform, error) { - /* - Xcode help: - Base SDK (SDKROOT) - The name or path of the base SDK being used during the build. - The product will be built against the headers and libraries located inside the indicated SDK. - This path will be prepended to all search paths, and will be passed through the environment to the compiler and linker. - Additional SDKs can be specified in the Additional SDKs (ADDITIONAL_SDKS) setting. - - Examples: - - /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator13.4.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.4.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk - - iphoneos - - macosx - - appletvos - - watchos - */ - sdk, err := buildSettings.String("SDKROOT") - if err != nil { - return "", fmt.Errorf("failed to get SDKROOT: %s", err) - } - - sdk = strings.ToLower(sdk) - if filepath.Ext(sdk) == ".sdk" { - sdk = filepath.Base(sdk) - } - - switch { - case strings.HasPrefix(sdk, "iphoneos"): - return iOS, nil - case strings.HasPrefix(sdk, "macosx"): - return osX, nil - case strings.HasPrefix(sdk, "appletvos"): - return tvOS, nil - case strings.HasPrefix(sdk, "watchos"): - return watchOS, nil - case strings.HasPrefix(sdk, "xros"): - // visionOS SDK is called xros (as of Xcode 15.2), but the platform is called visionOS (e.g. in the destination specifier) - return visionOS, nil - default: - return "", fmt.Errorf("unkown SDKROOT: %s", sdk) - } + /* + Xcode help: + Base SDK (SDKROOT) + The name or path of the base SDK being used during the build. + The product will be built against the headers and libraries located inside the indicated SDK. + This path will be prepended to all search paths, and will be passed through the environment to the compiler and linker. + Additional SDKs can be specified in the Additional SDKs (ADDITIONAL_SDKS) setting. + + Examples: + - /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator13.4.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.4.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk + - iphoneos + - macosx + - appletvos + - watchos + */ + sdk, err := buildSettings.String("SDKROOT") + if err != nil { + return "", fmt.Errorf("failed to get SDKROOT: %s", err) + } + + sdk = strings.ToLower(sdk) + if filepath.Ext(sdk) == ".sdk" { + sdk = filepath.Base(sdk) + } + + switch { + case strings.HasPrefix(sdk, "iphoneos"): + return iOS, nil + case strings.HasPrefix(sdk, "macosx"): + return osX, nil + case strings.HasPrefix(sdk, "appletvos"): + return tvOS, nil + case strings.HasPrefix(sdk, "watchos"): + return watchOS, nil + case strings.HasPrefix(sdk, "xros"): + // visionOS SDK is called xros (as of Xcode 15.2), but the platform is called visionOS (e.g. in the destination specifier) + return visionOS, nil + default: + return "", fmt.Errorf("unkown SDKROOT: %s", sdk) + } } From 5127d769f6d8ae4ec52e8c353fb3e26064018d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bala=CC=81zs=20Hajagos?= Date: Tue, 16 Sep 2025 12:38:48 +0200 Subject: [PATCH 3/7] Fix indentation --- step/platform.go | 274 +++++++++++++++++++++++------------------------ 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/step/platform.go b/step/platform.go index 2a3a436b..1b24ea35 100644 --- a/step/platform.go +++ b/step/platform.go @@ -1,174 +1,174 @@ package step import ( - "fmt" - "path/filepath" - "strings" - - "github.com/bitrise-io/go-utils/v2/log" - "github.com/bitrise-io/go-xcode/xcodeproject/schemeint" - "github.com/bitrise-io/go-xcode/xcodeproject/serialized" - "github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj" - "github.com/bitrise-io/go-xcode/xcodeproject/xcscheme" + "fmt" + "path/filepath" + "strings" + + "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-xcode/xcodeproject/schemeint" + "github.com/bitrise-io/go-xcode/xcodeproject/serialized" + "github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj" + "github.com/bitrise-io/go-xcode/xcodeproject/xcscheme" ) type Platform string const ( - detectPlatform Platform = "detect" - iOS Platform = "iOS" - osX Platform = "OS X" - tvOS Platform = "tvOS" - watchOS Platform = "watchOS" - visionOS Platform = "visionOS" - - // Not permitted on this steps UI, but may come from build-for-simulator - iOSSimulator Platform = "iOS Simulator" - watchOSSimulator Platform = "watchOS Simulator" - tvOSSimulator Platform = "tvOS Simulator" + detectPlatform Platform = "detect" + iOS Platform = "iOS" + osX Platform = "OS X" + tvOS Platform = "tvOS" + watchOS Platform = "watchOS" + visionOS Platform = "visionOS" + + // Not permitted on this steps UI, but may come from build-for-simulator + iOSSimulator Platform = "iOS Simulator" + watchOSSimulator Platform = "watchOS Simulator" + tvOSSimulator Platform = "tvOS Simulator" ) func parsePlatform(platform string) (Platform, error) { - switch strings.ToLower(platform) { - case "detect": - return detectPlatform, nil - case "ios": - return iOS, nil - case "tvos": - return tvOS, nil - case "watchos": - return watchOS, nil - case "visionos": - return visionOS, nil - case "generic/platform=iOS Simulator": - return iOSSimulator, nil - case "generic/platform=watchOS Simulator": - return watchOSSimulator, nil - case "generic/platform=tvOS Simulator": - return tvOSSimulator, nil - default: - return "", fmt.Errorf("unknown platform: %s", platform) - } + switch strings.ToLower(platform) { + case "detect": + return detectPlatform, nil + case "ios": + return iOS, nil + case "tvos": + return tvOS, nil + case "watchos": + return watchOS, nil + case "visionos": + return visionOS, nil + case "generic/platform=iOS Simulator": + return iOSSimulator, nil + case "generic/platform=watchOS Simulator": + return watchOSSimulator, nil + case "generic/platform=tvOS Simulator": + return tvOSSimulator, nil + default: + return "", fmt.Errorf("unknown platform: %s", platform) + } } func OpenArchivableProject(pth, schemeName, configurationName string) (*xcodeproj.XcodeProj, *xcscheme.Scheme, string, error) { - scheme, schemeContainerDir, err := schemeint.Scheme(pth, schemeName) - if err != nil { - return nil, nil, "", fmt.Errorf("could not get scheme (%s) from path (%s): %s", schemeName, pth, err) - } - if configurationName == "" { - configurationName = scheme.ArchiveAction.BuildConfiguration - } - - if configurationName == "" { - return nil, nil, "", fmt.Errorf("no configuration provided nor default defined for the scheme's (%s) archive action", schemeName) - } - - archiveEntry, ok := scheme.AppBuildActionEntry() - if !ok { - return nil, nil, "", fmt.Errorf("archivable entry not found") - } - - projectPth, err := archiveEntry.BuildableReference.ReferencedContainerAbsPath(filepath.Dir(schemeContainerDir)) - if err != nil { - return nil, nil, "", err - } - - xcodeProj, err := xcodeproj.Open(projectPth) - if err != nil { - return nil, nil, "", err - } - return &xcodeProj, scheme, configurationName, nil + scheme, schemeContainerDir, err := schemeint.Scheme(pth, schemeName) + if err != nil { + return nil, nil, "", fmt.Errorf("could not get scheme (%s) from path (%s): %s", schemeName, pth, err) + } + if configurationName == "" { + configurationName = scheme.ArchiveAction.BuildConfiguration + } + + if configurationName == "" { + return nil, nil, "", fmt.Errorf("no configuration provided nor default defined for the scheme's (%s) archive action", schemeName) + } + + archiveEntry, ok := scheme.AppBuildActionEntry() + if !ok { + return nil, nil, "", fmt.Errorf("archivable entry not found") + } + + projectPth, err := archiveEntry.BuildableReference.ReferencedContainerAbsPath(filepath.Dir(schemeContainerDir)) + if err != nil { + return nil, nil, "", err + } + + xcodeProj, err := xcodeproj.Open(projectPth) + if err != nil { + return nil, nil, "", err + } + return &xcodeProj, scheme, configurationName, nil } type TargetBuildSettingsProvider interface { - TargetBuildSettings(xcodeProj *xcodeproj.XcodeProj, target, configuration string, customOptions ...string) (serialized.Object, error) + TargetBuildSettings(xcodeProj *xcodeproj.XcodeProj, target, configuration string, customOptions ...string) (serialized.Object, error) } type XcodeBuild struct { } func (x XcodeBuild) TargetBuildSettings(xcodeProj *xcodeproj.XcodeProj, target, configuration string, customOptions ...string) (serialized.Object, error) { - return xcodeProj.TargetBuildSettings(target, configuration, customOptions...) + return xcodeProj.TargetBuildSettings(target, configuration, customOptions...) } func BuildableTargetPlatform( - xcodeProj *xcodeproj.XcodeProj, - scheme *xcscheme.Scheme, - configurationName string, - additionalOptions []string, - provider TargetBuildSettingsProvider, - logger log.Logger, + xcodeProj *xcodeproj.XcodeProj, + scheme *xcscheme.Scheme, + configurationName string, + additionalOptions []string, + provider TargetBuildSettingsProvider, + logger log.Logger, ) (Platform, error) { - logger.Printf("Finding platform type") + logger.Printf("Finding platform type") - archiveEntry, ok := scheme.AppBuildActionEntry() - if !ok { - return "", fmt.Errorf("archivable entry not found in project: %s, scheme: %s", xcodeProj.Path, scheme.Name) - } + archiveEntry, ok := scheme.AppBuildActionEntry() + if !ok { + return "", fmt.Errorf("archivable entry not found in project: %s, scheme: %s", xcodeProj.Path, scheme.Name) + } - mainTarget, ok := xcodeProj.Proj.Target(archiveEntry.BuildableReference.BlueprintIdentifier) - if !ok { - return "", fmt.Errorf("target not found: %s", archiveEntry.BuildableReference.BlueprintIdentifier) - } + mainTarget, ok := xcodeProj.Proj.Target(archiveEntry.BuildableReference.BlueprintIdentifier) + if !ok { + return "", fmt.Errorf("target not found: %s", archiveEntry.BuildableReference.BlueprintIdentifier) + } - settings, err := provider.TargetBuildSettings(xcodeProj, mainTarget.Name, configurationName, additionalOptions...) - if err != nil { - return "", fmt.Errorf("failed to get target (%s) build settings: %s", mainTarget.Name, err) - } + settings, err := provider.TargetBuildSettings(xcodeProj, mainTarget.Name, configurationName, additionalOptions...) + if err != nil { + return "", fmt.Errorf("failed to get target (%s) build settings: %s", mainTarget.Name, err) + } - platform, err := getPlatform(settings) + platform, err := getPlatform(settings) - logger.Printf("Platform type: %s", platform) + logger.Printf("Platform type: %s", platform) - return platform, err + return platform, err } func getPlatform(buildSettings serialized.Object) (Platform, error) { - /* - Xcode help: - Base SDK (SDKROOT) - The name or path of the base SDK being used during the build. - The product will be built against the headers and libraries located inside the indicated SDK. - This path will be prepended to all search paths, and will be passed through the environment to the compiler and linker. - Additional SDKs can be specified in the Additional SDKs (ADDITIONAL_SDKS) setting. - - Examples: - - /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator13.4.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.4.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk - - /Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk - - iphoneos - - macosx - - appletvos - - watchos - */ - sdk, err := buildSettings.String("SDKROOT") - if err != nil { - return "", fmt.Errorf("failed to get SDKROOT: %s", err) - } - - sdk = strings.ToLower(sdk) - if filepath.Ext(sdk) == ".sdk" { - sdk = filepath.Base(sdk) - } - - switch { - case strings.HasPrefix(sdk, "iphoneos"): - return iOS, nil - case strings.HasPrefix(sdk, "macosx"): - return osX, nil - case strings.HasPrefix(sdk, "appletvos"): - return tvOS, nil - case strings.HasPrefix(sdk, "watchos"): - return watchOS, nil - case strings.HasPrefix(sdk, "xros"): - // visionOS SDK is called xros (as of Xcode 15.2), but the platform is called visionOS (e.g. in the destination specifier) - return visionOS, nil - default: - return "", fmt.Errorf("unkown SDKROOT: %s", sdk) - } + /* + Xcode help: + Base SDK (SDKROOT) + The name or path of the base SDK being used during the build. + The product will be built against the headers and libraries located inside the indicated SDK. + This path will be prepended to all search paths, and will be passed through the environment to the compiler and linker. + Additional SDKs can be specified in the Additional SDKs (ADDITIONAL_SDKS) setting. + + Examples: + - /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator13.4.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.4.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk + - /Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk + - iphoneos + - macosx + - appletvos + - watchos + */ + sdk, err := buildSettings.String("SDKROOT") + if err != nil { + return "", fmt.Errorf("failed to get SDKROOT: %s", err) + } + + sdk = strings.ToLower(sdk) + if filepath.Ext(sdk) == ".sdk" { + sdk = filepath.Base(sdk) + } + + switch { + case strings.HasPrefix(sdk, "iphoneos"): + return iOS, nil + case strings.HasPrefix(sdk, "macosx"): + return osX, nil + case strings.HasPrefix(sdk, "appletvos"): + return tvOS, nil + case strings.HasPrefix(sdk, "watchos"): + return watchOS, nil + case strings.HasPrefix(sdk, "xros"): + // visionOS SDK is called xros (as of Xcode 15.2), but the platform is called visionOS (e.g. in the destination specifier) + return visionOS, nil + default: + return "", fmt.Errorf("unkown SDKROOT: %s", sdk) + } } From 854d3667d8c141484f14f95b2a619b9a7c5f9384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bala=CC=81zs=20Hajagos?= Date: Tue, 16 Sep 2025 12:48:59 +0200 Subject: [PATCH 4/7] Fix lower case platform parsing --- step/platform.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/step/platform.go b/step/platform.go index 1b24ea35..b1f528de 100644 --- a/step/platform.go +++ b/step/platform.go @@ -40,11 +40,11 @@ func parsePlatform(platform string) (Platform, error) { return watchOS, nil case "visionos": return visionOS, nil - case "generic/platform=iOS Simulator": + case "generic/platform=ios simulator": return iOSSimulator, nil - case "generic/platform=watchOS Simulator": + case "generic/platform=watchos simulator": return watchOSSimulator, nil - case "generic/platform=tvOS Simulator": + case "generic/platform=tvos simulator": return tvOSSimulator, nil default: return "", fmt.Errorf("unknown platform: %s", platform) @@ -168,6 +168,12 @@ func getPlatform(buildSettings serialized.Object) (Platform, error) { case strings.HasPrefix(sdk, "xros"): // visionOS SDK is called xros (as of Xcode 15.2), but the platform is called visionOS (e.g. in the destination specifier) return visionOS, nil + case strings.HasPrefix(sdk, "iphonesimulator"): + return iOSSimulator, nil + case strings.HasPrefix(sdk, "watchsimulator"): + return watchOSSimulator, nil + case strings.HasPrefix(sdk, "appletvsimulator"): + return tvOSSimulator, nil default: return "", fmt.Errorf("unkown SDKROOT: %s", sdk) } From 8d4c89c78b6462bfa98bcbdb09d0fee102bab604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bala=CC=81zs=20Hajagos?= Date: Tue, 16 Sep 2025 13:05:06 +0200 Subject: [PATCH 5/7] Make ParsePlatform public --- step/platform.go | 8 ++++---- step/platform_test.go | 38 +++++++++++++++++++++++++++++++++++++- step/step.go | 2 +- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/step/platform.go b/step/platform.go index b1f528de..bb789df6 100644 --- a/step/platform.go +++ b/step/platform.go @@ -28,7 +28,7 @@ const ( tvOSSimulator Platform = "tvOS Simulator" ) -func parsePlatform(platform string) (Platform, error) { +func ParsePlatform(platform string) (Platform, error) { switch strings.ToLower(platform) { case "detect": return detectPlatform, nil @@ -40,11 +40,11 @@ func parsePlatform(platform string) (Platform, error) { return watchOS, nil case "visionos": return visionOS, nil - case "generic/platform=ios simulator": + case "ios simulator": return iOSSimulator, nil - case "generic/platform=watchos simulator": + case "watchos simulator": return watchOSSimulator, nil - case "generic/platform=tvos simulator": + case "tvos simulator": return tvOSSimulator, nil default: return "", fmt.Errorf("unknown platform: %s", platform) diff --git a/step/platform_test.go b/step/platform_test.go index 3f496ad0..50975eff 100644 --- a/step/platform_test.go +++ b/step/platform_test.go @@ -165,8 +165,44 @@ func Test_getPlatform(t *testing.T) { wantErr: false, }, { - name: "unkown SDK path", + name: "iOS Simulator", + buildSettings: serialized.Object(map[string]interface{}{"SDKROOT": "iphonesimulator"}), + want: iOSSimulator, + wantErr: false, + }, + { + name: "tvOS Simulator", + buildSettings: serialized.Object(map[string]interface{}{"SDKROOT": "appletvsimulator"}), + want: tvOSSimulator, + wantErr: false, + }, + { + name: "watchOS Simulator", + buildSettings: serialized.Object(map[string]interface{}{"SDKROOT": "watchsimulator"}), + want: watchOSSimulator, + wantErr: false, + }, + { + name: "iOS simulator with SDK path", + buildSettings: serialized.Object(map[string]interface{}{"SDKROOT": "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"}), + want: iOSSimulator, + wantErr: false, + }, + { + name: "tvOS simulator with SDK path", + buildSettings: serialized.Object(map[string]interface{}{"SDKROOT": "/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk"}), + want: tvOSSimulator, + wantErr: false, + }, + { + name: "watchOS simulator with SDK path", buildSettings: serialized.Object(map[string]interface{}{"SDKROOT": "/Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk"}), + want: watchOSSimulator, + wantErr: false, + }, + { + name: "unknown SDK path", + buildSettings: serialized.Object(map[string]interface{}{"SDKROOT": "/Applications/Xcode.app/Contents/Developer/Platforms/Stuff.platform/Developer/SDKs/Stuff.sdk"}), want: Platform(""), wantErr: true, }, diff --git a/step/step.go b/step/step.go index 247b3791..75d7bd3f 100644 --- a/step/step.go +++ b/step/step.go @@ -201,7 +201,7 @@ func (s XcodebuildArchiveConfigParser) ProcessInputs() (Config, error) { } var err error - if config.DestinationPlatform, err = parsePlatform(config.Platform); err != nil { + if config.DestinationPlatform, err = ParsePlatform(config.Platform); err != nil { return Config{}, fmt.Errorf("issue with input Platform: %w", err) } From 1c48db9581b5aa1f54fce20d8e4cab938acfa267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bala=CC=81zs=20Hajagos?= Date: Tue, 16 Sep 2025 13:52:39 +0200 Subject: [PATCH 6/7] Make IosBaseApplication provisioning optional (simulator builds) --- go.mod | 2 +- go.sum | 4 ++-- .../bitrise-io/go-xcode/v2/xcarchive/ios.go | 20 +++++++++++++------ vendor/modules.txt | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 6628fe75..555e5ddc 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/bitrise-io/go-utils v1.0.14 github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.23 github.com/bitrise-io/go-xcode v1.3.0 - github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.67 + github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.67.0.20250916115031-007c7230724c github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/stretchr/testify v1.10.0 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index 39714657..493e51bb 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.23 h1:Dfh4nyZPuEtilBisidejqxBrkx9 github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.23/go.mod h1:3XUplo0dOWc3DqT2XA2SeHToDSg7+j1y1HTHibT2H68= github.com/bitrise-io/go-xcode v1.3.0 h1:QB8Vyr2oZQro/ocs9DJai80rlYL1hU1kwjHqdGslFLo= github.com/bitrise-io/go-xcode v1.3.0/go.mod h1:9OwsvrhZ4A2JxHVoEY7CPcABAKA+OE7FQqFfBfvbFuY= -github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.67 h1:Fz3LSRoH9p5u7yTqdsmE32RHGWEw8q3BVWoOSiHs7AY= -github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.67/go.mod h1:rSmzmqVD3Mn9dWwe19qiiGjlvk/At3D8bQh7n9E8S58= +github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.67.0.20250916115031-007c7230724c h1:7LVyacj3I5q54CSzzUGmigFxsINYdXTJgJPs9Z83tqY= +github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.67.0.20250916115031-007c7230724c/go.mod h1:rSmzmqVD3Mn9dWwe19qiiGjlvk/At3D8bQh7n9E8S58= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/xcarchive/ios.go b/vendor/github.com/bitrise-io/go-xcode/v2/xcarchive/ios.go index b92b1801..25ae7cf6 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/xcarchive/ios.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/xcarchive/ios.go @@ -3,6 +3,7 @@ package xcarchive import ( "errors" "fmt" + "log" "path/filepath" "github.com/bitrise-io/go-utils/v2/command" @@ -48,20 +49,27 @@ func NewIosBaseApplication(path string) (IosBaseApplication, error) { infoPlist = plist } - var provisioningProfile profileutil.ProvisioningProfileInfoModel - { + profileNotFoundErr := fmt.Errorf("profile not exists at: %s", filepath.Join(path, "embedded.mobileprovision")) + var provisioningProfileCreator = func() (profileutil.ProvisioningProfileInfoModel, error) { provisioningProfilePath := filepath.Join(path, "embedded.mobileprovision") if exist, err := pathChecker.IsPathExists(provisioningProfilePath); err != nil { - return IosBaseApplication{}, fmt.Errorf("failed to check if profile exists at: %s, error: %s", provisioningProfilePath, err) + return profileutil.ProvisioningProfileInfoModel{}, fmt.Errorf("failed to check if profile exists at: %s, error: %s", provisioningProfilePath, err) } else if !exist { - return IosBaseApplication{}, fmt.Errorf("profile not exists at: %s", provisioningProfilePath) + return profileutil.ProvisioningProfileInfoModel{}, profileNotFoundErr } profile, err := profileutil.NewProvisioningProfileInfoFromFile(provisioningProfilePath) if err != nil { - return IosBaseApplication{}, err + return profileutil.ProvisioningProfileInfoModel{}, err } - provisioningProfile = profile + + return profile, nil + } + provisioningProfile, err := provisioningProfileCreator() + if err != nil && err != profileNotFoundErr { + return IosBaseApplication{}, err + } else if err == profileNotFoundErr { + log.Printf("No embedded.mobileprovision found for app at: %s", path) } executable := executableNameFromInfoPlist(infoPlist) diff --git a/vendor/modules.txt b/vendor/modules.txt index 9c0a6b78..c68e84b2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -55,7 +55,7 @@ github.com/bitrise-io/go-xcode/xcodeproject/serialized github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj github.com/bitrise-io/go-xcode/xcodeproject/xcscheme github.com/bitrise-io/go-xcode/xcodeproject/xcworkspace -# github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.67 +# github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.67.0.20250916115031-007c7230724c ## explicit; go 1.22 github.com/bitrise-io/go-xcode/v2/autocodesign github.com/bitrise-io/go-xcode/v2/autocodesign/certdownloader From 68087514be4993a3f0a97b5e84b2d12d9bf48698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bala=CC=81zs=20Hajagos?= Date: Tue, 16 Sep 2025 14:10:00 +0200 Subject: [PATCH 7/7] Skip IPA creation on uncompatible platforms --- step/platform.go | 11 +++++++++++ step/step.go | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/step/platform.go b/step/platform.go index bb789df6..a1eccb73 100644 --- a/step/platform.go +++ b/step/platform.go @@ -178,3 +178,14 @@ func getPlatform(buildSettings serialized.Object) (Platform, error) { return "", fmt.Errorf("unkown SDKROOT: %s", sdk) } } + +func (p Platform) canExportIPA() bool { + switch p { + case iOS, tvOS, watchOS, visionOS: + return true + case osX, iOSSimulator, watchOSSimulator, tvOSSimulator: + return false + default: + return false + } +} diff --git a/step/step.go b/step/step.go index 75d7bd3f..1deee84b 100644 --- a/step/step.go +++ b/step/step.go @@ -454,6 +454,10 @@ func (s XcodebuildArchiver) Run(opts RunOpts) (RunResult, error) { out.Archive = archiveOut.Archive + if !opts.DestinationPlatform.canExportIPA() { + return out, nil + } + IPAExportOpts := xcodeIPAExportOpts{ XcodeMajorVersion: opts.XcodeMajorVersion, XcodeAuthOptions: authOptions,