diff --git a/.azure-pipelines/release.yml b/.azure-pipelines/release.yml index a95e96451..3e99b1454 100644 --- a/.azure-pipelines/release.yml +++ b/.azure-pipelines/release.yml @@ -31,12 +31,24 @@ parameters: - name: windows_matrix type: object default: - - id: windows_x64 + - id: windows_x86 jobName: 'Windows (x86)' runtime: win-x86 pool: GitClientPME-1ESHostedPool-intel-pc image: win-x86_64-ado1es os: windows + - id: windows_x64 + jobName: 'Windows (x64)' + runtime: win-x64 + pool: GitClientPME-1ESHostedPool-intel-pc + image: win-x86_64-ado1es + os: windows + - id: windows_arm64 + jobName: 'Windows (ARM64)' + runtime: win-arm64 + pool: GitClientPME-1ESHostedPool-intel-pc + image: win-x86_64-ado1es + os: windows - name: macos_matrix type: object @@ -136,14 +148,15 @@ extends: arguments: | -Configuration Release ` -Output $(Build.ArtifactStagingDirectory)\payload ` - -SymbolOutput $(Build.ArtifactStagingDirectory)\symbols_raw + -SymbolOutput $(Build.ArtifactStagingDirectory)\symbols_raw ` + -RuntimeIdentifier ${{ dim.runtime }} - task: ArchiveFiles@2 displayName: 'Archive symbols' inputs: rootFolderOrFile: '$(Build.ArtifactStagingDirectory)\symbols_raw' includeRootFolder: false archiveType: zip - archiveFile: '$(Build.ArtifactStagingDirectory)\symbols\gcm-win-x86-$(version)-symbols.zip' + archiveFile: '$(Build.ArtifactStagingDirectory)\symbols\gcm-${{ dim.runtime }}-$(version)-symbols.zip' - task: EsrpCodeSigning@5 condition: and(succeeded(), eq('${{ parameters.esrp }}', true)) displayName: 'Sign payload' @@ -195,6 +208,7 @@ extends: -p:NoLayout=true ` -p:PayloadPath="$(Build.ArtifactStagingDirectory)\payload" ` -p:OutputPath="$(Build.ArtifactStagingDirectory)\installers" + -p:RuntimeIdentifier="${{ dim.runtime }}" - task: EsrpCodeSigning@5 condition: and(succeeded(), eq('${{ parameters.esrp }}', true)) displayName: 'Sign installers' @@ -239,7 +253,7 @@ extends: rootFolderOrFile: '$(Build.ArtifactStagingDirectory)\payload' includeRootFolder: false archiveType: zip - archiveFile: '$(Build.ArtifactStagingDirectory)\installers\gcm-win-x86-$(version).zip' + archiveFile: '$(Build.ArtifactStagingDirectory)\installers\gcm-${{ dim.runtime }}-$(version).zip' - task: PowerShell@2 displayName: 'Collect artifacts for publishing' inputs: @@ -774,6 +788,12 @@ extends: - input: pipelineArtifact artifactName: 'win-x86' targetPath: $(Pipeline.Workspace)/assets/win-x86 + - input: pipelineArtifact + artifactName: 'win-x64' + targetPath: $(Pipeline.Workspace)/assets/win-x64 + - input: pipelineArtifact + artifactName: 'win-arm64' + targetPath: $(Pipeline.Workspace)/assets/win-arm64 - input: pipelineArtifact artifactName: 'osx-x64' targetPath: $(Pipeline.Workspace)/assets/osx-x64 @@ -805,6 +825,10 @@ extends: assets: | $(Pipeline.Workspace)/assets/win-x86/*.exe $(Pipeline.Workspace)/assets/win-x86/*.zip + $(Pipeline.Workspace)/assets/win-x64/*.exe + $(Pipeline.Workspace)/assets/win-x64/*.zip + $(Pipeline.Workspace)/assets/win-arm64/*.exe + $(Pipeline.Workspace)/assets/win-arm64/*.zip $(Pipeline.Workspace)/assets/osx-x64/*.pkg $(Pipeline.Workspace)/assets/osx-x64/*.tar.gz $(Pipeline.Workspace)/assets/osx-arm64/*.pkg diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 24617f881..7bb45f26a 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -13,7 +13,16 @@ jobs: # ================================ windows: name: Windows - runs-on: windows-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - runtime: win-x86 + os: windows-latest + - runtime: win-x64 + os: windows-latest + - runtime: win-arm64 + os: windows-11-arm steps: - uses: actions/checkout@v6 @@ -27,24 +36,29 @@ jobs: run: dotnet restore - name: Build - run: dotnet build --configuration WindowsRelease + run: | + dotnet build src/windows/Installer.Windows/Installer.Windows.csproj ` + --configuration=Release ` + --runtime=${{ matrix.runtime }} - name: Test run: | - dotnet test --verbosity normal --configuration=WindowsRelease + dotnet test --verbosity normal ` + --configuration=WindowsRelease ` + --runtime=${{ matrix.runtime }} - name: Prepare artifacts shell: bash run: | mkdir -p artifacts/bin - mv out/windows/Installer.Windows/bin/Release/net472/win-x86 artifacts/bin/ - cp out/windows/Installer.Windows/bin/Release/net472/win-x86.sym/* artifacts/bin/win-x86/ - mv out/windows/Installer.Windows/bin/Release/net472/gcm*.exe artifacts/ + mv out/windows/Installer.Windows/bin/Release/net472/${{ matrix.runtime }}/gcm*.exe artifacts/ + mv out/windows/Installer.Windows/bin/Release/net472/${{ matrix.runtime }} artifacts/bin/ + cp out/windows/Installer.Windows/bin/Release/net472/${{ matrix.runtime }}.sym/* artifacts/bin/${{ matrix.runtime }}/ - name: Upload artifacts uses: actions/upload-artifact@v6 with: - name: win-x86 + name: ${{ matrix.runtime }} path: | artifacts diff --git a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj index 456adf547..8c469897e 100644 --- a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj +++ b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj @@ -1,11 +1,10 @@ - + Exe net8.0 net472;net8.0 - win-x86;osx-x64;linux-x64;osx-arm64;linux-arm64;linux-arm - x86 + win-x86;win-x64;win-arm64;osx-x64;linux-x64;osx-arm64;linux-arm64;linux-arm git-credential-manager GitCredentialManager $(RepoAssetsPath)gcmicon.ico diff --git a/src/windows/Installer.Windows/Installer.Windows.csproj b/src/windows/Installer.Windows/Installer.Windows.csproj index bbd49a291..eae3631f0 100644 --- a/src/windows/Installer.Windows/Installer.Windows.csproj +++ b/src/windows/Installer.Windows/Installer.Windows.csproj @@ -1,12 +1,19 @@ - + + + + win-x64 + win-x86 + win-arm64 + + net472 false false - $(PlatformOutPath)Installer.Windows\bin\$(Configuration)\net472\win-x86 + $(PlatformOutPath)Installer.Windows\bin\$(Configuration)\net472\$(RuntimeIdentifier) 6.3.1 @@ -27,12 +34,20 @@ - "$(NuGetPackageRoot)Tools.InnoSetup\$(InnoSetupVersion)\tools\ISCC.exe" /DPayloadDir="$(PayloadPath)" /DInstallTarget=system "$(RepoSrcPath)\windows\Installer.Windows\Setup.iss" /O"$(OutputPath)" - "$(NuGetPackageRoot)Tools.InnoSetup\$(InnoSetupVersion)\tools\ISCC.exe" /DPayloadDir="$(PayloadPath)" /DInstallTarget=user "$(RepoSrcPath)\windows\Installer.Windows\Setup.iss" /O"$(OutputPath)" + "$(NuGetPackageRoot)Tools.InnoSetup\$(InnoSetupVersion)\tools\ISCC.exe" /DPayloadDir="$(PayloadPath)" /DInstallTarget=system /DGcmRuntimeIdentifier="$(RuntimeIdentifier)" "$(RepoSrcPath)\windows\Installer.Windows\Setup.iss" /O"$(OutputPath)" + "$(NuGetPackageRoot)Tools.InnoSetup\$(InnoSetupVersion)\tools\ISCC.exe" /DPayloadDir="$(PayloadPath)" /DInstallTarget=user /DGcmRuntimeIdentifier="$(RuntimeIdentifier)" "$(RepoSrcPath)\windows\Installer.Windows\Setup.iss" /O"$(OutputPath)" - + + + + + + diff --git a/src/windows/Installer.Windows/Setup.iss b/src/windows/Installer.Windows/Setup.iss index f03d16c9b..c15efe6d8 100644 --- a/src/windows/Installer.Windows/Setup.iss +++ b/src/windows/Installer.Windows/Setup.iss @@ -15,6 +15,10 @@ #error Installer target property 'InstallTarget' must be specifed #endif +#ifndef GcmRuntimeIdentifier + #error GCM Runtime Identifier 'GcmRuntimeIdentifier' must be specifed (e.g. win-x64) +#endif + #if InstallTarget == "user" #define GcmAppId "{{aa76d31d-432c-42ee-844c-bc0bc801cef3}}" #define GcmLongName "Git Credential Manager (User)" @@ -40,7 +44,6 @@ #define GcmRepoRoot "..\..\.." #define GcmAssets GcmRepoRoot + "\assets" #define GcmExe "git-credential-manager.exe" -#define GcmArch "x86" #ifnexist PayloadDir + "\" + GcmExe #error Payload files are missing @@ -67,9 +70,17 @@ AppUpdatesURL={#GcmUrl} AppContact={#GcmUrl} AppCopyright={#GcmCopyright} AppReadmeFile={#GcmReadme} +; Windows ARM64 supports installing and running x64 binaries, but not vice versa. +#if GcmRuntimeIdentifier=="win-x64" +ArchitecturesAllowed=x64compatible +ArchitecturesInstallIn64BitMode=x64compatible +#elif GcmRuntimeIdentifier=="win-arm64" +ArchitecturesAllowed=arm64 +ArchitecturesInstallIn64BitMode=arm64 +#endif VersionInfoVersion={#GcmVersion} LicenseFile={#GcmRepoRoot}\LICENSE -OutputBaseFilename={#GcmSetupExe}-win-{#GcmArch}-{#GcmVersionSimple} +OutputBaseFilename={#GcmSetupExe}-{#GcmRuntimeIdentifier}-{#GcmVersionSimple} DefaultDirName={autopf}\{#GcmShortName} Compression=lzma2 SolidCompression=yes diff --git a/src/windows/Installer.Windows/layout.ps1 b/src/windows/Installer.Windows/layout.ps1 index 818ee01c6..3fc43ab36 100644 --- a/src/windows/Installer.Windows/layout.ps1 +++ b/src/windows/Installer.Windows/layout.ps1 @@ -1,8 +1,29 @@ # Inputs -param ([Parameter(Mandatory)] $Configuration, [Parameter(Mandatory)] $Output, $SymbolOutput) +param ([Parameter(Mandatory)] $Configuration, [Parameter(Mandatory)] $Output, $RuntimeIdentifier, $SymbolOutput) Write-Output "Output: $Output" +# Determine a runtime if one was not provided +if (-not $RuntimeIdentifier) { + $arch = $env:PROCESSOR_ARCHITECTURE + switch ($arch) { + "AMD64" { $RuntimeIdentifier = "win-x64" } + "x86" { $RuntimeIdentifier = "win-x86" } + "ARM64" { $RuntimeIdentifier = "win-arm64" } + default { + Write-Host "Unknown architecture: $arch" + exit 1 + } + } +} + +Write-Output "Building for runtime '$RuntimeIdentifier'" + +if ($RuntimeIdentifier -ne 'win-x86' -and $RuntimeIdentifier -ne 'win-x64' -and $RuntimeIdentifier -ne 'win-arm64') { + Write-Host "Unsupported RuntimeIdentifier: $RuntimeIdentifier" + exit 1 +} + # Directories $THISDIR = $PSScriptRoot $ROOT = (Get-Item $THISDIR).Parent.Parent.Parent.FullName @@ -41,27 +62,55 @@ Write-Output "Publishing core application..." dotnet publish "$GCM_SRC" ` --framework net472 ` --configuration "$Configuration" ` - --runtime win-x86 ` + --runtime $RuntimeIdentifier ` --output "$PAYLOAD" # Delete libraries that are not needed for Windows but find their way # into the publish output. Remove-Item -Path "$PAYLOAD/*.dylib" -Force -ErrorAction Ignore -# Delete extraneous files that get included for other architectures -# We only care about x86 as the core GCM executable is only targeting x86 -Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/arm64/" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/x64/" -Recurse -Force -ErrorAction Ignore +# Delete extraneous files that get included for other runtimes Remove-Item -Path "$PAYLOAD/musl-x64/" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/runtimes/win-x64/" -Recurse -Force -ErrorAction Ignore - -# The Avalonia and MSAL binaries in these directories are already included in -# the $PAYLOAD directory directly, so we can delete these extra copies. -Remove-Item -Path "$PAYLOAD/x86/libSkiaSharp.dll" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/x86/libHarfBuzzSharp.dll" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/runtimes/win-x86/native/msalruntime_x86.dll" -Recurse -Force -ErrorAction Ignore + +switch ($RuntimeIdentifier) { + "win-x86" { + Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/arm64/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/x64/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/runtimes/win-x64/" -Recurse -Force -ErrorAction Ignore + # The Avalonia and MSAL binaries are already included in the $PAYLOAD directory directly + Remove-Item -Path "$PAYLOAD/x86/libSkiaSharp.dll" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/x86/libHarfBuzzSharp.dll" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/runtimes/win-x86/native/msalruntime_x86.dll" -Force -ErrorAction Ignore + } + "win-x64" { + Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/arm64/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/x86/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/runtimes/win-x86/" -Recurse -Force -ErrorAction Ignore + # The Avalonia and MSAL binaries are already included in the $PAYLOAD directory directly + Remove-Item -Path "$PAYLOAD/x64/libSkiaSharp.dll" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/x64/libHarfBuzzSharp.dll" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/x64/libSkiaSharp.so" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/x64/libHarfBuzzSharp.so" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/runtimes/win-x64/native/msalruntime.dll" -Force -ErrorAction Ignore + } + "win-arm64" { + Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/x86/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/x64/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/runtimes/win-x86/" -Recurse -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/runtimes/win-x64/" -Recurse -Force -ErrorAction Ignore + # The Avalonia and MSAL binaries are already included in the $PAYLOAD directory directly + Remove-Item -Path "$PAYLOAD/arm64/libSkiaSharp.dll" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/arm64/libHarfBuzzSharp.dll" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/arm64/libSkiaSharp.so" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/arm64/libHarfBuzzSharp.so" -Force -ErrorAction Ignore + Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/native/msalruntime_arm64.dll" -Force -ErrorAction Ignore + } +} # Delete localized resource assemblies - we don't localize the core GCM assembly anyway Get-ChildItem "$PAYLOAD" -Recurse -Include "*.resources.dll" | Remove-Item -Force -ErrorAction Ignore