Summary
The current entrypoint packages have grown beyond useful boundaries:
cmd/rascal/main.go contains root wiring, global config/client setup, and many unrelated command implementations.
cmd/rascald/main_test.go has become a catch-all test file covering many endpoint and lifecycle behaviors.
cmd/rascald/main.go is still acceptable as an entrypoint, but its remaining bootstrap/lifecycle wiring should be separated so the file stays thin.
This issue is a structural refactor only. The goal is to make command and endpoint code easier to navigate, isolate command-level tests, and reduce merge conflicts, without changing CLI behavior or API behavior.
Goals
- Split
cmd/rascal by top-level command/subtree boundaries.
- Keep command constructors thin and colocate them with related helpers/tests.
- Split
cmd/rascald bootstrap/lifecycle wiring into focused files.
- Split large test files into command-/endpoint-aligned unit test files.
- Preserve existing behavior, flags, aliases, output, and API contracts.
Non-goals
- No command renames.
- No API changes.
- No output format changes.
- No architecture changes in
internal/orchestrator, internal/state, or runtime behavior.
- No broad business-logic rewrite.
Current pain points
cmd/rascal
These command constructors all live in cmd/rascal/main.go:
newRootCmd
newInitCmd
newDeployCmd
newRunCmd
newPSCmd
newLogsCmd
newDoctorCmd
newOpenCmd
newRetryCmd
newCancelCmd
newTaskCmd
newConfigCmd
newAuthCmd
newAuthSyncCmd
newCompletionCmd
That mixes root wiring, operator workflows, run workflows, config, auth, help/completion, and render/output concerns in one file.
cmd/rascald
cmd/rascald/main_test.go mixes:
- webhook handling
- list/create/cancel API tests
- PR lifecycle behavior
- deploy drain/reclaim behavior
- ready/draining behavior
- fake runner/fake GitHub/test harness setup
That makes it hard to find relevant tests and encourages adding unrelated tests to the same file.
Proposed file structure
cmd/rascal
Keep package main, but split by command boundary.
Suggested target layout:
cmd/rascal/
main.go # process entrypoint only
root.go # newRootCmd, global command assembly
globals.go # app/global options, shared bootstrap helpers
output.go # emit/render/masking/general output helpers
init_cmd.go # newInitCmd and init-specific validation/helpers
deploy_cmd.go # newDeployCmd
provision_cmd.go # newProvisionCmd
doctor_cmd.go # newDoctorCmd
run_cmd.go # newRunCmd
retry_cmd.go # newRetryCmd
cancel_cmd.go # newCancelCmd
ps_cmd.go # newPSCmd
logs_cmd.go # newLogsCmd
open_cmd.go # newOpenCmd
task_cmd.go # newTaskCmd
config_cmd.go # newConfigCmd and config subcommands
auth_cmd.go # newAuthCmd, newAuthSyncCmd, auth rotate/sync root logic
auth_credentials.go # keep existing subtree, or split further if needed
github_cmd.go # newGitHubCmd
repo_cmd.go # repo enable/disable/status
webhook_cmd.go # webhook subtree/test command
completion_cmd.go # newCompletionCmd
Notes:
cmd/rascal/infra.go should be split so deploy and provision each have a clear command file.
- Existing focused files can be kept and renamed only if it improves consistency:
cmd/rascal/auth_credentials.go
cmd/rascal/github.go
cmd/rascal/repo.go
cmd/rascal/webhook.go
The main requirement is command-aligned placement, not any exact filename.
cmd/rascald
Keep package main, but split the entrypoint support code and the tests.
Suggested target layout:
cmd/rascald/
main.go # process entrypoint only
bootstrap.go # config/store/broker/runner/server wiring
http.go # mux/http.Server setup
lifecycle.go # beginDeployDrain, reclaimForDeploy, genericShutdown, helpers
test_helpers_test.go # fake runner, fake GitHub client, harness builders
webhook_issue_test.go
webhook_pr_comment_test.go
webhook_pr_review_test.go
webhook_pr_thread_test.go
webhook_pr_lifecycle_test.go
webhook_checks_test.go
runs_api_test.go
tasks_api_test.go
cancel_api_test.go
lifecycle_test.go
credentials_test.go # keep, but trim helper duplication
run_logs_test.go # keep
Notes:
cmd/rascald/main.go is not the main problem, but should remain a thin entrypoint.
cmd/rascald/main_test.go should be fully split by behavior area.
Concrete movement plan
cmd/rascal command mapping
Move the following constructors out of cmd/rascal/main.go:
newRootCmd -> root.go
newInitCmd -> init_cmd.go
newDeployCmd -> deploy_cmd.go
newRunCmd -> run_cmd.go
newRetryCmd -> retry_cmd.go
newCancelCmd -> cancel_cmd.go
newPSCmd -> ps_cmd.go
newLogsCmd -> logs_cmd.go
newDoctorCmd -> doctor_cmd.go
newOpenCmd -> open_cmd.go
newTaskCmd -> task_cmd.go
newConfigCmd -> config_cmd.go
newAuthCmd and newAuthSyncCmd -> auth_cmd.go
newCompletionCmd -> completion_cmd.go
newProvisionCmd -> provision_cmd.go
newDeployExistingCmd and deploy-specific helpers -> deploy_cmd.go or provision_cmd.go, depending on use
Shared helpers currently embedded in main.go should move only if they are command-specific. Truly shared helpers can live in globals.go or output.go.
cmd/rascal test mapping
Split cmd/rascal/main_test.go into:
root_cmd_test.go
- root flags/help/completion registration
- top-level command presence
completion_cmd_test.go
- completion-specific help/install behavior
init_cmd_test.go
- init defaults, plan output, validation, JSON output
deploy_cmd_test.go
- deploy command behavior not already covered in
infra_test.go
provision_cmd_test.go
- provision command behavior not already covered in
infra_test.go
doctor_cmd_test.go
- doctor JSON output and diagnostics rendering
run_cmd_test.go
run payload creation and validation
retry_cmd_test.go
retry payload creation, debug behavior, trigger behavior
cancel_cmd_test.go
- cancel command argument/behavior tests
ps_cmd_test.go
- defaults,
--all, --limit, status filtering, render columns
logs_cmd_test.go
- logs defaults and command-level behavior
config_cmd_test.go
config get/set/path/unset
auth_cmd_test.go
- auth root/help/rotate/sync top-level tests
Keep existing focused test files and align them to subtree ownership:
cmd/rascal/auth_credentials_test.go
cmd/rascal/auth_sync_test.go
cmd/rascal/infra_test.go
cmd/rascal/webhook_test.go
cmd/rascal/repo_test.go
cmd/rascal/util_test.go
cmd/rascal/task_payload_test.go
Unit-test guidance for cmd/rascal:
- Prefer testing the specific command constructor under test, not always
newRootCmd().
- Keep only a small number of root-level smoke tests to verify command registration and top-level help.
- Extract pure helpers where needed so tests do not need to execute the full CLI tree to validate one command’s logic.
cmd/rascald test mapping
Split cmd/rascald/main_test.go into:
test_helpers_test.go
fakeRunner
fakeGitHubClient
- request builders
- shared setup functions
webhook_issue_test.go
- issue labeled/closed/reopened/edited behavior
webhook_pr_comment_test.go
- PR issue comment behavior
webhook_pr_review_test.go
- PR review and review comment behavior
webhook_pr_thread_test.go
- review thread resolved/unresolved behavior
webhook_pr_lifecycle_test.go
- merged/closed/reopened/draft/ready-for-review/synchronize flows
webhook_checks_test.go
- check run/check suite failure flows
runs_api_test.go
- list runs, run subresources
tasks_api_test.go
- create task, create issue task, retry hydration, task get
cancel_api_test.go
- queued cancel, active cancel, cancel reasons
lifecycle_test.go
- begin drain, deploy reclaim, ready state, shutdown/drain semantics
Keep existing focused files:
cmd/rascald/credentials_test.go
cmd/rascald/run_logs_test.go
Unit-test guidance for cmd/rascald:
- Endpoint tests should target the specific handler/behavior area under test.
- Avoid using one mega test file as the default place for new HTTP behavior tests.
- Keep shared fakes in one test helper file rather than redefining them across test files.
Implementation constraints
- Keep package names unchanged unless there is a strong reason not to.
- Preserve all exported behavior, command names, flags, aliases, and help text.
- Preserve test coverage.
- Do not mix this refactor with feature work.
- Minimize non-functional churn inside
internal/* packages.
Acceptance criteria
cmd/rascal/main.go is reduced to entrypoint/root bootstrapping only.
- No top-level command constructor remains in
cmd/rascal/main.go.
cmd/rascal command constructors are grouped by command/subtree boundary.
cmd/rascal/main_test.go is removed or reduced to a small root smoke test file.
cmd/rascald/main.go remains thin and delegates bootstrap/lifecycle helpers to focused files.
cmd/rascald/main_test.go is removed and replaced with focused test files by endpoint/behavior area.
- Shared test fakes for
cmd/rascald live in test_helpers_test.go.
go test ./cmd/rascal ./cmd/rascald passes.
go test ./... passes.
Suggested execution order
- Split
cmd/rascal tests first so command boundaries are visible.
- Split
cmd/rascal command files to match the test layout.
- Split
cmd/rascald/main_test.go into focused files plus shared helpers.
- Extract
cmd/rascald bootstrap/lifecycle helpers from main.go.
- Run full test suite and fix any fallout without changing behavior.
Nice-to-have follow-up
After this refactor lands, consider a second issue to extract shared CLI runtime concerns from cmd/rascal into focused helpers:
- config/env resolution
- API client factory
- output/render helpers
That is useful, but should be separate from this structural split.
Summary
The current entrypoint packages have grown beyond useful boundaries:
cmd/rascal/main.gocontains root wiring, global config/client setup, and many unrelated command implementations.cmd/rascald/main_test.gohas become a catch-all test file covering many endpoint and lifecycle behaviors.cmd/rascald/main.gois still acceptable as an entrypoint, but its remaining bootstrap/lifecycle wiring should be separated so the file stays thin.This issue is a structural refactor only. The goal is to make command and endpoint code easier to navigate, isolate command-level tests, and reduce merge conflicts, without changing CLI behavior or API behavior.
Goals
cmd/rascalby top-level command/subtree boundaries.cmd/rascaldbootstrap/lifecycle wiring into focused files.Non-goals
internal/orchestrator,internal/state, or runtime behavior.Current pain points
cmd/rascalThese command constructors all live in
cmd/rascal/main.go:newRootCmdnewInitCmdnewDeployCmdnewRunCmdnewPSCmdnewLogsCmdnewDoctorCmdnewOpenCmdnewRetryCmdnewCancelCmdnewTaskCmdnewConfigCmdnewAuthCmdnewAuthSyncCmdnewCompletionCmdThat mixes root wiring, operator workflows, run workflows, config, auth, help/completion, and render/output concerns in one file.
cmd/rascaldcmd/rascald/main_test.gomixes:That makes it hard to find relevant tests and encourages adding unrelated tests to the same file.
Proposed file structure
cmd/rascalKeep package
main, but split by command boundary.Suggested target layout:
Notes:
cmd/rascal/infra.goshould be split sodeployandprovisioneach have a clear command file.cmd/rascal/auth_credentials.gocmd/rascal/github.gocmd/rascal/repo.gocmd/rascal/webhook.goThe main requirement is command-aligned placement, not any exact filename.
cmd/rascaldKeep package
main, but split the entrypoint support code and the tests.Suggested target layout:
Notes:
cmd/rascald/main.gois not the main problem, but should remain a thin entrypoint.cmd/rascald/main_test.goshould be fully split by behavior area.Concrete movement plan
cmd/rascalcommand mappingMove the following constructors out of
cmd/rascal/main.go:newRootCmd->root.gonewInitCmd->init_cmd.gonewDeployCmd->deploy_cmd.gonewRunCmd->run_cmd.gonewRetryCmd->retry_cmd.gonewCancelCmd->cancel_cmd.gonewPSCmd->ps_cmd.gonewLogsCmd->logs_cmd.gonewDoctorCmd->doctor_cmd.gonewOpenCmd->open_cmd.gonewTaskCmd->task_cmd.gonewConfigCmd->config_cmd.gonewAuthCmdandnewAuthSyncCmd->auth_cmd.gonewCompletionCmd->completion_cmd.gonewProvisionCmd->provision_cmd.gonewDeployExistingCmdand deploy-specific helpers ->deploy_cmd.goorprovision_cmd.go, depending on useShared helpers currently embedded in
main.goshould move only if they are command-specific. Truly shared helpers can live inglobals.gooroutput.go.cmd/rascaltest mappingSplit
cmd/rascal/main_test.gointo:root_cmd_test.gocompletion_cmd_test.goinit_cmd_test.godeploy_cmd_test.goinfra_test.goprovision_cmd_test.goinfra_test.godoctor_cmd_test.gorun_cmd_test.gorunpayload creation and validationretry_cmd_test.goretrypayload creation, debug behavior, trigger behaviorcancel_cmd_test.gops_cmd_test.go--all,--limit, status filtering, render columnslogs_cmd_test.goconfig_cmd_test.goconfig get/set/path/unsetauth_cmd_test.goKeep existing focused test files and align them to subtree ownership:
cmd/rascal/auth_credentials_test.gocmd/rascal/auth_sync_test.gocmd/rascal/infra_test.gocmd/rascal/webhook_test.gocmd/rascal/repo_test.gocmd/rascal/util_test.gocmd/rascal/task_payload_test.goUnit-test guidance for
cmd/rascal:newRootCmd().cmd/rascaldtest mappingSplit
cmd/rascald/main_test.gointo:test_helpers_test.gofakeRunnerfakeGitHubClientwebhook_issue_test.gowebhook_pr_comment_test.gowebhook_pr_review_test.gowebhook_pr_thread_test.gowebhook_pr_lifecycle_test.gowebhook_checks_test.goruns_api_test.gotasks_api_test.gocancel_api_test.golifecycle_test.goKeep existing focused files:
cmd/rascald/credentials_test.gocmd/rascald/run_logs_test.goUnit-test guidance for
cmd/rascald:Implementation constraints
internal/*packages.Acceptance criteria
cmd/rascal/main.gois reduced to entrypoint/root bootstrapping only.cmd/rascal/main.go.cmd/rascalcommand constructors are grouped by command/subtree boundary.cmd/rascal/main_test.gois removed or reduced to a small root smoke test file.cmd/rascald/main.goremains thin and delegates bootstrap/lifecycle helpers to focused files.cmd/rascald/main_test.gois removed and replaced with focused test files by endpoint/behavior area.cmd/rascaldlive intest_helpers_test.go.go test ./cmd/rascal ./cmd/rascaldpasses.go test ./...passes.Suggested execution order
cmd/rascaltests first so command boundaries are visible.cmd/rascalcommand files to match the test layout.cmd/rascald/main_test.gointo focused files plus shared helpers.cmd/rascaldbootstrap/lifecycle helpers frommain.go.Nice-to-have follow-up
After this refactor lands, consider a second issue to extract shared CLI runtime concerns from
cmd/rascalinto focused helpers:That is useful, but should be separate from this structural split.