Skip to content
Draft
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
62 changes: 40 additions & 22 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ on:
push:
branches: [master, release-*]
tags:
- '[0-9]+.[0-9]+.[0-9]+'
- '[0-9]+.[0-9]+.[0-9]+-*'
- "[0-9]+.[0-9]+.[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+-*"
pull_request:
workflow_dispatch:
jobs:
Expand All @@ -16,13 +16,13 @@ jobs:
strategy:
matrix:
include:
- os: windows-2019
- os: windows-2022
name: win-x86
param: -x86
- os: windows-2019
- os: windows-2022
name: win-x64
param: -x64
- os: windows-2019
- os: windows-2022
name: win-arm64
param: -arm64
- os: ubuntu-24.04
Expand All @@ -39,14 +39,14 @@ jobs:
name: linux-musl-arm
- os: ubuntu-24.04
name: linux-musl-arm64
- os: macos-13
- os: macos-26-intel
name: osx-x64
- os: macos-13
- os: macos-26
name: osx-arm64
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v6.0.2
with:
submodules: true
- name: Build Windows
Expand All @@ -56,39 +56,57 @@ jobs:
if: runner.os == 'macOS'
run: ./build.libgit2.sh
- name: Setup QEMU
if: matrix.name == 'linux-musl-arm' || matrix.name == 'linux-musl-arm64'
run: docker run --rm --privileged multiarch/qemu-user-static:register --reset
if: runner.os == 'Linux' && (matrix.name == 'linux-arm' || matrix.name == 'linux-arm64' || matrix.name == 'linux-ppc64le' || matrix.name == 'linux-musl-arm' || matrix.name == 'linux-musl-arm64')
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
if: runner.os == 'Linux'
uses: docker/setup-buildx-action@v4
- name: Build Linux
if: runner.os == 'Linux'
run: ./dockerbuild.sh
- name: Upload artifacts
uses: actions/upload-artifact@v4.4.3
uses: actions/upload-artifact@v7.0.0
with:
name: ${{ matrix.name }}
path: nuget.package/runtimes/${{ matrix.name }}
package:
name: Create package
needs: build
runs-on: ubuntu-24.04
env:
DOTNET_NOLOGO: true
steps:
name: Create package
needs: build
runs-on: ubuntu-24.04
env:
DOTNET_NOLOGO: true
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4.1.0
uses: actions/setup-dotnet@v5.2.0
with:
dotnet-version: 9.0.x
- name: Compute version suffix for branch builds
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
id: version
run: |
# 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)
echo "override=${SAFE_BRANCH}.${{ github.run_number }}" >> "$GITHUB_OUTPUT"
- name: Download artifacts
uses: actions/download-artifact@v4.1.8
uses: actions/download-artifact@v8.0.1
with:
path: nuget.package/runtimes/
- name: Create package
run: dotnet pack nuget.package
run: dotnet pack nuget.package ${{ steps.version.outputs.override && format('/p:MinVerDefaultPreReleaseIdentifiers="{0}"', steps.version.outputs.override) || '' }}
- name: Upload NuGet package
uses: actions/upload-artifact@v4.4.3
uses: actions/upload-artifact@v7.0.0
with:
name: NuGet package
path: ./nuget.package/*.nupkg
- 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 ./nuget.package/*.nupkg --api-key "$FEED_API_KEY" --source "$FEED_SOURCE"
10 changes: 5 additions & 5 deletions Dockerfile.linux
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
FROM bording/crossbuild
ARG ARCH='amd64'
ENV CROSS_TRIPLE=${ARCH}
RUN apt update && apt -y install pkg-config
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake pkg-config libssl-dev libssh2-1-dev patchelf \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /nativebinaries
COPY . /nativebinaries/

CMD ["/bin/bash", "-c", "./build.libgit2.sh"]
CMD ["/bin/bash", "-c", "./build.libgit2.sh"]
7 changes: 3 additions & 4 deletions Dockerfile.linux-musl
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
ARG ARCH='amd64'
FROM multiarch/alpine:${ARCH}-v3.13
RUN apk add --no-cache bash build-base cmake
FROM alpine:3.19
RUN apk add --no-cache bash build-base cmake openssl-dev libssh2-dev patchelf

WORKDIR /nativebinaries
COPY . /nativebinaries/

CMD ["/bin/bash", "-c", "./build.libgit2.sh"]
CMD ["/bin/bash", "-c", "./build.libgit2.sh"]
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ nuget.exe Pack nuget.package/NativeBinaries.nuspec -Version <version> -NoPackage
Where `<version>` is the version from the MinVer tool or manually chosen version.


## Releasing

Releases are triggered by pushing a git tag. The tag format is:

```
<upstream-version>-octopus.<n>
```

Where `<upstream-version>` is the version from the upstream libgit2sharp.nativebinaries repo (e.g., `2.0.312`) and `<n>` is an incrementing number starting at 1. The incrementing number resets to 1 when the upstream version changes.

For example, for upstream version `2.0.312`:

```
git tag 2.0.312-octopus.1
git push origin 2.0.312-octopus.1
```

This triggers CI, which builds all native binaries, packs the NuGet package with the tag as its version, and pushes it to the configured feed.


## Notes on Visual Studio

Visual Studio 2019 is required to build the Windows native binaries, however you
Expand Down
4 changes: 2 additions & 2 deletions UpdateLibgit2ToSha.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Push-Location $libgit2Directory
</Project>
"@

Set-Content -Encoding UTF8 (Join-Path $projectDirectory "nuget.package\build\LibGit2Sharp.NativeBinaries.props") $buildProperties
Set-Content -Encoding UTF8 (Join-Path $projectDirectory "nuget.package\build\Octopus.LibGit2Sharp.NativeBinaries.props") $buildProperties

$net46BuildProperties = @"
<Project>
Expand All @@ -116,7 +116,7 @@ Push-Location $libgit2Directory
</Project>
"@

Set-Content -Encoding UTF8 (Join-Path $projectDirectory "nuget.package\build\net46\LibGit2Sharp.NativeBinaries.props") $net46BuildProperties
Set-Content -Encoding UTF8 (Join-Path $projectDirectory "nuget.package\build\net46\Octopus.LibGit2Sharp.NativeBinaries.props") $net46BuildProperties

$dllConfig = @"
<configuration>
Expand Down
38 changes: 34 additions & 4 deletions build.libgit2.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ $x86Directory = Join-Path $projectDirectory "nuget.package\runtimes\win-x86\nati
$x64Directory = Join-Path $projectDirectory "nuget.package\runtimes\win-x64\native"
$arm64Directory = Join-Path $projectDirectory "nuget.package\runtimes\win-arm64\native"
$hashFile = Join-Path $projectDirectory "nuget.package\libgit2\libgit2_hash.txt"
$sha = Get-Content $hashFile
$sha = Get-Content $hashFile
$binaryFilename = "git2-" + $sha.Substring(0,7)

$build_tests = 'OFF'
Expand Down Expand Up @@ -101,6 +101,27 @@ function Assert-Consistent-Naming($expected, $path) {
Ensure-Property $expected $dll.VersionInfo.OriginalFilename "VersionInfo.OriginalFilename" $dll.Fullname
}

function Install-Libssh2($arch) {
$triplet = "$arch-windows"

$vcpkg = Join-Path $Env:VCPKG_INSTALLATION_ROOT "vcpkg.exe"
if (-not (Test-Path $vcpkg)) {
throw "Error: vcpkg not found at $Env:VCPKG_INSTALLATION_ROOT"
}

Write-Host "Installing libssh2 for $triplet via vcpkg..."
Run-Command -Fatal -Quiet { & $vcpkg install "libssh2:$triplet" }

$installedDir = Join-Path $Env:VCPKG_INSTALLATION_ROOT "installed\$triplet"

return @{
IncludeDir = Join-Path $installedDir "include"
LibDir = Join-Path $installedDir "lib"
BinDir = Join-Path $installedDir "bin"
Prefix = $installedDir
}
}

try {
if ((!$x86.isPresent -and !$x64.IsPresent) -and !$arm64.IsPresent) {
Write-Output -Stderr "Error: usage $MyInvocation.MyCommand [-x86] [-x64] [-arm64]"
Expand All @@ -118,7 +139,8 @@ try {

if ($x86.IsPresent) {
Write-Output "Building x86..."
Run-Command -Fatal { & $cmake -A Win32 -D USE_SSH=exec -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" .. }
$ssh2 = Install-Libssh2 "x86"
Run-Command -Fatal { & $cmake -A Win32 -D USE_SSH=ON -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" -D "CMAKE_PREFIX_PATH=$($ssh2.Prefix)" .. }
Run-Command -Fatal { & $cmake --build . --config $configuration }
if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } }
cd $configuration
Expand All @@ -127,14 +149,17 @@ try {
Run-Command -Quiet { & rm $x86Directory\* -ErrorAction Ignore }
Run-Command -Quiet { & mkdir -fo $x86Directory }
Run-Command -Quiet -Fatal { & copy -fo * $x86Directory -Exclude *.lib }
Run-Command -Quiet -Fatal { & copy -fo (Join-Path $ssh2.BinDir "*.dll") $x86Directory }
if (-not (Test-Path (Join-Path $x86Directory "libssh2.dll"))) { throw "Error: libssh2.dll was not copied to $x86Directory" }
cd ..
}

if ($x64.IsPresent) {
Write-Output "Building x64..."
$ssh2 = Install-Libssh2 "x64"
Run-Command -Quiet { & mkdir build64 }
cd build64
Run-Command -Fatal { & $cmake -A x64 -D USE_SSH=exec -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" ../.. }
Run-Command -Fatal { & $cmake -A x64 -D USE_SSH=ON -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" -D "CMAKE_PREFIX_PATH=$($ssh2.Prefix)" ../.. }
Run-Command -Fatal { & $cmake --build . --config $configuration }
if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } }
cd $configuration
Expand All @@ -143,13 +168,16 @@ try {
Run-Command -Quiet { & rm $x64Directory\* -ErrorAction Ignore }
Run-Command -Quiet { & mkdir -fo $x64Directory }
Run-Command -Quiet -Fatal { & copy -fo * $x64Directory -Exclude *.lib }
Run-Command -Quiet -Fatal { & copy -fo (Join-Path $ssh2.BinDir "*.dll") $x64Directory }
if (-not (Test-Path (Join-Path $x64Directory "libssh2.dll"))) { throw "Error: libssh2.dll was not copied to $x64Directory" }
}

if ($arm64.IsPresent) {
Write-Output "Building arm64..."
$ssh2 = Install-Libssh2 "arm64"
Run-Command -Quiet { & mkdir buildarm64 }
cd buildarm64
Run-Command -Fatal { & $cmake -A ARM64 -D USE_SSH=exec -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" ../.. }
Run-Command -Fatal { & $cmake -A ARM64 -D USE_SSH=ON -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" -D "CMAKE_PREFIX_PATH=$($ssh2.Prefix)" ../.. }
Run-Command -Fatal { & $cmake --build . --config $configuration }
if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } }
cd $configuration
Expand All @@ -158,6 +186,8 @@ try {
Run-Command -Quiet { & rm $arm64Directory\* -ErrorAction Ignore }
Run-Command -Quiet { & mkdir -fo $arm64Directory }
Run-Command -Quiet -Fatal { & copy -fo * $arm64Directory -Exclude *.lib }
Run-Command -Quiet -Fatal { & copy -fo (Join-Path $ssh2.BinDir "*.dll") $arm64Directory }
if (-not (Test-Path (Join-Path $arm64Directory "libssh2.dll"))) { throw "Error: libssh2.dll was not copied to $arm64Directory" }
}

Write-Output "Done!"
Expand Down
30 changes: 29 additions & 1 deletion build.libgit2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ ARCH=`uname -m`
PACKAGEPATH="nuget.package/runtimes"
OSXARCHITECTURE=$ARCH

EXTRA_CMAKE_FLAGS=""

if [[ $OS == "Darwin" ]]; then
USEHTTPS="ON"
if [[ $RID == "osx-arm64" ]]; then
Expand All @@ -28,11 +30,12 @@ export _BINPATH=`pwd`

cmake -DCMAKE_BUILD_TYPE:STRING=Release \
-DBUILD_TESTS:BOOL=OFF \
-DUSE_SSH=exec \
-DUSE_SSH=ON \
-DLIBGIT2_FILENAME=git2-$SHORTSHA \
-DCMAKE_OSX_ARCHITECTURES=$OSXARCHITECTURE \
-DUSE_HTTPS=$USEHTTPS \
-DUSE_BUNDLED_ZLIB=ON \
$EXTRA_CMAKE_FLAGS \
..
cmake --build .

Expand All @@ -53,3 +56,28 @@ rm -rf $PACKAGEPATH/$RID
mkdir -p $PACKAGEPATH/$RID/native

cp libgit2/build/libgit2-$SHORTSHA.$LIBEXT $PACKAGEPATH/$RID/native

# Bundle libssh2 shared library alongside libgit2
LIBGIT2_PATH="$PACKAGEPATH/$RID/native/libgit2-$SHORTSHA.$LIBEXT"

if [[ $OS == "Darwin" ]]; then
echo "macOS: libssh2 sourced from global installation"
else
# Linux: find libssh2 via ldd
LIBSSH2_PATH=$(ldd "$LIBGIT2_PATH" | grep libssh2 | awk '{print $3}')
if [[ -z "$LIBSSH2_PATH" ]]; then
echo "ERROR: libgit2 does not appear to link against libssh2"
exit 1
fi

LIBSSH2_BASENAME=$(basename "$LIBSSH2_PATH")

echo "Bundling $LIBSSH2_BASENAME from $LIBSSH2_PATH"
cp "$LIBSSH2_PATH" "$PACKAGEPATH/$RID/native/$LIBSSH2_BASENAME"

# Set RPATH so libgit2 finds libssh2 in the same directory at runtime
patchelf --set-rpath '$ORIGIN' "$LIBGIT2_PATH"
fi

echo "Contents of $PACKAGEPATH/$RID/native/:"
ls -la "$PACKAGEPATH/$RID/native/"
12 changes: 6 additions & 6 deletions dockerbuild.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ set -e
echo "building for $RID"

if [[ $RID =~ arm64 ]]; then
arch="arm64"
platform="linux/arm64"
elif [[ $RID =~ arm ]]; then
arch="armhf"
platform="linux/arm/v7"
elif [[ $RID =~ ppc64le ]]; then
arch="powerpc64le"
platform="linux/ppc64le"
else
arch="amd64"
platform="linux/amd64"
fi

if [[ $RID == linux-musl* ]]; then
Expand All @@ -19,9 +19,9 @@ else
dockerfile="Dockerfile.linux"
fi

docker buildx build -t $RID -f $dockerfile --build-arg ARCH=$arch .
docker buildx build --platform "$platform" --load -t $RID -f $dockerfile .

docker run -t -e RID=$RID --name=$RID $RID
docker run --platform "$platform" -t -e RID=$RID --name=$RID $RID

docker cp $RID:/nativebinaries/nuget.package/runtimes nuget.package

Expand Down
2 changes: 1 addition & 1 deletion libgit2
Submodule libgit2 updated 444 files
1 change: 1 addition & 0 deletions nuget.package/LibGit2Sharp.NativeBinaries.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<PackageLicenseFile>libgit2\libgit2.license.txt</PackageLicenseFile>
<PackageProjectUrl>https://github.com/libgit2/libgit2sharp.nativebinaries</PackageProjectUrl>
<PackageIcon>libgit2\libgit2.png</PackageIcon>
<PackageId>Octopus.LibGit2Sharp.NativeBinaries</PackageId>
<Description>Native binaries for LibGit2Sharp</Description>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageOutputPath>$(MSBuildThisFileDirectory)</PackageOutputPath>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<libgit2_propsfile>$(MSBuildThisFileFullPath)</libgit2_propsfile>
<libgit2_hash>3f4182d15eab74a302718f2de454ffadb1995626</libgit2_hash>
<libgit2_filename>git2-3f4182d</libgit2_filename>
<libgit2_hash>ca225744b992bf2bf24e9a2eb357ddef78179667</libgit2_hash>
<libgit2_filename>git2-ca22574</libgit2_filename>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<libgit2_propsfile>$(MSBuildThisFileFullPath)</libgit2_propsfile>
<libgit2_hash>3f4182d15eab74a302718f2de454ffadb1995626</libgit2_hash>
<libgit2_filename>git2-3f4182d</libgit2_filename>
<libgit2_hash>ca225744b992bf2bf24e9a2eb357ddef78179667</libgit2_hash>
<libgit2_filename>git2-ca22574</libgit2_filename>
</PropertyGroup>
<ItemGroup>
<ContentWithTargetPath Include="$(MSBuildThisFileDirectory)\..\..\runtimes\win-x86\native\*" TargetPath="lib\win32\x86\%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
Expand Down
Loading