Skip to content

Commit

Permalink
Added Git checkout option for GitRepoClone (#414)
Browse files Browse the repository at this point in the history
* Updated Functional Tests

Signed-off-by: Rakesh <[email protected]>

* Added Git Checkout

* Update Docs

* commit changes

* commit changes

* commit changes

* Rename Commit

* Commit changes

---------

Signed-off-by: Rakesh <[email protected]>
  • Loading branch information
RakeshwarK authored Dec 18, 2024
1 parent 8fc3478 commit 81f7761
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace VirtualClient.Dependencies
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using NUnit.Framework;
using VirtualClient.Common;
using VirtualClient.Common.Telemetry;

[TestFixture]
[Category("Unit")]
public class GitRepoCloneTests
{
private MockFixture mockFixture;

[Test]
public async Task GitRepoCloneRunsTheExpectedCommand()
{
this.mockFixture = new MockFixture();
this.mockFixture.File.Reset();
this.mockFixture.Setup(PlatformID.Unix);
this.mockFixture.File.Setup(f => f.Exists(It.IsAny<string>()))
.Returns(true);
this.mockFixture.Parameters = new Dictionary<string, IConvertible>()
{
{ nameof(GitRepoClone.PackageName), "coremark" },
{ nameof(GitRepoClone.RepoUri), "https://github.com/eembc/coremark.git" }
};

ProcessStartInfo expectedInfo = new ProcessStartInfo();
List<string> expectedCommands = new List<string>()
{
$@"git clone {this.mockFixture.Parameters[$"{nameof(GitRepoClone.RepoUri)}"]} {this.mockFixture.GetPackagePath()}/{this.mockFixture.Parameters[$"{nameof(GitRepoClone.PackageName)}"]}"
};

int commandExecuted = 0;
this.mockFixture.ProcessManager.OnCreateProcess = (exe, arguments, workingDir) =>
{
if (expectedCommands.Any(c => c == $"{exe} {arguments}"))
{
commandExecuted++;
}

IProcessProxy process = new InMemoryProcess()
{
ExitCode = 0,
OnStart = () => true,
OnHasExited = () => true
};
return process;
};

using (TestGitRepoClone installation = new TestGitRepoClone(this.mockFixture.Dependencies, this.mockFixture.Parameters))
{
await installation.ExecuteAsync(CancellationToken.None).ConfigureAwait(false);
}

Assert.AreEqual(1, commandExecuted);
}

[Test]
public async Task GitRepoCloneRunsTheExpectedCommandWithCheckout()
{
this.mockFixture = new MockFixture();
this.mockFixture.Setup(PlatformID.Unix);
this.mockFixture.File.Reset();
this.mockFixture.File.Setup(f => f.Exists(It.IsAny<string>()))
.Returns(true);

// The parameter Commit can be a branch-name, tag or a commit id.
this.mockFixture.Parameters = new Dictionary<string, IConvertible>()
{
{ nameof(GitRepoClone.PackageName), "coremark" },
{ nameof(GitRepoClone.RepoUri), "https://github.com/eembc/coremark.git" },
{ nameof(GitRepoClone.Commit), "Checkout-string" }
};

ProcessStartInfo expectedInfo = new ProcessStartInfo();
List<string> expectedCommands = new List<string>()
{
$@"git clone {this.mockFixture.Parameters[$"{nameof(GitRepoClone.RepoUri)}"]} {this.mockFixture.GetPackagePath()}/{this.mockFixture.Parameters[$"{nameof(GitRepoClone.PackageName)}"]}",
$@"git -C {this.mockFixture.GetPackagePath()}/{this.mockFixture.Parameters[$"{nameof(GitRepoClone.PackageName)}"]} checkout {this.mockFixture.Parameters[$"{nameof(GitRepoClone.Commit)}"]}",
};

int commandExecuted = 0;
this.mockFixture.ProcessManager.OnCreateProcess = (exe, arguments, workingDir) =>
{
if (expectedCommands.Any(c => c == $"{exe} {arguments}"))
{
commandExecuted++;
}

IProcessProxy process = new InMemoryProcess()
{
ExitCode = 0,
OnStart = () => true,
OnHasExited = () => true
};
return process;
};

using (TestGitRepoClone installation = new TestGitRepoClone(this.mockFixture.Dependencies, this.mockFixture.Parameters))
{
await installation.ExecuteAsync(CancellationToken.None).ConfigureAwait(false);
}

Assert.AreEqual(2, commandExecuted);
}

private class TestGitRepoClone : GitRepoClone
{
public TestGitRepoClone(IServiceCollection dependencies, IDictionary<string, IConvertible> parameters)
: base(dependencies, parameters)
{
}

public new Task ExecuteAsync(EventContext context, CancellationToken cancellationToken)
{
return base.ExecuteAsync(context, cancellationToken);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace VirtualClient.Dependencies
{
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -47,13 +48,30 @@ public Uri RepoUri
}
}

/// <summary>
/// Parameter to checkout to a specific branch, commit or tag in the repository
/// </summary>
public string Commit
{
get
{
return this.Parameters.GetValue<string>(nameof(GitRepoClone.Commit), string.Empty);
}

set
{
this.Parameters[nameof(GitRepoClone.Commit)] = value;
}
}

/// <summary>
/// Executes the git clone operation.
/// </summary>
protected override async Task ExecuteAsync(EventContext telemetryContext, CancellationToken cancellationToken)
{
telemetryContext.AddContext("repoUri", this.RepoUri);
telemetryContext.AddContext("packagesDirectory", this.PlatformSpecifics.PackagesDirectory);
telemetryContext.AddContext("Commit", this.Commit);

ISystemManagement systemManagement = this.Dependencies.GetService<ISystemManagement>();
ProcessManager processManager = systemManagement.ProcessManager;
Expand Down Expand Up @@ -100,6 +118,11 @@ await systemManagement.PackageManager.RegisterPackageAsync(
await systemManagement.PackageManager.RegisterPackageAsync(package, cancellationToken)
.ConfigureAwait(false);
}

if (!string.IsNullOrEmpty(this.Commit))
{
await this.ExecuteCommandAsync("git", $"-C {cloneDirectory} checkout {this.Commit}", this.PlatformSpecifics.PackagesDirectory, telemetryContext, cancellationToken);
}
}
}
}
2 changes: 2 additions & 0 deletions website/docs/dependencies/0040-install-git-repo.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The following section describes the parameters used by the individual component
|---------------|--------------|-----------------------------------------------------------------------------------------------------------------|
| PackageName | Yes | The logical name of the that will be registered with the Virtual Client runtime to represent the packages directory into which the repo was cloned. Other profile components can use this name to reference/discover the repo and its location. |
| RepoUri | Yes | The full URI to the Git repository to download/clone into the packages directory. |
| Commit | No | The branch-name or commit-hash or tag to checkout to a specific branch, commit, tag in the repository. |
| Scenario | No | A name/identifier for the specific component in the profile. This is used for telemetry purposes only with components in dependency sections of the profile (i.e. cannot be used with --scenarios option on the command line). |


Expand All @@ -36,6 +37,7 @@ In this example, VC clones https://github.com/eembc/coremark.git into the runtim
"Type": "GitRepoClone",
"Parameters": {
"RepoUri": "https://github.com/eembc/coremark.git",
"Commit": "v1.01"
"PackageName": "coremark"
}
}
Expand Down

0 comments on commit 81f7761

Please sign in to comment.