# lmrc-gitlab

> Part of the [LMRC Stack](https://gitlab.com/lemarco/lmrc-stack) - Infrastructure-as-Code toolkit for building production-ready Rust applications

A comprehensive Rust library for programmatic control of GitLab via its API.

[![Crates.io](https://img.shields.io/crates/v/lmrc-gitlab.svg)](https://crates.io/crates/lmrc-gitlab)
[![Documentation](https://docs.rs/lmrc-gitlab/badge.svg)](https://docs.rs/lmrc-gitlab)
[![License](https://img.shields.io/crates/l/lmrc-gitlab.svg)](https://gitlab.com/lemarco/lmrc-stack#license)

## Features

- **Type-safe API**: Strongly typed models for all GitLab resources
- **Async/await**: Built on tokio for efficient async operations
- **Comprehensive error handling**: Custom error types with detailed context
- **Builder patterns**: Fluent, ergonomic API design
- **Well documented**: Extensive documentation with examples
- **Tested**: Comprehensive test coverage

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
lmrc-gitlab = "0.1.0"
tokio = { version = "1", features = ["rt-multi-thread"] }
```

## Quick Start

```rust
use gitlab_client::{GitLabClient, models::PipelineStatus, Result};

#[tokio::main]
async fn main() -> Result<()> {
    // Create a client
    let client = GitLabClient::new("https://gitlab.com", "your-token")?;

    // List failed pipelines on main branch
    let pipelines = client
        .pipelines("myorg/myproject")
        .status(PipelineStatus::Failed)
        .ref_name("main")
        .limit(10)
        .list()
        .await?;

    for pipeline in pipelines {
        println!("Pipeline #{}: {}", pipeline.id, pipeline.status);
    }

    Ok(())
}
```

## Usage Examples

### Working with Pipelines

```rust
// Get pipeline details
let pipeline = client
    .pipeline("myorg/myproject", 12345)
    .get()
    .await?;

println!("Status: {}", pipeline.status);
println!("Duration: {:?}", pipeline.duration);

// Retry a failed pipeline
client
    .pipeline("myorg/myproject", 12345)
    .retry()
    .await?;

// Cancel a running pipeline
client
    .pipeline("myorg/myproject", 12345)
    .cancel()
    .await?;
```

### Filtering Pipelines

```rust
// Filter by status
let failed = client
    .pipelines("myorg/myproject")
    .status(PipelineStatus::Failed)
    .list()
    .await?;

// Filter by branch
let main_pipelines = client
    .pipelines("myorg/myproject")
    .ref_name("main")
    .list()
    .await?;

// Combine filters
let recent_failures = client
    .pipelines("myorg/myproject")
    .status(PipelineStatus::Failed)
    .ref_name("main")
    .limit(5)
    .list()
    .await?;
```

### Error Handling

The library provides comprehensive error types for better error handling:

```rust
use gitlab_client::{GitLabClient, GitLabError};

match client.pipeline("myorg/myproject", 999).get().await {
    Ok(pipeline) => println!("Found: {:?}", pipeline),
    Err(GitLabError::NotFound { resource, id }) => {
        println!("{} with id {} not found", resource, id);
    }
    Err(GitLabError::Authentication(msg)) => {
        println!("Auth error: {}", msg);
    }
    Err(e) => println!("Other error: {}", e),
}
```

### Checking Pipeline Status

```rust
let pipeline = client.pipeline("myorg/myproject", 12345).get().await?;

if pipeline.status.is_finished() {
    println!("Pipeline has completed");
}

if pipeline.status.is_successful() {
    println!("Pipeline succeeded!");
} else if pipeline.status.is_failed() {
    println!("Pipeline failed!");
}
```

## API Coverage

### Current Features

- ✅ Pipelines
  - List with filters (status, ref, limit)
  - Get details
  - Retry
  - Cancel

- ✅ Error Types
  - Authentication errors
  - API errors
  - Not found errors
  - Rate limiting
  - Validation errors
  - And more...

- ✅ Models
  - Pipeline (basic and detailed)
  - Job
  - Runner
  - Strong typing with enums for statuses

### Planned Features

- 🚧 Jobs
  - List jobs in pipeline
  - Get job details
  - Retry/cancel jobs
  - Download artifacts
  - View logs

- 🚧 Merge Requests
  - Create/update/merge MRs
  - List MRs with filters
  - Approve/unapprove
  - Add comments

- 🚧 Projects
  - Get project details
  - List projects
  - Create/update projects

- 🚧 Runners
  - List runners
  - Get runner details
  - Register/unregister runners

- 🚧 Container Registry
  - List repositories and tags
  - Delete old tags
  - Cleanup operations

- 🚧 CI/CD Variables
  - Get/set variables
  - Manage protected variables

- 🚧 Environments
  - List environments
  - Deploy to environment
  - Stop environment

## CI/CD Integration

This library is particularly useful for CI/CD automation. Common use cases include:

### Wait for Pipeline Completion

```rust
use tokio::time::{sleep, Duration};

async fn wait_for_pipeline(
    client: &GitLabClient,
    project: &str,
    pipeline_id: u64,
) -> Result<Pipeline> {
    loop {
        let pipeline = client.pipeline(project, pipeline_id).get().await?;

        if pipeline.status.is_finished() {
            return Ok(pipeline);
        }

        println!("Pipeline still running... ({})", pipeline.status);
        sleep(Duration::from_secs(30)).await;
    }
}
```

### Trigger and Monitor Pipeline

```rust
// In your CI/CD script
let client = GitLabClient::new(&gitlab_url, &token)?;

// Get current pipeline
let pipeline_id = std::env::var("CI_PIPELINE_ID")?.parse()?;
let pipeline = client.pipeline(&project, pipeline_id).get().await?;

if pipeline.status.is_failed() {
    // Retry failed jobs
    client.pipeline(&project, pipeline_id).retry().await?;
}
```

## Configuration

The library can be configured using environment variables:

```bash
export GITLAB_URL="https://gitlab.example.com"
export GITLAB_TOKEN="your-personal-access-token"
export GITLAB_PROJECT="myorg/myproject"
```

Or programmatically:

```rust
let client = GitLabClient::new(
    "https://gitlab.example.com",
    "your-token"
)?;
```

## Error Types

The library provides detailed error types for better error handling:

- `GitLabError::Authentication` - Invalid credentials
- `GitLabError::NotFound` - Resource not found
- `GitLabError::Api` - API-specific errors
- `GitLabError::RateLimit` - Rate limit exceeded
- `GitLabError::PermissionDenied` - Insufficient permissions
- `GitLabError::InvalidInput` - Invalid parameters
- `GitLabError::Timeout` - Operation timed out
- `GitLabError::Conflict` - Resource conflict
- `GitLabError::ServerError` - GitLab server error

All errors implement `std::error::Error` and can be used with `?` operator.

## Examples

See the [examples](examples/) directory for more comprehensive examples:

- `basic_usage.rs` - Demonstrates core library features

Run an example:

```bash
export GITLAB_TOKEN="your-token"
cargo run --example basic_usage
```

## Development

### Building

```bash
cargo build
```

### Testing

```bash
cargo test
```

### Documentation

Generate and view documentation:

```bash
cargo doc --open
```

### Code Quality

```bash
# Run clippy
cargo clippy -- -D warnings

# Format code
cargo fmt
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

Part of the LMRC Stack project. Licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

## Acknowledgments

Built on top of the excellent [gitlab](https://crates.io/crates/gitlab) crate for low-level API access.
