From 845076335d3470a5e30f970283b1914f22498119 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:59:23 -0800 Subject: [PATCH 1/3] [release/10.0.1xx] Source code updates from dotnet/dotnet (#1492) * Update dependencies from https://github.com/dotnet/dotnet build 288391 Updated Dependencies: Microsoft.Build, Microsoft.Build.Tasks.Core (Version 17.11.31 -> 18.0.2) Microsoft.DotNet.Arcade.Sdk (Version 10.0.0-beta.25513.109 -> 10.0.0-beta.25523.108) System.CommandLine (Version 2.0.0 -> 2.0.0) * Update dependencies from https://github.com/dotnet/dotnet build 288435 Updated Dependencies: Microsoft.Build, Microsoft.Build.Tasks.Core (Version 18.0.2 -> 18.0.2) Microsoft.DotNet.Arcade.Sdk (Version 10.0.0-beta.25523.108 -> 10.0.0-beta.25523.113) System.CommandLine (Version 2.0.0 -> 2.0.0) * Update dependencies from https://github.com/dotnet/dotnet build 288919 Updated Dependencies: Microsoft.Build, Microsoft.Build.Tasks.Core (Version 18.0.2 -> 18.0.2) Microsoft.DotNet.Arcade.Sdk (Version 10.0.0-beta.25523.113 -> 10.0.0-beta.25528.106) System.CommandLine (Version 2.0.0 -> 2.0.0) * Update dependencies from https://github.com/dotnet/dotnet build 289051 Updated Dependencies: Microsoft.Build, Microsoft.Build.Tasks.Core (Version 18.0.2 -> 18.0.3) Microsoft.DotNet.Arcade.Sdk (Version 10.0.0-beta.25528.106 -> 10.0.0-beta.25530.104) System.CommandLine (Version 2.0.0 -> 2.0.0) * Update dependencies from https://github.com/dotnet/dotnet build 289152 Updated Dependencies: Microsoft.Build, Microsoft.Build.Tasks.Core (Version 18.0.3 -> 18.0.3) Microsoft.DotNet.Arcade.Sdk (Version 10.0.0-beta.25530.104 -> 10.0.0-beta.25531.102) System.CommandLine (Version 2.0.0 -> 2.0.0) * Fix Json version * Fix MSBuild versions * Update dependencies from https://github.com/dotnet/dotnet build 289521 Updated Dependencies: Microsoft.Build, Microsoft.Build.Tasks.Core (Version 18.0.3 -> 18.0.3) Microsoft.DotNet.Arcade.Sdk (Version 10.0.0-beta.25531.102 -> 10.0.0-beta.25554.104) System.CommandLine (Version 2.0.0 -> 2.0.1) --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: tmat --- NuGet.config | 2 +- eng/Version.Details.props | 14 +++++------ eng/Version.Details.xml | 22 ++++++++-------- eng/Versions.props | 2 +- eng/common/SetupNugetSources.ps1 | 17 +++++++++++-- eng/common/SetupNugetSources.sh | 23 ++++++++++++----- .../steps/install-microbuild.yml | 15 ++++++----- global.json | 6 ++--- src/Directory.Packages.props | 25 ++++++++++++++++--- 9 files changed, 82 insertions(+), 44 deletions(-) diff --git a/NuGet.config b/NuGet.config index e2979ff6..53dd297a 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + diff --git a/eng/Version.Details.props b/eng/Version.Details.props index c1806d5c..2ae5cb76 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,19 +6,17 @@ This file should be imported by eng/Versions.props - 10.0.0-beta.25513.109 - 2.0.0 - - 17.11.31 - 17.11.31 + 18.0.3 + 18.0.3 + 10.0.0-beta.25554.104 + 2.0.1 - $(MicrosoftDotNetArcadeSdkPackageVersion) - $(SystemCommandLinePackageVersion) - $(MicrosoftBuildPackageVersion) $(MicrosoftBuildTasksCorePackageVersion) + $(MicrosoftDotNetArcadeSdkPackageVersion) + $(SystemCommandLinePackageVersion) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ac5ec951..4b112ce7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,25 +1,25 @@ - + - + https://github.com/dotnet/dotnet - 3a0c62bf027fbcb8683a13e78a5b21ae19028ca3 + 8ee0cc0bbdbacfeb5b7e703909c9731ff75600f1 - + https://github.com/dotnet/dotnet - 3a0c62bf027fbcb8683a13e78a5b21ae19028ca3 + 8ee0cc0bbdbacfeb5b7e703909c9731ff75600f1 - - https://github.com/dotnet/msbuild - 933b72e36e86c22ba73e8b8148488f8298bb73c7 + + https://github.com/dotnet/dotnet + 8ee0cc0bbdbacfeb5b7e703909c9731ff75600f1 - - https://github.com/dotnet/msbuild - 933b72e36e86c22ba73e8b8148488f8298bb73c7 + + https://github.com/dotnet/dotnet + 8ee0cc0bbdbacfeb5b7e703909c9731ff75600f1 diff --git a/eng/Versions.props b/eng/Versions.props index c19d7d61..36828ab8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -14,6 +14,6 @@ 6.12.1 - 8.0.5 + 9.0.0 diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1 index fc8d6180..65ed3a8a 100644 --- a/eng/common/SetupNugetSources.ps1 +++ b/eng/common/SetupNugetSources.ps1 @@ -1,6 +1,7 @@ # This script adds internal feeds required to build commits that depend on internal package sources. For instance, -# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. In addition also enables -# disabled internal Maestro (darc-int*) feeds. +# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. Similarly, +# dotnet-eng-internal and dotnet-tools-internal are added if dotnet-eng and dotnet-tools are present. +# In addition, this script also enables disabled internal Maestro (darc-int*) feeds. # # Optionally, this script also adds a credential entry for each of the internal feeds if supplied. # @@ -173,4 +174,16 @@ foreach ($dotnetVersion in $dotnetVersions) { } } +# Check for dotnet-eng and add dotnet-eng-internal if present +$dotnetEngSource = $sources.SelectSingleNode("add[@key='dotnet-eng']") +if ($dotnetEngSource -ne $null) { + AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "dotnet-eng-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-eng-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password +} + +# Check for dotnet-tools and add dotnet-tools-internal if present +$dotnetToolsSource = $sources.SelectSingleNode("add[@key='dotnet-tools']") +if ($dotnetToolsSource -ne $null) { + AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "dotnet-tools-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password +} + $doc.Save($filename) diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh index dd2564ae..b2163abb 100755 --- a/eng/common/SetupNugetSources.sh +++ b/eng/common/SetupNugetSources.sh @@ -1,8 +1,9 @@ #!/usr/bin/env bash # This script adds internal feeds required to build commits that depend on internal package sources. For instance, -# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. In addition also enables -# disabled internal Maestro (darc-int*) feeds. +# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. Similarly, +# dotnet-eng-internal and dotnet-tools-internal are added if dotnet-eng and dotnet-tools are present. +# In addition, this script also enables disabled internal Maestro (darc-int*) feeds. # # Optionally, this script also adds a credential entry for each of the internal feeds if supplied. # @@ -66,10 +67,8 @@ EnableInternalPackageSource() { grep -i " /dev/null if [ "$?" == "0" ]; then echo "Enabling internal source '$PackageSourceName'." - # Remove the disabled entry - local OldDisableValue="" - local NewDisableValue="" - sed -i.bak "s|$OldDisableValue|$NewDisableValue|" "$ConfigFile" + # Remove the disabled entry (including any surrounding comments or whitespace on the same line) + sed -i.bak "//d" "$ConfigFile" # Add the source name to PackageSources for credential handling PackageSources+=("$PackageSourceName") @@ -175,6 +174,18 @@ for DotNetVersion in ${DotNetVersions[@]} ; do fi done +# Check for dotnet-eng and add dotnet-eng-internal if present +grep -i " /dev/null +if [ "$?" == "0" ]; then + AddOrEnablePackageSource "dotnet-eng-internal" "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-eng-internal/nuget/$FeedSuffix" +fi + +# Check for dotnet-tools and add dotnet-tools-internal if present +grep -i " /dev/null +if [ "$?" == "0" ]; then + AddOrEnablePackageSource "dotnet-tools-internal" "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/$FeedSuffix" +fi + # I want things split line by line PrevIFS=$IFS IFS=$'\n' diff --git a/eng/common/core-templates/steps/install-microbuild.yml b/eng/common/core-templates/steps/install-microbuild.yml index d6b9878f..f2248ebf 100644 --- a/eng/common/core-templates/steps/install-microbuild.yml +++ b/eng/common/core-templates/steps/install-microbuild.yml @@ -11,23 +11,22 @@ parameters: # Unfortunately, _SignType can't be used to exclude the use of the service connection in non-real sign scenarios. The # variable is not available in template expression. _SignType has a very large proliferation across .NET, so replacing it is tough. microbuildUseESRP: true - # Location of the MicroBuild output folder - # NOTE: There's something that relies on this being in the "default" source directory for tasks such as Signing to work properly. - microBuildOutputFolder: '$(Build.SourcesDirectory)' continueOnError: false steps: - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - ${{ if eq(parameters.enableMicrobuildForMacAndLinux, 'true') }}: - # Needed to download the MicroBuild plugin nupkgs on Mac and Linux when nuget.exe is unavailable + # Installing .NET 8 is required to use the MicroBuild signing plugin on non-Windows platforms - task: UseDotNet@2 displayName: Install .NET 8.0 SDK for MicroBuild Plugin inputs: packageType: sdk version: 8.0.x - installationPath: ${{ parameters.microBuildOutputFolder }}/.dotnet - workingDirectory: ${{ parameters.microBuildOutputFolder }} + # Installing the SDK in a '.dotnet-microbuild' directory is required for signing. + # See target FindDotNetPathForMicroBuild in arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.proj + # Do not remove '.dotnet-microbuild' from the path without changing the corresponding logic. + installationPath: $(Agent.TempDirectory)/.dotnet-microbuild condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT')) - script: | @@ -65,7 +64,7 @@ steps: ConnectedPMEServiceName: 248d384a-b39b-46e3-8ad5-c2c210d5e7ca env: TeamName: $(_TeamName) - MicroBuildOutputFolderOverride: ${{ parameters.microBuildOutputFolder }} + MicroBuildOutputFolderOverride: $(Agent.TempDirectory)/MicroBuild SYSTEM_ACCESSTOKEN: $(System.AccessToken) continueOnError: ${{ parameters.continueOnError }} condition: and(succeeded(), eq(variables['Agent.Os'], 'Windows_NT'), in(variables['_SignType'], 'real', 'test')) @@ -85,7 +84,7 @@ steps: ConnectedPMEServiceName: c24de2a5-cc7a-493d-95e4-8e5ff5cad2bc env: TeamName: $(_TeamName) - MicroBuildOutputFolderOverride: ${{ parameters.microBuildOutputFolder }} + MicroBuildOutputFolderOverride: $(Agent.TempDirectory)/MicroBuild SYSTEM_ACCESSTOKEN: $(System.AccessToken) continueOnError: ${{ parameters.continueOnError }} condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'), eq(variables['_SignType'], 'real')) diff --git a/global.json b/global.json index e25e6ecf..334effb0 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "10.0.100-rc.1.25451.107", + "version": "10.0.100-rc.2.25502.107", "allowPrerelease": true, "rollForward": "latestFeature", "paths": [ @@ -10,10 +10,10 @@ "errorMessage": "The required .NET SDK wasn't found. Please run ./eng/common/dotnet.cmd/sh to install it." }, "tools": { - "dotnet": "10.0.100-rc.1.25451.107" + "dotnet": "10.0.100-rc.2.25502.107" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25513.109", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25554.104", "Microsoft.Build.NoTargets": "3.7.0" } } diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index a1ab4835..ad5b1a5b 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -13,10 +13,6 @@ - - - - @@ -24,6 +20,27 @@ + + + + + + + + + + + + + + + + + From ef47386597d1ce0a5c88d9aa22401f3bccbb153e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 08:04:21 -0800 Subject: [PATCH 2/3] [release/10.0.1xx] Source code updates from dotnet/dotnet (#1500) * Update dependencies from https://github.com/dotnet/dotnet build 289596 Updated Dependencies: Microsoft.Build, Microsoft.Build.Tasks.Core (Version 18.0.3 -> 18.0.3) Microsoft.DotNet.Arcade.Sdk (Version 10.0.0-beta.25554.104 -> 10.0.0-beta.25554.105) System.CommandLine (Version 2.0.1 -> 2.0.1) * Update dependencies from https://github.com/dotnet/dotnet build 289695 Updated Dependencies: Microsoft.Build, Microsoft.Build.Tasks.Core (Version 18.0.3 -> 18.0.3) Microsoft.DotNet.Arcade.Sdk (Version 10.0.0-beta.25554.105 -> 10.0.0-beta.25555.106) System.CommandLine (Version 2.0.1 -> 2.0.1) --------- Co-authored-by: dotnet-maestro[bot] --- NuGet.config | 2 +- eng/Version.Details.props | 2 +- eng/Version.Details.xml | 12 ++++++------ global.json | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/NuGet.config b/NuGet.config index 53dd297a..0f08cd2b 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,7 @@ - + diff --git a/eng/Version.Details.props b/eng/Version.Details.props index 2ae5cb76..f9a1127a 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -8,7 +8,7 @@ This file should be imported by eng/Versions.props 18.0.3 18.0.3 - 10.0.0-beta.25554.104 + 10.0.0-beta.25555.106 2.0.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4b112ce7..bb3d8982 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,25 +1,25 @@ - + https://github.com/dotnet/dotnet - 8ee0cc0bbdbacfeb5b7e703909c9731ff75600f1 + e17b0d08def649f30aed9c09cf4a2c5741a3c76c - + https://github.com/dotnet/dotnet - 8ee0cc0bbdbacfeb5b7e703909c9731ff75600f1 + e17b0d08def649f30aed9c09cf4a2c5741a3c76c https://github.com/dotnet/dotnet - 8ee0cc0bbdbacfeb5b7e703909c9731ff75600f1 + e17b0d08def649f30aed9c09cf4a2c5741a3c76c https://github.com/dotnet/dotnet - 8ee0cc0bbdbacfeb5b7e703909c9731ff75600f1 + e17b0d08def649f30aed9c09cf4a2c5741a3c76c diff --git a/global.json b/global.json index 334effb0..f22164a1 100644 --- a/global.json +++ b/global.json @@ -13,7 +13,7 @@ "dotnet": "10.0.100-rc.2.25502.107" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25554.104", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25555.106", "Microsoft.Build.NoTargets": "3.7.0" } } From 23b33d0904b5d4a12d34ad5f643117190dcecbed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Sep 2025 01:02:34 +0000 Subject: [PATCH 3/3] Add objectformat extension support for SHA256 repositories --- .../GitConfigTests.cs | 20 +++++ .../GitReferenceResolverTests.cs | 83 ++++++++++++++++++- .../GitRepositoryTests.cs | 31 +++++++ .../GitDataReader/GitConfig.cs | 58 ++++++++++++- .../GitDataReader/GitReferenceResolver.cs | 12 +-- .../GitDataReader/GitRepository.cs | 28 +------ .../GitDataReader/ObjectFormat.cs | 31 +++++++ 7 files changed, 228 insertions(+), 35 deletions(-) create mode 100644 src/Microsoft.Build.Tasks.Git/GitDataReader/ObjectFormat.cs diff --git a/src/Microsoft.Build.Tasks.Git.UnitTests/GitConfigTests.cs b/src/Microsoft.Build.Tasks.Git.UnitTests/GitConfigTests.cs index 0b506b1a..c0d7a6c7 100644 --- a/src/Microsoft.Build.Tasks.Git.UnitTests/GitConfigTests.cs +++ b/src/Microsoft.Build.Tasks.Git.UnitTests/GitConfigTests.cs @@ -20,6 +20,26 @@ private static GitConfig LoadFromString(string gitDirectory, string configPath, => new GitConfig.Reader(gitDirectory, gitDirectory, GitEnvironment.Empty, _ => new StringReader(configContent)). LoadFrom(configPath); + [Theory] + [InlineData("sha1", ObjectFormat.Sha1)] + [InlineData("sha256", ObjectFormat.Sha256)] + internal void TryParseObjectFormat_Valid(string str, ObjectFormat expected) + { + Assert.Equal(expected, GitConfig.ParseObjectFormat(str)); + } + + [Theory] + [InlineData("")] + [InlineData("Sha1")] + [InlineData("sha-1")] + [InlineData("sha-256")] + [InlineData("sha384")] + [InlineData("sha512")] + internal void TryParseObjectFormat_Invalid(string str) + { + Assert.Throws(() => GitConfig.ParseObjectFormat(str)); + } + [Fact] public void Sections() { diff --git a/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs b/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs index c61fb555..cd8a8c16 100644 --- a/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs +++ b/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs @@ -33,13 +33,40 @@ public void ResolveReference() Assert.Equal("0000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/br1")); Assert.Equal("0000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/br2")); - // branch without commits (emtpy repository) will have not file in refs/heads: + // branch without commits (empty repository) will have not file in refs/heads: Assert.Null(resolver.ResolveReference("ref: refs/heads/none")); Assert.Null(resolver.ResolveReference("ref: refs/heads/rec1 ")); Assert.Null(resolver.ResolveReference("ref: refs/heads/none" + string.Join("/", Path.GetInvalidPathChars()))); } + [Fact] + public void ResolveReference_SHA256() + { + using var temp = new TempRoot(); + + var gitDir = temp.CreateDirectory(); + + var commonDir = temp.CreateDirectory(); + var refsHeadsDir = commonDir.CreateDirectory("refs").CreateDirectory("heads"); + + // SHA256 hash (64 characters) + refsHeadsDir.CreateFile("master").WriteAllText("0000000000000000000000000000000000000000000000000000000000000000"); + refsHeadsDir.CreateFile("br1").WriteAllText("ref: refs/heads/br2"); + refsHeadsDir.CreateFile("br2").WriteAllText("ref: refs/heads/master"); + + var resolver = new GitReferenceResolver(gitDir.Path, commonDir.Path); + + // Verify SHA256 hash is accepted directly + Assert.Equal( + "0123456789ABCDEFabcdef00000000000000000000000000000000000000000000", + resolver.ResolveReference("0123456789ABCDEFabcdef00000000000000000000000000000000000000000000")); + + Assert.Equal("0000000000000000000000000000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/master")); + Assert.Equal("0000000000000000000000000000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/br1")); + Assert.Equal("0000000000000000000000000000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/br2")); + } + [Fact] public void ResolveReference_Errors() { @@ -59,8 +86,14 @@ public void ResolveReference_Errors() Assert.Throws(() => resolver.ResolveReference("ref: xyz/heads/rec1")); Assert.Throws(() => resolver.ResolveReference("ref:refs/heads/rec1")); Assert.Throws(() => resolver.ResolveReference("refs/heads/rec1")); + + // Invalid SHA1 hash lengths Assert.Throws(() => resolver.ResolveReference(new string('0', 39))); Assert.Throws(() => resolver.ResolveReference(new string('0', 41))); + + // Invalid SHA256 hash lengths + Assert.Throws(() => resolver.ResolveReference(new string('0', 63))); + Assert.Throws(() => resolver.ResolveReference(new string('0', 65))); } [Fact] @@ -87,6 +120,31 @@ 2222222222222222222222222222222222222222 refs/heads/br2 Assert.Equal("2222222222222222222222222222222222222222", resolver.ResolveReference("ref: refs/heads/br2")); } + [Fact] + public void ResolveReference_Packed_SHA256() + { + using var temp = new TempRoot(); + + var gitDir = temp.CreateDirectory(); + + // Packed refs with SHA256 hashes (64 characters) + gitDir.CreateFile("packed-refs").WriteAllText( +@"# pack-refs with: peeled fully-peeled sorted +1111111111111111111111111111111111111111111111111111111111111111 refs/heads/master +2222222222222222222222222222222222222222222222222222222222222222 refs/heads/br2 +"); + var commonDir = temp.CreateDirectory(); + var refsHeadsDir = commonDir.CreateDirectory("refs").CreateDirectory("heads"); + + refsHeadsDir.CreateFile("br1").WriteAllText("ref: refs/heads/br2"); + + var resolver = new GitReferenceResolver(gitDir.Path, commonDir.Path); + + Assert.Equal("1111111111111111111111111111111111111111111111111111111111111111", resolver.ResolveReference("ref: refs/heads/master")); + Assert.Equal("2222222222222222222222222222222222222222222222222222222222222222", resolver.ResolveReference("ref: refs/heads/br1")); + Assert.Equal("2222222222222222222222222222222222222222222222222222222222222222", resolver.ResolveReference("ref: refs/heads/br2")); + } + [Fact] public void ReadPackedReferences() { @@ -110,6 +168,29 @@ 7777777777777777777777777777777777777777 refs/heads/br }, actual.Select(e => $"{e.Key}:{e.Value}")); } + [Fact] + public void ReadPackedReferences_SHA256() + { + var packedRefs = +@"# pack-refs with: +1111111111111111111111111111111111111111111111111111111111111111 refs/heads/master +2222222222222222222222222222222222222222222222222222222222222222 refs/heads/br +^3333333333333333333333333333333333333333333333333333333333333333 +4444444444444444444444444444444444444444444444444444444444444444 x +5555555555555555555555555555555555555555555555555555555555555555 y +6666666666666666666666666666666666666666666666666666666666666666 y z +7777777777777777777777777777777777777777777777777777777777777777 refs/heads/br +"; + + var actual = GitReferenceResolver.ReadPackedReferences(new StringReader(packedRefs), ""); + + AssertEx.SetEqual(new[] + { + "refs/heads/br:2222222222222222222222222222222222222222222222222222222222222222", + "refs/heads/master:1111111111111111111111111111111111111111111111111111111111111111" + }, actual.Select(e => $"{e.Key}:{e.Value}")); + } + [Theory] [InlineData("# pack-refs with:")] [InlineData("# pack-refs with:xyz")] diff --git a/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs b/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs index 7ba9993d..7cc4eb83 100644 --- a/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs +++ b/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs @@ -226,6 +226,7 @@ public void OpenRepository_Version1_Extensions() preciousObjects = true partialClone = promisor_remote worktreeConfig = true + objectformat = sha256 "); Assert.True(GitRepository.TryFindRepository(gitDir.Path, out var location)); @@ -264,6 +265,36 @@ public void OpenRepository_Version1_UnknownExtension() Assert.Throws(() => GitRepository.OpenRepository(src.Path, new GitEnvironment(homeDir.Path))); } + [Fact] + public void OpenRepository_Version1_ObjectFormatExtension() + { + using var temp = new TempRoot(); + + var homeDir = temp.CreateDirectory(); + + var workingDir = temp.CreateDirectory(); + var gitDir = workingDir.CreateDirectory(".git"); + + gitDir.CreateFile("HEAD").WriteAllText("ref: refs/heads/master"); + gitDir.CreateDirectory("refs").CreateDirectory("heads").CreateFile("master").WriteAllText("0000000000000000000000000000000000000000"); + gitDir.CreateDirectory("objects"); + + gitDir.CreateFile("config").WriteAllText(@" +[core] + repositoryformatversion = 1 +[extensions] + objectformat = sha256"); + + var src = workingDir.CreateDirectory("src"); + + // Should not throw - objectformat extension should be supported + var repository = GitRepository.OpenRepository(src.Path, new GitEnvironment(homeDir.Path)); + Assert.NotNull(repository); + Assert.Equal(gitDir.Path, repository.GitDirectory); + Assert.Equal(gitDir.Path, repository.CommonDirectory); + Assert.Equal(workingDir.Path, repository.WorkingDirectory); + } + [Fact] public void OpenRepository_VersionNotSupported() { diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitConfig.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitConfig.cs index 5d57c7b6..1b120a46 100644 --- a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitConfig.cs +++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitConfig.cs @@ -5,11 +5,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Text; +using System.Runtime.Serialization; namespace Microsoft.Build.Tasks.Git { @@ -17,12 +15,57 @@ internal sealed partial class GitConfig { public static readonly GitConfig Empty = new GitConfig(ImmutableDictionary>.Empty); + private const int SupportedGitRepoFormatVersion = 1; + + public const string CoreSectionName = "core"; + public const string ExtensionsSectionName = "extensions"; + + public const string ObjectFormatVariableName = "objectFormat"; + public const string RepositoryFormatVersionVariableName = "repositoryformatversion"; + + private static readonly ImmutableArray s_knownExtensions = ["noop", "preciousObjects", "partialclone", "worktreeConfig", ObjectFormatVariableName]; + public readonly ImmutableDictionary> Variables; + /// + /// The parsed value of "extensions.objectFormat" variable. + /// + public ObjectFormat ObjectFormat { get; } + + /// public GitConfig(ImmutableDictionary> variables) { NullableDebug.Assert(variables != null); Variables = variables; + + ObjectFormat = GetVariableValue(ExtensionsSectionName, ObjectFormatVariableName) is { } objectFormatStr + ? ParseObjectFormat(objectFormatStr) + : ObjectFormat.Sha1; + } + + /// + internal void ValidateFormat() + { + // See https://github.com/git/git/blob/master/Documentation/technical/repository-version.txt + string? versionStr = GetVariableValue(CoreSectionName, RepositoryFormatVersionVariableName); + if (TryParseInt64Value(versionStr, out var version) && version > SupportedGitRepoFormatVersion) + { + throw new NotSupportedException(string.Format(Resources.UnsupportedRepositoryVersion, versionStr, SupportedGitRepoFormatVersion)); + } + + if (version == 1) + { + // All variables defined under extensions section must be known, otherwise a git implementation is not allowed to proced. + foreach (var variable in Variables) + { + if (variable.Key.SectionNameEquals(ExtensionsSectionName) && + !s_knownExtensions.Contains(variable.Key.VariableName, StringComparer.OrdinalIgnoreCase)) + { + throw new NotSupportedException(string.Format( + Resources.UnsupportedRepositoryExtension, variable.Key.VariableName, string.Join(", ", s_knownExtensions))); + } + } + } } // for testing: @@ -125,5 +168,14 @@ internal static bool TryParseInt64Value(string? str, out long value) return true; } + + // internal for testing + internal static ObjectFormat ParseObjectFormat(string value) + => value switch + { + "sha1" => ObjectFormat.Sha1, + "sha256" => ObjectFormat.Sha256, + _ => throw new InvalidDataException(), + }; } } diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs index 7d970c09..13840b2d 100644 --- a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs +++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs @@ -21,21 +21,23 @@ internal sealed class GitReferenceResolver private readonly string _commonDirectory; private readonly string _gitDirectory; + private readonly ObjectFormat _objectFormat; // maps refs/heads references to the correspondign object ids: private readonly Lazy> _lazyPackedReferences; - public GitReferenceResolver(string gitDirectory, string commonDirectory) + public GitReferenceResolver(string gitDirectory, string commonDirectory, ObjectFormat objectFormat) { Debug.Assert(PathUtils.IsNormalized(gitDirectory)); Debug.Assert(PathUtils.IsNormalized(commonDirectory)); _gitDirectory = gitDirectory; _commonDirectory = commonDirectory; + _objectFormat = objectFormat; _lazyPackedReferences = new Lazy>(() => ReadPackedReferences(_gitDirectory)); } - private static ImmutableDictionary ReadPackedReferences(string gitDirectory) + private ImmutableDictionary ReadPackedReferences(string gitDirectory) { // https://git-scm.com/docs/git-pack-refs @@ -62,7 +64,7 @@ private static ImmutableDictionary ReadPackedReferences(string g } // internal for testing - internal static ImmutableDictionary ReadPackedReferences(TextReader reader, string path) + internal ImmutableDictionary ReadPackedReferences(TextReader reader, string path) { var builder = ImmutableDictionary.CreateBuilder(); @@ -254,7 +256,7 @@ internal static string ReadReferenceFromFile(string path) private string? ResolvePackedReference(string reference) => _lazyPackedReferences.Value.TryGetValue(reference, out var objectId) ? objectId : null; - private static bool IsObjectId(string reference) - => reference.Length == 40 && reference.All(CharUtils.IsHexadecimalDigit); + private bool IsObjectId(string reference) + => reference.Length == _objectFormat.HashLength * 2 && reference.All(CharUtils.IsHexadecimalDigit); } } diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs index fc7446ea..4b677924 100644 --- a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs +++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs @@ -13,8 +13,6 @@ namespace Microsoft.Build.Tasks.Git { internal sealed class GitRepository { - private const int SupportedGitRepoFormatVersion = 1; - private const string CommonDirFileName = "commondir"; private const string GitDirName = ".git"; private const string GitDirPrefix = "gitdir: "; @@ -24,9 +22,6 @@ internal sealed class GitRepository private const string GitModulesFileName = ".gitmodules"; - private static readonly ImmutableArray s_knownExtensions = - ImmutableArray.Create("noop", "preciousObjects", "partialclone", "worktreeConfig"); - public GitConfig Config { get; } public GitIgnore Ignore => _lazyIgnore.Value; @@ -68,7 +63,7 @@ internal GitRepository(GitEnvironment environment, GitConfig config, string gitD WorkingDirectory = workingDirectory; Environment = environment; - _referenceResolver = new GitReferenceResolver(gitDirectory, commonDirectory); + _referenceResolver = new GitReferenceResolver(gitDirectory, commonDirectory, config.ObjectFormat); _lazySubmodules = new Lazy<(ImmutableArray, ImmutableArray)>(ReadSubmodules); _lazyIgnore = new Lazy(LoadIgnore); _lazyHeadCommitSha = new Lazy(ReadHeadCommitSha); @@ -121,29 +116,10 @@ public static GitRepository OpenRepository(GitRepositoryLocation location, GitEn var reader = new GitConfig.Reader(location.GitDirectory, location.CommonDirectory, environment); var config = reader.Load(); + config.ValidateFormat(); var workingDirectory = GetWorkingDirectory(config, location); - // See https://github.com/git/git/blob/master/Documentation/technical/repository-version.txt - string? versionStr = config.GetVariableValue("core", "repositoryformatversion"); - if (GitConfig.TryParseInt64Value(versionStr, out var version) && version > SupportedGitRepoFormatVersion) - { - throw new NotSupportedException(string.Format(Resources.UnsupportedRepositoryVersion, versionStr, SupportedGitRepoFormatVersion)); - } - - if (version == 1) - { - // All variables defined under extensions section must be known, otherwise a git implementation is not allowed to proced. - foreach (var variable in config.Variables) - { - if (variable.Key.SectionNameEquals("extensions") && !s_knownExtensions.Contains(variable.Key.VariableName, StringComparer.OrdinalIgnoreCase)) - { - throw new NotSupportedException(string.Format( - Resources.UnsupportedRepositoryExtension, variable.Key.VariableName, string.Join(", ", s_knownExtensions))); - } - } - } - return new GitRepository(environment, config, location.GitDirectory, location.CommonDirectory, workingDirectory); } diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/ObjectFormat.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/ObjectFormat.cs new file mode 100644 index 00000000..5fb67a8b --- /dev/null +++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/ObjectFormat.cs @@ -0,0 +1,31 @@ +// Licensed to the.NET Foundation under one or more agreements. +// The.NET Foundation licenses this file to you under the MIT license. +// See the License.txt file in the project root for more information. + +using System; + +namespace Microsoft.Build.Tasks.Git; + +/// +/// Format of object names. +/// https://git-scm.com/docs/hash-function-transition.html#_object_format +/// +internal enum ObjectFormat +{ + Sha1 = 1, + Sha256 = 2, +} + +internal static class ObjectFormatExtensions +{ + extension(ObjectFormat self) + { + public int HashLength + => self switch + { + ObjectFormat.Sha1 => 20, + ObjectFormat.Sha256 => 32, + _ => throw new InvalidOperationException() + }; + } +}