From 2b0a79701fe592f65e5f4c7f3c419727491d8488 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Mon, 30 Mar 2026 15:00:25 +0100 Subject: [PATCH 1/3] ci: separate Git and GVFS installation Split the combined install.bat into separate Git and GVFS installers to allow callers to provide their own Git build independently. - Move microsoft/git download from build to validate job (runs once) - Generate a Git-only install.bat inline for the MicrosoftGit artifact - Simplify GVFS install.bat to only install SetupGVFS (no Git) - Rename installer artifact from Installers to GVFS - Download Git (git\), GVFS (gvfs\), and FTs (ft\) separately - Upload logs from both git\logs and gvfs\logs --- .github/workflows/build.yaml | 86 +++++++++++++++++++++++++------- GVFS/GVFS.Installers/install.bat | 18 +------ 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 2e2f532d3..369df0155 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -122,6 +122,48 @@ jobs: -Tag $env:GIT_VERSION && ` Write-Host ::notice title=Validation::Using microsoft/git version $env:GIT_VERSION + - name: Download microsoft/git installers + if: steps.check.outputs.result == '' + shell: cmd + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release download %GIT_VERSION% --repo microsoft/git --pattern "Git*.exe" --dir MicrosoftGit + + - name: Create Git install script + if: steps.check.outputs.result == '' + shell: cmd + run: | + >MicrosoftGit\install.bat ( + echo @ECHO OFF + echo SETLOCAL + echo. + echo IF "%%PROCESSOR_ARCHITECTURE%%"=="AMD64" ^( + echo SET GIT_ARCH=64-bit + echo ^) ELSE IF "%%PROCESSOR_ARCHITECTURE%%"=="ARM64" ^( + echo SET GIT_ARCH=arm64 + echo ^) ELSE ^( + echo ECHO Unknown architecture: %%PROCESSOR_ARCHITECTURE%% + echo exit 1 + echo ^) + echo. + echo FOR /F "tokens=* USEBACKQ" %%%%F IN ^( `where /R %%~dp0 Git*-%%GIT_ARCH%%.exe` ^) DO SET GIT_INSTALLER=%%%%F + echo. + echo SET LOGDIR=%%~dp0\logs + echo IF EXIST %%LOGDIR%% ^( rmdir /S /Q %%LOGDIR%% ^) + echo mkdir %%LOGDIR%% + echo. + echo ECHO Installing Git ^(%%GIT_ARCH%%^)... + echo %%GIT_INSTALLER%% /LOG="%%LOGDIR%%\git.log" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /ALLOWDOWNGRADE=1 + ) + + - name: Upload microsoft/git installers + if: steps.check.outputs.result == '' + uses: actions/upload-artifact@v7 + with: + name: MicrosoftGit + path: MicrosoftGit + build: runs-on: windows-2025 name: Build and Unit Test @@ -173,14 +215,6 @@ jobs: shell: cmd run: src\scripts\CreateBuildArtifacts.bat ${{ matrix.configuration }} artifacts - - name: Download microsoft/git installers - if: steps.skip.outputs.result != 'true' - shell: cmd - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh release download %GIT_VERSION% --repo microsoft/git --pattern "Git*.exe" --dir artifacts\GVFS.Installers - - name: Upload functional tests drop if: steps.skip.outputs.result != 'true' uses: actions/upload-artifact@v7 @@ -195,11 +229,11 @@ jobs: name: FastFetch_${{ matrix.configuration }} path: artifacts\FastFetch - - name: Upload installers + - name: Upload GVFS installer if: steps.skip.outputs.result != 'true' uses: actions/upload-artifact@v7 with: - name: Installers_${{ matrix.configuration }} + name: GVFS_${{ matrix.configuration }} path: artifacts\GVFS.Installers functional_test: @@ -224,12 +258,19 @@ jobs: core.info(`Skipping: There already is a successful run: ${{ needs.validate.outputs.skip }}`) return true - - name: Download installers + - name: Download Git installer if: steps.skip.outputs.result != 'true' uses: actions/download-artifact@v8 with: - name: Installers_${{ matrix.configuration }} - path: install + name: MicrosoftGit + path: git + + - name: Download GVFS installer + if: steps.skip.outputs.result != 'true' + uses: actions/download-artifact@v8 + with: + name: GVFS_${{ matrix.configuration }} + path: gvfs - name: Download functional tests drop if: steps.skip.outputs.result != 'true' @@ -241,24 +282,31 @@ jobs: - name: ProjFS details (pre-install) if: steps.skip.outputs.result != 'true' shell: cmd - run: install\info.bat + run: gvfs\info.bat + + - name: Install Git + if: steps.skip.outputs.result != 'true' + shell: cmd + run: git\install.bat - - name: Install product + - name: Install VFS for Git if: steps.skip.outputs.result != 'true' shell: cmd - run: install\install.bat + run: gvfs\install.bat - name: ProjFS details (post-install) if: steps.skip.outputs.result != 'true' shell: cmd - run: install\info.bat + run: gvfs\info.bat - name: Upload installation logs if: always() && steps.skip.outputs.result != 'true' uses: actions/upload-artifact@v7 with: name: InstallationLogs_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} - path: install\logs + path: | + git\logs + gvfs\logs - name: Run functional tests if: steps.skip.outputs.result != 'true' @@ -285,7 +333,7 @@ jobs: - name: ProjFS details (post-test) if: always() && steps.skip.outputs.result != 'true' shell: cmd - run: install\info.bat + run: gvfs\info.bat ft_results: runs-on: ubuntu-latest # quickest runners diff --git a/GVFS/GVFS.Installers/install.bat b/GVFS/GVFS.Installers/install.bat index 8375be193..4a186743a 100644 --- a/GVFS/GVFS.Installers/install.bat +++ b/GVFS/GVFS.Installers/install.bat @@ -1,18 +1,7 @@ @ECHO OFF SETLOCAL -REM Determine the correct architecture for the installer -IF "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( - SET GIT_ARCH=64-bit -) ELSE IF "%PROCESSOR_ARCHITECTURE%"=="ARM64" ( - SET GIT_ARCH=arm64 -) ELSE ( - ECHO Unknown architecture: %PROCESSOR_ARCHITECTURE% - exit 1 -) - -REM Lookup full paths to Git and VFS for Git installers -FOR /F "tokens=* USEBACKQ" %%F IN ( `where /R %~dp0 Git*-%GIT_ARCH%.exe` ) DO SET GIT_INSTALLER=%%F +REM Lookup full path to VFS for Git installer FOR /F "tokens=* USEBACKQ" %%F IN ( `where /R %~dp0 SetupGVFS*.exe` ) DO SET GVFS_INSTALLER=%%F REM Create new empty directory for logs @@ -22,8 +11,5 @@ IF EXIST %LOGDIR% ( ) mkdir %LOGDIR% -ECHO Installing Git (%GIT_ARCH%)... -%GIT_INSTALLER% /LOG="%LOGDIR%\git.log" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /ALLOWDOWNGRADE=1 - ECHO Installing VFS for Git... -%GVFS_INSTALLER% /LOG="%LOGDIR%\gvfs.log" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /DIR="C:\Program Files\VFS for Git" +%GVFS_INSTALLER% /LOG="%LOGDIR%\gvfs.log" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /DIR="C:\Program Files\VFS for Git" From e7e46dc04c5386f4bd5e5c000bd700c30f6f168a Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Mon, 30 Mar 2026 15:06:09 +0100 Subject: [PATCH 2/3] ci: extract functional tests into reusable workflow Lift-and-shift the functional_test and ft_results jobs from build.yaml into a new functional-tests.yaml reusable workflow (workflow_call). build.yaml now calls the reusable workflow, passing only the skip input. No parameterisation yet - artifact names and download sources are hardcoded to match the current same-repo behaviour. --- .github/workflows/build.yaml | 117 ++---------------------- .github/workflows/functional-tests.yaml | 113 +++++++++++++++++++++++ 2 files changed, 119 insertions(+), 111 deletions(-) create mode 100644 .github/workflows/functional-tests.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 369df0155..e5c92f3a1 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -20,6 +20,7 @@ on: permissions: contents: read + actions: read env: GIT_VERSION: ${{ github.event.inputs.git_version || 'v2.53.0.vfs.0.5' }} @@ -236,123 +237,17 @@ jobs: name: GVFS_${{ matrix.configuration }} path: artifacts\GVFS.Installers - functional_test: - runs-on: ${{ matrix.architecture == 'arm64' && 'windows-11-arm' || 'windows-2025' }} + functional_tests: name: Functional Tests needs: [validate, build] - - strategy: - matrix: - configuration: [ Debug, Release ] - architecture: [ x86_64, arm64 ] - nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 10 parallel jobs to speed up the tests - fail-fast: false # most failures are flaky tests, no need to stop the other jobs from succeeding - - steps: - - name: Skip this job if there is a previous successful run - if: needs.validate.outputs.skip != '' - id: skip - uses: actions/github-script@v8 - with: - script: | - core.info(`Skipping: There already is a successful run: ${{ needs.validate.outputs.skip }}`) - return true - - - name: Download Git installer - if: steps.skip.outputs.result != 'true' - uses: actions/download-artifact@v8 - with: - name: MicrosoftGit - path: git - - - name: Download GVFS installer - if: steps.skip.outputs.result != 'true' - uses: actions/download-artifact@v8 - with: - name: GVFS_${{ matrix.configuration }} - path: gvfs - - - name: Download functional tests drop - if: steps.skip.outputs.result != 'true' - uses: actions/download-artifact@v8 - with: - name: FunctionalTests_${{ matrix.configuration }} - path: ft - - - name: ProjFS details (pre-install) - if: steps.skip.outputs.result != 'true' - shell: cmd - run: gvfs\info.bat - - - name: Install Git - if: steps.skip.outputs.result != 'true' - shell: cmd - run: git\install.bat - - - name: Install VFS for Git - if: steps.skip.outputs.result != 'true' - shell: cmd - run: gvfs\install.bat - - - name: ProjFS details (post-install) - if: steps.skip.outputs.result != 'true' - shell: cmd - run: gvfs\info.bat - - - name: Upload installation logs - if: always() && steps.skip.outputs.result != 'true' - uses: actions/upload-artifact@v7 - with: - name: InstallationLogs_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} - path: | - git\logs - gvfs\logs - - - name: Run functional tests - if: steps.skip.outputs.result != 'true' - shell: cmd - run: | - SET PATH=C:\Program Files\VFS for Git;%PATH% - SET GIT_TRACE2_PERF=C:\temp\git-trace2.log - ft\GVFS.FunctionalTests.exe /result:TestResult.xml --ci --slice=${{ matrix.nr }},10 - - - name: Upload functional test results - if: always() && steps.skip.outputs.result != 'true' - uses: actions/upload-artifact@v7 - with: - name: FunctionalTests_Results_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} - path: TestResult.xml - - - name: Upload Git trace2 output - if: always() && steps.skip.outputs.result != 'true' - uses: actions/upload-artifact@v7 - with: - name: GitTrace2_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} - path: C:\temp\git-trace2.log - - - name: ProjFS details (post-test) - if: always() && steps.skip.outputs.result != 'true' - shell: cmd - run: gvfs\info.bat - - ft_results: - runs-on: ubuntu-latest # quickest runners - name: Functional Tests - needs: [functional_test] - - strategy: - matrix: - configuration: [ Debug, Release ] - architecture: [ x86_64, arm64 ] - - steps: - - name: Success! # for easier identification of successful runs in the Checks Required for Pull Requests - run: echo "All functional test jobs successful for ${{ matrix.configuration }} / ${{ matrix.architecture }}!" + uses: ./.github/workflows/functional-tests.yaml + with: + skip: ${{ needs.validate.outputs.skip }} result: runs-on: ubuntu-latest name: Build, Unit and Functional Tests Successful - needs: [functional_test] + needs: [functional_tests] steps: - name: Success! # for easier identification of successful runs in the Checks Required for Pull Requests diff --git a/.github/workflows/functional-tests.yaml b/.github/workflows/functional-tests.yaml new file mode 100644 index 000000000..ab6810dea --- /dev/null +++ b/.github/workflows/functional-tests.yaml @@ -0,0 +1,113 @@ +name: Functional Tests + +on: + workflow_call: + inputs: + skip: + description: 'URL of a previous successful run; if non-empty, all steps are skipped (job still succeeds for required checks)' + required: false + type: string + default: '' + +permissions: + contents: read + actions: read + +jobs: + functional_test: + runs-on: ${{ matrix.architecture == 'arm64' && 'windows-11-arm' || 'windows-2025' }} + name: Test + + strategy: + matrix: + configuration: [ Debug, Release ] + architecture: [ x86_64, arm64 ] + nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 10 parallel jobs to speed up the tests + fail-fast: false # most failures are flaky tests, no need to stop the other jobs from succeeding + + steps: + - name: Skip this job if there is a previous successful run + if: inputs.skip != '' + id: skip + uses: actions/github-script@v8 + with: + script: | + core.info(`Skipping: There already is a successful run: ${{ inputs.skip }}`) + return true + + - name: Download Git installer + if: steps.skip.outputs.result != 'true' + uses: actions/download-artifact@v8 + with: + name: MicrosoftGit + path: git + + - name: Download GVFS installer + if: steps.skip.outputs.result != 'true' + uses: actions/download-artifact@v8 + with: + name: GVFS_${{ matrix.configuration }} + path: gvfs + + - name: Download functional tests drop + if: steps.skip.outputs.result != 'true' + uses: actions/download-artifact@v8 + with: + name: FunctionalTests_${{ matrix.configuration }} + path: ft + + - name: ProjFS details (pre-install) + if: steps.skip.outputs.result != 'true' + shell: cmd + run: gvfs\info.bat + + - name: Install Git + if: steps.skip.outputs.result != 'true' + shell: cmd + run: git\install.bat + + - name: Install VFS for Git + if: steps.skip.outputs.result != 'true' + shell: cmd + run: gvfs\install.bat + + - name: ProjFS details (post-install) + if: steps.skip.outputs.result != 'true' + shell: cmd + run: gvfs\info.bat + + - name: Upload installation logs + if: always() && steps.skip.outputs.result != 'true' + uses: actions/upload-artifact@v7 + with: + name: InstallationLogs_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} + path: | + git\logs + gvfs\logs + + - name: Run functional tests + if: steps.skip.outputs.result != 'true' + shell: cmd + run: | + SET PATH=C:\Program Files\VFS for Git;%PATH% + SET GIT_TRACE2_PERF=C:\temp\git-trace2.log + ft\GVFS.FunctionalTests.exe /result:TestResult.xml --ci --slice=${{ matrix.nr }},10 + + - name: Upload functional test results + if: always() && steps.skip.outputs.result != 'true' + uses: actions/upload-artifact@v7 + with: + name: FunctionalTests_Results_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} + path: TestResult.xml + + - name: Upload Git trace2 output + if: always() && steps.skip.outputs.result != 'true' + uses: actions/upload-artifact@v7 + with: + name: GitTrace2_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} + path: C:\temp\git-trace2.log + + - name: ProjFS details (post-test) + if: always() && steps.skip.outputs.result != 'true' + shell: cmd + run: gvfs\info.bat From 3e26fc6b0a145e162f3d5af58d741b6637784e77 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Mon, 30 Mar 2026 15:08:00 +0100 Subject: [PATCH 3/3] ci: parameterise functional tests workflow for cross-repo use Add inputs to allow microsoft/git (or other callers) to provide their own Git build and download VFSForGit artifacts cross-repo: - vfs_run_id: paired run ID for GVFS installer + FT executables - git_repository/git_run_id/git_artifact_name: Git installer source - output_prefix: namespace uploaded artifacts (e.g. 'VFSForGit') - vfs_token/git_token: secrets for cross-repo artifact downloads Add env vars ARTIFACT_PREFIX and FT_MATRIX_NAME to simplify artifact naming expressions. Add continue-on-error to diagnostic steps. Signed-off-by: Matthew John Cheetham --- .github/workflows/functional-tests.yaml | 57 +++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/.github/workflows/functional-tests.yaml b/.github/workflows/functional-tests.yaml index ab6810dea..9524aef20 100644 --- a/.github/workflows/functional-tests.yaml +++ b/.github/workflows/functional-tests.yaml @@ -3,11 +3,43 @@ name: Functional Tests on: workflow_call: inputs: + vfs_run_id: + description: 'Workflow run ID to download FT executables and GVFS installer from (defaults to the calling run)' + required: false + type: string + default: '' + git_repository: + description: 'Repository to download the Git installer artifact from (defaults to the calling repository)' + required: false + type: string + default: '' + git_run_id: + description: 'Workflow run ID to download the Git installer artifact from (defaults to the calling run)' + required: false + type: string + default: '' + git_artifact_name: + description: 'Name of the artifact containing the Git installer (must include an install.bat script)' + required: false + type: string + default: 'MicrosoftGit' skip: description: 'URL of a previous successful run; if non-empty, all steps are skipped (job still succeeds for required checks)' required: false type: string default: '' + output_prefix: + description: 'Prefix for uploaded artifact names (e.g. "VFSForGit" to namespace artifacts in cross-repo runs)' + required: false + type: string + default: '' + secrets: + vfs_token: + description: 'Token for downloading VFSForGit artifacts (required for cross-repository downloads; defaults to GITHUB_TOKEN)' + required: false + git_token: + description: 'Token for downloading the Git installer artifact (required for cross-repository downloads; defaults to GITHUB_TOKEN)' + required: false permissions: contents: read @@ -18,6 +50,10 @@ jobs: runs-on: ${{ matrix.architecture == 'arm64' && 'windows-11-arm' || 'windows-2025' }} name: Test + env: + ARTIFACT_PREFIX: ${{ inputs.output_prefix && format('{0}_', inputs.output_prefix) || '' }} + FT_MATRIX_NAME: ${{ format('{0}_{1}-{2}', matrix.configuration, matrix.architecture, matrix.nr) }} + strategy: matrix: configuration: [ Debug, Release ] @@ -39,8 +75,11 @@ jobs: if: steps.skip.outputs.result != 'true' uses: actions/download-artifact@v8 with: - name: MicrosoftGit + name: ${{ inputs.git_artifact_name }} path: git + repository: ${{ inputs.git_repository || github.repository }} + run-id: ${{ inputs.git_run_id || github.run_id }} + github-token: ${{ secrets.git_token || github.token }} - name: Download GVFS installer if: steps.skip.outputs.result != 'true' @@ -48,6 +87,9 @@ jobs: with: name: GVFS_${{ matrix.configuration }} path: gvfs + repository: microsoft/VFSForGit + run-id: ${{ inputs.vfs_run_id || github.run_id }} + github-token: ${{ secrets.vfs_token || github.token }} - name: Download functional tests drop if: steps.skip.outputs.result != 'true' @@ -55,10 +97,14 @@ jobs: with: name: FunctionalTests_${{ matrix.configuration }} path: ft + repository: microsoft/VFSForGit + run-id: ${{ inputs.vfs_run_id || github.run_id }} + github-token: ${{ secrets.vfs_token || github.token }} - name: ProjFS details (pre-install) if: steps.skip.outputs.result != 'true' shell: cmd + continue-on-error: true run: gvfs\info.bat - name: Install Git @@ -74,13 +120,15 @@ jobs: - name: ProjFS details (post-install) if: steps.skip.outputs.result != 'true' shell: cmd + continue-on-error: true run: gvfs\info.bat - name: Upload installation logs if: always() && steps.skip.outputs.result != 'true' uses: actions/upload-artifact@v7 + continue-on-error: true with: - name: InstallationLogs_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} + name: ${{ env.ARTIFACT_PREFIX }}InstallationLogs_${{ env.FT_MATRIX_NAME }} path: | git\logs gvfs\logs @@ -97,17 +145,18 @@ jobs: if: always() && steps.skip.outputs.result != 'true' uses: actions/upload-artifact@v7 with: - name: FunctionalTests_Results_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} + name: ${{ env.ARTIFACT_PREFIX }}FunctionalTests_Results_${{ env.FT_MATRIX_NAME }} path: TestResult.xml - name: Upload Git trace2 output if: always() && steps.skip.outputs.result != 'true' uses: actions/upload-artifact@v7 with: - name: GitTrace2_${{ matrix.configuration }}_${{ matrix.architecture }}-${{ matrix.nr }} + name: ${{ env.ARTIFACT_PREFIX }}GitTrace2_${{ env.FT_MATRIX_NAME }} path: C:\temp\git-trace2.log - name: ProjFS details (post-test) if: always() && steps.skip.outputs.result != 'true' shell: cmd + continue-on-error: true run: gvfs\info.bat