Skip to content

Commit 31f3f3a

Browse files
committed
Add GitHub Actions workflow for publishing NuGet packages and extend semaphore functionality
1 parent 8bfbe96 commit 31f3f3a

3 files changed

Lines changed: 106 additions & 4 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: Publish NuGet Packages
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: 'Package version (e.g. 3.1.0, 3.1.0-preview.1). Leave empty to derive from tag or branch.'
11+
required: false
12+
13+
permissions:
14+
packages: write
15+
contents: read
16+
17+
jobs:
18+
publish:
19+
runs-on: windows-latest
20+
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
with:
25+
fetch-depth: 0
26+
27+
- name: Setup .NET
28+
uses: actions/setup-dotnet@v4
29+
with:
30+
dotnet-version: |
31+
6.0.x
32+
8.0.x
33+
34+
- name: Determine version
35+
id: version
36+
shell: bash
37+
run: |
38+
if [[ -n "${{ github.event.inputs.version }}" ]]; then
39+
VERSION="${{ github.event.inputs.version }}"
40+
elif [[ "${{ github.ref_type }}" == "tag" ]]; then
41+
# Strip leading 'v' from tag (v3.1.0 -> 3.1.0)
42+
VERSION="${{ github.ref_name }}"
43+
VERSION="${VERSION#v}"
44+
else
45+
# Fallback: use VersionPrefix from Global.props + short SHA for pre-release
46+
VERSION="3.0.0-dev.${{ github.run_number }}"
47+
fi
48+
echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"
49+
echo "Resolved version: $VERSION"
50+
51+
- name: Restore dependencies
52+
run: dotnet restore
53+
54+
- name: Build
55+
run: dotnet build --configuration Release --no-restore /p:Version=${{ steps.version.outputs.VERSION }}
56+
57+
- name: Run tests
58+
run: dotnet test --configuration Release --no-build --verbosity normal
59+
60+
- name: Pack NuGet packages
61+
run: dotnet pack --configuration Release --no-build --output ./nupkgs /p:Version=${{ steps.version.outputs.VERSION }}
62+
63+
- name: Push to GitHub Packages
64+
run: dotnet nuget push "./nupkgs/*.nupkg" --source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate
65+
env:
66+
DOTNET_NOLOGO: true
67+
68+
- name: Upload packages as artifact
69+
uses: actions/upload-artifact@v4
70+
with:
71+
name: nuget-packages
72+
path: ./nupkgs/
73+
retention-days: 30

src/FubarDev.FtpServer/Networking/PausableFtpService.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,23 @@ public virtual async Task StartAsync(CancellationToken cancellationToken)
7171
throw new InvalidOperationException($"Status must be {FtpServiceStatus.ReadyToRun}, but was {Status}.");
7272
}
7373

74-
using var semaphore = new SemaphoreSlim(0, 1);
74+
using var semaphore = new SemaphoreSlimExt(0, 1);
7575
_jobPaused = new CancellationTokenSource();
7676
_task = RunAsync(
7777
new Progress<FtpServiceStatus>(
7878
status =>
7979
{
8080
Status = status;
8181

82-
if (status == FtpServiceStatus.Running)
82+
if (status == FtpServiceStatus.Running && !semaphore.IsDisposed)
8383
{
8484
// ReSharper disable once AccessToDisposedClosure
85-
semaphore.Release();
85+
semaphore?.Release();
8686
}
8787
}));
8888

89-
await semaphore.WaitAsync(cancellationToken);
89+
var res = semaphore.WaitAsync(cancellationToken);
90+
res.Wait(cancellationToken);
9091
}
9192

9293
/// <inheritdoc />
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// <copyright file="SemaphoreSlimExt.cs" company="Fubar Development Junker">
2+
// Copyright (c) Fubar Development Junker. All rights reserved.
3+
// </copyright>
4+
5+
using System.Threading;
6+
7+
namespace FubarDev.FtpServer
8+
{
9+
internal class SemaphoreSlimExt : SemaphoreSlim
10+
{
11+
public SemaphoreSlimExt(int initialCount)
12+
: base(initialCount)
13+
{
14+
}
15+
public SemaphoreSlimExt(int initialCount, int maxCount)
16+
: base(initialCount, maxCount)
17+
{
18+
}
19+
20+
public bool IsDisposed { get; internal set; }
21+
22+
protected override void Dispose(bool disposing)
23+
{
24+
base.Dispose(disposing);
25+
IsDisposed = true;
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)