Skip to content
Closed
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
65 changes: 43 additions & 22 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,39 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4.1.2
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install .NET SDK
uses: actions/setup-dotnet@v4.0.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: 9.0.x
- name: Compute version override for branch builds
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
id: version
run: |
# Latest release tag matching the convention <version>-octopus.<n>
LATEST=$(git tag --list --sort=-v:refname | grep -E '^[0-9]+\.[0-9]+\.[0-9]+-octopus\.[0-9]+$' | head -n 1)
if [ -z "$LATEST" ]; then
echo "::error::No release tag matching <version>-octopus.<n> found"
exit 1
fi
# Sanitize branch name: lowercase, replace non-alphanumeric with hyphen, trim to 20 chars
BRANCH="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME}}"
SAFE_BRANCH=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//' | sed 's/-$//' | cut -c1-20)
# Join with '.' (not '-') so branch/run land as separate prerelease IDs, keeping ordering correct vs the next octopus.<n+1>
echo "override=${LATEST}.${SAFE_BRANCH}.${{ github.run_number }}" >> "$GITHUB_OUTPUT"
- name: Build
run: dotnet build LibGit2Sharp.sln --configuration Release
run: dotnet build LibGit2Sharp.sln --configuration Release ${{ steps.version.outputs.override && format('/p:MinVerVersionOverride={0}', steps.version.outputs.override) || '' }}
- name: Upload packages
uses: actions/upload-artifact@v4.3.1
uses: actions/upload-artifact@v7
with:
name: NuGet packages
path: artifacts/package/
retention-days: 7
- name: Verify trimming compatibility
run: dotnet publish TrimmingTestApp

test:
name: Test / ${{ matrix.os }} / ${{ matrix.arch }} / ${{ matrix.tfm }}
runs-on: ${{ matrix.os }}
Expand All @@ -55,11 +71,11 @@ jobs:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4.1.2
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install .NET SDK
uses: actions/setup-dotnet@v4.0.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
9.0.x
Expand All @@ -72,26 +88,14 @@ jobs:
strategy:
matrix:
arch: [ amd64, arm64 ]
distro: [ alpine.3.17, alpine.3.18, alpine.3.19, alpine.3.20, centos.stream.9, debian.12, fedora.40, ubuntu.20.04, ubuntu.22.04, ubuntu.24.04 ]
distro: [ alpine.3.20, alpine.3.21, alpine.3.22, centos.stream.9, debian.12, fedora.41, fedora.42, ubuntu.22.04, ubuntu.24.04 ]
sdk: [ '8.0', '9.0', '10.0' ]
exclude:
- distro: alpine.3.17
sdk: '9.0'
- distro: alpine.3.17
sdk: '10.0'
- distro: alpine.3.18
sdk: '9.0'
- distro: alpine.3.18
sdk: '10.0'
- distro: alpine.3.19
sdk: '9.0'
- distro: alpine.3.19
sdk: '10.0'
- distro: alpine.3.20
sdk: '10.0'
- distro: fedora.40
- distro: alpine.3.21
sdk: '10.0'
- distro: ubuntu.20.04
- distro: fedora.41
sdk: '10.0'
include:
- sdk: '8.0'
Expand All @@ -107,7 +111,7 @@ jobs:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4.1.2
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run ${{ matrix.tfm }} tests
Expand All @@ -116,3 +120,20 @@ jobs:
test_command="dotnet test LibGit2Sharp.sln --configuration Release -p:TargetFrameworks=${{ matrix.tfm }} --logger "GitHubActions" -p:ExtraDefine=LEAKS_IDENTIFYING"
docker run -t --rm --platform linux/${{ matrix.arch }} -v "$PWD:/home/gittools/app" -w "/home/gittools/app" -e OPENSSL_ENABLE_SHA1_SIGNATURES=1 gittools/build-images:${{ matrix.distro }}-sdk-${{ matrix.sdk }} sh -c "$git_command && $test_command"

nuget-push:
name: Octopus NuGet Push
needs: [build, test, test-linux]
# && github.ref == 'refs/heads/octopus/master'
if: github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]' && github.event_name != 'schedule'
runs-on: ubuntu-22.04
steps:
- uses: actions/download-artifact@v8
with:
path: staging
- name: Push package to feed 🐙
id: push-feed
shell: bash
env:
FEED_API_KEY: ${{ secrets.FEED_API_KEY }}
FEED_SOURCE: ${{ secrets.FEED_SOURCE }}
run: dotnet nuget push staging/**/*.nupkg --api-key "$FEED_API_KEY" --source "$FEED_SOURCE" --skip-duplicate
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ _ReSharper*/
*.swp
*.DotSettings

.idea/
_NCrunch_LibGit2Sharp/
artifacts/
worktree.playlist
13 changes: 13 additions & 0 deletions .idea/.idea.LibGit2Sharp/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/.idea.LibGit2Sharp/.idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/.idea.LibGit2Sharp/.idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .idea/.idea.LibGit2Sharp/.idea/indexLayout.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/.idea.LibGit2Sharp/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions LibGit2Sharp.Tests/GlobalSettingsFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ public void LoadFromSpecifiedPath(string architecture)
{
Skip.IfNot(Platform.IsRunningOnNetFramework(), ".NET Framework only test.");

var nativeDllFileName = NativeDllName.Name + ".dll";
var testDir = Path.GetDirectoryName(typeof(GlobalSettingsFixture).Assembly.Location);
var testAppExe = Path.Combine(testDir, $"NativeLibraryLoadTestApp.{architecture}.exe");
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Expand All @@ -71,7 +70,10 @@ public void LoadFromSpecifiedPath(string architecture)
try
{
Directory.CreateDirectory(platformDir);
File.Copy(Path.Combine(libraryPath, nativeDllFileName), Path.Combine(platformDir, nativeDllFileName));
foreach (var file in Directory.GetFiles(libraryPath, "*.dll"))
{
File.Copy(file, Path.Combine(platformDir, Path.GetFileName(file)));
}

var (output, exitCode) = ProcessHelper.RunProcess(testAppExe, arguments: $@"{NativeDllName.Name} ""{platformDir}""", workingDirectory: tempDir);

Expand All @@ -90,17 +92,17 @@ public void SetExtensions()
var extensions = GlobalSettings.GetExtensions();

// Assert that "noop" is supported by default
Assert.Equal(new[] { "noop", "objectformat", "worktreeconfig" }, extensions);
Assert.Equal(new[] { "noop", "objectformat", "preciousobjects", "worktreeconfig" }, extensions);

// Disable "noop" extensions
GlobalSettings.SetExtensions("!noop");
extensions = GlobalSettings.GetExtensions();
Assert.Equal(new[] { "objectformat", "worktreeconfig" }, extensions);
Assert.Equal(new[] { "objectformat", "preciousobjects", "worktreeconfig" }, extensions);

// Enable two new extensions (it will reset the configuration and "noop" will be enabled)
GlobalSettings.SetExtensions("partialclone", "newext");
extensions = GlobalSettings.GetExtensions();
Assert.Equal(new[] { "newext", "noop", "objectformat", "partialclone", "worktreeconfig" }, extensions);
Assert.Equal(new[] { "newext", "noop", "objectformat", "partialclone", "preciousobjects", "worktreeconfig" }, extensions);
}

[Fact]
Expand Down
128 changes: 127 additions & 1 deletion LibGit2Sharp.Tests/NetworkFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public void CanListRemoteReferences(string url)
Remote remote = repo.Network.Remotes.Add(remoteName, url);
IList<Reference> references = repo.Network.ListReferences(remote).ToList();


foreach (var reference in references)
{
// None of those references point to an existing
Expand Down Expand Up @@ -136,6 +135,133 @@ public void CanListRemoteReferencesWithCredentials()
}
}

[Theory]
[InlineData("http://github.com/libgit2/TestGitRepository")]
[InlineData("https://github.com/libgit2/TestGitRepository")]
public void CanListRemoteReferencesWithListRemoteOptions(string url)
{
string remoteName = "testRemote";

string repoPath = InitNewRepository();

using (var repo = new Repository(repoPath))
{
Remote remote = repo.Network.Remotes.Add(remoteName, url);
var options = new ListRemoteOptions
{
ProxyOptions = new ProxyOptions()
};

IList<Reference> references = repo.Network.ListReferences(remote, options).ToList();

foreach (var reference in references)
{
Assert.Null(reference.ResolveToDirectReference().Target);
}

List<Tuple<string, string>> actualRefs = references.
Select(directRef => new Tuple<string, string>(directRef.CanonicalName, directRef.ResolveToDirectReference()
.TargetIdentifier)).ToList();

Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count);
Assert.True(references.Single(reference => reference.CanonicalName == "HEAD") is SymbolicReference);
for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++)
{
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2);
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1);
}
}
}

[Theory]
[InlineData("http://github.com/libgit2/TestGitRepository")]
[InlineData("https://github.com/libgit2/TestGitRepository")]
public void CanListRemoteReferencesFromUrlWithListRemoteOptions(string url)
{
string repoPath = InitNewRepository();

using (var repo = new Repository(repoPath))
{
var options = new ListRemoteOptions
{
ProxyOptions = new ProxyOptions()
};

IList<Reference> references = repo.Network.ListReferences(url, options).ToList();

foreach (var reference in references)
{
Assert.Null(reference.ResolveToDirectReference().Target);
}

List<Tuple<string, string>> actualRefs = references.
Select(directRef => new Tuple<string, string>(directRef.CanonicalName, directRef.ResolveToDirectReference()
.TargetIdentifier)).ToList();

Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count);
Assert.True(references.Single(reference => reference.CanonicalName == "HEAD") is SymbolicReference);
for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++)
{
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2);
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1);
}
}
}

[Theory]
[InlineData("https://github.com/libgit2/TestGitRepository")]
public void CanListRemoteReferencesWithCertificateCheckCallback(string url)
{
string repoPath = InitNewRepository();

bool certificateCheckCalled = false;

using (var repo = new Repository(repoPath))
{
var options = new ListRemoteOptions
{
CertificateCheck = (cert, valid, host) =>
{
certificateCheckCalled = true;
return true;
}
};

IList<Reference> references = repo.Network.ListReferences(url, options).ToList();

Assert.True(certificateCheckCalled);
Assert.NotEmpty(references);
}
}

[SkippableFact]
public void CanListRemoteReferencesWithCredentialsInListRemoteOptions()
{
InconclusiveIf(() => string.IsNullOrEmpty(Constants.PrivateRepoUrl),
"Populate Constants.PrivateRepo* to run this test");

string remoteName = "origin";

string repoPath = InitNewRepository();

using (var repo = new Repository(repoPath))
{
Remote remote = repo.Network.Remotes.Add(remoteName, Constants.PrivateRepoUrl);

var options = new ListRemoteOptions
{
CredentialsProvider = Constants.PrivateRepoCredentials
};

var references = repo.Network.ListReferences(remote, options);

foreach (var reference in references)
{
Assert.NotNull(reference);
}
}
}

[Theory]
[InlineData(FastForwardStrategy.Default)]
[InlineData(FastForwardStrategy.NoFastForward)]
Expand Down
12 changes: 12 additions & 0 deletions LibGit2Sharp.Tests/PushFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ public void CanInvokePrePushCallbackAndFail()
Assert.True(prePushHandlerCalled);
}

[Fact]
public void CanPushWithRemoteProgressCallback()
{
PushOptions options = new PushOptions()
{
OnPushStatusError = OnPushStatusError,
OnPushRemoteProgress = (progress) => { return true; },
};

AssertPush(repo => repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options));
}

[Fact]
public void PushingABranchThatDoesNotTrackAnUpstreamBranchThrows()
{
Expand Down
Loading