Skip to content

TO DROP

TO DROP #282

name: build-git-installers
on:
push:
tags:
- 'v[0-9]*vfs*' # matches "v<number><any characters>vfs<any characters>"
permissions:
id-token: write # required for Azure login via OIDC
env:
DO_WIN_CODESIGN: ${{ secrets.WIN_CODESIGN_CERT_SECRET_NAME != '' && secrets.WIN_CODESIGN_PASS_SECRET_NAME != '' }}
DO_WIN_GPGSIGN: ${{ secrets.WIN_GPG_KEYGRIP_SECRET_NAME != '' && secrets.WIN_GPG_PRIVATE_SECRET_NAME != '' && secrets.WIN_GPG_PASSPHRASE_SECRET_NAME != '' }}
jobs:
# Check prerequisites for the workflow
prereqs:
runs-on: ubuntu-latest
outputs:
tag_name: ${{ steps.tag.outputs.name }} # The full name of the tag, e.g. v2.32.0.vfs.0.0
tag_version: ${{ steps.tag.outputs.version }} # The version number (without preceding "v"), e.g. 2.32.0.vfs.0.0
steps:
- name: Validate tag
run: |
echo "$GITHUB_REF" |
grep -E '^refs/tags/v2\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.vfs\.0\.(0|[1-9][0-9]*)(\.rc[0-9])?$' || {
echo "::error::${GITHUB_REF#refs/tags/} is not of the form v2.<X>.<Y>.vfs.0.<W>[.rc<N>]" >&2
exit 1
}
- name: Determine tag to build
run: |
echo "name=${GITHUB_REF#refs/tags/}" >>$GITHUB_OUTPUT
echo "version=${GITHUB_REF#refs/tags/v}" >>$GITHUB_OUTPUT
id: tag
- name: Clone git
uses: actions/checkout@v4
- name: Validate the tag identified with trigger
run: |
die () {
echo "::error::$*" >&2
exit 1
}
# `actions/checkout` only downloads the peeled tag (i.e. the commit)
git fetch origin +$GITHUB_REF:$GITHUB_REF
# Verify that the tag is annotated
test $(git cat-file -t "$GITHUB_REF") == "tag" || die "Tag ${{ steps.tag.outputs.name }} is not annotated"
# Verify tag follows rules in GIT-VERSION-GEN (i.e., matches the specified "DEF_VER" in
# GIT-VERSION-FILE) and matches tag determined from trigger
make GIT-VERSION-FILE
test "${{ steps.tag.outputs.version }}" == "$(sed -n 's/^GIT_VERSION *= *//p'< GIT-VERSION-FILE)" || die "GIT-VERSION-FILE tag ($(cat GIT-VERSION-FILE)) does not match ${{ steps.tag.outputs.name }}"
# End check prerequisites for the workflow
# Build Windows installers (x86_64 & aarch64; installer & portable)
windows_pkg:
environment: release
needs: prereqs
strategy:
fail-fast: false
matrix:
arch:
- name: aarch64
artifact: pkg-aarch64
toolchain: clang-aarch64
mingwprefix: clangarm64
runner: windows-11-arm
runs-on: ${{ matrix.arch.runner }}
env:
GPG_OPTIONS: "--batch --yes --no-tty --list-options no-show-photos --verify-options no-show-photos --pinentry-mode loopback"
HOME: "${{github.workspace}}\\home"
USERPROFILE: "${{github.workspace}}\\home"
steps:
- name: Configure user
shell: bash
run:
USER_NAME="${{github.actor}}" &&
USER_EMAIL="${{github.actor}}@users.noreply.github.com" &&
mkdir -p "$HOME" &&
git config --global user.name "$USER_NAME" &&
git config --global user.email "$USER_EMAIL" &&
echo "PACKAGER=$USER_NAME <$USER_EMAIL>" >>$GITHUB_ENV
- uses: git-for-windows/setup-git-for-windows-sdk@v1
with:
flavor: build-installers
architecture: ${{ matrix.arch.name }}
- name: Clone build-extra
shell: bash
run: |
git clone --filter=blob:none --single-branch -b main https://github.com/git-for-windows/build-extra /usr/src/build-extra
- name: Clone git
shell: bash
run: |
# Since we cannot directly clone a specified tag (as we would a branch with `git clone -b <branch name>`),
# this clone has to be done manually (via init->fetch->reset).
tag_name="${{ needs.prereqs.outputs.tag_name }}" &&
git -c init.defaultBranch=main init &&
git remote add -f origin https://github.com/git-for-windows/git &&
git fetch "https://github.com/${{github.repository}}" refs/tags/${tag_name}:refs/tags/${tag_name} &&
git reset --hard ${tag_name}
- name: Log in to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Download code signing secrets
id: codesign-secrets
if: env.DO_WIN_CODESIGN == 'true'
uses: ./.github/actions/akv-secret
with:
vault: ${{ secrets.AZURE_VAULT }}
secrets: |
${{ secrets.WIN_CODESIGN_CERT_SECRET_NAME }} base64> home/.sig/codesign.p12
${{ secrets.WIN_CODESIGN_PASS_SECRET_NAME }} > home/.sig/codesign.pass
- name: Prepare home directory for code-signing
if: ${{ steps.codesign-secrets.outcome == 'success' }}
shell: bash
run: |
git config --global alias.signtool '!sh "/usr/src/build-extra/signtool.sh"'
- name: Download GPG secrets
id: gpg-secrets
if: env.DO_WIN_GPGSIGN == 'true'
uses: ./.github/actions/akv-secret
with:
vault: ${{ secrets.AZURE_VAULT }}
secrets: |
${{ secrets.WIN_GPG_KEYGRIP_SECRET_NAME }} > $output:keygrip
${{ secrets.WIN_GPG_PRIVATE_SECRET_NAME }} > $output:private-key
${{ secrets.WIN_GPG_PASSPHRASE_SECRET_NAME }} > $output:passphrase
- name: Prepare home directory for GPG signing
if: ${{ steps.gpg-secrets.outputs.keygrip != '' && steps.gpg-secrets.outputs.private-key != '' }}
shell: bash
run: |
# This section ensures that the identity for the GPG key matches the git user identity, otherwise
# signing will fail
# Import the GPG private key
echo -n '${{ steps.gpg-secrets.outputs.private-key }}' | gpg $GPG_OPTIONS --import &&
info="$(gpg --list-keys --with-colons '${{ steps.gpg-secrets.outputs.keygrip }}' | cut -d : -f 1,10 | sed -n '/^uid/{s|uid:||p;q}')" &&
git config --global user.name "${info% <*}" &&
git config --global user.email "<${info#*<}"
- name: Build mingw-w64-${{matrix.arch.toolchain}}-git
shell: bash
run: |
set -x
# Build the GPGKEY variable
export GPGKEY="${{ steps.gpg-secrets.outputs.keygrip }} --passphrase '${{ steps.gpg-secrets.outputs.passphrase }}' --yes --batch --no-tty --pinentry-mode loopback --digest-algo SHA256" &&
# Make sure that there is a `/usr/bin/git` that can be used by `makepkg-mingw`
printf '#!/bin/sh\n\nexec /${{matrix.arch.mingwprefix}}/bin/git.exe "$@"\n' >/usr/bin/git &&
sh -x /usr/src/build-extra/please.sh build-mingw-w64-git --only-${{matrix.arch.name}} --build-src-pkg -o artifacts HEAD &&
if test -n "${{ steps.gpg-secrets.outputs.keygrip }}"
then
for tar in artifacts/*.tar*
do
/usr/src/build-extra/gnupg-with-gpgkey.sh --detach-sign --no-armor $tar
done
fi &&
b=$PWD/artifacts &&
version=${{ needs.prereqs.outputs.tag_name }} &&
(cd /usr/src/MINGW-packages/mingw-w64-git &&
cp PKGBUILD.$version PKGBUILD &&
git commit -s -m "mingw-w64-git: new version ($version)" PKGBUILD &&
git bundle create "$b"/MINGW-packages.bundle origin/main..main)
- name: Publish mingw-w64-${{matrix.arch.toolchain}}-git
uses: actions/upload-artifact@v4
with:
name: "${{ matrix.arch.artifact }}"
path: artifacts
windows_artifacts:
environment: release
needs: [prereqs, windows_pkg]
env:
HOME: "${{github.workspace}}\\home"
strategy:
fail-fast: false
matrix:
arch:
- name: aarch64
artifact: pkg-aarch64
toolchain: clang-aarch64
mingwprefix: clangarm64
runner: windows-11-arm
type:
- name: installer
fileprefix: Git
- name: portable
fileprefix: PortableGit
runs-on: ${{ matrix.arch.runner }}
steps:
- name: Download ${{ matrix.arch.artifact }}
uses: actions/download-artifact@v4
with:
name: ${{ matrix.arch.artifact }}
path: ${{ matrix.arch.artifact }}
- uses: git-for-windows/setup-git-for-windows-sdk@v1
with:
flavor: build-installers
architecture: ${{ matrix.arch.name }}
- name: Clone build-extra
shell: bash
run: |
git clone --filter=blob:none --single-branch -b main https://github.com/git-for-windows/build-extra /usr/src/build-extra
- name: Download code signing secrets
id: codesign-secrets
if: env.DO_WIN_CODESIGN == 'true'
uses: ./.github/actions/akv-secret
with:
vault: ${{ secrets.AZURE_VAULT }}
secrets: |
${{ secrets.WIN_CODESIGN_CERT_SECRET_NAME }} base64> home/.sig/codesign.p12
${{ secrets.WIN_CODESIGN_PASS_SECRET_NAME }} > home/.sig/codesign.pass
- name: Prepare home directory for code-signing
if: ${{ steps.codesign-secrets.outcome == 'success' }}
shell: bash
run: |
git config --global alias.signtool '!sh "/usr/src/build-extra/signtool.sh"'
- name: Retarget auto-update to microsoft/git
shell: bash
run: |
set -x
b=/usr/src/build-extra &&
filename=$b/git-update-git-for-windows.config
tr % '\t' >$filename <<-\EOF &&
[update]
%fromFork = microsoft/git
EOF
sed -i -e '/^#include "file-list.iss"/a\
Source: {#SourcePath}\\..\\git-update-git-for-windows.config; DestDir: {app}\\${{matrix.arch.mingwprefix}}\\bin; Flags: replacesameversion; AfterInstall: DeleteFromVirtualStore' \
-e '/^Type: dirifempty; Name: {app}\\{#MINGW_BITNESS}$/i\
Type: files; Name: {app}\\{#MINGW_BITNESS}\\bin\\git-update-git-for-windows.config\
Type: dirifempty; Name: {app}\\{#MINGW_BITNESS}\\bin' \
$b/installer/install.iss
- name: Set alerts to continue until upgrade is taken
shell: bash
run: |
set -x
b=/${{matrix.arch.mingwprefix}}/bin &&
sed -i -e '6 a use_recently_seen=no' \
$b/git-update-git-for-windows
- name: Set the installer Publisher to the Git Client team
shell: bash
run: |
b=/usr/src/build-extra &&
sed -i -e 's/^\(AppPublisher=\).*/\1The Git Client Team at Microsoft/' $b/installer/install.iss
- name: Let the installer configure Visual Studio to use the installed Git
shell: bash
run: |
set -x
b=/usr/src/build-extra &&
sed -i "# First, find the autoupdater parts in the install/uninstall steps
/if IsComponentInstalled('autoupdate')/{
# slurp in the next two lines, where the call to InstallAutoUpdater()/UninstallAutoUpdater() happens
N
N
# insert the corresponding CustomPostInstall()/CustomPostUninstall() call before that block
s/^\\([ \t]*\\)\(.*\\)\\(Install\\|Uninstall\\)\\(AutoUpdater\\)/\\1CustomPost\\3();\\n\\1\\2\\3\\4/
}" $b/installer/install.iss &&
grep CustomPostInstall $b/installer/install.iss &&
grep CustomPostUninstall $b/installer/install.iss &&
cat >>$b/installer/helpers.inc.iss <<\EOF
procedure CustomPostInstall();
begin
if not RegWriteStringValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\15.0\TeamFoundation\GitSourceControl','GitPath',ExpandConstant('{app}')) or
not RegWriteStringValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\16.0\TeamFoundation\GitSourceControl','GitPath',ExpandConstant('{app}')) or
not RegWriteStringValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\17.0\TeamFoundation\GitSourceControl','GitPath',ExpandConstant('{app}')) or
not RegWriteStringValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\18.0\TeamFoundation\GitSourceControl','GitPath',ExpandConstant('{app}')) or
not RegWriteStringValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\19.0\TeamFoundation\GitSourceControl','GitPath',ExpandConstant('{app}')) or
not RegWriteStringValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\20.0\TeamFoundation\GitSourceControl','GitPath',ExpandConstant('{app}')) then
LogError('Could not register TeamFoundation\GitSourceControl');
end;
procedure CustomPostUninstall();
begin
if not RegDeleteValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\15.0\TeamFoundation\GitSourceControl','GitPath') or
not RegDeleteValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\16.0\TeamFoundation\GitSourceControl','GitPath') or
not RegDeleteValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\17.0\TeamFoundation\GitSourceControl','GitPath') or
not RegDeleteValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\18.0\TeamFoundation\GitSourceControl','GitPath') or
not RegDeleteValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\19.0\TeamFoundation\GitSourceControl','GitPath') or
not RegDeleteValue(HKEY_CURRENT_USER,'Software\Microsoft\VSCommon\20.0\TeamFoundation\GitSourceControl','GitPath') then
LogError('Could not register TeamFoundation\GitSourceControl');
end;
EOF
- name: Enable Scalar/C and the auto-updater in the installer by default
shell: bash
run: |
set -x
b=/usr/src/build-extra &&
sed -i -e "/ChosenOptions:=''/a\\
if (ExpandConstant('{param:components|/}')='/') then begin\n\
WizardSelectComponents('autoupdate');\n\
#ifdef WITH_SCALAR\n\
WizardSelectComponents('scalar');\n\
#endif\n\
end;" $b/installer/install.iss
- name: Build ${{matrix.type.name}} (${{matrix.arch.name}})
shell: bash
run: |
set -x
# Copy the PDB archive to the directory where `--include-pdbs` expects it
b=/usr/src/build-extra &&
mkdir -p $b/cached-source-packages &&
cp ${{matrix.arch.artifact}}/*-pdb* $b/cached-source-packages/ &&
# Build the installer, embedding PDBs
eval $b/please.sh make_installers_from_mingw_w64_git --include-pdbs \
--version=${{ needs.prereqs.outputs.tag_version }} \
-o artifacts --${{matrix.type.name}} \
--pkg=${{matrix.arch.artifact}}/mingw-w64-${{matrix.arch.toolchain}}-git-[0-9]*.tar.xz \
--pkg=${{matrix.arch.artifact}}/mingw-w64-${{matrix.arch.toolchain}}-git-doc-html-[0-9]*.tar.xz &&
if test portable = '${{matrix.type.name}}' && test -n "$(git config alias.signtool)"
then
git signtool artifacts/PortableGit-*.exe
fi &&
openssl dgst -sha256 artifacts/${{matrix.type.fileprefix}}-*.exe | sed "s/.* //" >artifacts/sha-256.txt
- name: Verify that .exe files are code-signed
env:
DO_CODE_SIGN: ${{ secrets.WIN_CODESIGN_CERT_SECRET_NAME != '' }}
if: env.DO_CODE_SIGN == 'true'
shell: bash
run: |
PATH=$PATH:"/c/Program Files (x86)/Windows Kits/10/App Certification Kit/" \
signtool verify //pa artifacts/${{matrix.type.fileprefix}}-*.exe
- name: Publish ${{matrix.type.name}}-${{matrix.arch.name}}
uses: actions/upload-artifact@v4
with:
name: win-${{matrix.type.name}}-${{matrix.arch.name}}
path: artifacts
# End build Windows installers
# Validate installers
validate-installers:
name: Validate installers
strategy:
matrix:
component:
- os: windows-11-arm
artifact: win-installer-aarch64
command: $PROGRAMFILES\Git\cmd\git.exe
runs-on: ${{ matrix.component.os }}
needs: [prereqs, windows_artifacts]
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: ${{ matrix.component.artifact }}
- name: Install Windows
if: contains(matrix.component.artifact, 'win-installer')
shell: pwsh
run: |
$exePath = Get-ChildItem -Path ./*.exe | %{$_.FullName}
Start-Process -Wait -FilePath "$exePath" -ArgumentList "/SILENT /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /ALLOWDOWNGRADE=1"
- name: Install Linux
if: contains(matrix.component.artifact, 'linux')
run: |
debpath=$(find ./*.deb)
sudo apt install $debpath
- name: Install macOS
if: contains(matrix.component.artifact, 'macos')
run: |
# avoid letting Homebrew's `git` in `/opt/homebrew/bin` override `/usr/local/bin/git`
arch="$(uname -m)"
test arm64 != "$arch" ||
brew uninstall git
pkgpath=$(find ./*universal*.pkg)
sudo installer -pkg $pkgpath -target /
- name: Validate
shell: bash
run: |
"${{ matrix.component.command }}" --version | sed 's/git version //' >actual
echo ${{ needs.prereqs.outputs.tag_version }} >expect
cmp expect actual || exit 1
- name: Validate universal binary CPU architecture
if: contains(matrix.component.os, 'macos')
shell: bash
run: |
set -ex
git version --build-options >actual
cat actual
grep "cpu: $(uname -m)" actual
# End validate installers