Skip to content

Commit

Permalink
Adding the feature knob
Browse files Browse the repository at this point in the history
  • Loading branch information
MantavyaDh committed Dec 19, 2024
1 parent a8e2f83 commit 12d2efd
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 36 deletions.
7 changes: 7 additions & 0 deletions src/Agent.Sdk/Knob/AgentKnobs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -779,5 +779,12 @@ public class AgentKnobs
"If true, agent will use sparse checkout in checkout task.",
new RuntimeKnobSource("AGENT_USE_SPARSE_CHECKOUT_IN_CHECKOUT_TASK"),
new BuiltInDefaultKnobSource("false"));

public static readonly Knob UseSha256InComputeHash = new Knob(
nameof(UseSha256InComputeHash),
"If true, agent will use SHA256 algorithm in ComputeHash.",
new RuntimeKnobSource("AGENT_USE_SHA256_IN_COMPUTE_HASH"),
new EnvironmentKnobSource("AGENT_USE_SHA256_IN_COMPUTE_HASH"),
new BuiltInDefaultKnobSource("true"));
}
}
3 changes: 2 additions & 1 deletion src/Agent.Worker/Build/TrackingConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.ComponentModel;
using System.Globalization;
using System.IO;
using Agent.Sdk.Knob;

namespace Microsoft.VisualStudio.Services.Agent.Worker.Build
{
Expand Down Expand Up @@ -98,7 +99,7 @@ public TrackingConfig(
}

// Now that we have all the repositories set up, we can compute the config hash
HashKey = TrackingConfigHashAlgorithm.ComputeHash(CollectionId, DefinitionId, RepositoryTrackingInfo);
HashKey = TrackingConfigHashAlgorithm.ComputeHash(CollectionId, DefinitionId, RepositoryTrackingInfo, AgentKnobs.UseSha256InComputeHash.GetValue(executionContext).AsBoolean());
}

[JsonIgnore]
Expand Down
37 changes: 27 additions & 10 deletions src/Agent.Worker/Build/TrackingConfigHashAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class TrackingConfigHashAlgorithm
/// <summary>
/// This method returns the hash key that combines repository hash keys.
/// </summary>
public static string ComputeHash(string collectionId, string definitionId, IList<RepositoryTrackingInfo> repositories)
public static string ComputeHash(string collectionId, string definitionId, IList<RepositoryTrackingInfo> repositories, bool UseSha256InComputeHash)
{
// Validate parameters.
ArgUtil.NotNull(collectionId, nameof(collectionId));
Expand Down Expand Up @@ -50,22 +50,39 @@ public static string ComputeHash(string collectionId, string definitionId, IList
definitionId,
string.Join(';', repositories.OrderBy(x => x.Identifier).Select(x => $"{x.Identifier}:{x.RepositoryUrl}")));
}
return CreateHash(hashInput);
return CreateHash(hashInput, UseSha256InComputeHash);
}

private static string CreateHash(string hashInput)
private static string CreateHash(string hashInput, bool UseSha256InComputeHash)
{
using (SHA256 sha256Hash = SHA256.Create())
if(UseSha256InComputeHash)
{
byte[] data = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(hashInput));
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < data.Length; i++)
using (SHA256 sha256Hash = SHA256.Create())
{
hexString.Append(data[i].ToString("x2"));
}
byte[] data = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(hashInput));
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
hexString.Append(data[i].ToString("x2"));
}

return hexString.ToString();
return hexString.ToString();
}
}
else
{
using (SHA1 SHA1 = SHA1.Create())
{
byte[] data = SHA1.ComputeHash(Encoding.UTF8.GetBytes(hashInput));
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
hexString.Append(data[i].ToString("x2"));
}

return hexString.ToString();
}
}
}
}
}
5 changes: 3 additions & 2 deletions src/Agent.Worker/ExecutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -718,8 +718,9 @@ private string GetWorkspaceIdentifier(Pipelines.AgentJobRequestMessage message)
Variables.TryGetValue(Constants.Variables.System.CollectionId, out string collectionId);
Variables.TryGetValue(Constants.Variables.System.DefinitionId, out string definitionId);
var repoTrackingInfos = message.Resources.Repositories.Select(repo => new Build.RepositoryTrackingInfo(repo, "/")).ToList();
var workspaceIdentifier = Build.TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, repoTrackingInfos);

// Determine the hash algorithm based on the knob value
var workspaceIdentifier = Build.TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, repoTrackingInfos, AgentKnobs.UseSha256InComputeHash.GetValue(_parentExecutionContext).AsBoolean());

Trace.Info($"WorkspaceIdentifier '{workspaceIdentifier}' created for repos {String.Join(',', repoTrackingInfos)}");
return workspaceIdentifier;
}
Expand Down
44 changes: 22 additions & 22 deletions src/Test/L0/Worker/Build/TrackingConfigHashAlgorithmL0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void ComputeHash_returns_correct_hash()
};

// Act.
string hashKey = TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repoInfo });
string hashKey = TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repoInfo }, true);

// Assert.
Assert.Equal("55e3171bf43a983b419387b5d952d3ee7dcb195e262fc4c78d47a92763b6b001", hashKey);
Expand All @@ -62,12 +62,12 @@ public void ComputeHash_should_throw_when_parameters_invalid()
string collectionId = "866A5D79-7735-49E3-87DA-02E76CF8D03A";
string definitionId = "123";

Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(null, null, null));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, null));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { new RepositoryTrackingInfo() }));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(null, null, new[] { repo }));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(null, definitionId, new[] { repo }));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, null, new[] { repo }));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(null, null, null, true));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, null, true));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { new RepositoryTrackingInfo() }, true));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(null, null, new[] { repo }, true));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(null, definitionId, new[] { repo }, true));
Assert.Throws<ArgumentNullException>(() => TrackingConfigHashAlgorithm.ComputeHash(collectionId, null, new[] { repo }, true));
}
}

Expand Down Expand Up @@ -96,19 +96,19 @@ public void ComputeHash_with_single_repo_should_return_correct_hash()
string definitionId = "123";

// Make sure that only the coll, def, and url are used in the hash
Assert.Equal("a42b0f8ccd83cec8294b0c861a8d769e4f7fbc53ad3d3c96d2d1b66afdcdcca7", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }));
Assert.Equal("a42b0f8ccd83cec8294b0c861a8d769e4f7fbc53ad3d3c96d2d1b66afdcdcca7", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo2 }));
Assert.Equal(TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }), TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }));
Assert.Equal("a42b0f8ccd83cec8294b0c861a8d769e4f7fbc53ad3d3c96d2d1b66afdcdcca7", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }, true));
Assert.Equal("a42b0f8ccd83cec8294b0c861a8d769e4f7fbc53ad3d3c96d2d1b66afdcdcca7", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo2 }, true));
Assert.Equal(TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }, true), TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }, true));

// Make sure that different coll creates different hash
Assert.Equal("55437a6c3c12ea17847e33c3d96697833a05519e06acbe90fff74a64734fca1c", TrackingConfigHashAlgorithm.ComputeHash("FFFA5D79-7735-49E3-87DA-02E76CF8D03A", definitionId, new[] { repo1 }));
Assert.Equal("55437a6c3c12ea17847e33c3d96697833a05519e06acbe90fff74a64734fca1c", TrackingConfigHashAlgorithm.ComputeHash("FFFA5D79-7735-49E3-87DA-02E76CF8D03A", definitionId, new[] { repo1 }, true));

// Make sure that different def creates different hash
Assert.Equal("72443dbf31971f84922a6f3a6c58052fc0c60d9f1eb17b83a35e6e099098c179", TrackingConfigHashAlgorithm.ComputeHash(collectionId, "321", new[] { repo1 }));
Assert.Equal("72443dbf31971f84922a6f3a6c58052fc0c60d9f1eb17b83a35e6e099098c179", TrackingConfigHashAlgorithm.ComputeHash(collectionId, "321", new[] { repo1 }, true));

// Make sure that different url creates different hash
repo1.RepositoryUrl = "https://jpricket@codedev.ms/jpricket/MyFirstProject/_git/new_url";
Assert.Equal("2b29540cb9d2b68cc068af7afd0593276fc9e0b09af4e5d7b2065cc9021070fc", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }));
Assert.Equal("2b29540cb9d2b68cc068af7afd0593276fc9e0b09af4e5d7b2065cc9021070fc", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1 }, true));
}
}

Expand Down Expand Up @@ -160,29 +160,29 @@ public void ComputeHash_with_multi_repos_should_return_correct_hash()
string definitionId = "123";

// Make sure we get the same hash every time
Assert.Equal("0a7fcd16ea54872456169a3cbf5a7d8e8efda976b755a13278b193fedaeb5784", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }));
Assert.Equal("0a7fcd16ea54872456169a3cbf5a7d8e8efda976b755a13278b193fedaeb5784", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }, true));

// Make sure that only the coll, def, identifier, and url are used in the hash
Assert.Equal(
TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }),
TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2_newPath }));
TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }, true),
TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2_newPath }, true));

// Make sure that different coll creates different hash
Assert.Equal("b3956a6be8dde823bce2373fdef7358e255107bc4de986a61aeaffd11e253118", TrackingConfigHashAlgorithm.ComputeHash("FFFA5D79-7735-49E3-87DA-02E76CF8D03A", definitionId, new[] { repo1, repo2 }));
Assert.Equal("b3956a6be8dde823bce2373fdef7358e255107bc4de986a61aeaffd11e253118", TrackingConfigHashAlgorithm.ComputeHash("FFFA5D79-7735-49E3-87DA-02E76CF8D03A", definitionId, new[] { repo1, repo2 }, true));

// Make sure that different def creates different hash
Assert.Equal("dff47196d014b4373641e33627901f986cde0815de0122fa76f401abd1140701", TrackingConfigHashAlgorithm.ComputeHash(collectionId, "321", new[] { repo1, repo2 }));
Assert.Equal("dff47196d014b4373641e33627901f986cde0815de0122fa76f401abd1140701", TrackingConfigHashAlgorithm.ComputeHash(collectionId, "321", new[] { repo1, repo2 }, true));

// Make sure that different url creates different hash
Assert.Equal("ce83c8cd4f9b603345d21d2a294f7126e1e37c6d13cf6225516106a69528cc95", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1_newUrl, repo2 }));
Assert.Equal("ce83c8cd4f9b603345d21d2a294f7126e1e37c6d13cf6225516106a69528cc95", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1_newUrl, repo2 }, true));

// Make sure that different alias creates different hash
Assert.Equal("2ca4bc7221eb412db850596fc02dc4e5b61c2125c997ea07f11215bffe605d33", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1_newAlias, repo2 }));
Assert.Equal("2ca4bc7221eb412db850596fc02dc4e5b61c2125c997ea07f11215bffe605d33", TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1_newAlias, repo2 }, true));

// Make sure order doesn't change hash
Assert.Equal(
TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }),
TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo2, repo1 }));
TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo1, repo2 }, true),
TrackingConfigHashAlgorithm.ComputeHash(collectionId, definitionId, new[] { repo2, repo1 }, true));

}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Test/L1/Worker/L1TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public TrackingConfig GetTrackingConfig(Pipelines.AgentJobRequestMessage message
if (message.Variables.TryGetValue("agent.useWorkspaceId", out _))
{
var repoTrackingInfos = message.Resources.Repositories.Select(repo => new RepositoryTrackingInfo(repo, "/")).ToList();
var workspaceIdentifier = TrackingConfigHashAlgorithm.ComputeHash(collectionIdVar?.Value, definitionIdVar?.Value, repoTrackingInfos);
var workspaceIdentifier = TrackingConfigHashAlgorithm.ComputeHash(collectionIdVar?.Value, definitionIdVar?.Value, repoTrackingInfos, true);
filename = Path.Combine(GetWorkingDirectory(testName),
Constants.Build.Path.SourceRootMappingDirectory,
collectionIdVar.Value,
Expand Down

0 comments on commit 12d2efd

Please sign in to comment.