# cicd
**Repository Path**: jungle/cicd
## Basic Information
- **Project Name**: cicd
- **Description**: Simple CI/CD Service (Built with FastAPI)
- **Primary Language**: Python
- **License**: MIT
- **Default Branch**: master
- **Homepage**: https://cicd.happyoj.com
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-04-21
- **Last Updated**: 2026-10-25
## Categories & Tags
**Categories**: Uncategorized
**Tags**: cicd, pipeline
## README
# Simple CI/CD Service
A FastAPI-based CI/CD service for building Git repositories, running ordered or parallel
pipeline stages, dispatching stages to remote agents, streaming logs, collecting artifacts,
and publishing downloadable releases. The web UI is served by the same application.
## 1. Features
- Create and manage build jobs from the web UI or API.
- Clone a repository and run custom stages, a Dockerfile build, a CMake build,
or a repository-provided `ci_build.sh`.
- Run stages locally or dispatch them to remote agents. Leave agent targeting empty to run a
stage on the CI/CD server. Stages in the same wave run concurrently; waves run in order.
- Configure an ordered list of agents for a stage. Offline, full, or otherwise unavailable
candidates are skipped before a task is accepted.
- Stream build logs to the job page and retain per-run logs, status, duration, and commit data.
- Collect artifacts per run, download them, and publish finished runs as public releases.
- Manage Python build plugins, local user accounts (in bypass mode), agents, and user access
from the web UI.
- Trigger builds with Gitee/GitHub push webhooks (one auto-detected URL, extensible to other
vendors with a declarative provider file) or per-job cron/interval schedules.
## 2. Requirements
- Python 3.11 or later for the service (the Docker image and CI use Python 3.11).
- Git on the server. Build tools required by your repositories must also be installed.
- Docker Engine and a reachable Docker daemon only if you use repository `Dockerfile` builds.
- Python 3.8 or later on remote agent machines.
- Redis is optional. The default configuration uses the service's built-in local worker and
does not require Redis.
## 3. Quick start
Run these commands from the repository root.
### 3.1 Windows PowerShell
```powershell
py -3.11 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
Copy-Item example.env .env
```
Edit `.env` before starting the service. For a local-only development instance, the checked-in
example enables bypass authentication and includes example credentials. Change those values
before use, and never expose bypass mode to an untrusted network.
```powershell
python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
```
### 3.2 Linux or macOS
```bash
python3.11 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements.txt
cp example.env .env
```
Edit `.env`, then start the development server:
```bash
python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
```
Open . FastAPI's interactive API documentation is available at
.
### 3.3 Docker Compose
The repository's Compose file is a development example that builds and starts the web
container:
```bash
docker compose up --build
```
It publishes port `8000`, bind-mounts the source directory at `/app`, and does not start
Redis or an RQ worker. Before using it, edit `.env` for paths inside the Linux container;
the Windows paths in `example.env` are not valid container paths. The Compose file does not
mount the default temporary repository/artifact/release/plugin directories, so configure
and mount persistent storage before relying on them across container recreation. Dockerfile
build jobs also need the container to be configured to reach a Docker daemon; the example
Compose file does not provide that connection.
The server applies database migrations during startup. To apply them manually:
```bash
python -m app.apply_migrations
```
The default SQLite database is `cicd.db` in the working directory. Keep repository checkouts,
artifacts, uploaded plugins, and published releases outside the project directory, especially
when using `--reload`. The example environment file shows Windows-style paths; update them for
your operating system.
## 4. Configuration
The application loads `.env` during startup. Restart the API after changing configuration.
When running a separate compatible worker, restart that process as well.
### 4.1 Service, database, and storage
| Variable | Default | Purpose |
| --- | --- | --- |
| `DATABASE_URL` | `sqlite:///./cicd.db` | SQLAlchemy database URL. SQLite is the default. |
| `CICD_REPOS_ROOT` | System temp directory + `cicd_repos` | Cloned repositories, run logs, and build workspaces. |
| `CICD_ARTIFACTS_ROOT` | System temp directory + `cicd_artifacts` | Build artifacts and agent uploads. |
| `CICD_RELEASES_ROOT` | System temp directory + `cicd_releases` | Published release files. Keep this outside `CICD_ARTIFACTS_ROOT`; artifact cleanup must not remove releases. |
| `CICD_PLUGINS_ROOT` | System temp directory + `cicd_plugins` | Uploaded plugin source files. Built-in plugins are shipped with the application. |
| `CICD_WEBHOOK_PROVIDERS_ROOT` | System temp directory + `cicd_webhook_providers` | Declarative webhook provider files (`*.json`), loaded at startup. Keep it outside the project tree so `--reload` does not restart mid-build. |
| `REDIS_URL` | Unset | Optional Redis connection for Redis-backed queue/pub-sub integration. See the worker note below. |
For a durable installation, configure persistent storage paths. The service creates these
directories when needed. Back up the database and persistent storage as part of operations.
Example:
```dotenv
DATABASE_URL=sqlite:///D:/ci-data/cicd.db
CICD_REPOS_ROOT=D:/ci-data/repos
CICD_ARTIFACTS_ROOT=D:/ci-data/artifacts
CICD_RELEASES_ROOT=D:/ci-data/releases
CICD_PLUGINS_ROOT=D:/ci-data/plugins
CICD_WEBHOOK_PROVIDERS_ROOT=D:/ci-data/webhook-providers
```
SQLite URL syntax varies by platform. For a Windows absolute path, use
`sqlite:///D:/path/to/cicd.db`; for a Unix absolute path, use
`sqlite:////var/lib/cicd/cicd.db`.
### 4.2 Authentication
| Variable | Default | Purpose |
| --- | --- | --- |
| `AUTH_DISABLED` | `0` | Set to `1` only for local-account/bypass mode. |
| `AUTH_CENTER_URL` | `http://localhost` | SSO service base URL; the application validates its session endpoint. |
| `AUTH_LOGIN_URL` | `http://localhost/enter` | Login page used by the SSO integration. |
| `AUTH_LOGOUT_URL` | Unset | Optional SSO logout URL. When unset, logout is local to this service. |
| `AUTH_BYPASS_USERNAME` | `dev` | Built-in account name in bypass mode. |
| `AUTH_BYPASS_ADMIN` | `1` | Whether the built-in bypass account is an administrator. |
| `AUTH_BYPASS_PASSWORD` | Empty | Password for the built-in bypass account. An empty value disables its login. |
| `AUTH_BYPASS_SECRET` | Unset | Stable signing secret for bypass-mode sessions. Falls back to `WEBHOOK_SECRET`, then a process-random secret. |
| `AUTH_BYPASS_SESSION_TTL` | `43200` | Maximum session lifetime in seconds when “Remember me” is not selected. |
| `AUTH_BYPASS_REMEMBER_TTL` | `2592000` | Session lifetime in seconds when “Remember me” is selected. |
Use SSO mode for a trusted production deployment. Set `AUTH_CENTER_URL` and `AUTH_LOGIN_URL`
to the actual authentication service. In bypass mode, set `AUTH_DISABLED=1` and a strong
`AUTH_BYPASS_PASSWORD`. Local users can then register from the login dialog; new accounts are
regular users and an administrator can manage them from the Users page.
If bypass mode runs in a multi-process deployment, set a stable `AUTH_BYPASS_SECRET` so
sessions can be verified consistently. Do not rely on the process-random fallback.
### 4.3 Webhooks and build execution
| Variable | Default | Purpose |
| --- | --- | --- |
| `WEBHOOK_SECRET` | Unset | Fallback verification secret when a job has no job-specific one: the Gitee token, the GitHub HMAC-SHA256 secret, or the token/signature secret of an installed provider. |
| `CICD_ENABLE_TIMEOUTS` | `1` | Enables the default command timeout. |
| `CICD_CMD_TIMEOUT` | `600` | Default build-stage command timeout in seconds. A stage can set its own timeout. |
| `CICD_STAGE_AGENT_TIMEOUT` | `3600` | Default wait limit for a stage dispatched to an agent. A stage can set its own timeout. |
| `CICD_DETACH_STARTUP_SECONDS` | `5` | Time to capture startup output for a detached stage. |
| `CICD_TOOLCHAIN_CC` | `gcc` | Compiler name exposed to build stages. |
| `CICD_TOOLCHAIN_CXX` | `g++` | C++ compiler name exposed to build stages. |
| `CICD_TOOLCHAIN_CMAKE_GENERATOR` | `MinGW Makefiles` | CMake generator setting for configured toolchain environments. |
| `CICD_TOOLCHAIN_MSYS_PATHS` | `D:\msys64\mingw64\bin;D:\msys64\usr\bin` | Windows MSYS2 paths added to the toolchain environment. |
| `CICD_TOOLCHAIN_PROBE_CMD` | Unset | Optional command used to check toolchain availability. |
| `CLEANUP_ENABLED` | `1` | Enables periodic cleanup of expired soft-deleted jobs and old artifact runs. |
| `CLEANUP_INTERVAL_SECONDS` | `86400` | Periodic cleanup interval. |
| `CLEANUP_RETENTION_DAYS` | `30` | Age after which soft-deleted jobs may be permanently removed. |
| `CICD_ARTIFACT_KEEP_RUNS` | `5` | Number of recent artifact runs to retain for each job. |
| `AUTO_SCHEDULE_ENABLED` | `1` | Enables the background auto-schedule runner. |
| `AUTO_SCHEDULE_TICK_SECONDS` | `30` | Auto-schedule polling interval; values below 5 are raised to 5. |
| `CICD_PLUGIN_MAX_BYTES` | `131072` | Maximum uploaded plugin source size in bytes. |
| `CICD_PLUGIN_TEST_TIMEOUT` | `30` | Plugin editor test-run timeout in seconds (clamped to 300 seconds). |
Set `CICD_ENABLE_TIMEOUTS=0` to disable the default command timeout. Explicit per-stage
timeouts still apply. Plugin test runs always have a bounded timeout.
Cleanup is enabled by default. Its job-retention setting applies to soft-deleted jobs;
`CICD_ARTIFACT_KEEP_RUNS` separately limits each job's retained build artifacts. Published
releases are stored separately and are not removed by artifact retention.
### 4.4 Remote agent settings
Agents are normally configured using the **New Agent** flow on the Agents page. The generated
startup command registers the agent and sets its service URL, label, one-time token, and
capacity. Keep that command private until it has been used.
The standalone agent also accepts these environment variables:
| Variable | Default | Purpose |
| --- | --- | --- |
| `CICD_SERVICE_URL` | `http://localhost:8000` | Service base URL. |
| `CICD_AGENT_NAME` | Machine hostname | Agent's displayed name. |
| `CICD_AGENT_LABEL` | Unset | Primary routing label. |
| `CICD_AGENT_LABELS` | Unset | Comma-separated capabilities/labels. |
| `CICD_AGENT_CAPACITY` | `1` | Maximum concurrent tasks on the agent. |
| `CICD_AGENT_WORK_ROOT` | System temp directory + `cicd_agent_work` | Root directory for agent task workspaces. |
| `CICD_AGENT_HEARTBEAT_INTERVAL` | `20` | Heartbeat interval in seconds. |
| `CICD_AGENT_ARTIFACT_GLOB` | `artifacts/*` | Agent-side artifact collection pattern. |
| `CICD_AGENT_LOG_LEVEL` | `INFO` | Agent log level. |
| `CICD_AGENT_LOG_FILE` | `/agent.log`, or `/agent.log` when run from a checkout | Persistent agent log. Always written unless the path is unwritable; console output is kept too. |
| `CICD_AGENT_LOG_MAX_BYTES` | `10485760` (10 MiB) | Size at which the agent log rotates. |
| `CICD_AGENT_LOG_BACKUPS` | `5` | Number of rotated agent log files kept. |
The agent writes its log to a rotating file beside its install (`agent_state.json`'s directory)
so the log survives version switches and is still there when the agent was started in the
background. Set `CICD_AGENT_LOG_LEVEL=DEBUG` to include every line a task printed; at `INFO`
the agent's own milestones and the generated stage script's `[agent-stage]`/`[toolchain]`
diagnostics are recorded, while the full build output is streamed to the job log as before.
A failing log file never stops the agent — it falls back to console output. Agent-side stage
diagnostics are also stamped as they are emitted, e.g.
`[2026-10-23 09:15:02] [agent:build-01] [agent-stage] restore build bundle start ...`, so a
line in the job log says which machine produced it and when. Build command output is relayed
unchanged.
The agent also accepts `CICD_AGENT_API_KEY`, `CICD_AGENT_TOKEN`, `CICD_AGENT_VERSION`, and
`CICD_AGENT_INSTALL_ROOT`; these are normally managed by the generated startup process.
Bootstrapped agents can be upgraded manually from the Agents page. Agents started directly
from a source checkout do not support self-upgrade.
### 4.5 Optional S3 integrations
S3 support is optional and has two separate configuration paths. `S3_BUCKET` and optional
`S3_PREFIX` make the job-artifact download endpoint return a presigned GET URL instead of a
local file response; this expects the matching objects to exist in that bucket/key layout.
`CICD_S3_BUCKET` enables the agent artifact-upload presign endpoint, which creates a key under
`host_/task_/`. Both paths use the AWS SDK's configured credential chain
and require `boto3` plus appropriate IAM permissions. Without a working presigned upload,
agents fall back to the service's regular upload endpoint. These settings do not configure
the database, repository checkout, or release storage.
## 5. Creating and running builds
Use **New Build** in the web UI to configure a repository, branch, visibility, credentials,
stages, webhooks, and schedules. A job's default branch is `master`; its default visibility is
private. Jobs are owned by their creator. Owners and administrators can manage a job, and a
private job can be shared with explicitly allowed users. Regular users have a default quota of
two non-deleted jobs they own; administrators are not subject to that quota.
When code download is enabled, the service performs a shallow clone of the selected branch.
Build behavior is selected in this order:
1. If custom stages are configured, the service runs those stages.
2. Otherwise, a repository `Dockerfile` is built and its container is started (requires a
configured Docker daemon).
3. Otherwise, a repository containing `CMakeLists.txt` is configured and built with CMake.
4. Otherwise, `ci_build.sh` is run with Bash.
If none of these build methods is available, the job fails with a “nothing to do” build error.
The build page's **Help** tab renders this README. The **Pipeline** preview API is an
administrator-only inspection tool; it can inspect supported repository YAML metadata but
does not execute YAML pipeline files. `app/static/pipeline.example.yml` is an example, not an
active build mode.
When **Prepare/download code** is disabled, the service skips the clone and uses the
job-and-branch workspace already on disk. It does not guarantee that workspace is empty or
matches the current remote branch, so use this option only when you intentionally manage that
workspace. A source archive cannot be made from a run that has no matching checked-out commit.
### 5.1 Custom stages
Each stage needs a name and either a shell command or a plugin. For example:
```json
{
"git_url": "https://example.com/team/project.git",
"branch": "main",
"custom_stages": [
{
"name": "build",
"command": "cmake -S . -B build && cmake --build build",
"artifact_dir": "build",
"group": 1
},
{
"name": "test",
"command": "ctest --test-dir build",
"group": 2,
"agent_labels": ["linux-builder", "linux-backup"]
}
]
}
```
Stages with the same positive `group` value run in parallel; groups run in ascending order.
A stage without a positive group uses its position in the stage list as its group number. As a
result, an explicitly assigned group number can coincide with an ungrouped stage's position.
`artifact_dir` collects output from a local stage. For compatibility, a legacy/API-defined
stage with no agent target runs on the server; new stages in the editor must select **Local**
explicitly to do so. An `agent_labels` array is tried in order, skipping an agent that is
offline, full, or cannot be used. A single legacy `agent_label` is also accepted.
The Agents page lists **Locally on the CI/CD server** as a built-in agent by default. It shares
the agent table and stage picker with remote agents; only administrators can edit its settings,
and it has no reconnect or delete action. Administrators can enable or disable Local execution
and choose whether it is available to all users or only to named users. Administrators remain
authorized while Local is enabled. Its row reports the service version and detected tool
versions; unavailable tools are omitted from the detected-version list.
The stage editor exposes additional settings such as timeout, detached execution, and artifact
filename. A local `artifact_dir` can name a file or directory; directories are archived as
`.tar.gz`. `artifact_name` can override the collected filename. Agent stages use
`CICD_STAGE_AGENT_TIMEOUT` as their default wait limit; local commands use
`CICD_CMD_TIMEOUT` when timeouts are enabled. An explicit stage timeout applies to that stage.
A detached command stage reports whether it started successfully; it is not suitable for
plugin stages. Stage commands run in the repository workspace, with service credentials
filtered from their environment.
Plugin-stage parameters may be bound to prior-stage output instead of using literal values:
```json
{
"name": "publish",
"type": "plugin",
"plugin": "release-publisher",
"params": {
"version": {"from": "log", "key": "VERSION"},
"package_name": {"from": "file", "path": ".cicd/package.json", "key": "name"}
}
}
```
An earlier stage publishes a log value by printing `::cicd-set VERSION=1.2.3`. Log bindings
are resolved from the current run's log. File bindings read a JSON file in the repository
workspace and may therefore work when the earlier stage ran on an agent. Missing values or
files fail the stage with an explanation rather than passing an empty value.
### 5.2 Job, branch, and run lifecycle
Jobs are long-lived configurations; each execution creates a separate run with its own
branch, status, timestamps, commit information, log, and artifacts. Use a job's branch
selector to choose a branch, then start or re-run the job. **Build History** opens a specific
run's log and artifacts; the job-level log download always refers to the latest run. A
branch can have several historical runs, and branch-run deletion is separate from deleting
the job.
Use **Cancel** for a queued or running job. A locally executing command is terminated by the
server. There is no stop channel from the server to an agent after a remote task has been
dispatched: cancellation marks the job cancelled, but the remote process may continue until
it finishes. **Stop** is for a detached process started by a build, not a substitute for
canceling an ordinary stage. If an agent candidate is skipped before accepting a task, the
next configured candidate is tried; a task that was accepted and then fails is not
automatically retried on another agent.
Deleting a job from the UI is a soft delete; an owner or administrator can restore it.
Purge permanently removes the job and its artifact files. The cleanup runner permanently
removes aged soft-deleted jobs after `CLEANUP_RETENTION_DAYS`.
### 5.3 Git access and checkout behavior
The service performs shallow, single-branch checkouts, so only the selected branch's current
commit is guaranteed to be present. Use a read-only repository credential with the narrowest
scope possible for private repositories. The credential is not returned as a normal job
setting, but the authenticated clone URL is used as the checkout's Git remote; build code
that reads `.git/config` can therefore access it. Avoid printing Git remote configuration or
environment dumps in build output.
## 6. Remote agents
1. Open **Agents** and choose **New Agent**.
2. Set a name, routing label(s), and task capacity.
3. Run the generated startup command on a machine that can reach the service.
4. In a stage's **Execute on agent group** selector, choose one or more agents in priority
order. Type in the selector to search by hostname, operating system, label, or toolchain.
Leave the stage's agent group empty to execute that stage on the server. Agent registration
tokens are temporary; the registered agent uses its API key for later requests. Agent
visibility can be public or private. A private agent can be used by its owner, an
administrator, or users explicitly listed in its sharing settings; only its owner or an
administrator can manage, delete, or upgrade it.
The server considers an agent live only while it is online and has sent a heartbeat within
60 seconds. Its configured capacity includes pending reservations as well as running tasks;
the agent polls only while it has a free slot and executes accepted tasks concurrently up to
that capacity. Remote stages routed to the same agent label can reuse that job-and-branch
workspace; a different agent has a different filesystem. To pass a file or directory from
one remote stage to a later remote stage on another agent, configure `artifact_dir` on the
producing stage; the successful task exports it and the later stage restores it. The ordered
agent list is a pre-dispatch fallback, not a retry policy: offline, full, inaccessible, or
otherwise unassignable agents are skipped, but a task failure after acceptance fails the
stage.
The generated command is the recommended installation method. For a source checkout, install
`requirements-agent.txt` and start the standalone process with
`python -m app.agents.agent --service-url --token --label