Skip to content

diomonogatari/Bitbucket.Net

 
 

Repository files navigation

Bitbucket.Net

NuGet NuGet Downloads CI codecov license

Modernized C# client for Bitbucket Server (Stash) REST API.

Contributing

Development setup (including the pre-commit formatting hook) is documented in CONTRIBUTING.md.

Fork notice — This is an actively maintained fork of lvermeulen/Bitbucket.Net, which appears to be abandoned (last release 2020). The 1.0.0 API surface is stable; breaking changes follow semver. The library is used in production by the author (as the backend for an MCP Server talking to on-prem Bitbucket Server), but not every endpoint has been verified against a live instance. Contributions, bug reports, and feedback are welcome.

What changed from the original

  • .NET 10 target (dropped .NET Framework / .NET Standard)
  • System.Text.Json with source generation (no runtime reflection)
  • CancellationToken on every async method
  • IAsyncEnumerable streaming for paginated endpoints
  • Streaming diffs and raw file content
  • Typed exception hierarchy (BitbucketNotFoundException, etc.)
  • IHttpClientFactory / DI-friendly constructors
  • IDisposable with ownership tracking
  • IBitbucketClient decomposed into 12 domain-specific sub-interfaces
  • Fluent query builders for pull requests, commits, branches, and projects
  • Dedicated request DTOs for write operations
  • Input validation on all public API methods
  • OpenTelemetry tracing via ActivitySource
  • Bitbucket Server 9.0+ blocker-comment (task) support with legacy fallback
  • Flurl.Http 4.x

If you're looking for Bitbucket Cloud API, try this repository.

Installation

dotnet add package BitbucketServer.Net

Usage

Basic Authentication

var client = new BitbucketClient("https://bitbucket.example.com", "username", "password");

Token Authentication

var client = new BitbucketClient("https://bitbucket.example.com", () => GetAccessToken());

Resource management

BitbucketClient implements IDisposable. Clients created with a URL own the underlying HTTP connection and dispose it:

using var client = new BitbucketClient("https://bitbucket.example.com", "user", "pass");
var projects = await client.GetProjectsAsync();

When you inject an HttpClient or IFlurlClient, the caller retains ownership; the client will not dispose it.

Dependency Injection with IHttpClientFactory

For production scenarios, you can inject an externally managed HttpClient to leverage IHttpClientFactory for connection pooling, resilience policies, and centralized configuration.

Standard resilience (recommended)

The simplest approach uses Microsoft.Extensions.Http.Resilience which provides retry, circuit breaker, and timeout out of the box:

// Requires: dotnet add package Microsoft.Extensions.Http.Resilience

services.AddHttpClient<BitbucketClient>(client =>
{
    client.Timeout = TimeSpan.FromMinutes(2);
})
.AddStandardResilienceHandler(options =>
{
    options.Retry.MaxRetryAttempts = 3;
    options.Retry.Delay = TimeSpan.FromSeconds(1);
    options.Retry.BackoffType = DelayBackoffType.Exponential;
    options.CircuitBreaker.FailureRatio = 0.5;
    options.CircuitBreaker.SamplingDuration = TimeSpan.FromSeconds(30);
    options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(30);
});

// Register IBitbucketClient for dependency injection
services.AddSingleton<IBitbucketClient>(sp =>
{
    var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
    var httpClient = httpClientFactory.CreateClient(nameof(BitbucketClient));

    return new BitbucketClient(
        httpClient,
        "https://bitbucket.example.com",
        () => sp.GetRequiredService<ITokenProvider>().GetToken());
});

Custom resilience pipeline

For fine-grained control over which responses trigger retries:

services.AddHttpClient<BitbucketClient>(client =>
{
    client.Timeout = TimeSpan.FromMinutes(2);
})
.AddResilienceHandler("bitbucket", builder =>
{
    builder
        .AddRetry(new HttpRetryStrategyOptions
        {
            MaxRetryAttempts = 3,
            BackoffType = DelayBackoffType.Exponential,
            Delay = TimeSpan.FromSeconds(1),
            ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
                .HandleResult(r => r.StatusCode == HttpStatusCode.TooManyRequests
                                || r.StatusCode >= HttpStatusCode.InternalServerError)
        })
        .AddCircuitBreaker(new HttpCircuitBreakerStrategyOptions
        {
            FailureRatio = 0.5,
            SamplingDuration = TimeSpan.FromSeconds(30),
            BreakDuration = TimeSpan.FromSeconds(15),
        })
        .AddTimeout(TimeSpan.FromSeconds(30));
});

Advanced: Using IFlurlClient

For fine-grained control over Flurl's configuration:

services.AddSingleton<IFlurlClientCache>(sp => new FlurlClientCache()
    .Add("Bitbucket", "https://bitbucket.example.com", builder => builder
        .WithSettings(s => s.Timeout = TimeSpan.FromMinutes(5))
        .WithHeader("X-Custom-Header", "value")));

services.AddSingleton<IBitbucketClient>(sp =>
{
    var flurlClient = sp.GetRequiredService<IFlurlClientCache>().Get("Bitbucket");
    return new BitbucketClient(flurlClient, () => GetToken());
});

Streaming with IAsyncEnumerable

For memory-efficient processing of large result sets, use the streaming variants:

// Stream projects without buffering all pages in memory
await foreach (var project in client.GetProjectsStreamAsync())
{
    Console.WriteLine(project.Name);
}

// With cancellation support
var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
await foreach (var pr in client.GetPullRequestsStreamAsync("PROJ", "repo", cancellationToken: cts.Token))
{
    await ProcessPullRequestAsync(pr);
}

// Stream PR activities
await foreach (var activity in client.GetPullRequestActivitiesStreamAsync(
    "PROJ", "repo", pullRequestId: 42))
{
    ProcessActivity(activity);
}

// Stream dashboard PRs
await foreach (var pr in client.GetDashboardPullRequestsStreamAsync())
{
    Console.WriteLine($"#{pr.Id}: {pr.Title}");
}

Fluent query builders

For endpoints with many optional filters, query builders provide a typed alternative to the flat method signatures:

var openPRs = await client.PullRequests("PROJ", "repo")
    .InState(PullRequestStates.Open)
    .OrderBy(PullRequestOrders.Newest)
    .PageSize(25)
    .GetAsync();

// Streaming variant
await foreach (var pr in client.PullRequests("PROJ", "repo")
    .InState(PullRequestStates.Open)
    .StreamAsync())
{
    Console.WriteLine(pr.Title);
}

Builders are available for pull requests, commits, branches, and projects. The original flat methods still work and are not deprecated.

Exception handling

Typed exceptions give you precise control over error handling:

try
{
    var repo = await client.GetRepositoryAsync("PROJ", "repo");
}
catch (BitbucketNotFoundException ex)
{
    Console.WriteLine($"Repository not found: {ex.Context}");
}
catch (BitbucketAuthenticationException)
{
    Console.WriteLine("Invalid credentials");
}
catch (BitbucketForbiddenException ex)
{
    Console.WriteLine($"Access denied: {ex.Message}");
}
catch (BitbucketApiException ex)
{
    Console.WriteLine($"API error {ex.StatusCode}: {ex.Message}");
}

Benchmarks

Performance benchmarks are available in the benchmarks/ folder using BenchmarkDotNet:

cd benchmarks/Bitbucket.Net.Benchmarks
dotnet run -c Release

See benchmarks/README.md for detailed instructions.

Features

  • Audit
    • Project Events
    • Repository Events
  • Branches
    • Create Branch
    • Delete Branch
    • Branch Info
    • Branch Model
  • Builds
    • Commits Build Stats
    • Commit Build Stats
    • Commit Build Status
    • Associate Build Status
  • Comment Likes
    • Repository Comment Likes
    • Pull Request Comment Likes
  • Core
    • Admin
      • Groups
      • Users
      • Cluster
      • License
      • Mail Server
      • Permissions
      • Pull Requests
    • Application Properties
    • Dashboard
    • Groups
    • Hooks
    • Inbox
    • Logs
    • Markup
    • Profile
    • Projects
      • Projects
      • Permissions
      • Repos
        • Repos
        • Branches
        • Browse
        • Changes
        • Commits
        • Compare
        • Diff
        • Files
        • Last Modified
        • Participants
        • Permissions
        • Pull Requests
        • Raw
        • Settings
        • Tags
        • Webhooks
      • Settings
    • Repos
    • Tasks
    • Users
  • Default Reviewers
    • Project Default Reviewers
    • Repository Default Reviewers
  • Git
  • JIRA
    • Create JIRA Issue
    • Get Commits For JIRA Issue
    • Get JIRA Issues For Commits
  • Personal Access Tokens
  • Ref Restrictions
    • Project Restrictions
    • Repository Restrictions
  • Repository Ref Synchronization
  • SSH

About

C# client for Atlassian Bitbucket Server

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Languages

  • C# 99.7%
  • Other 0.3%