Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# CLAUDE.md

## Project Overview

**WRPT** is a Rust CLI tool for deploying and managing Docker Compose stacks on Portainer. It supports both manual usage and CI/CD pipeline integration. Published on [crates.io](https://crates.io/crates/wrpt) and [Docker Hub](https://hub.docker.com/r/wahl/wrpt).

- **Language:** Rust (Edition 2021)
- **Version:** 0.6.3
- **License:** MIT

## Quick Reference Commands

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

# Test
cargo test --verbose

# Lint
cargo clippy --verbose

# Format
cargo fmt --all --verbose

# Full CI check (matches GitHub Actions)
cargo build --verbose && cargo test --verbose && cargo clippy --verbose && cargo fmt --all --verbose
```

## Project Structure

```
src/
├── main.rs # Entry point (minimal)
└── commands/
├── mod.rs # Command dispatch/routing, CliContext initialization
├── wrpt.rs # CLI args struct, logger init, global args
├── consts.rs # API endpoint path constants
├── error.rs # CliError enum (Config, Api, Io, Http)
├── helpers.rs # Shared utilities (CliContext, HTTP client, table formatting, env parsing)
├── stacks/ # Stack management (deploy, remove, list, start, stop, resource-control)
│ ├── args/ # clap argument definitions
│ ├── handlers/ # Business logic
│ └── models/ # Data structures
├── endpoints/ # Endpoint listing
│ ├── args/ handlers/ models/
├── teams/ # Team listing
│ ├── args/ handlers/ models/
└── users/ # User listing
├── args/ handlers/ models/
```

## Architecture

Each command domain follows **args → handlers → models**:
- **args/**: CLI argument definitions using `clap::Args` and `clap::Subcommand`
- **handlers/**: Business logic and API calls
- **models/**: Data structures for API requests/responses (with Serde)

Shared utilities live in `helpers.rs` (HTTP client factory, URL construction, table formatting, env file parsing, API response handling).

## Code Conventions

- **Naming:** snake_case for modules/functions, PascalCase for structs/enums, UPPER_SNAKE_CASE for constants
- **Error handling:** Custom `CliError` enum (`Config`, `Api`, `Io`, `Http`) with `Result<T, CliError>` propagation via `?` operator
- **Shared context:** `CliContext` struct holds the reusable HTTP client (with 30s timeout) and base URL, passed to all handlers
- **HTTP:** Centralized `create_client()` in helpers; custom headers for Portainer auth (`x-api-key`)
- **Constants:** Compile-time string formatting via `const_format` crate for API paths
- **Output:** `prettytable-rs` for ASCII table display; `simplelog` with Paris for colored logging
- **Global args:** URL (`-l`/`PORTAINER_URL`), access token (`-A`/`PORTAINER_ACCESS_TOKEN`), `--insecure`, verbosity (`-v`), quiet (`-q`), color control

## Key Dependencies

| Crate | Purpose |
|-------|---------|
| `clap` (4.x) | CLI argument parsing with derive macros |
| `reqwest` | HTTP client for Portainer API |
| `serde` / `serde_json` | JSON serialization |
| `prettytable-rs` | ASCII table output |
| `simplelog` / `log` | Logging |
| `chrono` | Date/time handling |
| `const_format` | Compile-time string formatting |

## CI/CD

Three GitHub Actions workflows in `.github/workflows/`:
- **tests.yml**: Build, test, clippy, fmt on push/PR
- **release.yml**: Manual dispatch → Cocogitto SemVer bump → changelog → GitHub release → crates.io publish
- **docker.yml**: Multi-platform Docker build (amd64/arm64) → Docker Hub

## Release Process

Uses [Cocogitto](https://docs.cocogitto.io/) (`cog.toml`) with conventional commits. Pre-bump hooks run test, clippy, and fmt. Post-bump hooks push and publish to crates.io.

## Docker

Multi-stage Dockerfile in `docker/Dockerfile`: Rust build → Debian 12 slim runtime with OpenSSL and Docker Compose.

## Important Notes

- Conventional commits are required (feat:, fix:, docs:, refactor:, etc.)
- Branch whitelist for releases: `main` only
- No `.rustfmt.toml` or `clippy.toml` overrides — uses default Rust toolchain settings
- `.env` files are gitignored; the tool supports parsing them at runtime
11 changes: 1 addition & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ reqwest = { version = "0.12.9" , features = ["blocking", "json"] }
anstyle = "1.0.10"
log = "0.4.22"
simplelog = { version = "^0.12.2", features = ["paris"] }
log_err = "1.1.1"
serde_json = "1.0.134"
prettytable-rs = "0.10.0"
serde = { version = "1.0.216", features = ["derive"] }
serde_repr = "0.1.19"
chrono = { version = "0.4.39", features = ["serde"] }

[dev-dependencies]
tempfile = "3"
165 changes: 163 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
<p align="center">
<a href="#about">About</a> •
<a href="#roadmap">Roadmap</a> •
<a href="#installation">Installation</a> •
<a href="#quick-start">Quick Start</a> •
<a href="#available-commands">Available Commands</a> •
<a href="#docker">Docker</a> •
<a href="#cicd-integration">CI/CD Integration</a> •
<a href="#changelog">Changelog</a> •
<a href="#license">License</a>
</p>
Expand All @@ -37,8 +40,8 @@ It is also my first project written in Rust and is under **active development**,
Here are the planned enhancements and features for WRPT:

- 🚧 **Access Control Management:** Enable stack deployments with fine-grained access control, allowing assignment to specific users and/or groups.
- 🚧 **Comprehensive Documentation:** Write detailed usage guides, including setup instructions for integration into CI/CD pipelines on GitLab and GitHub.
- **Automated Testing:** Write tests to ensure the reliability and stability of the tool.
- **Comprehensive Documentation:** Write detailed usage guides, including setup instructions for integration into CI/CD pipelines on GitLab and GitHub.
- **Automated Testing:** Write tests to ensure the reliability and stability of the tool.
- 💭 **Kubernetes Compatibility:** Extend the tool to support Portainer deployments on Kubernetes environment.
- ✅ **Automated Release Process:** Implement CI pipelines to generate changelogs and releases automatically based on versioning and commit history.
- ✅ **Docker Image:** Create a Docker image.
Expand All @@ -52,6 +55,77 @@ Here are the planned enhancements and features for WRPT:

---

## Installation

### From crates.io

```bash
cargo install wrpt
```

### Docker

```bash
docker pull wahl/wrpt:latest
```

### From source

```bash
git clone https://github.com/wahl-dev/wrpt.git
cd wrpt
cargo build --release
# Binary available at ./target/release/wrpt
```

---

## Quick Start

### 1. Generate a Portainer access token

In your Portainer instance, go to **My Account** > **Access tokens** > **Add access token**.

See the [Portainer documentation](https://docs.portainer.io/api/access#creating-an-access-token) for more details.

### 2. Set your environment variables

```bash
export PORTAINER_URL="https://portainer.example.com"
export PORTAINER_ACCESS_TOKEN="your-access-token"
```

### 3. List your endpoints

```bash
wrpt endpoint list
```

### 4. List your stacks

```bash
wrpt stack list
```

### 5. Deploy a stack

```bash
wrpt stack deploy my-stack \
--endpoint 1 \
--compose-file docker-compose.yml
```

You can also pass environment variables to the stack:

```bash
wrpt stack deploy my-stack \
--endpoint 1 \
--compose-file docker-compose.yml \
--env-file .env
```

---

## Available Commands

| Name | Description |
Expand Down Expand Up @@ -296,6 +370,93 @@ docker run -it --rm \

---

## CI/CD Integration

WRPT's Docker image makes it easy to integrate stack deployments into your CI/CD pipelines.

### GitHub Actions

Add this workflow to `.github/workflows/deploy.yml`:

```yaml
name: Deploy Stack

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest
container:
image: wahl/wrpt:latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Deploy stack
env:
PORTAINER_URL: ${{ secrets.PORTAINER_URL }}
PORTAINER_ACCESS_TOKEN: ${{ secrets.PORTAINER_ACCESS_TOKEN }}
run: |
wrpt stack deploy my-stack \
--endpoint ${{ vars.PORTAINER_ENDPOINT }} \
--compose-file docker-compose.yml
```

**Required secrets** (Settings > Secrets and variables > Actions):

| Secret | Description |
|--------|-------------|
| `PORTAINER_URL` | URL of your Portainer instance (e.g. `https://portainer.example.com`) |
| `PORTAINER_ACCESS_TOKEN` | Portainer API access token |

**Required variables** (Settings > Secrets and variables > Actions > Variables):

| Variable | Description |
|----------|-------------|
| `PORTAINER_ENDPOINT` | ID of the Portainer endpoint to deploy to |

### GitLab CI

Add this to your `.gitlab-ci.yml`:

```yaml
stages:
- deploy

deploy-stack:
stage: deploy
image: wahl/wrpt:latest
only:
- main
script:
- wrpt stack deploy my-stack
--endpoint $PORTAINER_ENDPOINT
--compose-file docker-compose.yml
variables:
PORTAINER_URL: $PORTAINER_URL
PORTAINER_ACCESS_TOKEN: $PORTAINER_ACCESS_TOKEN
```

**Required CI/CD variables** (Settings > CI/CD > Variables):

| Variable | Protected | Masked | Description |
|----------|-----------|--------|-------------|
| `PORTAINER_URL` | Yes | No | URL of your Portainer instance |
| `PORTAINER_ACCESS_TOKEN` | Yes | Yes | Portainer API access token |
| `PORTAINER_ENDPOINT` | Yes | No | ID of the Portainer endpoint |

### CI/CD Best Practices

- **Never hardcode tokens** in your pipeline files. Always use secrets/protected variables.
- **Use `--insecure` only if necessary** (e.g. self-signed certificates in internal environments). Prefer proper SSL certificates.
- **Use `-vv` for debugging** pipeline failures — it enables verbose output to help diagnose issues.
- **Verify your endpoint first** by running `wrpt endpoint list` as a preliminary step to confirm connectivity.
- **Pin the Docker image tag** to a specific version (e.g. `wahl/wrpt:0.6.3`) in production pipelines for reproducible deployments.

---

## Changelog

The changelog is available in the [CHANGELOG.md](./CHANGELOG.md) file.
Expand Down
20 changes: 10 additions & 10 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
FROM rust:1 AS base
FROM rust:1.83-slim AS build
WORKDIR /app
RUN apt-get update && apt-get upgrade -y
RUN rustup component add clippy
RUN rustup component add rustfmt


FROM base AS build
RUN apt-get update && apt-get install -y pkg-config libssl-dev && rm -rf /var/lib/apt/lists/*
COPY . /app
RUN cargo build --release


FROM debian:12-slim AS final

RUN apt-get update && apt install -y openssl curl
RUN apt-get update && apt-get install -y --no-install-recommends openssl ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*

RUN useradd -m -u 1000 wrpt

COPY --from=build /app/target/release/wrpt /usr/bin/
COPY --from=docker/compose-bin:latest /docker-compose /usr/bin/docker-compose
COPY --from=docker/compose-bin:v2.32.4 /docker-compose /usr/bin/docker-compose

USER wrpt

ENTRYPOINT ["/bin/wrpt"]
ENTRYPOINT ["/usr/bin/wrpt"]
Loading
Loading