bitbucket-server-rs 0.3.2

An API client library for Bitbucket Data Center
Documentation

bitbucket-server-rs

Rust License Crate API

A Rust client library for interacting with the Bitbucket Data Center REST API. This library provides a type-safe, ergonomic interface for Bitbucket Server (on-premise Bitbucket Data Center) operations, making it ideal for automation tools, CI/CD integrations, and Rust applications that need to interact with Bitbucket.

Features

  • Type-safe API: Strongly typed interfaces for Bitbucket Server REST API endpoints
  • Async/Await Support: Built on tokio and reqwest for modern asynchronous workflows
  • Error Handling: Comprehensive error types for better error management
  • Builder Pattern: Fluent API design for constructing requests
  • JSON Serialization/Deserialization: Automatic handling of JSON payloads
  • Authentication: Bearer token authentication support

Currently Supported APIs

  • Build Status: Get and post build statuses for commits
  • Pull Request Changes: Retrieve changes in pull requests

Installation

Add this to your Cargo.toml:

[dependencies]
bitbucket-server-rs = "0.3.1"
tokio = { version = "1.0", features = ["full"] } # For async runtime

Usage

Creating a Client

use bitbucket_server_rs::client::new;

// Create a new client with base URL and API token
let client = new(
    "https://bitbucket-server/rest",
    "YOUR_API_TOKEN"
);

Getting Build Status

use bitbucket_server_rs::client::{new, ApiError, ApiRequest, ApiResponse};
use bitbucket_server_rs::api::build_status_get::BuildStatus;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = new(
        "https://bitbucket-server/rest",
        "YOUR_API_TOKEN"
    );

    // Get build status for a specific commit
    let response = client
        .api()
        .build_status_get(
            "PROJECT_KEY",
            "COMMIT_ID",
            "REPOSITORY_SLUG"
        )
        .key("build-123") // Optional: filter by build key
        .build()?
        .send()
        .await?;

    // Handle the response
    match response {
        Some(build_status) => {
            println!("Build state: {:?}", build_status.state);
            println!("Build URL: {}", build_status.url);
            // Access other fields as needed
        },
        None => println!("No build status found")
    }

    Ok(())
}

Posting Build Status

use bitbucket_server_rs::client::new;
use bitbucket_server_rs::api::build_status::BuildStatusState;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = new(
        "https://bitbucket-server/rest",
        "YOUR_API_TOKEN"
    );

    // Post a build status for a commit
    let response = client
        .api()
        .build_status_post(
            "PROJECT_KEY",
            "COMMIT_ID",
            "REPOSITORY_SLUG"
        )
        .key("build-123")
        .state(BuildStatusState::Successful)
        .url("https://ci.example.com/build/123")
        .description("Build passed successfully")
        .name("CI Build")
        .build()?
        .send()
        .await?;

    println!("Build status posted successfully");

    Ok(())
}

Getting Pull Request Changes

use bitbucket_server_rs::client::new;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = new(
        "https://bitbucket-server/rest",
        "YOUR_API_TOKEN"
    );

    // Get changes for a pull request
    let response = client
        .api()
        .pull_request_changes_get(
            "PROJECT_KEY",
            "REPOSITORY_SLUG",
            123 // Pull request ID
        )
        .start(0)
        .limit(100)
        .build()?
        .send()
        .await?;

    // Handle the response
    if let Some(changes) = response {
        println!("Found {} changes", changes.values.len());
        for change in changes.values {
            println!("Change: {:?}", change.path);
        }
    }

    Ok(())
}

Error Handling

The library provides a comprehensive error type ApiError that covers various failure scenarios:

pub enum ApiError {
    // Error building the request
    RequestError,
    
    // Error getting the response
    ResponseError,
    
    // Authentication error
    Unauthorized,
    
    // HTTP 4xx errors
    HttpClientError(u16, String),
    
    // HTTP 5xx errors
    HttpServerError(u16, String),
    
    // Unexpected response
    UnexpectedResponse(u16, String),
    
    // Error deserializing the response body
    DeserializationError(String),
}

Example of error handling:

match client.api().build_status_get("PROJECT", "COMMIT", "REPO").build()?.send().await {
    Ok(response) => {
        // Handle successful response
    },
    Err(ApiError::Unauthorized) => {
        eprintln!("Authentication failed. Check your API token.");
    },
    Err(ApiError::HttpClientError(status, message)) => {
        eprintln!("Client error ({}): {}", status, message);
    },
    Err(e) => {
        eprintln!("Request failed: {:?}", e);
    }
}

Custom HTTP Client Configuration

You can customize the HTTP client configuration:

use bitbucket_server_rs::client::{Client, new};
use reqwest::ClientBuilder;

// Create a custom HTTP client
let http_client = ClientBuilder::new()
    .timeout(std::time::Duration::from_secs(30))
    .build()
    .expect("Failed to build HTTP client");

// Create a new Bitbucket client
let mut client = new("https://bitbucket-server/rest", "API_TOKEN");

// Set the custom HTTP client
client.with_http_client(http_client);

CI/CD

This project uses GitHub Actions for continuous integration and deployment:

  • PR Check: Runs tests and ensures version is bumped on pull requests
  • Publish: Automatically publishes to crates.io when changes are merged to main

Setting up for Publishing

To enable publishing to crates.io with manual approval, you need to:

  1. Generate a new token on crates.io
  2. Go to your GitHub repository settings → Secrets and variables → Actions
  3. Add a new repository secret named CRATES_IO_TOKEN with your crates.io API token as the value
  4. Go to Settings → Environments → New environment
  5. Create an environment named crates-io-publish
  6. Add required reviewers who must approve the publishing step

With this setup, the workflow will:

  1. Automatically prepare the release when changes are merged to main
  2. Run build and tests to verify everything works
  3. Wait for manual approval from the required reviewers
  4. After approval, publish to crates.io, which triggers docs.rs to build and publish the documentation

You can also manually trigger the publishing workflow from the Actions tab in GitHub.

Contributing

Contributions are welcome! Here's how you can contribute:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature-name
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin feature-name
  5. Submit a pull request

Please make sure to update tests as appropriate and follow the Rust code style guidelines.

Version Bumping

When making changes, remember to bump the version in Cargo.toml according to Semantic Versioning principles:

  • MAJOR version for incompatible API changes
  • MINOR version for adding functionality in a backwards compatible manner
  • PATCH version for backwards compatible bug fixes

The CI workflow will verify that the version has been bumped in pull requests.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • reqwest - HTTP client for Rust
  • serde - Serialization framework for Rust
  • tokio - Asynchronous runtime for Rust