diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..22d5376407 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +# especially +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot#enabling-dependabot-version-updates-for-actions + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a30be08797..2dc811ea47 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -17,17 +17,17 @@ jobs: steps: - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: src - name: Install .NET SDK - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: dotnet-version: 5.0.201 - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1.0.2 + uses: microsoft/setup-msbuild@v2.0.0 - name: Build VFS for Git shell: cmd @@ -42,25 +42,25 @@ jobs: run: src\scripts\CreateBuildArtifacts.bat ${{ matrix.configuration }} artifacts - name: Upload functional tests drop - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: FunctionalTests_${{ matrix.configuration }} path: artifacts\GVFS.FunctionalTests - name: Upload FastFetch drop - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: FastFetch_${{ matrix.configuration }} path: artifacts\FastFetch - name: Upload installers - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Installers_${{ matrix.configuration }} path: artifacts\GVFS.Installers - name: Upload NuGet packages - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: NuGetPackages_${{ matrix.configuration }} path: artifacts\NuGetPackages @@ -76,13 +76,13 @@ jobs: steps: - name: Download installers - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: Installers_${{ matrix.configuration }} path: install - name: Download functional tests drop - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: FunctionalTests_${{ matrix.configuration }} path: ft @@ -101,7 +101,7 @@ jobs: - name: Upload installation logs if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: InstallationLogs_${{ matrix.configuration }} path: install\logs @@ -115,14 +115,14 @@ jobs: - name: Upload functional test results if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: FunctionalTests_Results_${{ matrix.configuration }} path: TestResult.xml - name: Upload Git trace2 output if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: GitTrace2_${{ matrix.configuration }} path: C:\temp\git-trace2.log diff --git a/GVFS/FastFetch/FastFetch.csproj b/GVFS/FastFetch/FastFetch.csproj index 52bb94654f..1a2bdaae99 100644 --- a/GVFS/FastFetch/FastFetch.csproj +++ b/GVFS/FastFetch/FastFetch.csproj @@ -12,7 +12,7 @@ - + diff --git a/GVFS/GVFS.Common/GVFS.Common.csproj b/GVFS/GVFS.Common/GVFS.Common.csproj index e96c88ba78..e19e8ee2ec 100644 --- a/GVFS/GVFS.Common/GVFS.Common.csproj +++ b/GVFS/GVFS.Common/GVFS.Common.csproj @@ -6,7 +6,7 @@ - + diff --git a/GVFS/GVFS.Common/Http/HttpRequestor.cs b/GVFS/GVFS.Common/Http/HttpRequestor.cs index 1f5271d679..ca850c9fb5 100644 --- a/GVFS/GVFS.Common/Http/HttpRequestor.cs +++ b/GVFS/GVFS.Common/Http/HttpRequestor.cs @@ -134,6 +134,14 @@ protected GitEndPointResponseData SendRequest( { response = this.client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).GetAwaiter().GetResult(); } + catch (HttpRequestException httpRequestException) when (TryGetResponseMessageFromHttpRequestException(httpRequestException, request, out response)) + { + /* HttpClientHandler will automatically resubmit in certain circumstances, such as a 401 unauthorized response when UseDefaultCredentials + * is true but another credential was provided. This resubmit can throw (instead of returning a proper status code) in some case cases, such + * as when there is an exception loading the default credentials. + * If we can extract the original response message from the exception, we can continue and process the original failed status code. */ + Tracer.RelatedWarning(responseMetadata, $"An exception occurred while resubmitting the request, but the original response is available."); + } finally { responseWaitTime = requestStopwatch.Elapsed; @@ -278,5 +286,48 @@ private static string GetSingleHeaderOrEmpty(HttpHeaders headers, string headerN return string.Empty; } + + /// + /// This method is based on a private method System.Net.Http.HttpClientHandler.CreateResponseMessage + /// + private static bool TryGetResponseMessageFromHttpRequestException(HttpRequestException httpRequestException, HttpRequestMessage request, out HttpResponseMessage httpResponseMessage) + { + var webResponse = (httpRequestException?.InnerException as WebException)?.Response as HttpWebResponse; + if (webResponse == null) + { + httpResponseMessage = null; + return false; + } + + httpResponseMessage = new HttpResponseMessage(webResponse.StatusCode); + httpResponseMessage.ReasonPhrase = webResponse.StatusDescription; + httpResponseMessage.Version = webResponse.ProtocolVersion; + httpResponseMessage.RequestMessage = request; + httpResponseMessage.Content = new StreamContent(webResponse.GetResponseStream()); + request.RequestUri = webResponse.ResponseUri; + WebHeaderCollection rawHeaders = webResponse.Headers; + HttpContentHeaders responseContentHeaders = httpResponseMessage.Content.Headers; + HttpResponseHeaders responseHeaders = httpResponseMessage.Headers; + if (webResponse.ContentLength >= 0) + { + responseContentHeaders.ContentLength = webResponse.ContentLength; + } + + for (int i = 0; i < rawHeaders.Count; i++) + { + string key = rawHeaders.GetKey(i); + if (string.Compare(key, "Content-Length", StringComparison.OrdinalIgnoreCase) != 0) + { + string[] values = rawHeaders.GetValues(i); + if (!responseHeaders.TryAddWithoutValidation(key, values)) + { + bool flag = responseContentHeaders.TryAddWithoutValidation(key, values); + } + } + } + + return true; + + } } } diff --git a/GVFS/GVFS.FunctionalTests.LockHolder/GVFS.FunctionalTests.LockHolder.csproj b/GVFS/GVFS.FunctionalTests.LockHolder/GVFS.FunctionalTests.LockHolder.csproj index 9a1615fbf3..290a12b469 100644 --- a/GVFS/GVFS.FunctionalTests.LockHolder/GVFS.FunctionalTests.LockHolder.csproj +++ b/GVFS/GVFS.FunctionalTests.LockHolder/GVFS.FunctionalTests.LockHolder.csproj @@ -6,7 +6,7 @@ - + diff --git a/GVFS/GVFS.Installers/GVFS.Installers.csproj b/GVFS/GVFS.Installers/GVFS.Installers.csproj index 1f5b692d1c..44c166d565 100644 --- a/GVFS/GVFS.Installers/GVFS.Installers.csproj +++ b/GVFS/GVFS.Installers/GVFS.Installers.csproj @@ -12,7 +12,7 @@ - + diff --git a/GVFS/GVFS.Installers/Setup.iss b/GVFS/GVFS.Installers/Setup.iss index ca93ac9142..109f4f45bc 100644 --- a/GVFS/GVFS.Installers/Setup.iss +++ b/GVFS/GVFS.Installers/Setup.iss @@ -221,8 +221,12 @@ begin WizardForm.StatusLabel.Caption := 'Installing GVFS.Service.'; WizardForm.ProgressGauge.Style := npbstMarquee; + // Spaces after the equal signs are REQUIRED. + // https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/sc-create#remarks try - if Exec(ExpandConstant('{sys}\SC.EXE'), ExpandConstant('create GVFS.Service binPath="{app}\GVFS.Service.exe" start=auto'), '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0) then + // We must add additional quotes to the binPath to ensure that they survive argument parsing. + // Without quotes, sc.exe will try to start a file located at C:\Program if it exists. + if Exec(ExpandConstant('{sys}\SC.EXE'), ExpandConstant('create GVFS.Service binPath= "\"{app}\GVFS.Service.exe\"" start= auto'), '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0) then begin if Exec(ExpandConstant('{sys}\SC.EXE'), 'failure GVFS.Service reset= 30 actions= restart/10/restart/5000//1', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then begin diff --git a/GVFS/GVFS.Mount/GVFS.Mount.csproj b/GVFS/GVFS.Mount/GVFS.Mount.csproj index b770e6f99c..6e41c00081 100644 --- a/GVFS/GVFS.Mount/GVFS.Mount.csproj +++ b/GVFS/GVFS.Mount/GVFS.Mount.csproj @@ -16,7 +16,7 @@ - + diff --git a/GVFS/GVFS/GVFS.csproj b/GVFS/GVFS/GVFS.csproj index 8c143ebbc7..6d9d579f9c 100644 --- a/GVFS/GVFS/GVFS.csproj +++ b/GVFS/GVFS/GVFS.csproj @@ -16,7 +16,7 @@ - + diff --git a/Version.props b/Version.props index 6ee26e84bc..1547245cec 100644 --- a/Version.props +++ b/Version.props @@ -18,7 +18,7 @@ including taking version numbers 2.X.Y from upstream and updating .W if we have any hotfixes to microsoft/git. --> - 2.20211115.1 + 2.20220414.4 v2.31.0.vfs.0.1