<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Cradicle Explorer</title>
    <link href="/css/bootstrap/bootstrap.min.css" rel="stylesheet">
    <style>
      .form-control-dark::placeholder {
          color: #aaa;
          opacity: 1;
      }
    </style>
    <link rel="stylesheet" href="/assets/fontawesome/css/all.min.css">
    <link rel="icon" type="image/png" href="/favicon.png">


                <link href="/css/dashboard.css" rel="stylesheet">
                </head>
                <body>
                <header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
                  <a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 fs-6" href="/">Cradicle Explorer</a>
                  <button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                  </button>
                  <form method="get" action="/cgi-bin/main" style="width:100%;"><input class="form-control form-control-dark w-100 rounded-0 border-0" type="text" name="q" placeholder="Search repos" aria-label="Search"></form>
                  <div class="navbar-nav flex-row">
                    <div class="nav-item text-nowrap">
                      <a class="nav-link px-3 active" href="/cgi-bin/repo?id=zg2VS9DsGqxqLCWJ8Km3ztrd3ba1">radicle-tekton-adapter</a>
                    </div>
                  </div>
                </header>
                <div class="container-fluid">
                  <div class="row">
                    <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-dark sidebar collapse">
                      <div class="position-sticky pt-3 sidebar-sticky">
                        <ul class="nav flex-column">
                          <li class="nav-item">
                            <a class="nav-link active" href="/cgi-bin/repo?id=zg2VS9DsGqxqLCWJ8Km3ztrd3ba1">
                              <i class="align-text-bottom fa-solid fa-info"></i>
                              Info
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zg2VS9DsGqxqLCWJ8Km3ztrd3ba1&issue=list">
                              <i class="align-text-bottom fa-solid fa-layer-group"></i>
                              Issues
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zg2VS9DsGqxqLCWJ8Km3ztrd3ba1&patch=list">
                              <i class="align-text-bottom fa-solid fa-vest-patches"></i>
                              Patches
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zg2VS9DsGqxqLCWJ8Km3ztrd3ba1&wallet=list">
                              <i class="align-text-bottom fa-solid fa-wallet"></i>
                              Wallets
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zg2VS9DsGqxqLCWJ8Km3ztrd3ba1&source=.">
                              <i class="align-text-bottom fa-solid fa-code"></i>
                              Source
                            </a>
                          </li>
                        <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted text-uppercase">
                          <span></span>
                        </h6>
                        <ul class="nav flex-column mb-2">
                        
                        </ul>
                      </div>
                    </nav>
                <main class="col-md-9 ms-sm-auto col-lg-10">
                  <div class="container px-1 py-3">
        

    <div class="list-group">
    <div class="list-group-item">
    <div style="font-size:1.3rem;">radicle-tekton-adapter</div>
    <div class="repo-item">CI adapter that bridges Radicle CI Broker to Tekton Pipelines</div>
    <div>rad:zg2VS9DsGqxqLCWJ8Km3ztrd3ba1</div>
    </div>
    <div class="list-group-item">
    <div>Visibility</div>
    <div class="repo-item">public</div>
    </div>
    <div class="list-group-item">
    <div>Delegates</div><div class="repo-item">did:key:z6MkwTophCrK3siwQvJ5AVpSX2SKvqprqiyuwEGY56eLKtHV</div>
    </div>
    <div class="list-group-item">
    <div>Default branch</div>
    <div><span class="repo-item">main &#8594 290608171b027f9b37b125d0a29c51d6d765c81a</span> (Tue Oct 21 08:27:27 2025)</div>
    </div>
    <div class="list-group-item">
    <div>Threshold</div>
    <div class="repo-item">1</div>
    </div>
    </div>
    
        <div class="list-group mt-3">
        <div class="list-group-item">
        <div class="mb-2" style="font-weight:bold;"><i class="fa-solid fa-book"></i> README.md</div>
        <pre style="margin:0; font-size:0.85rem; overflow-x:auto; color:#fafafa;"># Radicle Tekton Adapter

A CI adapter that bridges [Radicle CI Broker](https://seed.radicle.garden/rad:zwTxygwuz5LDGBq255RA2CbNGrz8) events to [Tekton Pipelines](https://tekton.dev/).

---

## What Does It Do?

The **radicle-tekton-adapter** receives Radicle CI events via stdin (JSON), matches them against routing rules, triggers Tekton pipelines via webhook, polls for status, and reports results back via stdout.

```
radicle-ci-broker (monitors Radicle events)
    ↓ (stdin: JSON event)
radicle-tekton-adapter (this component)
    ↓ (HTTP POST: trigger webhook)
Tekton EventListener
    ↓ (creates PipelineRun)
Tekton Pipeline
    ↓ (adapter polls for status)
radicle-tekton-adapter
    ↓ (stdout: JSON status)
radicle-ci-broker (reports back)
```

---

## Features

- ✅ **Event-driven** - Triggers pipelines based on git push, patches, tags
- ✅ **Flexible routing** - Route different events to different pipelines
- ✅ **Status reporting** - Real-time pipeline status back to broker
- ✅ **Kubernetes-native** - Works with Tekton&#x27;s native resources
- ✅ **Configurable** - YAML-based routing rules

---

## Quick Start

### Build

```bash
# Build from source
cargo build --release

# Build Docker image
docker build -t radicle-tekton-adapter:latest .
```

### Configure

Create a configuration file:

```yaml
# config.yaml
tekton:
  webhook_url: &quot;http://el-radicle-events.tekton-ci.svc.cluster.local:8080&quot;
  api_url: &quot;https://kubernetes.default.svc&quot;
  namespace: &quot;tekton-ci&quot;
  dashboard_url: &quot;https://ci.example.com&quot;

rules:
  - name: &quot;main-deploy&quot;
    event_type: &quot;push&quot;
    branch_pattern: &quot;^main$&quot;
    pipeline: &quot;build-and-deploy&quot;
```

### Test

```bash
# Send a test event via stdin
echo &#x27;{
  &quot;event_type&quot;: &quot;push&quot;,
  &quot;version&quot;: 1,
  &quot;repository&quot;: {
    &quot;id&quot;: &quot;rad:z2u2CP1xPx7HgZ8u6HQHbRQjfBrjW&quot;,
    &quot;name&quot;: &quot;my-project&quot;
  },
  &quot;branch&quot;: &quot;main&quot;,
  &quot;after&quot;: &quot;abc123&quot;
}&#x27; | radicle-tekton-adapter --config config.yaml
```

Expected output (JSON on stdout):
```json
{&quot;Triggered&quot;:{&quot;run_id&quot;:&quot;build-abc123&quot;,&quot;info_url&quot;:&quot;https://...&quot;}}
{&quot;Finished&quot;:{&quot;result&quot;:&quot;Success&quot;}}
```

---

## How It Works

### Input Protocol (stdin)

The adapter reads JSON events from stdin. Example:

```json
{
  &quot;event_type&quot;: &quot;push&quot;,
  &quot;version&quot;: 1,
  &quot;repository&quot;: {
    &quot;id&quot;: &quot;rad:z2u2CP1xPx7HgZ8u6HQHbRQjfBrjW&quot;,
    &quot;name&quot;: &quot;my-project&quot;,
    &quot;description&quot;: &quot;My project&quot;,
    &quot;private&quot;: false,
    &quot;default_branch&quot;: &quot;main&quot;
  },
  &quot;pusher&quot;: {
    &quot;id&quot;: &quot;did:key:z6Mk...&quot;,
    &quot;alias&quot;: &quot;alice&quot;
  },
  &quot;branch&quot;: &quot;main&quot;,
  &quot;before&quot;: &quot;abc123&quot;,
  &quot;after&quot;: &quot;def456&quot;,
  &quot;commits&quot;: [&quot;def456&quot;]
}
```

### Output Protocol (stdout)

The adapter writes JSON status messages to stdout:

```json
{&quot;Triggered&quot;:{&quot;run_id&quot;:&quot;build-abc123&quot;,&quot;info_url&quot;:&quot;https://ci.example.com/...&quot;}}
{&quot;Running&quot;:{&quot;status&quot;:&quot;Running&quot;}}
{&quot;Finished&quot;:{&quot;result&quot;:&quot;Success&quot;}}
```

### Routing Logic

1. **Receive event** from stdin
2. **Match against rules** (first match wins)
3. **Trigger webhook** (POST to Tekton EventListener)
4. **Poll for status** (query Tekton API)
5. **Report results** to stdout

---

## Configuration

### Supported Event Types

- **`push`** - Push to a branch
- **`patch`** - Patch created/updated/merged
- **`tag`** - Tag created

### Routing Rules

Rules are evaluated top-to-bottom. First match wins.

```yaml
rules:
  # Skip WIP branches
  - name: &quot;skip-wip&quot;
    event_type: &quot;push&quot;
    branch_pattern: &quot;^wip/.*$&quot;
    pipeline: &quot;skip&quot;
  
  # Deploy main branch
  - name: &quot;main-deploy&quot;
    event_type: &quot;push&quot;
    branch_pattern: &quot;^main$&quot;
    pipeline: &quot;build-and-deploy&quot;
    params:
      environment: &quot;production&quot;
  
  # Test feature branches
  - name: &quot;feature-test&quot;
    event_type: &quot;push&quot;
    branch_pattern: &quot;^feature/.*$&quot;
    pipeline: &quot;test-suite&quot;
  
  # Test patches
  - name: &quot;patch-review&quot;
    event_type: &quot;patch&quot;
    pipeline: &quot;test-and-review&quot;
```

See **[Configuration Reference](doc/configuration.md)** for complete documentation.

---

## Documentation

- **[Configuration Reference](doc/configuration.md)** - Complete configuration guide
- **[Architecture](ARCHITECTURE.md)** - How the adapter works internally
- **[Build Guide](BUILD.md)** - Build from source

---

## Integration

### With radicle-ci-broker

The broker calls this adapter when events occur. Configure the broker to use this adapter:

```yaml
# broker config.yaml
adapter: &quot;/usr/local/bin/radicle-tekton-adapter&quot;
adapter_env:
  RADICLE_TEKTON_ADAPTER_CONFIG: &quot;/etc/radicle-tekton-adapter/config.yaml&quot;

repos:
  - repo_id: &quot;rad:z2u2CP1xPx7HgZ8u6HQHbRQjfBrjW&quot;
    events:
      - push
      - patch
      - tag
```

### With Tekton

You need:
1. **Tekton Pipelines** installed
2. **EventListener** configured to accept webhooks
3. **Pipelines** defined (referenced in routing rules)

Example EventListener:

```yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: radicle-events
spec:
  serviceAccountName: tekton-triggers
  triggers:
    - name: radicle-trigger
      bindings:
        - ref: radicle-binding
      template:
        ref: radicle-template
```

---

## Docker Image

The Dockerfile builds a minimal Alpine-based image (~20MB) containing only the adapter binary.

```bash
# Build
docker build -t radicle-tekton-adapter:latest .

# Run
docker run --rm \
  -v /path/to/config.yaml:/etc/config.yaml \
  radicle-tekton-adapter:latest \
  --config /etc/config.yaml
```

---

## Development

### Build from Source

```bash
# Clone repository
git clone &lt;repo-url&gt;
cd radicle-tekton-adapter

# Build
cargo build --release

# Run tests
cargo test

# Run
./target/release/radicle-tekton-adapter --config config.yaml
```

### Project Structure

```
src/
├── main.rs       # Entry point and orchestration
├── config.rs     # Configuration loading
├── protocol.rs   # Stdin/stdout protocol
├── routing.rs    # Event-to-pipeline routing
├── tekton.rs     # Tekton API operations
└── io.rs         # I/O with broker
```

### Testing

```bash
# Run all tests
cargo test

# Run specific module tests
cargo test config::
cargo test routing::
cargo test protocol::

# Test with a real event
echo &#x27;{&quot;event_type&quot;:&quot;push&quot;,...}&#x27; | cargo run -- --config config.yaml
```

---

## Deployment

### Standalone

This adapter is a component that requires:
- **radicle-ci-broker** (calls the adapter)
- **Tekton Pipelines** (runs the CI/CD)

For a complete deployment solution, see the **radicle-tekton-ci** repository which provides a Helm chart deploying all components together.

### Kubernetes Example

The adapter typically runs as part of the radicle-ci-broker pod:

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: radicle-ci-broker
spec:
  containers:
  - name: broker
    image: radicle-ci-broker:latest
    command: [&quot;/usr/local/bin/cib&quot;, &quot;process-events&quot;]
    env:
      - name: RADICLE_TEKTON_ADAPTER_CONFIG
        value: &quot;/etc/adapter/config.yaml&quot;
    volumeMounts:
      - name: adapter-config
        mountPath: /etc/adapter
  volumes:
    - name: adapter-config
      configMap:
        name: radicle-tekton-adapter-config
```

---

## Exit Codes

- `0` - Success (pipeline completed successfully)
- `1` - Failure (pipeline completed but failed)
- `2` - Error (pipeline could not run, or adapter error)

---

## Troubleshooting

### No pipeline triggered

Check logs (stderr) to see rule evaluation:
```
INFO: Received event type &#x27;push&#x27; for branch &#x27;main&#x27;
INFO: Evaluating rule &#x27;main-deploy&#x27;
INFO: Rule matched, triggering pipeline &#x27;build-and-deploy&#x27;
```

### Webhook fails

- Verify `webhook_url` is accessible
- Check EventListener is running: `kubectl get eventlistener -n tekton-ci`
- Test webhook manually:
```bash
curl -X POST http://el-radicle-events.tekton-ci.svc.cluster.local:8080 \
  -H &quot;Content-Type: application/json&quot; \
  -d &#x27;{&quot;repo_id&quot;:&quot;rad:z...&quot;,&quot;event_type&quot;:&quot;push&quot;}&#x27;
```

### Status polling fails

- Verify `api_url` is accessible
- Check RBAC permissions (needs `get`, `list` on PipelineRuns)
- Test API access: `kubectl get pipelineruns -n tekton-ci`

---

## Related Projects

- **[radicle-ci-broker](https://seed.radicle.garden/rad:zwTxygwuz5LDGBq255RA2CbNGrz8)** - Event dispatcher (calls this adapter)
- **[Tekton Pipelines](https://tekton.dev/)** - Kubernetes-native CI/CD
- **[Radicle](https://radicle.xyz/)** - Decentralized code collaboration

---

## Contributing

Contributions welcome! Submit patches to the Radicle repository.

---

## License

MIT License - See [LICENSE](LICENSE) file.

---

**Made with ❤️ for the decentralized web**</pre>
        </div>
        </div>

</div>
</main>
</div>
</div>


</body>
</html>

