diff --git a/images/macos/helpers/Xcode.Installer.psm1 b/images/macos/helpers/Xcode.Installer.psm1 index 619d167e9..e076f5e07 100644 --- a/images/macos/helpers/Xcode.Installer.psm1 +++ b/images/macos/helpers/Xcode.Installer.psm1 @@ -5,17 +5,14 @@ function Install-XcodeVersion { [Parameter(Mandatory)] [string]$Version, [Parameter(Mandatory)] - [string]$LocalLink + [string]$LinkTo ) $xcodeDownloadDirectory = "$env:HOME/Library/Caches/XcodeInstall" - $xcodeTargetPath = Get-XcodeRootPath -Version $LocalLink - Push-Location $xcodeDownloadDirectory + $xcodeTargetPath = Get-XcodeRootPath -Version $LinkTo Invoke-DownloadXcodeArchive -Version $Version Expand-XcodeXipArchive -DownloadDirectory $xcodeDownloadDirectory -TargetPath $xcodeTargetPath - Confirm-XcodeIntegrity -XcodeRootPath $xcodeTargetPath - Approve-XcodeLicense -XcodeRootPath $xcodeTargetPath Get-ChildItem $xcodeDownloadDirectory | Remove-Item -Force } @@ -33,6 +30,7 @@ function Invoke-DownloadXcodeArchive { # TO-DO: Consider replacing of xcversion with own implementation Write-Host "Downloading Xcode $resolvedVersion" + # TO-DO: handle exit code xcversion install "$resolvedVersion" --no-install } @@ -58,12 +56,13 @@ function Expand-XcodeXipArchive { Write-Host "Extracting Xcode from '$xcodeXipPath'" Push-Location $DownloadDirectory + # TO-DO: handle exit code xip -x $xcodeXipPath Pop-Location if (Test-Path "$DownloadDirectory/Xcode-beta.app") { Write-Host "Renaming Xcode-beta.app to Xcode.app" - Rename-File -Path "$DownloadDirectory/Xcode-beta.app" -NewName "Xcode.app" + Rename-Item -Path "$DownloadDirectory/Xcode-beta.app" -NewName "Xcode.app" } if (-not (Test-Path "$DownloadDirectory/Xcode.app")) { @@ -77,10 +76,12 @@ function Expand-XcodeXipArchive { function Confirm-XcodeIntegrity { param( [Parameter(Mandatory)] - [string]$XcodeRootPath + [string]$Version ) + $XcodeRootPath = Get-XcodeRootPath -Version $Version if (Test-XcodeStableRelease -XcodeRootPath $XcodeRootPath) { + # TO-DO: handle exit code spctl --assess --raw $XcodeRootPath } } @@ -88,10 +89,11 @@ function Confirm-XcodeIntegrity { function Approve-XcodeLicense { param( [Parameter(Mandatory)] - $XcodeRootPath + [string]$Version ) - $xcodeBuildPath = Get-XcodeToolPath -XcodeRootPath $XcodeRootPath -ToolName "xcodebuild" + $xcodeBuildPath = Get-XcodeToolPath -Version $Version -ToolName "xcodebuild" + # TO-DO: handle exit code sudo $xcodeBuildPath -license accept } @@ -103,8 +105,9 @@ function Install-XcodeAdditionalPackages { Write-Host "Installing additional packages for Xcode $Version..." $xcodeRootPath = Get-XcodeRootPath -Version $Version - $packages = Get-ChildItem -Path "$xcodeRootPath/Contents/Resources/Packages" -Filter "*.pkg" -Name -File - $packages | ForEach-Object { & sudo installer -pkg $_ -target / -allowUntrusted } + $packages = Get-ChildItem -Path "$xcodeRootPath/Contents/Resources/Packages" -Filter "*.pkg" -File + # TO-DO: handle exit code + $packages | ForEach-Object { & sudo installer -pkg $_.FullName -target / -allowUntrusted } } function Invoke-XcodeRunFirstLaunch { @@ -119,6 +122,7 @@ function Invoke-XcodeRunFirstLaunch { Write-Host "Running 'runFirstLaunch' for Xcode $Version..." $xcodeRootPath = Get-XcodeToolPath -Version $Version -ToolName "xcodebuild" + # TO-DO: handle exit code & sudo $xcodeRootPath -runFirstLaunch } @@ -156,5 +160,26 @@ function Build-ProvisionatorSymlink { } function Set-XcodeDeveloperDirEnvironmentVariables { - # TO-DO + param( + [Parameter(Mandatory)] + [string[]]$XcodeList + ) + + $exactVersionsList = $XcodeList | Where-Object { Test-XcodeStableRelease -Version $_ } | ForEach-Object { + $xcodeRootPath = Get-XcodeRootPath -Version $_ + $xcodeVersionInfo = Get-XcodeVersionInfo -XcodeRootPath $xcodeRootPath + return @{ + RootPath = $xcodeRootPath + Version = [SemVer]::Parse($xcodeVersionInfo.Version) + } + } | Sort-Object -Property Version -Descending + + $majorVersions = $exactVersionsList.Version.Major | Select-Object -Unique + $majorVersions | ForEach-Object { + $latestXcodeVersion = $exactVersionsList | Where-Object { $_.Version.Major -eq $_ } | Select-Object -First 1 + $variableName = "XCODE_${_}_DEVELOPER_DIR" + $variableValue = "$($latestXcodeVersion.RootPath)/Contents/Developer" + Write-Host "Set ${variableName}=${variableValue}" + "export ${variableName}=${variableValue}" | Out-File "$env:HOME/.bashrc" -Append + } } \ No newline at end of file diff --git a/images/macos/provision/core/xcode.ps1 b/images/macos/provision/core/xcode.ps1 index f3ea55647..58f100a35 100644 --- a/images/macos/provision/core/xcode.ps1 +++ b/images/macos/provision/core/xcode.ps1 @@ -14,25 +14,29 @@ $os = Get-OSVersion $xcodeVersions = Get-ToolsetValue "xcode.versions" $defaultXcode = Get-ToolsetValue "xcode.default" -& xcversion update - Write-Host "Installing Xcode versions..." -foreach ($xcode in $xcodeVersions) { - Install-XcodeVersion -Version $xcode.version -LocalLink $xcode.localLink - Build-XcodeSymlinks -Version $xcode.localLink -Symlinks $xcode.symlinks - Build-ProvisionatorSymlink -Version $xcode.version +$xcodeVersions | ForEach-Object { + Install-XcodeVersion -Version $_.version -LinkTo $_.link + Confirm-XcodeIntegrity -Version $_.link + Approve-XcodeLicense -Version $_.link } Write-Host "Configuring Xcode versions..." if ($os.IsLessThanCatalina) { - Install-XcodeAdditionalPackages -Version $xcodeVersions[0].localLink + Install-XcodeAdditionalPackages -Version $xcodeVersions[0].link } -$xcodeVersions | ForEach-Object { Invoke-XcodeRunFirstLaunch -Version $_.localLink } +$xcodeVersions | ForEach-Object { Invoke-XcodeRunFirstLaunch -Version $_.link } Invoke-XcodeRunFirstLaunch -Version $defaultXcode +Write-Host "Configuring Xcode symlinks..." +$xcodeVersions | ForEach-Object { + Build-XcodeSymlinks -Version $_.link -Symlinks $_.symlinks + Build-ProvisionatorSymlink -Version $_.link +} + Write-Host "Setting default Xcode to $defaultXcode" Switch-Xcode -Version $defaultXcode New-Item -Path "/Applications/Xcode.app" -ItemType SymbolicLink -Value (Get-XcodeRootPath -Version $defaultXcode) Write-Host "Setting environment variables 'XCODE__DEVELOPER_DIR'" -Set-XcodeDeveloperDirEnvironmentVariables \ No newline at end of file +Set-XcodeDeveloperDirEnvironmentVariables -XcodeList $xcodeVersions.link \ No newline at end of file diff --git a/images/macos/tests/Xcode.Tests.ps1 b/images/macos/tests/Xcode.Tests.ps1 index fd12db68f..af7ac81f9 100644 --- a/images/macos/tests/Xcode.Tests.ps1 +++ b/images/macos/tests/Xcode.Tests.ps1 @@ -2,39 +2,39 @@ Import-Module "$PSScriptRoot/../helpers/Common.Helpers.psm1" Import-Module "$PSScriptRoot/../helpers/Xcode.Helpers.psm1" Import-Module "$PSScriptRoot/../helpers/Tests.Helpers.psm1" -$XCODE_VERSIONS = Get-ToolsetValue "xcode.versions" -$DEFAULT_XCODE = Get-ToolsetValue "xcode.default" -$LATEST_XCODE_VERSION = $XCODE_VERSIONS | Select-Object -First 1 -$OS = Get-OSVersion +$xcodeVersions = Get-ToolsetValue "xcode.versions" +$defaultXcode = Get-ToolsetValue "xcode.default" +$latestXcodeVersion = $xcodeVersions | Select-Object -First 1 +$os = Get-OSVersion Describe "Xcode" { - It "Default Xcode is $DEFAULT_XCODE" { + $defaultXcodeTestCase = @{ DefaultXcode = $defaultXcode } + It "Default Xcode is " -TestCases $defaultXcodeTestCase { "xcodebuild -version" | Should -ReturnZeroExitCode - (Get-CommandResult "xcodebuild -version").Output | Should -BeLike "Xcode $DEFAULT_XCODE*" + (Get-CommandResult "xcodebuild -version").Output | Should -BeLike "Xcode ${DefaultXcode}.*" } - It "Xcode.app points to default Xcode" { - + It "Xcode.app points to default Xcode" -TestCases $defaultXcodeTestCase { + $xcodeApp = "/Applications/Xcode.app" + $expectedTarget = Get-XcodeRootPath -Version $DefaultXcode + $xcodeApp | Should -Exist + $expectedTarget | Should -Exist + (Get-Item $xcodeApp).Target | Should -Be $expectedTarget } - # Cut "_beta" postfix for test cases - $testCases = $XCODE_VERSIONS | ForEach-Object { @{XcodeVersion = $_.Split("_")[0] } } + $testCases = $xcodeVersions | ForEach-Object { @{ XcodeVersion = $_.link; LatestXcodeVersion = $xcodeVersions[0].link; Symlinks = $_.symlinks } } It "" -TestCases $testCases { - param ( [string] $XcodeVersion ) - $xcodebuildPath = Get-XcodeToolPath -Version $XcodeVersion -ToolName "xcodebuild" "$xcodebuildPath -version" | Should -ReturnZeroExitCode } It "Xcode tools are installed" -TestCases $testCases -Skip:($os.IsHighSierra) { - param ( [string] $XcodeVersion ) - $TOOLS_NOT_INSTALLED_EXIT_CODE = 69 $xcodebuildPath = Get-XcodeToolPath -Version $XcodeVersion -ToolName "xcodebuild" $result = Get-CommandResult "$xcodebuildPath -checkFirstLaunchStatus" - if ($XcodeVersion -ne $LATEST_XCODE_VERSION) { + if ($XcodeVersion -ne $LatestXcodeVersion) { $result.ExitCode | Should -Not -Be $TOOLS_NOT_INSTALLED_EXIT_CODE } else { $result.ExitCode | Should -BeIn (0, $TOOLS_NOT_INSTALLED_EXIT_CODE) @@ -42,13 +42,12 @@ Describe "Xcode" { } It "Xcode has correct beta symlink" -TestCases $testCases { - param ( [string] $XcodeVersion ) - - $xcodesWithBetaSymlink = @("12", "9.3", "9.4") - $shouldBetaSymlinkExists = $XcodeVersion.StartsWith("10") -or $XcodeVersion.StartsWith("11") -or ($XcodeVersion -in $xcodesWithBetaSymlink) - - $betaSymlinkPath = Get-XcodeRootPath -Version "${XcodeVersion}_beta" - Test-Path $betaSymlinkPath | Should -Be $shouldBetaSymlinkExists + $sourcePath = Get-XcodeRootPath -Version $XcodeVersion + $Symlinks | ForEach-Object { + $targetPath = Get-XcodeRootPath -Version $_ + $targetPath | Should -Exist + (Get-Item $targetPath).Target | Should -Be $sourcePath + } } It "/Applications/Xcode* symlinks are valid" { @@ -58,37 +57,32 @@ Describe "Xcode" { $_ | Should -Exist } } +} - Context "XCODE_DEVELOPER_DIR" { - $stableXcodeVersions = $XCODE_VERSIONS | ForEach-Object { $_.Split("_")[0] } | Where-Object { Test-XcodeStableRelease -Version $_ } - $majorXcodeVersions = $stableXcodeVersions | ForEach-Object { $_.Split(".")[0] } | Select-Object -Unique - $testCases = $majorXcodeVersions | ForEach-Object { - $majorXcodeVersion = $_ - $expectedVersion = $stableXcodeVersions | Where-Object { $_.StartsWith("$majorXcodeVersion") } | Select-Object -First 1 - return @{ - MajorXcodeVersion = $majorXcodeVersion - ExpectedVersion = $expectedVersion - } +Describe "XCODE_DEVELOPER_DIR variables" { + $exactVersionsList = $xcodeVersions.link | Where-Object { Test-XcodeStableRelease -Version $_ } | ForEach-Object { + $xcodeRootPath = Get-XcodeRootPath -Version $_ + $xcodeVersionInfo = Get-XcodeVersionInfo -XcodeRootPath $xcodeRootPath + return @{ + RootPath = $xcodeRootPath + Version = [SemVer]::Parse($xcodeVersionInfo.Version) } + } | Sort-Object -Property Version -Descending + $majorVersions = $exactVersionsList.Version.Major | Select-Object -Unique + $testCases = $majorVersions | ForEach-Object { @{ MajorVersion = $_; VersionsList = $exactVersionsList } } - It "XCODE__DEVELOPER_DIR" -TestCases $testCases { - param ( - [string] $MajorXcodeVersion, - [string] $ExpectedVersion - ) - - $variableName = "XCODE_${MajorXcodeVersion}_DEVELOPER_DIR" - $actualPath = Get-EnvironmentVariable $variableName - $expectedPath = Join-Path (Get-XcodeRootPath -Version $ExpectedVersion) "Contents/Developer" - - $actualPath | Should -Exist - $actualPath | Should -Be $expectedPath - } + It "XCODE__DEVELOPER_DIR" -TestCases $testCases { + $variableName = "XCODE_${MajorVersion}_DEVELOPER_DIR" + $actualPath = Get-EnvironmentVariable $variableName + $expectedVersion = $VersionsList | Where-Object { $_.Version.Major -eq $MajorVersion } | Select-Object -First 1 + $expectedPath = "$($expectedVersion.RootPath)/Contents/Developer" + $actualPath | Should -Exist + $actualPath | Should -Be $expectedPath } } Describe "Xcode simulators" { - $XCODE_VERSIONS | Where-Object { Test-XcodeStableRelease -Version $_ } | ForEach-Object { + $xcodeVersions | Where-Object { Test-XcodeStableRelease -Version $_ } | ForEach-Object { Switch-Xcode -Version $_ Context "$_" { @@ -105,7 +99,7 @@ Describe "Xcode simulators" { } AfterAll { - $DEFAULT_XCODE = Get-ToolsetValue "xcode.default" - Switch-Xcode -Version $DEFAULT_XCODE + $defaultXcode = Get-ToolsetValue "xcode.default" + Switch-Xcode -Version $defaultXcode } } \ No newline at end of file