xuanwu-ci-bot:基于 Rust 与 Jenkins 的 GitCode CI/CD 机器人项目

可用于自动化处理 GitCode 仓库的 PR 构建检查,通过发现 .xuanwu/ 目录下 Dockerfiles,创建 Jenkins Pipeline 任务,执行并行构建并通过 PR 评论和标签反馈状态。【此简介由AI生成】

分支1Tags2

xuanwu-ci-bot

GitCode PR webhook bot that:

  1. pr-check — discovers .xuanwu/ Dockerfiles, ensures a per-repo Jenkins Pipeline job, runs parallel docker build checks, and reports status via PR comments and labels.
  2. push-image — when a repo has .xuanwu/push-image.yaml and a push updates the branch named in that file, builds the configured Dockerfile and pushes to Harbor (does not change ci/* labels; no PR comment when triggered by push).
  3. release — when a repo has .xuanwu/release.yaml and a tag is pushed, builds the configured Dockerfile, extracts artifacts from the image, and creates/uploads a GitCode Release.
  4. nightly — bot daily tick (NIGHTLY_*) for allowlisted repos that have .xuanwu/nightly/ Dockerfiles on the latest v* tag; failure SMTP. See docs/nightly.md.
  5. issue-notify — on Issue opened for repos in ISSUE_NOTIFY_REPOS, emails configured recipients via SMTP (Tencent Exmail).
  6. PR commands — slash commands in PR comments: /retest, /cancel, /ci status, /help, /lgtm, /approve, /hold. Permissions follow GitCode collaborator roles. See docs/pr-commands.md.

Invite the bot user lxbot into each repository and set the role to Maintainer (comments and ci/* labels). See docs/onboarding.md.

Flow

GitCode MR open/sync  → xuanwu-ci-bot → Jenkins …/pr-check  → comment + ci/pass|fail
GitCode push to branch → if .xuanwu/push-image.yaml matches → Jenkins …/push-image
GitCode tag push       → if .xuanwu/release.yaml present → Jenkins …/release → GitCode Release assets
Bot cron (NIGHTLY_*)   → allowlist + .xuanwu/nightly/* on latest v* → Jenkins …/nightly
Manual POST /hooks/nightly may pass ref/sha (fork branch verify; not used by cron)
GitCode Issue opened   → if repo in ISSUE_NOTIFY_REPOS → SMTP mail to ISSUE_NOTIFY_TO
GitCode PR comment     → /retest | /cancel | /lgtm | /approve | /hold … → Jenkins / labels + reply

Shared Rust botgate L0

Org-wide base image (tools only): registry.xuanwu.openatom.cn/xuanwu/ci-cache/rust-botgate-base:<tag> — see ci-cache/. The tag is rust<channel>-gate<bot-gate>-metric<bot-metric>-audit<cargo-audit>-r<revision> (default rust1.99.1-gate1.4.0-metric1.3.0-audit0.22.1-r1). Yaml overrides any field; Jenkins builds and pushes a missing tag. New Rust repos copy examples/.xuanwu/botgate/.

pr-check

  • Skip: no matching Dockerfiles / botgate.yaml → no comment and no label
  • Running: build triggered → comment with Jenkins URL + ci/running
  • Done: callback → result table + ci/pass or ci/fail
  • Checkout: MR builds clone the target (upstream) repo at refs/merge-requests/<n>/head (GitLab-style; not GitHub refs/pull/*). Private forks work as long as the CI git credential can read the target repo. Push-triggered pr-check still checks out by commit SHA.
  • Clone strategy (default: shallow depth=1, no tags): optional per-check Dockerfile directive # xuanwu-ci-clone: shallow=false fetch_tags=true (also depth=N). Bot merges all checks with the most permissive settings for the single Checkout stage.

push-image

  • Opt-in: push SHA must contain .xuanwu/push-image.yaml (otherwise skip silently)
  • Trigger: push event and event.branch matches YAML branch (default main); optional trigger_paths path filter
  • Job: xuanwu-ci/{owner}/{repo}/push-image (separate from pr-check)
  • Image / Dockerfile / registry / tag: from YAML (image_tag_prefix+SHA, image_tag_from: rust-toolchain → channel, rust-toolchain-sha → immutable <channel>-<sha7>, or l0-versions → version tag)
  • Jenkins credentials: bot defaults only (not in repo YAML)
  • Does not stop or share state with pr-check; Redis claim prefix is xuanwu-ci:push-image:…

release

  • Opt-in: tag SHA must contain .xuanwu/release.yaml (otherwise skip silently)
  • Trigger: push with refs/tags/* (tag delete ignored)
  • Job: xuanwu-ci/{owner}/{repo}/release
  • Dockerfile + artifact paths (+ optional tag_pattern / name / body / prerelease): from YAML
  • Pipeline creates the GitCode Release if missing, then uploads assets via upload_url
  • Redis claim: xuanwu-ci:release:result:{owner}/{repo}:{tag}

Jenkins build Console under xuanwu-ci/** is intended to be anonymously readable (see docs/onboarding.md). Website (and similar) can still pin tags via terraform (website_image) after a successful push.

Multi-replica: Redis SET NX trigger leases (plus existing result claims) serialize webhook intake across pods — see docs/onboarding.md § Redis.

Quick start

cp .env.example .env
# fill secrets — `cargo run` loads `.env` via dotenvy
cargo run

Usage docs (Chinese): GET /
Health: GET /healthz
Webhooks: POST /hooks/gitcode, POST /hooks/jenkins

Environment variables

Variable Required Default Description
LISTEN_ADDR no 0.0.0.0:8080 Bind address
BOT_PUBLIC_BASE_URL yes — Public base URL (docs / external)
JENKINS_CALLBACK_BASE_URL no BOT_PUBLIC_BASE_URL URL Jenkins agents POST results to; on k3s use http://xuanwu-ci-bot.ci-bot.svc.cluster.local:8080
GITCODE_API_BASE no https://api.gitcode.com/api/v5 GitCode API base
GITCODE_TOKEN yes — PAT for tree/comment/labels
GITCODE_WEBHOOK_SECRET yes — Webhook password or HMAC key
GITCODE_WEBHOOK_ENCRYPTION_TYPE no 0 0 password, 1 HMAC-SHA256
JENKINS_URL yes — Jenkins root URL
JENKINS_USER yes — Jenkins user
JENKINS_TOKEN yes — Jenkins API token
JENKINS_CALLBACK_SECRET yes — Shared secret for /hooks/jenkins
JENKINS_GIT_CREDENTIALS_ID no d4cedbd2-… Git credentials id for checkout
JENKINS_FOLDER_ROOT no xuanwu-ci Root folder for generated jobs
JENKINS_INSECURE_TLS no false true to skip Jenkins TLS verify (private CA)
PUSH_IMAGE_ENABLED no true Global kill-switch for branch-push Harbor push
RELEASE_ENABLED no true Global kill-switch for tag → GitCode Release
JENKINS_HARBOR_CREDENTIALS_ID no 3cefd32b-… Harbor username/password credentials id
JENKINS_GITCODE_TOKEN_CREDENTIALS_ID no 29188ace-… String credentials for GITCODE_TOKEN build-arg
JENKINS_GITEE_TOKEN_CREDENTIALS_ID no d73f7f06-… String credentials for GITEE_TOKEN build-arg
GITHUB_TOKEN no empty GitHub PAT passed as docker --build-arg GITHUB_TOKEN (website README fetch)
REDIS_URL yes — Redis for PR-run state (redis://:pass@redis-master:6379)
SMTP_HOST no — SMTP host (e.g. smtp.exmail.qq.com); omit to disable issue mail
SMTP_PORT no 465 SMTP port
SMTP_USERNAME no* — SMTP username (* required with host/password)
SMTP_PASSWORD no* — SMTP password / Exmail client password
SMTP_FROM no username From header
SMTP_IMPLICIT_TLS no true if port 465 Implicit TLS wrapper
ISSUE_NOTIFY_TO no empty Recipients (comma/;/whitespace); multiple To
ISSUE_NOTIFY_REPOS no empty owner/repo allowlist for issue-open mail
PR_COMMANDS_ENABLED no true Global kill-switch for PR comment slash commands
GITCODE_BOT_USERNAME no empty Bot account login; its comments are never parsed as commands
PR_COMMAND_ALLOWLIST no empty GitCode logins that may run any PR command, bypassing role and author rules

Webhook auth

  • Password (0): query ?password=, header X-GitCode-Token, or body password/token
  • HMAC (1): header X-Gitcode-Signature (also accepts X-Hub-Signature-256) as sha256=<hex> of HMAC-SHA256(body, secret)

Callback auth

Header X-Xuanwu-Callback-Secret must match JENKINS_CALLBACK_SECRET.

.xuanwu convention

pr-check Dockerfiles

Recursive scan under .xuanwu/ for:

  • Dockerfile
  • Dockerfile.*
  • *.Dockerfile

*.dockerignore is ignored by check discovery (not treated as a Dockerfile).

Each file is one check; all must succeed. See examples/.xuanwu/.

CI Rust Dockerfiles (and repo .cargo/config.toml) replace crates.io with:

[source.crates-io]
replace-with = "xuanwu"

[source.xuanwu]
registry = "sparse+https://crates.xuanwu.openatom.cn/api/v1/cratesio/"

push-image config

Add .xuanwu/push-image.yaml to opt in:

branch: main
harbor_registry: registry.xuanwu.openatom.cn
# Single image (legacy) or multi-target:
images:
  - dockerfile: Dockerfile
    harbor_repo: xuanwu/website   # optional; default {owner}/{repo}
    image_tag_prefix: ""          # optional; e.g. beta-
  # - dockerfile: ci-cache/Dockerfile.rust-botgate-base
  #   harbor_repo: xuanwu/ci-cache/rust-botgate-base
  #   image_tag_from: rust-toolchain
  #   trigger_paths: [ci-cache/]

When image_tag_from: rust-toolchain, default trigger_paths cover ci-cache/ / toolchain so routine app commits do not rebuild the base. Do not put secrets or Jenkins credentialsId in this file.

release config

Add .xuanwu/release.yaml to opt in on tag push:

dockerfile: .xuanwu/Dockerfile.release
artifacts:
  - /out/hello.txt
# tag_pattern: "^v"   # optional regex
# name: ""            # default = tag
# body: "notes"        # GitCode requires non-empty; omit → "Release {tag}"
# prerelease: false

The release Dockerfile must leave files at the listed absolute paths; Jenkins docker create + docker cp extracts them into Release assets. If the final stage is scratch, set an explicit CMD (e.g. the binary path) — otherwise docker create fails with no command specified. See examples/.xuanwu/Dockerfile.release.

Labels

Mutually exclusive: ci/running, ci/pass, ci/fail, ci/cancelled. A head SHA with no .xuanwu checks is silent (no comment, no label). A new run always sets exclusive ci/running (replacing any prior terminal label); the result callback then replaces it with ci/pass or ci/fail. /cancel sets ci/cancelled. A merge-request webhook does not do this for a head SHA that already has a posted result, or when the MR state is already merged or closed. Only /retest or a new head SHA replaces the terminal label with ci/running.

Review labels (set by PR commands, independent of ci/*): lgtm, approved, do-not-merge/hold. See docs/pr-commands.md.

Docker

docker build -f docker/Dockerfile -t registry.xuanwu.openatom.cn/xuanwu/xuanwu-ci-bot:local .

Harbor publish for this repo: push the branch named in .xuanwu/push-image.yaml (bot-managed push-image job). Pin the resulting tag in xuanwu-terraform/envs/onprem/ci-bot as app_image_tag.

Development

cargo test
cargo clippy --all-targets --locked -- -D warnings
cargo build --release

PR checks: .xuanwu/Dockerfile.clippy (via xuanwu-ci pr-check).

项目介绍

可用于自动化处理 GitCode 仓库的 PR 构建检查,通过发现 .xuanwu/ 目录下 Dockerfiles,创建 Jenkins Pipeline 任务,执行并行构建并通过 PR 评论和标签反馈状态。【此简介由AI生成】

定制我的领域