# 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