@@ -31,58 +31,67 @@ const xcrun = '/usr/bin/xcrun';
31
31
const WORKSPACE = process . env . GITHUB_WORKSPACE || process . cwd ( ) ;
32
32
33
33
export async function GetOrSetXcodeVersion ( ) : Promise < SemVer > {
34
- let xcodeVersionString = core . getInput ( 'xcode-version' ) ;
34
+ let xcodeVersionString = core . getInput ( 'xcode-version' ) || 'latest' ;
35
35
36
- if ( xcodeVersionString ) {
37
- core . info ( `Setting xcode version to ${ xcodeVersionString } ` ) ;
38
- let xcodeVersionOutput = '' ;
36
+ core . info ( `Setting xcode version to ${ xcodeVersionString } ` ) ;
37
+ let xcodeVersionOutput = '' ;
39
38
40
- const installedExitCode = await exec ( 'xcodes' , [ 'installed' ] , {
41
- listeners : {
42
- stdout : ( data : Buffer ) => {
43
- xcodeVersionOutput += data . toString ( ) ;
44
- }
39
+ const installedExitCode = await exec ( 'xcodes' , [ 'installed' ] , {
40
+ listeners : {
41
+ stdout : ( data : Buffer ) => {
42
+ xcodeVersionOutput += data . toString ( ) ;
45
43
}
46
- } ) ;
47
-
48
- if ( installedExitCode !== 0 ) {
49
- throw new Error ( 'Failed to get installed Xcode versions!' ) ;
50
44
}
45
+ } ) ;
51
46
52
- const installedXcodeVersions = xcodeVersionOutput . split ( '\n' ) . map ( line => {
53
- const match = line . match ( / ( \d + \. \d + ( \s \w + ) ? ) / ) ;
54
- return match ? match [ 1 ] : null ;
55
- } ) . filter ( Boolean ) as string [ ] ;
56
-
57
- core . info ( `Installed Xcode versions:` ) ;
58
- installedXcodeVersions . forEach ( version => core . info ( ` > ${ version } ` ) ) ;
59
-
60
- if ( installedXcodeVersions . length === 0 || ! xcodeVersionString . includes ( 'latest' ) ) {
61
- if ( installedXcodeVersions . length === 0 || ! installedXcodeVersions . includes ( xcodeVersionString ) ) {
62
- throw new Error ( `Xcode version ${ xcodeVersionString } is not installed! You will need to install this is a step before this one.` ) ;
63
- }
64
- } else {
65
- // Exclude versions containing 'Beta' and select the latest version
66
- const nonBetaVersions = installedXcodeVersions . filter ( v => ! / B e t a / i. test ( v ) ) ;
67
-
68
- if ( nonBetaVersions . length === 0 ) {
69
- throw new Error ( 'No Xcode versions installed!' ) ;
70
- }
47
+ if ( installedExitCode !== 0 ) {
48
+ throw new Error ( 'Failed to get installed Xcode versions!' ) ;
49
+ }
50
+
51
+ // Keep full lines so we can detect Beta & Release Candidate builds
52
+ const installedLines = xcodeVersionOutput . split ( '\n' ) . filter ( l => l . trim ( ) . length > 0 ) ;
53
+ type XcodeInstallEntry = { version : string ; raw : string ; isBeta : boolean ; isRC : boolean ; isSelected ?: boolean ; } ;
54
+ const installedXcodeEntries : XcodeInstallEntry [ ] = installedLines . map ( line => {
55
+ const match = line . match ( / ^ ( \d + \. \d + ) / ) ; // first number like 16.4, 26.0
56
+ if ( ! match ) { return null ; }
57
+ const version = match [ 1 ] ;
58
+ const isBeta = / B e t a / i. test ( line ) ;
59
+ // Detect various RC naming styles (Release Candidate, Release_Candidate, RC suffix/word)
60
+ const isRC = / ( R e l e a s e [ _ \s ] ? C a n d i d a t e | \b R C \b ) / i. test ( line ) ;
61
+ const isSelected = / ( S e l e c t e d ) / i. test ( line ) ;
62
+ return { version, raw : line , isBeta, isRC, isSelected } ;
63
+ } ) . filter ( Boolean ) as XcodeInstallEntry [ ] ;
64
+
65
+ core . info ( `Installed Xcode versions:` ) ;
66
+ installedXcodeEntries . forEach ( e => core . info ( ` > ${ e . version } ${ e . isBeta ? ' (Beta)' : e . isRC ? ' (RC)' : '' } ` ) ) ;
67
+
68
+ if ( installedXcodeEntries . length === 0 || ! xcodeVersionString . includes ( 'latest' ) ) {
69
+ if ( installedXcodeEntries . length === 0 || ! installedXcodeEntries . some ( e => e . version === xcodeVersionString ) ) {
70
+ throw new Error ( `Xcode version ${ xcodeVersionString } is not installed! You will need to install this in a step before this one.` ) ;
71
+ }
72
+ } else {
73
+ // Exclude Beta & Release Candidate versions when selecting 'latest'
74
+ const stableVersions = installedXcodeEntries . filter ( e => ! e . isBeta && ! e . isRC ) ;
71
75
72
- xcodeVersionString = nonBetaVersions [ nonBetaVersions . length - 1 ] ;
76
+ if ( stableVersions . length === 0 ) {
77
+ throw new Error ( 'No stable (non-Beta / non-RC) Xcode versions installed!' ) ;
73
78
}
74
79
75
- core . info ( `Selecting latest installed Xcode version ${ xcodeVersionString } ...` ) ;
80
+ xcodeVersionString = stableVersions [ stableVersions . length - 1 ] . version ;
81
+ }
82
+
83
+ if ( installedXcodeEntries . some ( e => e . isSelected && e . version !== xcodeVersionString ) ) {
84
+ core . info ( `Selecting new Xcode version ${ xcodeVersionString } ...` ) ;
76
85
const selectExitCode = await exec ( 'xcodes' , [ 'select' , xcodeVersionString ] ) ;
77
86
78
87
if ( selectExitCode !== 0 ) {
79
88
throw new Error ( `Failed to select Xcode version ${ xcodeVersionString } !` ) ;
80
89
}
81
- }
82
90
83
- await exec ( 'xcodes' , [ 'installed' ] ) ;
91
+ await exec ( 'xcodes' , [ 'installed' ] ) ;
92
+ }
84
93
85
- let xcodeVersionOutput = '' ;
94
+ xcodeVersionOutput = '' ;
86
95
await exec ( 'xcodebuild' , [ '-version' ] , {
87
96
listeners : {
88
97
stdout : ( data : Buffer ) => {
0 commit comments