Run tests and CI checks
Run the right checks for your change scope before committing. CI runs through GitHub Actions and covers static checks, type checks, tests, builds, automatic format fixes, and documentation deployment. A CircleCI watchdog (.circleci/) mirrors the check pipeline: when GitHub Actions entirely fails for a commit (for example a GitHub platform outage), CircleCI automatically takes over the full static analysis, database test matrix, and docs checks. Builds, releases, and deployment remain GitHub Actions only. Local automation uses Taskfile.yml as the main entrypoint.
Taskfile entrypoints
Section titled “Taskfile entrypoints”task checktask testtask buildtask citask check covers Ruff, Ruff format check, Markdown lint, Turbo lint, Pyright, ty, and Turbo type check. task test covers root pytest, lingc-cli pytest, and docs Vitest. task ci runs check, test, and build in order.
Python / code focused checks
Section titled “Python / code focused checks”uv run -m ruff check . --output-format=githubuv run -m ruff format --check .uv run -m pyrightuv run -m ty check --output-format githubuv run -m pytestIf only one module changed, run the related test file first, then broaden the scope as needed.
Runtime smoke test
Section titled “Runtime smoke test”After hook, adapter, or startup-flow changes, static checks are not enough. Run the three-stage live smoke test below to catch forward-reference signature errors, import-order issues, schema-write leaks, and CLI regressions that static analysis misses.
Stage 1 — Development environment
Section titled “Stage 1 — Development environment”Start the bot with the development environment selected by ENVIRONMENT=dev so NoneBot2 loads .env + .env.dev:
uvx --from nb-cli nb.exe runWait until you see Application startup complete. and at least one event cycle. To bound the run, wrap the command with timeout (e.g. timeout 10s); exit code 124 is expected when the timeout kills the process. If the process exits before startup finishes, increase the timeout.
Stage 2 — Production environment (clean localstore)
Section titled “Stage 2 — Production environment (clean localstore)”Verify the bot starts cleanly from a pristine localstore state, which proves startup is schema-write-free and survives a fresh deployment.
-
Delete every localstore-owned directory under the project:
Terminal window rm -rf config/nonebot_plugin_lingchu_bot/ \data/nonebot_plugin_lingchu_bot/ \data/nonebot_plugin_orm/ \cache/nonebot_plugin_lingchu_bot/These four paths are resolved by
nonebot_plugin_localstore(setLOCALSTORE_USE_CWD=truein.env). Repository-rootconfig/,data/, andcache/are local development artifacts and disposable. -
Set
ENVIRONMENT=prodso NoneBot2 loads.env+.env.prodand start the bot:Terminal window ENVIRONMENT=prod uvx --from nb-cli nb.exe run -
Acceptance: the process reaches
Application startup complete.without hard errors. ALLM configuration missing or invalid; AI is unavailablewarning is acceptable; any traceback, schema-write, or migration side effect is a hard failure.
CI/CD smoke test
Section titled “CI/CD smoke test”In addition to the manual runtime smoke test, CI/CD runs an automated smoke test stage after the build job and before deployment. This verifies that the built container can start NoneBot, register runtime hooks, initialize core services, and produce a JUnit report.
Stage position and dependencies
Section titled “Stage position and dependencies”smoke-testruns after thebuildjob in👷 CI-buildsand only starts when the build succeeds.docs-smokeruns after the docs build job in📚 Docs Deployand only starts when the docs build succeeds.
Failure handling
Section titled “Failure handling”If any smoke check fails, the workflow stops immediately and does not deploy. The job uploads smoke-test-results.xml as an artifact so you can inspect the failing assertion and traceback.
Local debugging
Section titled “Local debugging”You can run the same smoke checks locally:
# Build and run the smoke test container with Docker Composetask smoke
# Run in CI mode and emit the JUnit XML reporttask ci:smoke
# Equivalent raw Docker Compose commanddocker compose --profile smoke up --build --abort-on-container-exit smoke-testDatabase testing
Section titled “Database testing”The project supports four database backends for testing via the SQLALCHEMY_DATABASE_URL environment variable, following NoneBot database testing best practices.
Local multi-database testing
Section titled “Local multi-database testing”By default, tests use SQLite. To test against PostgreSQL / MySQL / MariaDB locally:
- Install the database drivers (already in the
testdependency group):
uv sync --all-groups-
Start a database server (via Docker or local install).
-
Set the
SQLALCHEMY_DATABASE_URLenvironment variable and run tests:
# PostgreSQLexport SQLALCHEMY_DATABASE_URL="postgresql+psycopg://postgres:postgres@localhost:5432/postgres"uv run -m pytest
# MySQLexport SQLALCHEMY_DATABASE_URL="mysql+aiomysql://mysql:mysql@localhost:3306/mymysql"uv run -m pytest
# MariaDB (SQLAlchemy auto-detects MariaDB via VERSION() without dedicated driver)export SQLALCHEMY_DATABASE_URL="mysql+aiomysql://mariadb:mariadb@localhost:3306/mymariadb"uv run -m pytest- Run migrations before testing:
uv run nb orm upgradeCI multi-database matrix
Section titled “CI multi-database matrix”CI runs tests on 8 jobs across 4 database engines, covering both LTS and latest versions:
- SQLite (default, no service required; version pinned by Python
sqlite3/aiosqlite) - PostgreSQL 16 (
postgres:16-alpine, supported until Nov 2028) and PostgreSQL 18 (postgres:18-alpine, latest) - MySQL 8.4 LTS (
mysql:8.4, until ~2032) and MySQL 9.7 LTS (mysql:9.7, until ~2034) - MariaDB 11.4 LTS (
mariadb:11.4, until May 2029) and MariaDB 11.8 LTS (mariadb:11.8, until Jun 2028)
Each matrix entry carries an engine + image field; service containers select their image via ${{ matrix.db.engine == '<engine>' && matrix.db.image || '' }} so multiple versions of the same engine coexist in one matrix. The fail-fast: false strategy ensures all databases are tested even if one fails.
Docs / frontend focused checks
Section titled “Docs / frontend focused checks”The docs site uses pnpm, Astro Starlight, Vitest, Playwright, ESLint, and Turbo:
pnpm --filter docs lintpnpm --filter docs testpnpm --filter docs run test:e2e:hookpnpm --filter docs run test:e2epnpm --filter docs check-typespnpm turbo run build --filter=docsVitest covers component and library behavior under apps/docs/src/__tests__. Playwright tests live under apps/docs/e2e and cover browser-level docs navigation. Local hooks run the Chromium smoke command (test:e2e:hook) on docs changes; CI runs all configured Playwright browser projects and uploads the HTML report plus traces.
Write Playwright tests with role/text locators and web-first assertions such as toBeVisible() and toHaveAttribute(). Avoid sleeps, screenshot assertions, and broad visual checks unless the change specifically needs them.
Markdown checks
Section titled “Markdown checks”pnpm exec markdownlint-cli2Globs and ignores are configured centrally in .markdownlint-cli2.jsonc at the repository root, so no path arguments are needed.
Internationalization checks
Section titled “Internationalization checks”After changing translatable strings, run:
task i18nIf you only change documentation that describes i18n, gettext catalogs do not need to be regenerated.
CI workflows
Section titled “CI workflows”🧪 Python CI: A shareddetect-changescomposite action (.github/actions/detect-changes) outputs boolean flags per file type (python/markdown/frontend/frontend-code/frontend-style/frontend-content/frontend-tsx), then conditionally runs Static Analysis (on Python or markdown changes, viatask ci:static) and Tests & Type Check (on Python changes, across the multi-database matrix). Auto Fix & Format runs onmain/devpushes. Conditions align with pre-commit v3NEEDS_LINT/NEEDS_TYPE_CHECK/NEEDS_DOCS_TEST.🧪 Frontend CI: Uses the samedetect-changesaction, then conditionally runs Docs Check — ESLint on code/style, check-types on any frontend, link validation on content, Vitest on code/content.🎭 Playwright: runs docs E2E tests forapps/docsandpackageschanges, installs browser dependencies, and uploads Playwright report artifacts.👷 CI-builds: runstask ci:build; theversioned-buildjob runs on a daily schedule (02:00 Asia/Shanghai, UTC0 18 * * *) — it syncs the version from the latest tag, bumps the dev version, writescore_version, builds, archives artifacts, generates provenance, and tags the version.📚 Docs Deploy: when docs-related paths are pushed tomainordev, it runs pnpm/Turbo lint, docs test, docs build, and deploys GitHub Pages.
Handling CI failures
Section titled “Handling CI failures”Open the failing job logs and locate the command, rule, and line number. Fix only the smallest related scope and rerun the corresponding local command.