Radish alpha
r
rad:z2UcCU1LgMshWvXj6hXSDDrwB8q8M
Radicle Job Collaborative Object
Radicle
Git
radicle-job README.md

radicle-job

A crate for all† your automated job needs on the Radicle Network.

†: well maybe almost all.

Overview

radicle-job provides a collaborative framework for managing automated tasks across the Radicle peer-to-peer network. Multiple nodes can pick up and execute jobs (like CI/CD pipelines) for any given Git commit, with results synchronized across the network using Radicle’s Collaborative Objects (COBs).

Key Features

  • Decentralized Execution: Any node in the network can pick up and run jobs
  • Collaborative Tracking: Multiple nodes can contribute runs for the same job
  • Rich Status Reporting: Track job lifecycle from start to completion with success/failure reasons
  • External Log Integration: Link to external logging services via URLs
  • Git Integration: Jobs are tied to specific Git commits using OIDs

Key Concepts

  • Job: Represents an automated task for a specific Git commit that can be executed by multiple nodes
  • Run: A single execution attempt of a job by a particular node, identified by a UUID
  • Status: The current state of a run (Started, Finished(Succeeded), Finished(Failed))
  • COB (Collaborative Object): The underlying Radicle primitive that enables decentralized synchronization of job data

Installation

Add this to your Cargo.toml:

[dependencies]
radicle-job = "0.1"
radicle >= "0.15" # Required for core Radicle functionality

This crate is designed to work seamlessly with the radicle ecosystem.

Quick Start

Creating and Managing Jobs

use radicle_job::{Jobs, Reason};
use radicle::git::Oid;
use url::Url;
use uuid::Uuid;

// Open the jobs store for a repository
let mut jobs = Jobs::open(&repo)?;

// Create a new job for a specific commit
let commit_oid = /* your commit OID */;
let mut job = jobs.create(commit_oid, &signer)?;

// Node starts a run
let run_id = Uuid::new_v4();
let log_url = Url::parse("https://ci.example.com/logs/run-123")?;
job.run(run_id, log_url, &signer)?;

// Node reports completion
job.finish(run_id, Reason::Succeeded, &signer)?;

Querying Job Status

// Get all runs that are currently in progress
let started_runs = job.started();

// Get successful runs from all nodes
let successful_runs = job.succeeded();

// Get the latest run from a specific node
if let Some((uuid, run)) = job.latest_of(&node_id) {
    println!("Latest run: {} - Status: {:?}", uuid, run.status());
    println!("Logs available at: {}", run.log());
}

// Partition runs by status
let all_nodes_status = job.partition();
for (node_id, (started, succeeded, failed)) in all_nodes_status {
    println!("Node {}: {} started, {} succeeded, {} failed", 
             node_id, started.len(), succeeded.len(), failed.len());
}

Use Cases

Continuous Integration

The primary use case is distributed CI execution:

  1. A developer creates a patch
  2. The job is broadcast to the network
  3. Available CI nodes pick up the job and execute tests
  4. Results are reported back with logs and status
  5. The developer can see which nodes ran CI and their results

Future Possibilities

  • Continuous Deployment: Automated deployment pipelines
  • Code Analysis: Static analysis, security scanning, performance benchmarking
  • Marketplace: Nodes could offer specialized compute resources for different job types

API Overview

Core Types

  • Jobs<R>: The main store for managing jobs in a repository
  • Job: A read-only view of a job and its runs across all nodes
  • JobMut: A mutable job handle for adding runs and updating status
  • Run: Represents a single execution attempt with status and log URL
  • Runs: A collection of runs with insertion-order iteration

Key Methods

  • Jobs::create(): Create a new job for a commit
  • Jobs::get() / Jobs::get_mut(): Retrieve existing jobs
  • JobMut::run(): Start a new run
  • JobMut::finish(): Mark a run as completed
  • Job::latest(): Get the most recent run

Collaborative Nature

Jobs in radicle-job are inherently collaborative:

  • Multiple Executors: Many nodes can run the same job independently
  • Decentralized Results: Each node reports its own results without requiring coordination
  • Automatic Synchronization: The Radicle protocol handles data synchronization across nodes
  • No Consensus Required: This crate doesn’t enforce consensus on results — that’s left to higher-level applications

This design enables resilient, distributed job execution where no single point of failure can prevent job completion.

License

This project is licensed under the MIT License or Apache License 2.0 at your option.

# `radicle-job`

A crate for all† your automated job needs on the [Radicle
Network](https://radicle.xyz).

†: _well maybe almost all._

## Overview

`radicle-job` provides a collaborative framework for managing automated tasks
across the Radicle peer-to-peer network. Multiple nodes can pick up and execute
jobs (like CI/CD pipelines) for any given Git commit, with results synchronized
across the network using Radicle's Collaborative Objects (COBs).

### Key Features

- **Decentralized Execution**: Any node in the network can pick up and run jobs
- **Collaborative Tracking**: Multiple nodes can contribute runs for the same
  job
- **Rich Status Reporting**: Track job lifecycle from start to completion with
  success/failure reasons
- **External Log Integration**: Link to external logging services via URLs
- **Git Integration**: Jobs are tied to specific Git commits using OIDs

## Key Concepts

- **Job**: Represents an automated task for a specific Git commit that can be
  executed by multiple nodes
- **Run**: A single execution attempt of a job by a particular node, identified
  by a UUID
- **Status**: The current state of a run (`Started`, `Finished(Succeeded)`,
  `Finished(Failed)`)
- **COB (Collaborative Object)**: The underlying Radicle primitive that enables
  decentralized synchronization of job data

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
radicle-job = "0.1"
radicle >= "0.15" # Required for core Radicle functionality
```

This crate is designed to work seamlessly with the
[`radicle`](https://crates.io/crates/radicle) ecosystem.

## Quick Start

### Creating and Managing Jobs

```rust
use radicle_job::{Jobs, Reason};
use radicle::git::Oid;
use url::Url;
use uuid::Uuid;

// Open the jobs store for a repository
let mut jobs = Jobs::open(&repo)?;

// Create a new job for a specific commit
let commit_oid = /* your commit OID */;
let mut job = jobs.create(commit_oid, &signer)?;

// Node starts a run
let run_id = Uuid::new_v4();
let log_url = Url::parse("https://ci.example.com/logs/run-123")?;
job.run(run_id, log_url, &signer)?;

// Node reports completion
job.finish(run_id, Reason::Succeeded, &signer)?;
```

### Querying Job Status

```rust
// Get all runs that are currently in progress
let started_runs = job.started();

// Get successful runs from all nodes
let successful_runs = job.succeeded();

// Get the latest run from a specific node
if let Some((uuid, run)) = job.latest_of(&node_id) {
    println!("Latest run: {} - Status: {:?}", uuid, run.status());
    println!("Logs available at: {}", run.log());
}

// Partition runs by status
let all_nodes_status = job.partition();
for (node_id, (started, succeeded, failed)) in all_nodes_status {
    println!("Node {}: {} started, {} succeeded, {} failed", 
             node_id, started.len(), succeeded.len(), failed.len());
}
```

## Use Cases

### Continuous Integration

The primary use case is distributed CI execution:

1. A developer creates a patch
2. The job is broadcast to the network
3. Available CI nodes pick up the job and execute tests
4. Results are reported back with logs and status
5. The developer can see which nodes ran CI and their results

### Future Possibilities

- **Continuous Deployment**: Automated deployment pipelines
- **Code Analysis**: Static analysis, security scanning, performance
  benchmarking
- **Marketplace**: Nodes could offer specialized compute resources for different
  job types

## API Overview

### Core Types

- **`Jobs<R>`**: The main store for managing jobs in a repository
- **`Job`**: A read-only view of a job and its runs across all nodes
- **`JobMut`**: A mutable job handle for adding runs and updating status
- **`Run`**: Represents a single execution attempt with status and log URL
- **`Runs`**: A collection of runs with insertion-order iteration

### Key Methods

- **`Jobs::create()`**: Create a new job for a commit
- **`Jobs::get()`** / **`Jobs::get_mut()`**: Retrieve existing jobs
- **`JobMut::run()`**: Start a new run
- **`JobMut::finish()`**: Mark a run as completed
- **`Job::latest()`**: Get the most recent run

## Collaborative Nature

Jobs in `radicle-job` are inherently collaborative:

- **Multiple Executors**: Many nodes can run the same job independently
- **Decentralized Results**: Each node reports its own results without requiring
  coordination
- **Automatic Synchronization**: The Radicle protocol handles data
  synchronization across nodes
- **No Consensus Required**: This crate doesn't enforce consensus on results —
  that's left to higher-level applications

This design enables resilient, distributed job execution where no single point
of failure can prevent job completion.

## License

This project is licensed under the [MIT License](LICENSE-MIT) or [Apache License
2.0](LICENSE-APACHE) at your option.

## Related Projects

- [`radicle`](https://crates.io/crates/radicle) - Core Radicle protocol
  implementation
- [`radicle-ci-broker`](https://crates.io/crates/radicle-ci-broker) - Radicle
  library for brokering CI events