diff --git a/.ai-context/COMMANDS.md b/.ai-context/COMMANDS.md index 03c06833..ddb39457 100644 --- a/.ai-context/COMMANDS.md +++ b/.ai-context/COMMANDS.md @@ -63,10 +63,11 @@ options. checkout. Plain `repo init` writes local baseline files without committing or pushing them; `repo init --pr` commits baseline changes on a branch, pushes to `origin`, and opens a PR. -- `basectl ci ` - run Base setup/check/doctor +- `basectl --ci ` - run Base setup/check/doctor with CI-safe defaults. It does not run project tests or create CI runners/VMs. - `ci setup --format json` uses `output` for the compact final status and adds - `output_lines` on failures for intermediate context. + `setup --ci --format json` uses `output` for the compact final status and + adds `output_lines` on failures for intermediate context. `basectl ci` + remains a compatibility alias. - `basectl release ` - inspect release readiness, print plans/notes, and publish guarded GitHub-side release artifacts. - `basectl gh ` - manage GitHub issues, PRs, branches, repo diff --git a/.ai-context/DECISIONS.md b/.ai-context/DECISIONS.md index 47012ec6..8c07739f 100644 --- a/.ai-context/DECISIONS.md +++ b/.ai-context/DECISIONS.md @@ -6,8 +6,9 @@ architecture discussion. ## Product And Scope - Base is a Mac-first workspace control plane. -- Linux runtime and CI support are actively being rolled out, with - `basectl ci` and Ubuntu GitHub Actions coverage as the current proof points. +- Linux runtime and CI support are actively being rolled out, with `--ci` mode + on setup/check/doctor and Ubuntu GitHub Actions coverage as the current proof + points. Full Linux setup/bootstrap remains a narrower planned contract; keep platform details in `docs/linux-support.md`. - Windows support is not currently in scope. diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 52a26c39..0ad5bf6c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -136,8 +136,8 @@ jobs: - name: Run Base setup and check smoke tests run: | - ./bin/basectl ci setup base --format json - ./bin/basectl ci check base --format json + ./bin/basectl setup --ci base --format json + ./bin/basectl check --ci base --format json - name: Verify shell profile integration run: | @@ -203,9 +203,9 @@ jobs: sudo apt-get update sudo apt-get install -y bats - - name: Run basectl ci smoke check + - name: Run basectl --ci smoke check run: | - ./bin/basectl ci check base --format json + ./bin/basectl check --ci base --format json - name: Run integration tests env: @@ -265,7 +265,7 @@ jobs: - name: Run Ubuntu source-checkout validation run: | - ./bin/basectl ci check base --format json + ./bin/basectl check --ci base --format json env -u BASE_HOME ./bin/base-test security: diff --git a/CHANGELOG.md b/CHANGELOG.md index 68296521..0599541d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and Base versions are tracked in the repo-root `VERSION` file. ### Added +- Added `--ci` mode to `basectl setup`, `basectl check`, and `basectl doctor` + as the preferred CI-safe command surface while keeping `basectl ci` as a + compatibility alias. - Added `bootstrap.sh --ensure-bash` to verify or install only the Bash 4.2+ prerequisite on macOS and Ubuntu/Debian before the full Base setup path is available. @@ -21,8 +24,8 @@ and Base versions are tracked in the repo-root `VERSION` file. ### Changed -- Clarified `basectl ci` help and docs so CI-safe setup/readiness/diagnostics - are not confused with running tests, launching GitHub Actions, or creating +- Clarified CI-safe setup/readiness/diagnostics help and docs so `--ci` mode is + not confused with running tests, launching GitHub Actions, or creating Ubuntu/Multipass VMs. ### Fixed diff --git a/README.md b/README.md index a7af051b..8fb6871f 100644 --- a/README.md +++ b/README.md @@ -289,7 +289,7 @@ Current implemented commands include: - `basectl setup [project]` - `basectl check` - `basectl doctor` -- `basectl ci ` +- `basectl --ci ` - `basectl clean --older-than ` - `basectl clean --keep-last ` - `basectl config path` @@ -321,12 +321,13 @@ Current implemented commands include: - `basectl onboard` - `basectl version` -`basectl ci` wraps setup, check, and doctor with CI-safe defaults such as -non-interactive behavior and JSON-capable output. It does not run project tests, -launch GitHub Actions locally, or create Ubuntu/Multipass VMs. Use +`--ci` runs setup, check, and doctor with CI-safe defaults such as +non-interactive behavior and JSON-capable output. The legacy `basectl ci` +wrapper remains as a compatibility alias. Neither surface runs project tests, +launches GitHub Actions locally, or creates Ubuntu/Multipass VMs. Use `basectl test` for a project's declared test command and `bin/base-test` for Base's full source-checkout validation suite. See -[basectl ci](docs/basectl-ci.md) for the CI contract, and +[CI-safe mode](docs/basectl-ci.md) for the CI contract, and [Command Quick Reference](docs/command-reference.md) for a scannable command lookup table. diff --git a/cli/bash/commands/basectl/README.md b/cli/bash/commands/basectl/README.md index f69f180e..aad86fb9 100644 --- a/cli/bash/commands/basectl/README.md +++ b/cli/bash/commands/basectl/README.md @@ -35,7 +35,7 @@ such command directories exist. Optional utility CLIs such as `caff` and - `activate` - `setup` - `check` -- `ci setup/check/doctor` +- `ci setup/check/doctor` (compatibility alias for `setup/check/doctor --ci`) - `clean` - `config` - `doctor` @@ -71,9 +71,10 @@ such command directories exist. Optional utility CLIs such as `caff` and project argument validates `project.name`. - `basectl check [project]` verifies the same local requirements without making changes and can include project manifest artifacts. -- `basectl ci setup/check/doctor ` runs Base setup, readiness checks, - and diagnostics with CI-safe defaults and text or JSON output. It does not - run project tests or launch CI runners/VMs. +- `basectl setup/check/doctor --ci ` runs Base setup, readiness + checks, and diagnostics with CI-safe defaults and text or JSON output. + `basectl ci setup/check/doctor ` remains a compatibility alias. + Neither surface runs project tests or launches CI runners/VMs. - `basectl setup/check/doctor --profile ` manage opt-in prerequisite profiles. `sre` is the first additional built-in profile, and profiles compose as comma-separated lists such as `--profile dev,sre`. diff --git a/cli/bash/commands/basectl/subcommands/check.sh b/cli/bash/commands/basectl/subcommands/check.sh index 9450f4bb..5626fefe 100644 --- a/cli/bash/commands/basectl/subcommands/check.sh +++ b/cli/bash/commands/basectl/subcommands/check.sh @@ -14,6 +14,7 @@ Usage: basectl check [project] [options] Options: + --ci Run checks with CI-safe defaults. --profile Include named prerequisite profiles. Known profiles: dev, sre, ai, linux-lab. --format Select output format. Defaults to text. --manifest Use a specific base_manifest.yaml path for project checks. @@ -34,6 +35,7 @@ Purpose: See also: basectl doctor [project] [options] + basectl ci check [options] Compatibility alias for check --ci. Check does: 1. Verify platform-specific runtime prerequisites. @@ -65,6 +67,9 @@ base_check_subcommand_main() { base_check_subcommand_usage return 0 ;; + --ci) + setup_enable_ci_mode + ;; --format) shift if [[ -z "${1:-}" ]]; then diff --git a/cli/bash/commands/basectl/subcommands/ci.sh b/cli/bash/commands/basectl/subcommands/ci.sh index a90a255e..434b91c6 100644 --- a/cli/bash/commands/basectl/subcommands/ci.sh +++ b/cli/bash/commands/basectl/subcommands/ci.sh @@ -32,7 +32,8 @@ Profiles: linux-lab - Multipass tooling for local Ubuntu lab VMs on macOS hosts. Purpose: - Run Base setup, checks, and diagnostics with CI-safe defaults. + Compatibility alias for setup/check/doctor --ci. + Prefer: basectl --ci [options] Sets BASE_CI=true so setup and diagnostic paths can choose CI-safe behavior. Does not run project tests, launch GitHub Actions, or create Ubuntu/Multipass VMs. EOF @@ -45,11 +46,7 @@ base_ci_usage_error() { } base_ci_apply_environment() { - export BASE_CI=true - export CI=true - export BASE_SETUP_NOTIFY=false - export BASE_SETUP_ALLOW_SYSTEM_PYTHON=true - export BASE_SETUP_ALLOW_NONINTERACTIVE_XCODE_INSTALL=false + setup_enable_ci_mode } base_ci_source_subcommand_module() { @@ -118,7 +115,7 @@ base_ci_parse_args() { ;; --recreate-venv) [[ "$command" == setup ]] || { - base_ci_usage_error "Option '--recreate-venv' is only supported for 'ci setup'." + base_ci_usage_error "Option '--recreate-venv' is only supported for setup --ci." return $? } BASE_CI_RECREATE_VENV=1 @@ -148,6 +145,7 @@ base_ci_parse_args() { } base_ci_common_delegate_args() { + printf '%s\n' --ci if [[ -n "$BASE_CI_PROFILE" ]]; then printf '%s\n' --profile "$BASE_CI_PROFILE" fi @@ -161,6 +159,7 @@ base_ci_common_delegate_args() { base_ci_setup_delegate_args() { base_ci_common_delegate_args + printf '%s\n' --format "$BASE_CI_FORMAT" if ((BASE_CI_RECREATE_VENV)); then printf '%s\n' --recreate-venv fi @@ -172,64 +171,11 @@ base_ci_check_or_doctor_delegate_args() { printf '%s\n' "$BASE_CI_PROJECT" --format "$BASE_CI_FORMAT" } -base_ci_print_setup_json() { - local exit_code="$1" - local stdout_file="$2" - local stderr_file="$3" - local python_bin - - python_bin="$(setup_diagnostics_python_bin)" || - fatal_error "Python is required to render Base CI setup JSON." - setup_ensure_cached_paths - env BASE_HOME="$BASE_HOME" PYTHONPATH="$_BASE_SETUP_PYTHONPATH_CACHE" \ - "$python_bin" -m base_setup.ci_json setup-json \ - --project "$BASE_CI_PROJECT" \ - --exit-code "$exit_code" \ - --stdout-file "$stdout_file" \ - --stderr-file "$stderr_file" -} - -base_ci_run_setup_json() { - local args=("$@") - local stdout_file - local stderr_file - local exit_code - local render_status - - std_make_temp_file stdout_file base-ci-setup-stdout || return 1 - std_make_temp_file stderr_file base-ci-setup-stderr || return 1 - - base_setup_subcommand_main "${args[@]}" > "$stdout_file" 2> "$stderr_file" - exit_code=$? - - # Keep JSON as stdout-only; replay setup logs to stderr for CI visibility. - if [[ -s "$stdout_file" ]]; then - cat "$stdout_file" >&2 - fi - if [[ -s "$stderr_file" ]]; then - cat "$stderr_file" >&2 - fi - - base_ci_print_setup_json "$exit_code" "$stdout_file" "$stderr_file" - render_status=$? - rm -f "$stdout_file" "$stderr_file" - if ((render_status)); then - return "$render_status" - fi - return "$exit_code" -} - base_ci_run_setup() { local args=() mapfile -t args < <(base_ci_setup_delegate_args) base_ci_source_subcommand_module setup || return 1 - - if [[ "$BASE_CI_FORMAT" == json ]]; then - base_ci_run_setup_json "${args[@]}" - return $? - fi - base_setup_subcommand_main "${args[@]}" } diff --git a/cli/bash/commands/basectl/subcommands/doctor.sh b/cli/bash/commands/basectl/subcommands/doctor.sh index f831b21d..8a0ba12f 100644 --- a/cli/bash/commands/basectl/subcommands/doctor.sh +++ b/cli/bash/commands/basectl/subcommands/doctor.sh @@ -14,6 +14,7 @@ Usage: basectl doctor [project] [options] Options: + --ci Run diagnostics with CI-safe defaults. --profile Include named prerequisite profiles. Known profiles: dev, sre, ai, linux-lab. --format Select output format. Defaults to text. --manifest Use a specific base_manifest.yaml path for project diagnostics. @@ -35,6 +36,7 @@ Purpose: See also: basectl check [project] [options] + basectl ci doctor [options] Compatibility alias for doctor --ci. EOF } @@ -183,6 +185,9 @@ base_doctor_subcommand_main() { base_doctor_subcommand_usage return 0 ;; + --ci) + setup_enable_ci_mode + ;; --profile) shift if [[ -z "${1:-}" ]]; then diff --git a/cli/bash/commands/basectl/subcommands/setup.sh b/cli/bash/commands/basectl/subcommands/setup.sh index 33f6b469..858720de 100644 --- a/cli/bash/commands/basectl/subcommands/setup.sh +++ b/cli/bash/commands/basectl/subcommands/setup.sh @@ -14,6 +14,9 @@ Usage: basectl setup [options] [project] Options: + --ci Run setup with CI-safe defaults. + --format + Select setup output format when --ci is used. Defaults to text. --profile Install named prerequisite profiles. Known profiles: dev, sre, ai, linux-lab. --dry-run Log what would happen without making changes. --manifest Use a specific base_manifest.yaml path. @@ -45,6 +48,8 @@ Setup does: Notes: - This command is intentionally idempotent. + - Use --ci for non-interactive CI-safe setup. The legacy + `basectl ci setup` command remains as a compatibility alias. - On Ubuntu/Debian Linux, setup can install apt prerequisites with interactive consent or --yes. - The optional project argument resolves a Base project from the workspace @@ -59,8 +64,72 @@ base_setup_usage_error() { return 2 } -base_setup_subcommand_main() { +base_setup_print_ci_json() { + local exit_code="$1" + local stdout_file="$2" + local stderr_file="$3" + local python_bin + + python_bin="$(setup_diagnostics_python_bin)" || + fatal_error "Python is required to render Base CI setup JSON." + setup_ensure_cached_paths + env BASE_HOME="$BASE_HOME" PYTHONPATH="$_BASE_SETUP_PYTHONPATH_CACHE" \ + "$python_bin" -m base_setup.ci_json setup-json \ + --project "${BASE_SETUP_PROJECT_NAME:-}" \ + --exit-code "$exit_code" \ + --stdout-file "$stdout_file" \ + --stderr-file "$stderr_file" +} + +base_setup_run_text() { local exit_code + + BASE_SETUP_START_TIME="$(setup_epoch_seconds)" || BASE_SETUP_START_TIME=0 + export BASE_SETUP_START_TIME + log_debug "Running 'basectl setup' (DRY_RUN=$(setup_is_dry_run && printf true || printf false))." + if setup_notifications_enabled; then + trap 'setup_notify_completion "$?"' EXIT + fi + setup_run_install + exit_code=$? + if setup_notifications_enabled; then + trap - EXIT + setup_notify_completion "$exit_code" + fi + return "$exit_code" +} + +base_setup_run_ci_json() { + local stdout_file + local stderr_file + local exit_code + local render_status + + std_make_temp_file stdout_file base-ci-setup-stdout || return 1 + std_make_temp_file stderr_file base-ci-setup-stderr || return 1 + + base_setup_run_text > "$stdout_file" 2> "$stderr_file" + exit_code=$? + + # Keep JSON as stdout-only; replay setup logs to stderr for CI visibility. + if [[ -s "$stdout_file" ]]; then + cat "$stdout_file" >&2 + fi + if [[ -s "$stderr_file" ]]; then + cat "$stderr_file" >&2 + fi + + base_setup_print_ci_json "$exit_code" "$stdout_file" "$stderr_file" + render_status=$? + rm -f "$stdout_file" "$stderr_file" + if ((render_status)); then + return "$render_status" + fi + return "$exit_code" +} + +base_setup_subcommand_main() { + local ci_mode=false format_requested=false output_format="text" local project_name="" setup_clear_run_state @@ -71,6 +140,27 @@ base_setup_subcommand_main() { base_setup_subcommand_usage return 0 ;; + --ci) + ci_mode=true + setup_enable_ci_mode + ;; + --format) + format_requested=true + shift + if [[ -z "${1:-}" ]]; then + base_setup_usage_error "Option '--format' requires an argument." + return $? + fi + case "$1" in + text|json) + output_format="$1" + ;; + *) + base_setup_usage_error "Unsupported setup output format '$1'." + return $? + ;; + esac + ;; --dry-run) setup_enable_dry_run ;; @@ -124,19 +214,16 @@ base_setup_subcommand_main() { shift done + if [[ "$format_requested" == true && "$ci_mode" != true ]]; then + base_setup_usage_error "Option '--format' is only supported when '--ci' is passed." + return $? + fi + BASE_SETUP_PROJECT_NAME="$project_name" - BASE_SETUP_START_TIME="$(setup_epoch_seconds)" || BASE_SETUP_START_TIME=0 - export BASE_SETUP_START_TIME export BASE_SETUP_PROJECT_NAME - log_debug "Running 'basectl setup' (DRY_RUN=$(setup_is_dry_run && printf true || printf false))." - if setup_notifications_enabled; then - trap 'setup_notify_completion "$?"' EXIT + if [[ "$ci_mode" == true && "$output_format" == json ]]; then + base_setup_run_ci_json + return $? fi - setup_run_install - exit_code=$? - if setup_notifications_enabled; then - trap - EXIT - setup_notify_completion "$exit_code" - fi - return "$exit_code" + base_setup_run_text } diff --git a/cli/bash/commands/basectl/subcommands/setup_common.sh b/cli/bash/commands/basectl/subcommands/setup_common.sh index 2fa0dedf..7e459824 100644 --- a/cli/bash/commands/basectl/subcommands/setup_common.sh +++ b/cli/bash/commands/basectl/subcommands/setup_common.sh @@ -249,6 +249,14 @@ setup_disable_notifications() { export BASE_SETUP_NOTIFY=false } +setup_enable_ci_mode() { + export BASE_CI=true + export CI=true + export BASE_SETUP_NOTIFY=false + export BASE_SETUP_ALLOW_SYSTEM_PYTHON=true + export BASE_SETUP_ALLOW_NONINTERACTIVE_XCODE_INSTALL=false +} + setup_notify_min_seconds() { printf '%s\n' "${BASE_SETUP_NOTIFY_MIN_SECONDS:-30}" } @@ -505,7 +513,7 @@ setup_recovery_base_bash_libraries() { } setup_recovery_ci_python() { - printf "%s\n" "Install Python 3.13 or set BASE_SETUP_PYTHON_BIN, then rerun 'basectl ci'." + printf "%s\n" "Install Python 3.13 or set BASE_SETUP_PYTHON_BIN, then rerun with '--ci'." } setup_recovery_linux_python() { diff --git a/cli/bash/commands/basectl/tests/ci.bats b/cli/bash/commands/basectl/tests/ci.bats index a7d1c1f2..ade74271 100644 --- a/cli/bash/commands/basectl/tests/ci.bats +++ b/cli/bash/commands/basectl/tests/ci.bats @@ -46,6 +46,8 @@ prepare_ci_runtime() { [[ "$output" == *"sre - production/SRE prerequisite tooling."* ]] [[ "$output" == *"ai - AI coding assistant tooling."* ]] [[ "$output" == *"linux-lab - Multipass tooling for local Ubuntu lab VMs on macOS hosts."* ]] + [[ "$output" == *"Compatibility alias for setup/check/doctor --ci."* ]] + [[ "$output" == *"Prefer: basectl --ci [options]"* ]] [[ "$output" == *"BASE_CI=true"* ]] [[ "$output" == *"Does not run project tests, launch GitHub Actions, or create Ubuntu/Multipass VMs."* ]] } @@ -96,6 +98,23 @@ prepare_ci_runtime() { [ "$(cat "$TEST_STATE_DIR/project-setup-ci")" = "true" ] } +@test "basectl check --ci delegates with CI defaults and JSON output" { + local workspace="$TEST_TMPDIR/workspace" + + prepare_ci_runtime "$workspace" + + run_base_command BASE_SETUP_TEST_WORKSPACE="$workspace" check --ci demo --format json + + [ "$status" -eq 0 ] + [[ "$output" == *'"schema_version": 1'* ]] + assert_base_check_json_status_for_readiness "$output" + [[ "$output" == *'"project": "demo"'* ]] + [ "$(cat "$TEST_STATE_DIR/project-setup-args")" = "$(printf '%s\n' --manifest "$workspace/demo/base_manifest.yaml" --action check --format json demo)" ] + [ "$(cat "$TEST_STATE_DIR/project-setup-project")" = "demo" ] + [ "$(cat "$TEST_STATE_DIR/project-setup-base-ci")" = "true" ] + [ "$(cat "$TEST_STATE_DIR/project-setup-ci")" = "true" ] +} + @test "basectl ci setup disables notifications and writes JSON when requested" { local workspace="$TEST_TMPDIR/workspace" @@ -116,6 +135,42 @@ prepare_ci_runtime() { [ ! -f "$TEST_STATE_DIR/osascript-args" ] } +@test "basectl setup --ci disables notifications and writes JSON when requested" { + local workspace="$TEST_TMPDIR/workspace" + + prepare_ci_runtime "$workspace" + create_osascript_stub + + run_base_command BASE_SETUP_TEST_WORKSPACE="$workspace" setup --ci demo --format json + + [ "$status" -eq 0 ] + [[ "$output" == *'"schema_version": 1'* ]] + [[ "$output" == *'"command": "setup"'* ]] + [[ "$output" == *'"project": "demo"'* ]] + [[ "$output" == *'"status": "ok"'* ]] + [ "$(cat "$TEST_STATE_DIR/project-setup-base-ci")" = "true" ] + [ "$(cat "$TEST_STATE_DIR/project-setup-ci")" = "true" ] + [ "$(cat "$TEST_STATE_DIR/project-setup-notify")" = "false" ] + [ ! -f "$TEST_STATE_DIR/osascript-args" ] +} + +@test "basectl doctor --ci delegates with CI defaults and JSON output" { + local workspace="$TEST_TMPDIR/workspace" + + prepare_ci_runtime "$workspace" + + run_base_command BASE_SETUP_TEST_WORKSPACE="$workspace" doctor --ci demo --format json + + [ "$status" -eq 0 ] + [[ "$output" == *'"schema_version": 1'* ]] + [[ "$output" == *'"project": "demo"'* ]] + [[ "$output" == *'"project_findings":'* ]] + [ "$(cat "$TEST_STATE_DIR/project-setup-args")" = "$(printf '%s\n' --manifest "$workspace/demo/base_manifest.yaml" --action doctor --format json demo)" ] + [ "$(cat "$TEST_STATE_DIR/project-setup-project")" = "demo" ] + [ "$(cat "$TEST_STATE_DIR/project-setup-base-ci")" = "true" ] + [ "$(cat "$TEST_STATE_DIR/project-setup-ci")" = "true" ] +} + @test "basectl ci setup json output summarizes stderr without embedding log stream" { local workspace="$TEST_TMPDIR/workspace" diff --git a/cli/bash/commands/basectl/tests/completions.bats b/cli/bash/commands/basectl/tests/completions.bats index a220f317..afe0199d 100644 --- a/cli/bash/commands/basectl/tests/completions.bats +++ b/cli/bash/commands/basectl/tests/completions.bats @@ -255,7 +255,7 @@ EOF [[ "$output" == *"run_projects=base demo"* ]] [[ "$output" == *"export_context_projects=base demo"* ]] [[ "$output" == *"update_projects=base demo"* ]] - [[ "$output" == *"check_options=--profile --format --manifest --remote-network"* ]] + [[ "$output" == *"check_options=--ci --profile --format --manifest --remote-network"* ]] [[ "$output" == *"update_options=--dry-run"* ]] [[ "$output" == *"check_profiles=dev sre ai linux-lab dev,sre dev,ai dev,linux-lab sre,ai sre,linux-lab ai,linux-lab dev,sre,ai dev,sre,linux-lab dev,ai,linux-lab sre,ai,linux-lab dev,sre,ai,linux-lab"* ]] [[ "$output" == *"test_options=--workspace --dry-run"* ]] diff --git a/cli/bash/commands/basectl/tests/setup_helpers.bash b/cli/bash/commands/basectl/tests/setup_helpers.bash index 58b6d37b..75609fc4 100644 --- a/cli/bash/commands/basectl/tests/setup_helpers.bash +++ b/cli/bash/commands/basectl/tests/setup_helpers.bash @@ -881,6 +881,8 @@ if [[ "${1:-}" == "-m" && "${2:-}" == "base_setup" ]]; then printf '{"schema_version":1,"status":"ok","project":"demo","checks":[{"id":"BASE-P040","status":"ok","name":"demo-artifact","message":"Project artifact check passed.","fix":""}]}\n' elif [[ "$action" == "check" ]]; then printf 'Project artifact check passed.\n' >&2 + elif [[ "$action" == "doctor" && "$output_format" == "json" ]]; then + printf '[{"id":"BASE-P040","status":"ok","name":"demo-artifact","message":"Project artifact check passed.","fix":""}]\n' elif [[ "$action" == "doctor" ]]; then printf 'ok demo-artifact Project artifact check passed.\n' fi diff --git a/cli/python/base_setup/tests/test_ci_supply_chain_policy.py b/cli/python/base_setup/tests/test_ci_supply_chain_policy.py index 3019c350..45226639 100644 --- a/cli/python/base_setup/tests/test_ci_supply_chain_policy.py +++ b/cli/python/base_setup/tests/test_ci_supply_chain_policy.py @@ -135,7 +135,7 @@ def test_ci_includes_ubuntu_source_checkout_base_test_job() -> None: assert "-r requirements-dev.txt" in venv_command validation_command = steps["Run Ubuntu source-checkout validation"].get("run", "") - assert "./bin/basectl ci check base --format json" in validation_command + assert "./bin/basectl check --ci base --format json" in validation_command assert "env -u BASE_HOME ./bin/base-test" in validation_command diff --git a/docs/README.md b/docs/README.md index 6a7f0b59..b6453d57 100644 --- a/docs/README.md +++ b/docs/README.md @@ -138,7 +138,7 @@ reference. The filename should answer "what is this about?" path for reducing Bash ownership without adding shell fragments by topic. - [`basectl onboard`](basectl-onboard.md) captures the guided setup experience and its relationship to project installers. -- [`basectl ci`](basectl-ci.md) defines CI-safe setup/readiness/diagnostic +- [CI-safe mode](basectl-ci.md) defines `--ci` setup/readiness/diagnostic behavior and its relationship to Linux runtime support. - [`basectl check` parallelism](check-parallelism.md) documents the shipped base-probe concurrency model and its deterministic rendering constraints. diff --git a/docs/basectl-ci.md b/docs/basectl-ci.md index 9351a9d0..3b99c8ea 100644 --- a/docs/basectl-ci.md +++ b/docs/basectl-ci.md @@ -1,9 +1,9 @@ -# basectl ci +# CI-Safe Mode -`basectl ci` is the CI-safe entry point for Base setup, readiness checks, and -diagnostics. It reuses the same setup, check, doctor, and project manifest -logic as local development, while avoiding user-facing prompts and macOS-specific -UI behaviors. +`--ci` is the CI-safe mode for Base setup, readiness checks, and diagnostics. +It reuses the same setup, check, doctor, and project manifest logic as local +development, while avoiding user-facing prompts and macOS-specific UI +behaviors. It is not a CI runner. It does not run project tests, launch GitHub Actions locally, or create Ubuntu or Multipass virtual machines. CI systems compose it @@ -19,21 +19,25 @@ with their own runners and test commands. ## Interface ```bash -basectl ci setup [--format text|json] -basectl ci check [--format text|json] -basectl ci doctor [--format text|json] +basectl setup --ci [--format text|json] +basectl check --ci [--format text|json] +basectl doctor --ci [--format text|json] ``` All commands also accept `--manifest ` for CI jobs that know the manifest path directly, plus `--profile ` for opt-in prerequisite profiles. -`basectl ci setup` additionally accepts `--recreate-venv`. +`basectl setup --ci` additionally accepts `--recreate-venv`. The default mode is non-interactive. If a required action cannot be performed -without prompting, `basectl ci` fails with a clear fix message. +without prompting, the command fails with a clear fix message. + +`basectl ci setup|check|doctor` remains a backward-compatible alias for the +same behavior, but new docs and automation should prefer the `--ci` flag on the +underlying command. ## Behavior -`basectl ci setup ` should: +`basectl setup --ci ` should: - set CI-oriented defaults such as `BASE_CI=true` - skip shell profile updates @@ -42,7 +46,7 @@ without prompting, `basectl ci` fails with a clear fix message. - run project artifact setup through the same manifest path as `basectl setup` - emit a small JSON wrapper when `--format json` is requested -For `basectl ci setup --format json`, stdout is reserved for the JSON +For `basectl setup --ci --format json`, stdout is reserved for the JSON wrapper. The `output` field contains a compact final status line. On failures, `output_lines` also includes compacted non-empty setup output lines so CI logs retain intermediate context without embedding timestamped Base log prefixes in @@ -53,13 +57,13 @@ to select non-interactive, CI-safe behavior, including the runtime-only Linux path that can allow system Python when Homebrew bootstrap is not available. `CI=true` is also set for compatibility with common CI-aware tools. -`basectl ci check ` should: +`basectl check --ci ` should: - run read-only Base and project checks - emit JSON output when `--format json` is supplied - exit non-zero only for errors, not warnings -`basectl ci doctor ` should: +`basectl doctor --ci ` should: - produce actionable diagnostics with fix commands - support `--format json` @@ -67,7 +71,7 @@ path that can allow system Python when Homebrew bootstrap is not available. ## Relationship To Tests -`basectl ci check ` verifies readiness for a CI environment. It does +`basectl check --ci ` verifies readiness for a CI environment. It does not execute the project's declared test command. Use `basectl test ` to run the manifest-declared test command, or `bin/base-test` in the Base repository when the job needs the full source-checkout validation suite. @@ -99,8 +103,8 @@ manual Ubuntu lab work on macOS. It does not create or mutate VM instances. ## Acceptance Criteria -- `basectl ci check --format json` is deterministic and parseable. -- `basectl ci doctor --format json` reports ok, warn, and error +- `basectl check --ci --format json` is deterministic and parseable. +- `basectl doctor --ci --format json` reports ok, warn, and error findings. - The command works in GitHub Actions on Ubuntu when Python and project prerequisites are already installed. @@ -117,13 +121,13 @@ manual Ubuntu lab work on macOS. It does not create or mutate VM instances. "$HOME/.base.d/base/.venv/bin/python" -m pip install PyYAML click - name: Check Base project - run: ./bin/basectl ci check base --format json + run: ./bin/basectl check --ci base --format json - name: Run Base source-checkout tests run: env -u BASE_HOME ./bin/base-test ``` -This example is a minimal starter for source-checkout CI. The `ci check` step +This example is a minimal starter for source-checkout CI. The `check --ci` step validates Base readiness; the separate `bin/base-test` step runs the repository's full validation suite. Workflows that install Python packages or third-party Actions should also follow the diff --git a/docs/command-reference.md b/docs/command-reference.md index 9a91c08a..fcb699a3 100644 --- a/docs/command-reference.md +++ b/docs/command-reference.md @@ -30,7 +30,7 @@ full compatibility contract. | Command | What it does | Important flags | |---|---|---| -| `basectl setup [project]` | Install or reconcile Base and optional project artifacts. | `--profile `, `--dry-run`, `--manifest `, `--recreate-venv`, `--notify`, `--no-notify` | +| `basectl setup [project]` | Install or reconcile Base and optional project artifacts. | `--ci`, `--format `, `--profile `, `--dry-run`, `--manifest `, `--recreate-venv`, `--notify`, `--no-notify` | | `basectl update-profile` | Create, refresh, or remove Base-managed Bash and Zsh startup snippets, backing up existing dotfiles before changes. | `--defaults`, `--no-defaults`, `--remove`, `--dry-run` | | `basectl update [project]` | Update a Base-managed project checkout through Git, or update Base through Homebrew when Base is Homebrew-managed, then run setup for the selected project. | `--dry-run` | | `basectl onboard [project]` | Guide first-run setup by orchestrating check, setup, shell profile, doctor, and project discovery. Defaults to `base`. | `--profile `, `--dry-run`, `--yes`, `--no-profile` | @@ -62,11 +62,10 @@ inspect the resolved command contract first. | Command | What it does | Important flags | |---|---|---| -| `basectl check [project]` | Verify Base and optional project readiness without making changes. Project checks record the latest result under `~/.base.d//checks/last.json`. | `--profile `, `--format `, `--manifest `, `--remote-network` | -| `basectl doctor [project]` | Explain Base and optional project findings with stable finding IDs and fixes. | `--profile `, `--format `, `--manifest `, `--remote-network` | -| `basectl ci setup ` | Run setup with CI-safe defaults. Does not run tests or create runners/VMs. | `--format `, `--manifest `, `--profile `, `--recreate-venv` | -| `basectl ci check ` | Run readiness checks with CI-safe defaults. Does not run the project test command. | `--format `, `--manifest `, `--profile ` | -| `basectl ci doctor ` | Run diagnostics with CI-safe defaults. Does not launch GitHub Actions or Ubuntu VMs. | `--format `, `--manifest `, `--profile ` | +| `basectl setup --ci ` | Run setup with CI-safe defaults. Does not run tests or create runners/VMs. | `--format `, `--manifest `, `--profile `, `--recreate-venv` | +| `basectl check [project]` | Verify Base and optional project readiness without making changes. Project checks record the latest result under `~/.base.d//checks/last.json`. | `--ci`, `--profile `, `--format `, `--manifest `, `--remote-network` | +| `basectl doctor [project]` | Explain Base and optional project findings with stable finding IDs and fixes. | `--ci`, `--profile `, `--format `, `--manifest `, `--remote-network` | +| `basectl ci setup\|check\|doctor ` | Compatibility alias for the corresponding `--ci` mode command. | Same options as the target command. | | `basectl logs` | List recent Base CLI runtime logs. | `--command `, `--limit ` | | `basectl logs --path` | Print the newest matching log path only. | `--command ` | | `basectl logs --open` | Open the newest matching log in `PAGER` or `EDITOR`. | `--command ` | diff --git a/docs/github-workflow.md b/docs/github-workflow.md index ab775698..70740f08 100644 --- a/docs/github-workflow.md +++ b/docs/github-workflow.md @@ -538,7 +538,7 @@ Historical shipped Base milestones: Project test execution, mise integration, manifest refinement, and a real Base-managed demo project. - `SHIPPED - v0.4.0 - CI and Linux foundation` - Linux runtime support and CI-oriented `basectl ci` behavior. + Linux runtime support and CI-oriented setup/check/doctor behavior. - `SHIPPED - v1.0.0 - Stable public release` Stable manifest contracts, compatibility expectations, and upgrade policy. diff --git a/docs/linux-support.md b/docs/linux-support.md index 3eeeb4c0..2262501c 100644 --- a/docs/linux-support.md +++ b/docs/linux-support.md @@ -10,7 +10,7 @@ This is Base's current Ubuntu/Debian source-checkout support contract: - `bootstrap.sh --source --dry-run` prints the manual Ubuntu/Debian checkout path instead of running `sudo apt` from a piped script. -- `basectl check`, `basectl doctor`, and `basectl ci` report Ubuntu/Debian +- `basectl check`, `basectl doctor`, and `--ci` mode report Ubuntu/Debian runtime readiness without requiring Homebrew or Xcode. - `basectl setup --dry-run` previews supported apt-backed setup work before any mutation. @@ -202,7 +202,7 @@ the setup dry-run: ./bin/basectl setup --yes ./bin/basectl setup --profile dev --dry-run ./bin/basectl setup --profile dev -./bin/basectl ci check base --format text +./bin/basectl check --ci base --format text ./bin/basectl check base --format text ./bin/basectl doctor base --format text env -u BASE_HOME ./bin/base-test @@ -262,7 +262,7 @@ Ubuntu/Debian treats the artifact as satisfied by system package `bats`. IDE extension checks are developer-workstation polish, not part of the default Ubuntu/Debian runtime acceptance path. Default `basectl check` and -`basectl ci check` runs do not fail solely because editor CLIs such as `code` +`basectl check --ci` runs do not fail solely because editor CLIs such as `code` are absent; run with `--profile dev` when you want Base to validate declared IDE extensions. @@ -293,7 +293,7 @@ Prefer fixing or unlocking the desktop keyring for long-lived machines. Then run: ```bash -./bin/basectl ci check base --format text +./bin/basectl check --ci base --format text ./bin/basectl check base --format text ./bin/basectl doctor base --format text env -u BASE_HOME ./bin/base-test @@ -370,14 +370,15 @@ environment overrides. Linux support should make GitHub Actions a first-class validation target: ```bash -basectl ci check base --format json -basectl ci doctor base --format json +basectl check --ci base --format json +basectl doctor --ci base --format json env -u BASE_HOME ./bin/base-test ``` The first CI-compatible milestone is live: workflows install their own -prerequisites before invoking Base, and `basectl ci`, `basectl check`, and -`basectl doctor` run Linux runtime checks without requiring Homebrew or Xcode. +prerequisites before invoking Base, and `basectl check --ci`, `basectl check`, +and `basectl doctor --ci` run Linux runtime checks without requiring Homebrew or +Xcode. The `ubuntu-source-checkout` job also runs the full source-checkout suite through `bin/base-test` after preparing the Base-managed test virtual environment and the sibling `base-bash-libs` checkout expected by source tests. @@ -386,10 +387,10 @@ environment and the sibling `base-bash-libs` checkout expected by source tests. | Phase | Status | Notes | |---|---|---| -| 1. Split macOS-only setup checks from portable runtime checks. | Done | Initial support exists through the live `basectl ci` entry point. | +| 1. Split macOS-only setup checks from portable runtime checks. | Done | Initial support exists through `--ci` mode on setup/check/doctor, with `basectl ci` retained as a compatibility alias. | | 2. Add platform detection and explicit unsupported-platform messages. | Done | `BASE_PLATFORM` classifies Ubuntu/Debian as `linux-debian`, keeps `BASE_OS=linux`, and fails unsupported platforms explicitly. | | 3. Make `basectl check` and `doctor` report Linux prerequisite status without requiring Homebrew or Xcode. | Done | `check` and `doctor` report Ubuntu/Debian prerequisite findings with apt-oriented recovery hints. | -| 4. Add Ubuntu CI coverage for read-only commands and the source-checkout suite. | Done for source-checkout validation | The `ubuntu-source-checkout` job installs hosted-runner prerequisites, runs `basectl ci check base --format json`, and runs `env -u BASE_HOME ./bin/base-test`. | +| 4. Add Ubuntu CI coverage for read-only commands and the source-checkout suite. | Done for source-checkout validation | The `ubuntu-source-checkout` job installs hosted-runner prerequisites, runs `basectl check --ci base --format json`, and runs `env -u BASE_HOME ./bin/base-test`. | | 5. Add conservative Ubuntu setup guidance. | Done | `basectl setup --dry-run` previews Ubuntu/Debian apt prerequisites before mutation. | | 6. Add apt-backed setup for simple prerequisites. | Done | `basectl setup --yes` runs `apt-get update`, installs the supported apt package list, creates the Base virtual environment, installs Base Python bootstrap packages, invokes the project setup layer, and seeds user config. | | 7. Make `basectl setup --profile dev` use apt-backed developer tools on Ubuntu/Debian. | Done | The dev profile maps `bats-core` and `shellcheck` to apt-backed tools and skips them when already installed. | diff --git a/docs/presentations/base-newcomer-orientation.md b/docs/presentations/base-newcomer-orientation.md index 12650a52..e38b744e 100644 --- a/docs/presentations/base-newcomer-orientation.md +++ b/docs/presentations/base-newcomer-orientation.md @@ -227,19 +227,20 @@ Read more: [Base-managed demo project](../base-managed-demo-project.md) ## CI Posture -`basectl ci` is the CI-safe setup, readiness, and diagnostics entry point. +`--ci` is the CI-safe setup, readiness, and diagnostics mode. ```bash -basectl ci setup --format json -basectl ci check --format json -basectl ci doctor --format json +basectl setup --ci --format json +basectl check --ci --format json +basectl doctor --ci --format json ``` It sets CI-safe defaults, avoids prompts, and reuses the same manifest and diagnostic paths as local development. It does not run project tests, launch -GitHub Actions locally, or create Ubuntu/Multipass VMs. +GitHub Actions locally, or create Ubuntu/Multipass VMs. `basectl ci` remains a +compatibility alias for older automation. -Read more: [`basectl ci`](../basectl-ci.md) +Read more: [CI-safe mode](../basectl-ci.md) --- diff --git a/docs/runtime-environment.md b/docs/runtime-environment.md index fcce55f5..09633d0f 100644 --- a/docs/runtime-environment.md +++ b/docs/runtime-environment.md @@ -85,14 +85,16 @@ post-migration boundary, see ## CI Runtime Variables -`basectl ci` sets these variables while delegating to setup, check, and doctor -paths. They are scoped to that command invocation and are not part of the -readonly `base_init.sh` runtime contract. +`basectl setup --ci`, `basectl check --ci`, and `basectl doctor --ci` set these +variables while running the existing setup, check, and doctor paths. They are +scoped to that command invocation and are not part of the readonly +`base_init.sh` runtime contract. The legacy `basectl ci` wrapper sets the same +variables as a compatibility alias. | Variable | Owner | Meaning and impact | User changes | | --- | --- | --- | --- | -| `BASE_CI` | Base | Set to `true` by `basectl ci` so Base setup and diagnostics can choose non-interactive CI-safe behavior, including the runtime-only Linux system-Python fallback gate. | Do not set directly; use `basectl ci`. | -| `CI` | Base/tooling convention | Set to `true` by `basectl ci` for compatibility with common CI-aware tools. | CI systems may already set this. Base sets it for delegated commands when using `basectl ci`. | +| `BASE_CI` | Base | Set to `true` by `--ci` so Base setup and diagnostics can choose non-interactive CI-safe behavior, including the runtime-only Linux system-Python fallback gate. | Do not set directly; use `--ci` on setup, check, or doctor. | +| `CI` | Base/tooling convention | Set to `true` by `--ci` for compatibility with common CI-aware tools. | CI systems may already set this. Base sets it for delegated commands when using `--ci`. | ## Command Dispatch Variables diff --git a/docs/technical-overview.md b/docs/technical-overview.md index 9648c9cc..f10609cd 100644 --- a/docs/technical-overview.md +++ b/docs/technical-overview.md @@ -203,7 +203,7 @@ and their own build systems. See [Setup Hooks Boundary](setup-hooks.md). | Command | What it does | |---|---| -| `basectl ci setup\|check\|doctor [--format json]` | CI-safe setup/readiness/diagnostics | +| `basectl setup\|check\|doctor --ci [--format json]` | CI-safe setup/readiness/diagnostics | **Prerequisite profiles** (compose with commas: `--profile dev,linux-lab`): @@ -271,7 +271,7 @@ explicit `python.manager: uv` project support, standalone and source-checkout `base-bash-libs` consumption, repository baseline creation, guarded GitHub release publishing, AI context export, repo-owned prompt rendering, local command history, manifest-declared PR policy, Base-managed artifact -declarations, `basectl ci` for non-interactive CI, IDE bootstrapping (VS +declarations, `--ci` mode for non-interactive CI, IDE bootstrapping (VS Code/Cursor), release readiness inspection, the `basectl docs` documentation shortcut, CI setup JSON output improvements, CI supply-chain policy enforcement, and pinned Homebrew installer variables for verified first-mile bootstrap. diff --git a/docs/why-base.md b/docs/why-base.md index 7fd2491a..603303b8 100644 --- a/docs/why-base.md +++ b/docs/why-base.md @@ -52,7 +52,7 @@ workflow without relearning every repository from scratch?" - A small manifest contract for setup, diagnostics, test, run, demo, build, activation, IDE, and release delegation. - Human-readable and machine-readable readiness checks through `basectl check`, - `basectl doctor`, and `basectl ci`. + `basectl doctor`, and `--ci` mode for automation. - Explicit project activation that avoids hidden `cd`-driven environment changes. - A shared shell and Python execution foundation for Base-aware scripts. diff --git a/lib/shell/completions/basectl_completion.sh b/lib/shell/completions/basectl_completion.sh index 9864989e..c1e11c56 100644 --- a/lib/shell/completions/basectl_completion.sh +++ b/lib/shell/completions/basectl_completion.sh @@ -206,10 +206,10 @@ _base_basectl_completion() { setup) _base_basectl_completion_profiles_or_options \ "$cur" \ - "--profile --dry-run --manifest --notify --no-notify --recreate-venv -v -h --help" + "--ci --format --profile --dry-run --manifest --notify --no-notify --recreate-venv --yes -v -h --help" ;; check) - _base_basectl_completion_project_profiles_or_options "$cur" "--profile --format --manifest --remote-network -v -h --help" + _base_basectl_completion_project_profiles_or_options "$cur" "--ci --profile --format --manifest --remote-network -v -h --help" ;; test) _base_basectl_completion_project_or_options "--workspace --dry-run -v -h --help" "$cur" @@ -299,7 +299,7 @@ _base_basectl_completion() { fi ;; doctor) - _base_basectl_completion_project_profiles_or_options "$cur" "--profile --format --manifest --remote-network --no-color -v -h --help" + _base_basectl_completion_project_profiles_or_options "$cur" "--ci --profile --format --manifest --remote-network --no-color -v -h --help" ;; gh) case "${COMP_WORDS[2]:-}" in diff --git a/lib/shell/completions/basectl_completion.zsh b/lib/shell/completions/basectl_completion.zsh index 8afea82c..3f5b16c0 100644 --- a/lib/shell/completions/basectl_completion.zsh +++ b/lib/shell/completions/basectl_completion.zsh @@ -210,16 +210,20 @@ _base_basectl_completion() { esac ;; setup) - _arguments '--profile[Install prerequisite profiles]:profile:(dev sre ai linux-lab dev,sre dev,ai dev,linux-lab sre,ai sre,linux-lab ai,linux-lab dev,sre,ai dev,sre,linux-lab dev,ai,linux-lab sre,ai,linux-lab dev,sre,ai,linux-lab)' \ + _arguments '--ci[Run setup with CI-safe defaults]' \ + '--format[Output format for --ci]:format:(text json)' \ + '--profile[Install prerequisite profiles]:profile:(dev sre ai linux-lab dev,sre dev,ai dev,linux-lab sre,ai sre,linux-lab ai,linux-lab dev,sre,ai dev,sre,linux-lab dev,ai,linux-lab sre,ai,linux-lab dev,sre,ai,linux-lab)' \ '--dry-run[Log without making changes]' \ '--manifest[Use a specific manifest]:path:_files' \ '--notify[Force a setup completion notification]' \ '--no-notify[Disable setup completion notification]' \ '--recreate-venv[Recreate the Base venv]' \ + '--yes[Apply setup changes that require explicit confirmation]' \ '-v[Enable DEBUG logging]' '(-h --help)'{-h,--help}'[Show help text]' ;; check) - _arguments '--profile[Include prerequisite profiles]:profile:(dev sre ai linux-lab dev,sre dev,ai dev,linux-lab sre,ai sre,linux-lab ai,linux-lab dev,sre,ai dev,sre,linux-lab dev,ai,linux-lab sre,ai,linux-lab dev,sre,ai,linux-lab)' \ + _arguments '--ci[Run checks with CI-safe defaults]' \ + '--profile[Include prerequisite profiles]:profile:(dev sre ai linux-lab dev,sre dev,ai dev,linux-lab sre,ai sre,linux-lab ai,linux-lab dev,sre,ai dev,sre,linux-lab dev,ai,linux-lab sre,ai,linux-lab dev,sre,ai,linux-lab)' \ '--format[Output format]:format:(text json)' \ '--manifest[Use a specific manifest]:path:_files' \ '--remote-network[Opt in to bounded project Git origin reachability checks]' \ @@ -447,7 +451,8 @@ _base_basectl_completion() { _arguments '1:config command:(path show doctor)' ;; doctor) - _arguments '--profile[Include prerequisite profiles]:profile:(dev sre ai linux-lab dev,sre dev,ai dev,linux-lab sre,ai sre,linux-lab ai,linux-lab dev,sre,ai dev,sre,linux-lab dev,ai,linux-lab sre,ai,linux-lab dev,sre,ai,linux-lab)' \ + _arguments '--ci[Run diagnostics with CI-safe defaults]' \ + '--profile[Include prerequisite profiles]:profile:(dev sre ai linux-lab dev,sre dev,ai dev,linux-lab sre,ai sre,linux-lab ai,linux-lab dev,sre,ai dev,sre,linux-lab dev,ai,linux-lab sre,ai,linux-lab dev,sre,ai,linux-lab)' \ '--format[Output format]:format:(text json)' \ '--manifest[Use a specific manifest]:path:_files' \ '--remote-network[Opt in to bounded project Git origin reachability diagnostics]' \ diff --git a/lib/shell/completions/tests/completions.bats b/lib/shell/completions/tests/completions.bats index 1e41c8f1..358e6add 100644 --- a/lib/shell/completions/tests/completions.bats +++ b/lib/shell/completions/tests/completions.bats @@ -208,6 +208,7 @@ assert_bash_completion_options_match_help() { } @test "Bash option completions match command help" { + assert_bash_completion_options_match_help setup setup assert_bash_completion_options_match_help check check assert_bash_completion_options_match_help doctor doctor assert_bash_completion_options_match_help devcontainer devcontainer diff --git a/tests/test_linux_support_docs.py b/tests/test_linux_support_docs.py index 966c1119..bd8937dc 100644 --- a/tests/test_linux_support_docs.py +++ b/tests/test_linux_support_docs.py @@ -42,7 +42,7 @@ def test_linux_support_docs_include_apt_backed_ubuntu_bootstrap() -> None: def test_linux_support_docs_include_final_acceptance_commands() -> None: text = linux_support_text() - assert "./bin/basectl ci check base --format text" in text + assert "./bin/basectl check --ci base --format text" in text assert "./bin/basectl check base --format text" in text assert "./bin/basectl doctor base --format text" in text assert "env -u BASE_HOME ./bin/base-test" in text