Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions tools/azsdk-cli/Azure.Sdk.Tools.Cli.Tests/Helpers/GitHelperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using Azure.Sdk.Tools.Cli.Helpers;
using Azure.Sdk.Tools.Cli.Services;
using Azure.Sdk.Tools.Cli.Tests.TestHelpers;
using LibGit2Sharp;
using Moq;

namespace Azure.Sdk.Tools.Cli.Tests.Helpers
{
[TestFixture]
internal class GitHelperTests
{
private GitHelper gitHelper;
private Mock<IGitHubService> mockGitHubService;
private TestLogger<GitHelper> logger;

[SetUp]
public void Setup()
{
mockGitHubService = new Mock<IGitHubService>();
logger = new TestLogger<GitHelper>();
gitHelper = new GitHelper(mockGitHubService.Object, logger);
}

[Test]
public void GetRepoRemoteUri_WithSshOrigin_ReturnsHttpsUri()
{
var testRepoPath = CreateTestRepoWithRemote("git@github.com:Azure/azure-rest-api-specs.git");

try
{
var result = gitHelper.GetRepoRemoteUri(testRepoPath);

Assert.That(result.ToString(), Is.EqualTo("https://github.com/Azure/azure-rest-api-specs.git"));
}
finally
{
CleanupTestRepo(testRepoPath);
}
}

[Test]
public void GetRepoRemoteUri_WithHttpsOrigin_ReturnsHttpsUri()
{
var testRepoPath = CreateTestRepoWithRemote("https://github.com/Azure/azure-rest-api-specs.git");

try
{
var result = gitHelper.GetRepoRemoteUri(testRepoPath);

Assert.That(result.ToString(), Is.EqualTo("https://github.com/Azure/azure-rest-api-specs.git"));
}
finally
{
CleanupTestRepo(testRepoPath);
}
}

[Test]
public void GetRepoRemoteUri_WithNoOrigin_ThrowsException()
{
var testRepoPath = CreateTestRepoWithoutRemote();

try
{
var ex = Assert.Throws<InvalidOperationException>(() => gitHelper.GetRepoRemoteUri(testRepoPath));
Assert.That(ex.Message, Is.EqualTo("Unable to determine remote URL."));
}
finally
{
CleanupTestRepo(testRepoPath);
}
}

[Test]
public void GetRepoRemoteUri_WithNonGitDirectory_ThrowsException()
{
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);

try
{
Assert.Throws<RepositoryNotFoundException>(() => gitHelper.GetRepoRemoteUri(tempDir));
}
finally
{
if (Directory.Exists(tempDir))
{
Directory.Delete(tempDir, true);
}
}
}

#region Helper Methods

private static string CreateTestRepoWithRemote(string url)
{
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);

Repository.Init(tempDir);
using var repo = new Repository(tempDir);
repo.Network.Remotes.Add("origin", url);

return tempDir;
}

private static string CreateTestRepoWithoutRemote()
{
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);
Repository.Init(tempDir);
return tempDir;
}

private static void CleanupTestRepo(string path)
{
if (Directory.Exists(path))
{
try
{
// Remove read-only attributes from .git folder
var gitDir = Path.Combine(path, ".git");
if (Directory.Exists(gitDir))
{
foreach (var file in Directory.GetFiles(gitDir, "*", SearchOption.AllDirectories))
{
File.SetAttributes(file, FileAttributes.Normal);
}
}

Directory.Delete(path, true);
}
catch (Exception)
{
// Ignore cleanup errors in tests
}
}
}

#endregion
}
}
33 changes: 32 additions & 1 deletion tools/azsdk-cli/Azure.Sdk.Tools.Cli/Helpers/GitHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,42 @@ public Uri GetRepoRemoteUri(string path)
var remote = repo.Network?.Remotes["origin"];
if (remote != null)
{
return new Uri(remote.Url);
var url = ConvertSshToHttpsUrl(remote.Url);
return new Uri(url);
}
throw new InvalidOperationException("Unable to determine remote URL.");
}

/// <summary>
/// Converts SSH GitHub URLs to HTTPS format
/// </summary>
/// <param name="gitUrl">The Git URL (SSH or HTTPS)</param>
/// <returns>HTTPS formatted Git URL</returns>
private static string ConvertSshToHttpsUrl(string gitUrl)
{
if (string.IsNullOrEmpty(gitUrl))
{
return gitUrl;
}

// If it's already HTTPS, return as-is
if (gitUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
return gitUrl;
}

// Handle GitHub SSH URLs (e.g., git@github.com:Azure/azure-rest-api-specs.git)
if (gitUrl.StartsWith("git@github.com:", StringComparison.OrdinalIgnoreCase))
Comment thread
chrisradek marked this conversation as resolved.
{
// Convert SSH URL to HTTPS URL
// git@github.com:Azure/azure-rest-api-specs.git -> https://github.com/Azure/azure-rest-api-specs.git
return gitUrl.Replace("git@github.com:", "https://github.com/");
}

// Return as-is if it's not a recognized format
return gitUrl;
}

public async Task<string> GetRepoOwnerNameAsync(string path, bool findUpstreamParent = true)
{
var uri = GetRepoRemoteUri(path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ public bool IsRepoPathForPublicSpecRepo(string path)

public bool IsRepoPathForSpecRepo(string path)
{
var uri = _gitHelper.GetRepoRemoteUri(path);
// Docs say this method should work for paths within a repo,
// so we need to find the repo root first.
var repoRootPath = _gitHelper.DiscoverRepoRoot(path);
var uri = _gitHelper.GetRepoRemoteUri(repoRootPath);
return RestApiSpecsPublicOrPrivateRegex().IsMatch(uri.ToString());
}

Expand Down
Loading