@@ -31,58 +31,67 @@ const xcrun = '/usr/bin/xcrun';
3131const WORKSPACE = process . env . GITHUB_WORKSPACE || process . cwd ( ) ;
3232
3333export async function GetOrSetXcodeVersion ( ) : Promise < SemVer > {
34- let xcodeVersionString = core . getInput ( 'xcode-version' ) ;
34+ let xcodeVersionString = core . getInput ( 'xcode-version' ) || 'latest' ;
3535
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 = '' ;
3938
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 ( ) ;
4543 }
46- } ) ;
47-
48- if ( installedExitCode !== 0 ) {
49- throw new Error ( 'Failed to get installed Xcode versions!' ) ;
5044 }
45+ } ) ;
5146
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 ) ;
7175
72- xcodeVersionString = nonBetaVersions [ nonBetaVersions . length - 1 ] ;
76+ if ( stableVersions . length === 0 ) {
77+ throw new Error ( 'No stable (non-Beta / non-RC) Xcode versions installed!' ) ;
7378 }
7479
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 } ...` ) ;
7685 const selectExitCode = await exec ( 'xcodes' , [ 'select' , xcodeVersionString ] ) ;
7786
7887 if ( selectExitCode !== 0 ) {
7988 throw new Error ( `Failed to select Xcode version ${ xcodeVersionString } !` ) ;
8089 }
81- }
8290
83- await exec ( 'xcodes' , [ 'installed' ] ) ;
91+ await exec ( 'xcodes' , [ 'installed' ] ) ;
92+ }
8493
85- let xcodeVersionOutput = '' ;
94+ xcodeVersionOutput = '' ;
8695 await exec ( 'xcodebuild' , [ '-version' ] , {
8796 listeners : {
8897 stdout : ( data : Buffer ) => {
0 commit comments