diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5482c7d4..b4b075cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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: @@ -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 @@ -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 @@ -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" diff --git a/Dockerfile.linux b/Dockerfile.linux index 4421da3d..fccc8457 100644 --- a/Dockerfile.linux +++ b/Dockerfile.linux @@ -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"] \ No newline at end of file +CMD ["/bin/bash", "-c", "./build.libgit2.sh"] diff --git a/Dockerfile.linux-musl b/Dockerfile.linux-musl index 1cfa1e4e..ecae039a 100644 --- a/Dockerfile.linux-musl +++ b/Dockerfile.linux-musl @@ -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"] \ No newline at end of file +CMD ["/bin/bash", "-c", "./build.libgit2.sh"] diff --git a/README.md b/README.md index a6f68879..e57fd50d 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,26 @@ nuget.exe Pack nuget.package/NativeBinaries.nuspec -Version -NoPackage Where `` is the version from the MinVer tool or manually chosen version. +## Releasing + +Releases are triggered by pushing a git tag. The tag format is: + +``` +-octopus. +``` + +Where `` is the version from the upstream libgit2sharp.nativebinaries repo (e.g., `2.0.312`) and `` 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 diff --git a/UpdateLibgit2ToSha.ps1 b/UpdateLibgit2ToSha.ps1 index a3111d3d..151f8e74 100644 --- a/UpdateLibgit2ToSha.ps1 +++ b/UpdateLibgit2ToSha.ps1 @@ -97,7 +97,7 @@ Push-Location $libgit2Directory "@ - 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 = @" @@ -116,7 +116,7 @@ Push-Location $libgit2Directory "@ - 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 = @" diff --git a/build.libgit2.ps1 b/build.libgit2.ps1 index 9c86db2c..f2ea1a1f 100644 --- a/build.libgit2.ps1 +++ b/build.libgit2.ps1 @@ -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' @@ -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]" @@ -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 @@ -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 @@ -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 @@ -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!" diff --git a/build.libgit2.sh b/build.libgit2.sh index 3ac9e48e..58807859 100755 --- a/build.libgit2.sh +++ b/build.libgit2.sh @@ -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 @@ -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 . @@ -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/" diff --git a/dockerbuild.sh b/dockerbuild.sh index 4ee5a0a2..f9e5b0fa 100755 --- a/dockerbuild.sh +++ b/dockerbuild.sh @@ -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 @@ -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 diff --git a/libgit2 b/libgit2 index 3f4182d1..ca225744 160000 --- a/libgit2 +++ b/libgit2 @@ -1 +1 @@ -Subproject commit 3f4182d15eab74a302718f2de454ffadb1995626 +Subproject commit ca225744b992bf2bf24e9a2eb357ddef78179667 diff --git a/nuget.package/LibGit2Sharp.NativeBinaries.csproj b/nuget.package/LibGit2Sharp.NativeBinaries.csproj index 5d72ef07..f472fe28 100644 --- a/nuget.package/LibGit2Sharp.NativeBinaries.csproj +++ b/nuget.package/LibGit2Sharp.NativeBinaries.csproj @@ -9,6 +9,7 @@ libgit2\libgit2.license.txt https://github.com/libgit2/libgit2sharp.nativebinaries libgit2\libgit2.png + Octopus.LibGit2Sharp.NativeBinaries Native binaries for LibGit2Sharp true $(MSBuildThisFileDirectory) diff --git a/nuget.package/build/LibGit2Sharp.NativeBinaries.props b/nuget.package/build/Octopus.LibGit2Sharp.NativeBinaries.props similarity index 53% rename from nuget.package/build/LibGit2Sharp.NativeBinaries.props rename to nuget.package/build/Octopus.LibGit2Sharp.NativeBinaries.props index 65110797..0dd5096b 100644 --- a/nuget.package/build/LibGit2Sharp.NativeBinaries.props +++ b/nuget.package/build/Octopus.LibGit2Sharp.NativeBinaries.props @@ -1,7 +1,7 @@ $(MSBuildThisFileFullPath) - 3f4182d15eab74a302718f2de454ffadb1995626 - git2-3f4182d + ca225744b992bf2bf24e9a2eb357ddef78179667 + git2-ca22574 diff --git a/nuget.package/build/net46/LibGit2Sharp.NativeBinaries.props b/nuget.package/build/net46/Octopus.LibGit2Sharp.NativeBinaries.props similarity index 90% rename from nuget.package/build/net46/LibGit2Sharp.NativeBinaries.props rename to nuget.package/build/net46/Octopus.LibGit2Sharp.NativeBinaries.props index 46d2d754..0691ec98 100644 --- a/nuget.package/build/net46/LibGit2Sharp.NativeBinaries.props +++ b/nuget.package/build/net46/Octopus.LibGit2Sharp.NativeBinaries.props @@ -1,8 +1,8 @@ $(MSBuildThisFileFullPath) - 3f4182d15eab74a302718f2de454ffadb1995626 - git2-3f4182d + ca225744b992bf2bf24e9a2eb357ddef78179667 + git2-ca22574 diff --git a/nuget.package/buildMultiTargeting/LibGit2Sharp.NativeBinaries.props b/nuget.package/buildMultiTargeting/LibGit2Sharp.NativeBinaries.props deleted file mode 100644 index 5a6b0742..00000000 --- a/nuget.package/buildMultiTargeting/LibGit2Sharp.NativeBinaries.props +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/nuget.package/buildMultiTargeting/Octopus.LibGit2Sharp.NativeBinaries.props b/nuget.package/buildMultiTargeting/Octopus.LibGit2Sharp.NativeBinaries.props new file mode 100644 index 00000000..844e9946 --- /dev/null +++ b/nuget.package/buildMultiTargeting/Octopus.LibGit2Sharp.NativeBinaries.props @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/nuget.package/libgit2/LibGit2Sharp.dll.config b/nuget.package/libgit2/LibGit2Sharp.dll.config index 95f4b0bc..6ba12666 100644 --- a/nuget.package/libgit2/LibGit2Sharp.dll.config +++ b/nuget.package/libgit2/LibGit2Sharp.dll.config @@ -1,8 +1,8 @@ - - - - - - + + + + + + diff --git a/nuget.package/libgit2/libgit2_hash.txt b/nuget.package/libgit2/libgit2_hash.txt index e2370b1a..8eedcbb9 100644 --- a/nuget.package/libgit2/libgit2_hash.txt +++ b/nuget.package/libgit2/libgit2_hash.txt @@ -1 +1 @@ -3f4182d15eab74a302718f2de454ffadb1995626 +ca225744b992bf2bf24e9a2eb357ddef78179667