Skip to content

Commit 08a430e

Browse files
committed
docs: refactor documentation into separate file and apply formatting
1 parent 36d150f commit 08a430e

5 files changed

Lines changed: 221 additions & 143 deletions

File tree

README.md

Lines changed: 23 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -2,146 +2,45 @@
22

33
A lightweight, local-first CI/CD tool written in Rust with a modern, real-time Terminal User Interface (TUI).
44

5-
## Features
6-
- **Artifact Management**: Define `artifacts` in your jobs. Conveyor will automatically collect and preserve these files (binaries, reports, etc.) in the build history.
7-
- **Interactive History**: Browse previous builds, view their statuses, and inspect full terminal logs directly from the history tab.
8-
- **Log Highlighting**: Real-time log search (`/`) not only filters lines but also highlights matching substrings for better visibility.
9-
- **Cron Scheduling**: Automate your pipelines with standard cron expressions (e.g., `schedule: "0 */6 * * *"`).
10-
- **Stages & Jobs**: Group related jobs into stages for better organization and a clearer overview of your pipeline's progress.
11-
- **Build History & Persistence**: Automatically saves build results and logs to a local history, allowing you to review past performance and failures.
12-
- **Sequential by Default**: Jobs run one-by-one in the order defined in your pipeline, ensuring a predictable flow.
13-
- **Explicit Parallelism**: Use the `parallel: true` flag to run independent jobs concurrently.
14-
- **Dependency Tracking (DAG)**: Fine-tune execution order with the `needs` keyword for complex dependency graphs.
15-
- **Log Search & Filtering**: Quickly find errors or specific output with real-time log filtering (`/`).
16-
- **Pipeline Hooks**: Define `on_success` and `on_failure` commands to run after the pipeline completes.
17-
- **Responsive TUI**: A spacious, modern interface with OneDark colors that adapts to your terminal size.
18-
- **Headless Mode**: Run pipelines in a non-interactive mode with real-time log streaming to stdout. Ideal for AI agents, CI automation, and scripts.
19-
- **Git Integration**: Live display of current branch and latest commit info in the header.
20-
- **Credential & Secret Management**: Declare required secrets in your pipeline. Conveyor will securely prompt for missing values at startup and automatically mask them (as `****`) in all TUI logs.
21-
- **Environment Variables**: Support for pipeline-level, job-specific, local `env.yaml` variables, and secure `secrets.yaml`.
22-
- **Cross-Platform**: Automatically selects the correct shell (`cmd` for Windows, `sh` for Linux/macOS).
23-
- **Graceful Process Termination**: Safely cancels running jobs and cleans up orphaned compilation processes instantly when quitting (`Q`) or retrying (`R`).
24-
- **Isolated Workspaces**: Remote pipelines clone into dynamically generated, globally unique directories to prevent file locking and stomping collisions.
5+
## Key Features
6+
- **Real-time TUI**: Modern, OneDark-inspired interface for live build monitoring.
7+
- **Artifacts & History**: Preserve build outputs and browse full logs of previous runs.
8+
- **Dependency Tracking**: Fine-grained execution control with DAG-based job dependencies.
9+
- **Flexible Scheduling**: Automate builds with standard Cron expressions.
10+
- **Secure by Default**: Automatic masking of secrets in logs and interactive credential prompting.
11+
- **Headless Mode**: Ideal for AI agents and CLI automation.
2512

26-
## Installation
27-
Ensure you have the Rust toolchain installed.
13+
## Quick Start
2814

15+
### 1. Installation
2916
```bash
30-
git clone https://github.com/yourusername/conveyor.git
17+
git clone https://github.com/sumant1122/conveyor.git
3118
cd conveyor
3219
cargo build --release
3320
```
3421

35-
## Usage
36-
1. Create a `pipeline.yaml` in your project root.
37-
2. (Optional) Create an `env.yaml` for local/secret environment variables.
38-
3. Run Conveyor:
39-
```bash
40-
cargo run
41-
```
42-
43-
### Remote Repositories
44-
Conveyor can also run pipelines directly from a remote Git repository. It will clone the repository into a temporary workspace and automatically load the `pipeline.yaml` from its root.
45-
46-
```bash
47-
# Run the default branch (usually main)
48-
cargo run -- https://github.com/user/repo.git
49-
50-
# Run a specific branch
51-
cargo run -- https://github.com/user/repo.git my-feature-branch
52-
```
53-
54-
### Navigation & Controls
55-
- **'1' / '2' / '3' / '4'**: Switch between **Dashboard**, **History**, **Pipeline Config**, and **Env Variables**.
56-
- **Up/Down Arrows**:
57-
- **Dashboard**: Select a job to view its logs.
58-
- **History**: Select a previous build record.
59-
- **'Enter'**:
60-
- **History**: View the full details and logs of the selected historical build.
61-
- **'Esc'**:
62-
- **History Detail**: Return to the build list.
63-
- **Search**: Clear search query or exit search mode.
64-
- **'R'**: **Retry** the current pipeline (resets states and starts fresh).
65-
- **'/'**: Enter **Search Mode** to filter and **highlight** logs in real-time.
66-
- **'PgUp' / 'PgDn'**: Scroll through logs.
67-
- **'q'**: Quit the application.
68-
69-
## Pipeline Configuration (`pipeline.yaml`)
70-
Example `pipeline.yaml` using modern features like **Stages**, **Cron**, and **Artifacts**, with **Simplified Syntax**:
71-
22+
### 2. Define your Pipeline
23+
Create a `pipeline.yaml` in your project root:
7224
```yaml
73-
# name: Example Service (Optional: Defaults to 'Conveyor Build')
74-
schedule: "0 */1 * * * *" # Run every minute
75-
on_success: "echo 'Success!'"
76-
77-
stages:
25+
jobs:
7826
- name: Build
79-
jobs:
80-
- name: Compile
81-
command: cargo build --release
82-
artifacts:
83-
- "target/release/conveyor"
84-
27+
command: cargo build
8528
- name: Test
86-
jobs:
87-
- name: Unit Tests
88-
steps:
89-
- cargo test # Shorthand for simple commands
90-
artifacts:
91-
- "target/debug/deps/"
92-
93-
- name: Deploy
94-
jobs:
95-
- name: Push Image
96-
needs: ["Unit Tests"]
97-
command: echo "Pushing..."
98-
```
99-
100-
*Note: The older flat `jobs:` format is still supported for backward compatibility.*
101-
102-
## Local Environment Variables (`env.yaml` & `secrets.yaml`)
103-
Store sensitive or machine-specific variables in an `env.yaml` file. Use `secrets.yaml` for credentials; any value defined here will be **masked** in the TUI logs.
104-
105-
Example `env.yaml`:
106-
```yaml
107-
DEBUG: "true"
108-
LOG_LEVEL: "info"
109-
```
110-
111-
Example `secrets.yaml`:
112-
```yaml
113-
API_KEY: "my-very-secret-key"
114-
SSH_PRIVATE_KEY: |
115-
-----BEGIN RSA PRIVATE KEY-----
116-
...
117-
```
118-
119-
To enforce secret entry, add them to your `pipeline.yaml`:
120-
```yaml
121-
name: My Pipeline
122-
secrets:
123-
- API_KEY
124-
- DOCKER_PASSWORD
29+
command: cargo test
12530
```
126-
If these are not present in `secrets.yaml`, Conveyor will prompt for them securely at startup.
127-
128-
### Headless Mode (for AI Agents & Automation)
129-
To run Conveyor without the TUI, use the `--headless` flag. This will stream all logs directly to stdout and exit with a proper status code (0 for success, 1 for failure).
13031
32+
### 3. Run
13133
```bash
132-
# Run local pipeline
133-
cargo run -- --headless
134-
135-
# Run remote repository
136-
cargo run -- https://github.com/user/repo.git --headless
34+
cargo run
13735
```
13836

139-
## Roadmap / Upcoming Enhancements
140-
To closely mirror the capabilities of professional CI systems like Jenkins, the following features are planned:
37+
## Documentation
38+
For detailed information on configuration, navigation, and advanced features, see **[documentation.md](./documentation.md)**.
14139

142-
- **🎛️ Input Parameters**: Support for "Build with Parameters," allowing users to select options (like environment or version) before a pipeline starts.
143-
- **🏗️ Distributed Agents**: The ability to delegate jobs to remote machines via SSH or a custom agent protocol.
144-
- **🐳 Container Isolation**: Run jobs inside Docker/Podman containers for clean, reproducible environments.
40+
- **[Pipeline Configuration](./documentation.md#pipeline-configuration-pipelineyaml)**: Stages, Jobs, DAG, and Simplified Syntax.
41+
- **[Artifacts & Cron](./documentation.md#artifact-management)**: How to preserve build outputs and automate triggers.
42+
- **[Secrets Management](./documentation.md#environment--secrets)**: Local variables and automatic log masking.
43+
- **[Navigation Reference](./documentation.md#navigation--controls)**: Full list of TUI keybindings.
14544

14645
## License
14746
MIT

documentation.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Conveyor Documentation 🏗️
2+
3+
This document provides a comprehensive guide to configuring and using Conveyor, a lightweight, local-first CI/CD runner.
4+
5+
---
6+
7+
## Table of Contents
8+
1. [Navigation & Controls](#navigation--controls)
9+
2. [Pipeline Configuration (pipeline.yaml)](#pipeline-configuration-pipelineyaml)
10+
- [Stages & Jobs](#stages--jobs)
11+
- [Simplified Syntax](#simplified-syntax)
12+
- [Dependency Tracking (DAG)](#dependency-tracking-dag)
13+
- [Artifact Management](#artifact-management)
14+
- [Cron Scheduling](#cron-scheduling)
15+
3. [Environment & Secrets](#environment--secrets)
16+
- [env.yaml](#envyaml)
17+
- [secrets.yaml](#secretsyaml)
18+
4. [Headless Mode](#headless-mode)
19+
5. [Remote Repositories](#remote-repositories)
20+
21+
---
22+
23+
## Navigation & Controls
24+
25+
Conveyor provides a real-time TUI for managing your builds.
26+
27+
- **'1' / '2' / '3' / '4'**: Switch between **Dashboard**, **History**, **Pipeline Config**, and **Env Variables**.
28+
- **Up/Down Arrows**:
29+
- **Dashboard**: Select a job to view its logs.
30+
- **History**: Select a previous build record.
31+
- **'Enter'**:
32+
- **History**: View the full details and logs of the selected historical build.
33+
- **'Esc'**:
34+
- **History Detail**: Return to the build list.
35+
- **Search**: Clear search query or exit search mode.
36+
- **'R'**: **Retry** the current pipeline (resets states and starts fresh).
37+
- **'/'**: Enter **Search Mode** to filter and **highlight** logs in real-time.
38+
- **'PgUp' / 'PgDn'**: Scroll through logs.
39+
- **'q'**: Quit the application.
40+
41+
---
42+
43+
## Pipeline Configuration (pipeline.yaml)
44+
45+
Conveyor searches for `pipeline.yaml` in your project root.
46+
47+
### Stages & Jobs
48+
Stages allow you to group related jobs. Jobs within a stage can run in parallel, while stages themselves generally progress sequentially.
49+
50+
### Simplified Syntax
51+
You can omit verbose fields for simple tasks:
52+
- **Shorthand Step**: A string instead of an object if only a command is needed.
53+
- **Shorthand Job**: Use `command` directly on the job if it only has one step.
54+
55+
```yaml
56+
# Optional: Defaults to 'Conveyor Build'
57+
name: My Pipeline
58+
schedule: "0 */1 * * * *" # Cron: sec min hour day month dow
59+
60+
stages:
61+
- name: Build
62+
jobs:
63+
- name: Compile
64+
command: cargo build --release # Shorthand job
65+
artifacts:
66+
- "target/release/app"
67+
68+
- name: Test
69+
jobs:
70+
- name: Unit Tests
71+
steps:
72+
- cargo test # Shorthand step
73+
```
74+
75+
### Dependency Tracking (DAG)
76+
Use `needs` to define a Directed Acyclic Graph of dependencies.
77+
```yaml
78+
jobs:
79+
- name: Deploy
80+
needs: ["Unit Tests", "Integration Tests"]
81+
command: ./deploy.sh
82+
```
83+
84+
### Artifact Management
85+
Specify files or directories to preserve after a successful job. They are stored in `history/build_{id}/artifacts/`.
86+
```yaml
87+
artifacts:
88+
- "target/release/binary"
89+
- "docs/html/"
90+
```
91+
92+
### Cron Scheduling
93+
Standard 6-field cron expressions are supported for automated runs.
94+
`sec min hour day month dow`
95+
96+
---
97+
98+
## Environment & Secrets
99+
100+
### env.yaml
101+
Store non-sensitive local variables here.
102+
```yaml
103+
DEBUG: "true"
104+
API_URL: "http://localhost:8080"
105+
```
106+
107+
### secrets.yaml
108+
Store sensitive credentials here. Values are **automatically masked** in all TUI logs.
109+
```yaml
110+
DATABASE_PASSWORD: "super-secret-password"
111+
```
112+
113+
To require a secret, declare it in `pipeline.yaml`. Conveyor will prompt for it at startup if missing.
114+
```yaml
115+
secrets:
116+
- DATABASE_PASSWORD
117+
```
118+
119+
---
120+
121+
## Headless Mode
122+
123+
For use in CI environments or by AI agents. Logs stream to `stdout` and the process exits with `0` (success) or `1` (failure).
124+
125+
```bash
126+
cargo run -- --headless
127+
```
128+
129+
---
130+
131+
## Remote Repositories
132+
133+
Run a pipeline directly from a Git URL. Conveyor clones it into a unique temporary workspace.
134+
135+
```bash
136+
cargo run -- https://github.com/user/repo.git [optional-branch]
137+
```

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ jobs:
285285
r_clone.reset().await;
286286
r_clone.run().await;
287287
});
288-
288+
289289
if let Some(schedule_str) = &pipeline.schedule {
290290
if let Ok(schedule) = schedule_str.parse::<cron::Schedule>() {
291291
next_run = schedule.upcoming(chrono::Local).next();

src/runner.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,10 @@ impl Runner {
629629
None => return,
630630
};
631631

632-
let artifact_root = self.history.root.join(format!("build_{}/artifacts/{}", self.build_id, job_name));
632+
let artifact_root = self
633+
.history
634+
.root
635+
.join(format!("build_{}/artifacts/{}", self.build_id, job_name));
633636
let _ = tokio::fs::create_dir_all(&artifact_root).await;
634637

635638
for art_path in artifacts {
@@ -643,36 +646,57 @@ impl Runner {
643646

644647
{
645648
let mut states = self.states.lock().await;
646-
states[index].logs.push(format!("📦 Collecting artifact: {}", art_path).dim().to_string());
649+
states[index].logs.push(
650+
format!("📦 Collecting artifact: {}", art_path)
651+
.dim()
652+
.to_string(),
653+
);
647654
}
648655

649656
if src.is_file() {
650657
if let Err(e) = tokio::fs::copy(&src, &dest).await {
651658
let mut states = self.states.lock().await;
652-
states[index].logs.push(format!("❌ Failed to copy artifact {}: {}", art_path, e).red().to_string());
659+
states[index].logs.push(
660+
format!("❌ Failed to copy artifact {}: {}", art_path, e)
661+
.red()
662+
.to_string(),
663+
);
653664
}
654665
} else if src.is_dir() {
655666
// For directories, we'll do a simple recursive copy or just log it's not supported for now if we want to be strict "Exact Paths"
656667
// But usually people mean the folder too. Let's do a simple recursive copy logic.
657668
if let Err(e) = self.copy_dir_recursive(&src, &dest).await {
658669
let mut states = self.states.lock().await;
659-
states[index].logs.push(format!("❌ Failed to copy artifact directory {}: {}", art_path, e).red().to_string());
670+
states[index].logs.push(
671+
format!("❌ Failed to copy artifact directory {}: {}", art_path, e)
672+
.red()
673+
.to_string(),
674+
);
660675
}
661676
}
662677
} else {
663678
let mut states = self.states.lock().await;
664-
states[index].logs.push(format!("⚠️ Artifact not found: {}", art_path).yellow().to_string());
679+
states[index].logs.push(
680+
format!("⚠️ Artifact not found: {}", art_path)
681+
.yellow()
682+
.to_string(),
683+
);
665684
}
666685
}
667686
}
668687

669-
async fn copy_dir_recursive(&self, src: &std::path::Path, dst: &std::path::Path) -> std::io::Result<()> {
688+
async fn copy_dir_recursive(
689+
&self,
690+
src: &std::path::Path,
691+
dst: &std::path::Path,
692+
) -> std::io::Result<()> {
670693
tokio::fs::create_dir_all(&dst).await?;
671694
let mut entries = tokio::fs::read_dir(src).await?;
672695
while let Some(entry) = entries.next_entry().await? {
673696
let file_type = entry.file_type().await?;
674697
if file_type.is_dir() {
675-
Box::pin(self.copy_dir_recursive(&entry.path(), &dst.join(entry.file_name()))).await?;
698+
Box::pin(self.copy_dir_recursive(&entry.path(), &dst.join(entry.file_name())))
699+
.await?;
676700
} else {
677701
tokio::fs::copy(entry.path(), dst.join(entry.file_name())).await?;
678702
}

0 commit comments

Comments
 (0)