-
-
Notifications
You must be signed in to change notification settings - Fork 215
refactor(config): load only necessary config for context #1467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Warning Rate limit exceeded@yottahmd has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 5 minutes and 17 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughReplaces Config.Global with Config.Core, adds a service-aware ConfigLoader owning per-command Viper instances and service bitflags, makes flag binding explicit to a Viper instance, and standardizes many "key=value" parsing sites from strings.SplitN to strings.Cut. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant CLI as CLI (cobra)
participant V as Viper (per-command)
participant Loader as ConfigLoader
participant Ctx as NewContext
participant Cmd as Command
CLI->>V: initFlags(cmd) (create & register flags)
CLI->>V: bindFlags(v, cmd, ...) (bind flags under lock)
CLI->>Loader: NewConfigLoader(v, WithService(service))
Loader->>V: bind env vars, set defaults
Loader->>Loader: loadCoreConfig()
alt service requires additional sections
Loader->>Loader: loadPathsConfig()/loadServerConfig()/...
end
Loader->>Ctx: Load() -> *Config (cfg.Core populated)
Ctx->>Cmd: initialize logger/agents using cfg.Core.*
Cmd->>Cmd: execute command logic (agent, scheduler, exec, etc.)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/common/stringutil/kv.go (1)
53-63: Comment doesn't match implementation regarding empty keys.The documentation states "with non-empty key" but the code doesn't enforce this. An entry like
"=VALUE"would insertmap[""] = "VALUE". Additionally, the phrase "exactly one '='" is misleading sincestrings.Cutsplits on the first occurrence, meaning"KEY=VAL=MORE"is accepted.Apply this diff to enforce non-empty keys as documented:
func KeyValuesToMap(kvSlice []string) map[string]string { result := make(map[string]string, len(kvSlice)) for _, kv := range kvSlice { key, value, found := strings.Cut(kv, "=") - if found { + if found && key != "" { result[key] = value } } return result }Alternatively, update the comment to reflect that empty keys are allowed (though this is likely not the intended behavior for most use cases).
🧹 Nitpick comments (3)
internal/common/config/loader.go (3)
121-129: Parameter shadows imported package name.The parameter
vipershadows the importedviperpackage, which can be confusing. Consider renaming tovorviperInstancefor clarity.// NewConfigLoader creates a new ConfigLoader instance with an isolated viper instance // and applies all given options. -func NewConfigLoader(viper *viper.Viper, options ...ConfigLoaderOption) *ConfigLoader { - loader := &ConfigLoader{v: viper} +func NewConfigLoader(v *viper.Viper, options ...ConfigLoaderOption) *ConfigLoader { + loader := &ConfigLoader{v: v} for _, option := range options { option(loader) } return loader }
920-927: Mutating environment variables as side effect.Calling
os.Setenvto normalize path values modifies the process environment, which could have unintended side effects on other components or child processes. Consider normalizing paths during value retrieval in the config loading phase instead of mutating the environment.
838-861: Clarify precedence for duplicate environment variable bindings.Multiple bindings exist for the same config keys (e.g.,
ui.maxDashboardPageLimit→ bothUI_MAX_DASHBOARD_PAGE_LIMITandMAX_DASHBOARD_PAGE_LIMIT;auth.basic.username→ bothAUTH_BASIC_USERNAMEandBASICAUTH_USERNAME).When both legacy and new environment variables are set, the behavior depends on viper's binding order. Consider documenting which takes precedence, or logging a warning when conflicting env vars are detected.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (39)
internal/cmd/agent_executor.go(1 hunks)internal/cmd/agent_executor_test.go(1 hunks)internal/cmd/context.go(8 hunks)internal/cmd/coordinator.go(1 hunks)internal/cmd/dry.go(1 hunks)internal/cmd/exec.go(1 hunks)internal/cmd/flags.go(1 hunks)internal/cmd/restart.go(1 hunks)internal/cmd/retry.go(1 hunks)internal/cmd/scheduler.go(1 hunks)internal/cmd/start.go(1 hunks)internal/common/collections/syncmap.go(1 hunks)internal/common/config/config.go(2 hunks)internal/common/config/context.go(1 hunks)internal/common/config/context_test.go(1 hunks)internal/common/config/env.go(1 hunks)internal/common/config/env_test.go(1 hunks)internal/common/config/loader.go(15 hunks)internal/common/config/loader_test.go(12 hunks)internal/common/config/timezone_test.go(4 hunks)internal/common/config/timzone.go(1 hunks)internal/common/masking/masker.go(1 hunks)internal/common/stringutil/kv.go(2 hunks)internal/core/dag.go(1 hunks)internal/core/execution/context.go(1 hunks)internal/core/spec/builder_test.go(2 hunks)internal/core/spec/variables.go(1 hunks)internal/integration/base_dag_test.go(2 hunks)internal/integration/parallel_test.go(1 hunks)internal/runtime/agent/dbclient.go(1 hunks)internal/runtime/env.go(4 hunks)internal/runtime/env_test.go(2 hunks)internal/runtime/runner.go(2 hunks)internal/runtime/subcmd.go(1 hunks)internal/runtime/subcmd_test.go(1 hunks)internal/service/frontend/server.go(2 hunks)internal/service/scheduler/scheduler.go(1 hunks)internal/service/worker/handler_test.go(1 hunks)internal/test/helper.go(4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Backend entrypoint incmd/orchestrates the scheduler and CLI; runtime, persistence, and service layers sit underinternal/*(for exampleinternal/runtime,internal/persistence)
Keep Go filesgofmt/goimportsclean; use tabs, PascalCase for exported symbols (SchedulerClient), lowerCamelCase for locals, andErr...names for package-level errors
Repository linting relies ongolangci-lint; prefer idiomatic Go patterns, minimal global state, and structured logging helpers ininternal/common
Files:
internal/integration/base_dag_test.gointernal/runtime/agent/dbclient.gointernal/cmd/coordinator.gointernal/cmd/exec.gointernal/common/config/timezone_test.gointernal/common/config/timzone.gointernal/runtime/subcmd.gointernal/cmd/start.gointernal/runtime/env.gointernal/common/config/env_test.gointernal/cmd/agent_executor.gointernal/cmd/retry.gointernal/common/masking/masker.gointernal/cmd/agent_executor_test.gointernal/integration/parallel_test.gointernal/core/spec/builder_test.gointernal/common/stringutil/kv.gointernal/core/execution/context.gointernal/cmd/dry.gointernal/core/dag.gointernal/service/frontend/server.gointernal/service/scheduler/scheduler.gointernal/cmd/flags.gointernal/common/config/context.gointernal/cmd/scheduler.gointernal/common/collections/syncmap.gointernal/service/worker/handler_test.gointernal/runtime/subcmd_test.gointernal/common/config/context_test.gointernal/common/config/env.gointernal/common/config/config.gointernal/runtime/runner.gointernal/runtime/env_test.gointernal/core/spec/variables.gointernal/cmd/restart.gointernal/cmd/context.gointernal/test/helper.gointernal/common/config/loader_test.gointernal/common/config/loader.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Co-locate Go tests as*_test.go; favour table-driven cases and cover failure paths
Usestretchr/testify/requireand shared fixtures frominternal/testinstead of duplicating mocks
Files:
internal/integration/base_dag_test.gointernal/common/config/timezone_test.gointernal/common/config/env_test.gointernal/cmd/agent_executor_test.gointernal/integration/parallel_test.gointernal/core/spec/builder_test.gointernal/service/worker/handler_test.gointernal/runtime/subcmd_test.gointernal/common/config/context_test.gointernal/runtime/env_test.gointernal/common/config/loader_test.go
🧠 Learnings (3)
📚 Learning: 2025-12-04T10:34:17.051Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.051Z
Learning: Applies to **/*_test.go : Co-locate Go tests as `*_test.go`; favour table-driven cases and cover failure paths
Applied to files:
internal/common/config/timezone_test.gointernal/integration/parallel_test.gointernal/common/config/loader_test.go
📚 Learning: 2025-12-04T10:34:17.051Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.051Z
Learning: Applies to **/*_test.go : Use `stretchr/testify/require` and shared fixtures from `internal/test` instead of duplicating mocks
Applied to files:
internal/common/config/timezone_test.gointernal/integration/parallel_test.gointernal/common/config/context_test.gointernal/common/config/loader_test.go
📚 Learning: 2025-12-04T10:34:17.051Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.051Z
Learning: Applies to **/*.go : Backend entrypoint in `cmd/` orchestrates the scheduler and CLI; runtime, persistence, and service layers sit under `internal/*` (for example `internal/runtime`, `internal/persistence`)
Applied to files:
internal/cmd/context.go
🧬 Code graph analysis (23)
internal/integration/base_dag_test.go (1)
internal/common/config/config.go (2)
Core(53-81)Peer(286-301)
internal/cmd/coordinator.go (1)
internal/common/config/config.go (3)
Core(53-81)Peer(286-301)TLSConfig(233-237)
internal/common/config/timezone_test.go (1)
internal/common/config/config.go (1)
Core(53-81)
internal/common/config/timzone.go (1)
internal/common/config/config.go (1)
Core(53-81)
internal/runtime/subcmd.go (2)
internal/common/config/config.go (1)
Core(53-81)internal/common/config/env.go (1)
BaseEnv(9-11)
internal/cmd/start.go (1)
internal/common/config/config.go (3)
Config(9-39)Core(53-81)Peer(286-301)
internal/cmd/agent_executor.go (2)
internal/common/config/config.go (2)
Config(9-39)Core(53-81)internal/common/logger/logger.go (4)
Config(45-50)WithDebug(55-59)WithQuiet(76-80)WithFormat(62-66)
internal/cmd/retry.go (1)
internal/common/config/config.go (2)
Core(53-81)Peer(286-301)
internal/cmd/agent_executor_test.go (1)
internal/common/config/config.go (1)
Core(53-81)
internal/cmd/dry.go (1)
internal/common/config/config.go (3)
Config(9-39)Core(53-81)Peer(286-301)
internal/service/frontend/server.go (1)
internal/common/config/config.go (1)
Core(53-81)
internal/service/scheduler/scheduler.go (1)
internal/common/config/config.go (1)
Core(53-81)
internal/common/config/context.go (2)
internal/common/config/config.go (1)
Core(53-81)internal/common/config/env.go (1)
BaseEnv(9-11)
internal/cmd/scheduler.go (1)
internal/common/config/config.go (2)
Config(9-39)Core(53-81)
internal/service/worker/handler_test.go (1)
internal/common/config/config.go (1)
Core(53-81)
internal/runtime/subcmd_test.go (1)
internal/common/config/config.go (1)
Core(53-81)
internal/common/config/context_test.go (2)
internal/common/config/config.go (1)
Core(53-81)internal/common/config/env.go (1)
BaseEnv(9-11)
internal/runtime/runner.go (3)
internal/common/logger/context.go (1)
Error(50-52)internal/runtime/eval.go (1)
EvalString(14-16)internal/common/cmdutil/eval.go (1)
EvalString(126-190)
internal/runtime/env_test.go (3)
internal/runtime/env.go (1)
Env(24-54)internal/runtime/eval.go (1)
EvalString(14-16)internal/common/collections/syncmap.go (1)
SyncMap(10-14)
internal/core/spec/variables.go (1)
internal/core/spec/errors.go (1)
ErrInvalidEnvValue(27-27)
internal/cmd/context.go (3)
internal/common/config/config.go (3)
Config(9-39)Core(53-81)Peer(286-301)internal/common/config/loader.go (3)
WithService(79-83)NewConfigLoader(123-129)Service(21-21)internal/common/config/context.go (1)
WithConfig(12-14)
internal/test/helper.go (2)
internal/common/config/loader.go (1)
NewConfigLoader(123-129)internal/common/config/config.go (3)
Core(53-81)Config(9-39)Peer(286-301)
internal/common/config/loader.go (3)
internal/common/config/definition.go (1)
Definition(5-138)internal/common/config/config.go (9)
Config(9-39)Core(53-81)Peer(286-301)Server(84-121)UI(207-213)Coordinator(252-257)Scheduler(267-283)Auth(144-150)AuthToken(177-179)internal/common/config/path.go (1)
Paths(13-30)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Test on ubuntu-latest
🔇 Additional comments (61)
internal/common/stringutil/kv.go (2)
15-18: LGTM! Clean refactor tostrings.Cut.The use of
strings.Cutsimplifies the logic and correctly handles cases where no "=" delimiter exists by returning the entire string as the key.
20-26: LGTM! Correct handling of delimiter presence.The conditional return based on
foundensures that entries without "=" correctly return an empty value.internal/common/collections/syncmap.go (1)
29-32: LGTM: Improved key-value parsing withstrings.Cut.The refactor from
strings.SplitNtostrings.Cutis cleaner and more efficient. Thefoundflag properly guards against malformed entries (strings without "="), ensuring only valid key-value pairs are inserted.internal/common/masking/masker.go (1)
76-80: LGTM: Consistent use ofstrings.Cutfor env parsing.The migration to
strings.Cutis consistent with the broader refactor and improves clarity. Returning empty strings when "=" is not found is more explicit than checking array bounds.internal/runtime/agent/dbclient.go (1)
44-47: LGTM: Output variable parsing aligned with refactor.The use of
strings.Cutwith thefoundguard is consistent with the repository-wide refactor and correctly handles output variable parsing.internal/runtime/env_test.go (2)
371-372: LGTM: Test correctly usesstrings.Cutfor env parsing.The test properly mirrors the production code refactor, extracting key-value pairs and handling evaluated values.
Also applies to: 377-377
399-400: LGTM: Consistent env parsing in test setup.The test setup correctly uses
strings.Cutto parse and evaluate step environment variables, consistent with the refactor pattern.Also applies to: 406-407
internal/integration/base_dag_test.go (1)
72-72: LGTM: Config namespace migration to Core.The change from
Global.PeertoCore.Peeris consistent with the PR's config refactor objectives.Also applies to: 186-186
internal/common/config/context.go (1)
36-36: LGTM: BaseEnv access migrated to Core namespace.The change from
Global.BaseEnvtoCore.BaseEnvaligns with the config refactor and is straightforward.internal/cmd/start.go (1)
491-491: LGTM: Peer config migrated to Core namespace.The change from
Global.PeertoCore.Peeris consistent with the config refactor across the codebase.internal/cmd/dry.go (1)
102-102: LGTM: Peer config migrated to Core namespace.The change from
Global.PeertoCore.Peeraligns with the PR's config namespace refactor.internal/service/frontend/server.go (2)
75-87: Frontend funcsConfig: TZ/TzOffsetInSec now sourced from Core – consistent with new config modelSwitching
TZandTzOffsetInSectocfg.Core.*aligns this server with the newCoreconfiguration struct; types and semantics remain unchanged.
149-157: HTTP request logger now reads log format from Core.LogFormat – LGTMUsing
srv.config.Core.LogFormat == "json"to control structured logging matches the Core-based config refactor and keeps behavior equivalent to the previous Global-based check.internal/cmd/scheduler.go (1)
42-45: Scheduler logging: log-format now read from Core.LogFormat – OKThe info log during scheduler initialization correctly pulls
ctx.Config.Core.LogFormat, consistent with the new Core config struct.internal/cmd/retry.go (1)
166-183: Retry agent: peer config switched to Core.Peer – consistent with Core migrationPassing
ctx.Config.Core.Peerintoagent.Newmaintains the expected peer TLS configuration and aligns this call site with the new Core-based config API.internal/cmd/agent_executor_test.go (1)
104-115: Tests updated to use Config.Core – matches new public config structInitializing
Config.Core{Debug, LogFormat}mirrors the newconfig.Configshape and keepsconfigureLoggerForProgresstests exercising the right fields.internal/common/config/env.go (1)
40-52: Env filtering: strings.Cut-based parsing is a safe, clearer improvementUsing
strings.Cutto derivekeyand skipping entries without"="simplifies the code and avoids relying on malformed environment entries; allowed-key and prefix checks remain unchanged.internal/common/config/config.go (1)
10-12: Config API: introduction of Core field/type looks coherent with repo-wide usageDefining an exported
Corestruct and hanging it offConfig.Corecleanly encapsulates global settings (debug, log format, TZ/location, peer, base env). The field and type are well-documented and line up with all observed call sites in commands and services.Also applies to: 52-81
internal/service/scheduler/scheduler.go (1)
75-78: Scheduler time location: now taken from Core.Location – behavior preservedUsing
cfg.Core.Location(falling back totime.Localwhen nil) is consistent with the new Core config and maintains the same defaulting semantics for the scheduler.internal/cmd/restart.go (1)
150-162: Restart agent: peer config migrated to Core.Peer – consistent and correctRouting
ctx.Config.Core.Peerintoagent.Newbrings the restart flow in line with the Core-based config model without changing agent behavior.internal/cmd/exec.go (1)
165-169: LGTM! Clean refactor tostrings.Cut.The migration from
strings.SplitNtostrings.Cutis more idiomatic and improves readability. The validation logic correctly checksfound,key, andvalueto ensure proper key=value format.internal/runtime/subcmd.go (1)
29-29: LGTM! Configuration namespace migration.The change from
cfg.Global.BaseEnvtocfg.Core.BaseEnvaligns with the broader refactor migrating configuration to the Core namespace.internal/cmd/coordinator.go (1)
146-151: LGTM! TLS configuration migrated to Core namespace.The TLS configuration now correctly reads from
cfg.Core.Peer.*fields, aligning with the project-wide configuration refactor.internal/common/config/timezone_test.go (1)
14-64: LGTM! Test updated for Core-based configuration.All test cases correctly use
&Core{}instead of&Global{}, aligning with the updatedsetTimezonefunction signature.internal/core/dag.go (1)
352-355: LGTM! Cleaner parsing withstrings.Cut.The refactor from
strings.SplitNtostrings.Cutimproves readability and is more idiomatic. The behavior remains the same: only parameters containing "=" are included in the map.internal/common/config/timzone.go (1)
9-9: LGTM! Function signature updated for Core configuration.The parameter type change from
*Globalto*Corealigns with the configuration refactor. The function body remains unchanged as the required fields exist in the Core struct.internal/integration/parallel_test.go (1)
970-974: LGTM! Test helper refactored to usestrings.Cut.The parsing logic is cleaner with
strings.Cut. Thefoundflag provides explicit validation, and the code is more readable than array indexing.internal/cmd/agent_executor.go (1)
72-77: LGTM! Logger configuration updated to Core namespace.The logger configuration now correctly reads from
ctx.Config.Core.Debugandctx.Config.Core.LogFormat, consistent with the configuration refactor.internal/runtime/subcmd_test.go (1)
24-26: LGTM! Clean migration to Core-based configuration.The test correctly updates from
GlobaltoCoreconfiguration namespace, aligning with the new public API structure.internal/core/spec/variables.go (1)
38-42: LGTM! More idiomatic string parsing.The migration from
strings.SplitNtostrings.Cutis cleaner and more readable for extracting key-value pairs. Thefoundflag makes the intent explicit.internal/core/execution/context.go (1)
37-40: LGTM! Consistent key-value parsing.The
strings.Cutapproach correctly handles environment variable parsing, skipping entries without "=" delimiters. This aligns with the broader migration to Cut-based parsing across the codebase.internal/common/config/env_test.go (1)
50-53: LGTM! Test helper aligns with production code.The test correctly adopts
strings.Cutfor environment variable parsing, matching the updated production code patterns.internal/core/spec/builder_test.go (1)
3657-3660: LGTM! Consistent test updates.Both test segments correctly adopt
strings.Cutfor environment variable parsing, maintaining consistency with the broader codebase refactor.Also applies to: 3685-3688
internal/common/config/context_test.go (1)
72-72: LGTM! Correct configuration namespace update.The test properly updates from
GlobaltoCoreconfiguration, aligning with the new API structure.internal/runtime/runner.go (1)
473-490: LGTM! Improved environment variable evaluation logic.The refactor correctly:
- Uses
strings.Cutfor cleaner key-value extraction- Evaluates only the value portion (not the entire "KEY=value" string), which is the correct behavior
- Maintains proper storage format as
KEY=evaluatedValue- Adds appropriate error logging for malformed entries
This is a logical improvement over the previous approach.
internal/service/worker/handler_test.go (1)
203-205: LGTM! Test configuration updated correctly.The test properly migrates from
GlobaltoCoreconfiguration namespace, consistent with the broader refactor.internal/runtime/env.go (3)
77-82: LGTM! Clean refactor tostrings.Cut.The use of
strings.Cutis more idiomatic thanstrings.SplitNand thefoundcheck properly handles entries without an=separator.
117-121: LGTM! Consistent use ofstrings.Cutfor param parsing.The pattern correctly stores the full
paramstring (inkey=valueformat) when a separator is found, using the extracted key as the map key.
390-394: LGTM! Consistent refactor tostrings.Cut.The change aligns with the rest of the codebase and properly handles the
foundflag to skip malformed entries.internal/cmd/flags.go (1)
294-304: LGTM! Explicit Viper instance injection.Passing an explicit
*viper.Viperinstance enables per-command configuration isolation and aligns with the newConfigLoaderpattern. This improves testability and avoids global state pollution.internal/cmd/context.go (6)
60-68: LGTM! Migration toCore.*configuration paths.The logger options now correctly reference
Core.DebugandCore.LogFormatinstead of the removedGlobal.*paths.
80-81: LGTM! Isolated Viper instance for command context.Creating a fresh
viper.New()instance and passing it tobindFlagsprevents configuration leakage between commands and improves testability.
108-112: LGTM! Service-scoped configuration loading.The
serviceForCommandhelper enables loading only necessary configuration sections per command, which improves startup performance and reduces configuration coupling.
231-235: LGTM! Migration toCore.Peerfor coordinator client.The peer configuration is now correctly sourced from
Core.Peerinstead ofGlobal.Peer.
291-291: LGTM! Migration toCore.SkipExamples.The DAG store option now correctly references
Core.SkipExamples.
181-199: Verify command name coverage for service mappingCoverage is comprehensive and correct. All CLI commands are properly accounted for: infrastructure commands (server, scheduler, worker, coordinator) have explicit mappings; agent commands (start, restart, retry, dry, exec) map to ServiceAgent; queue operations (enqueue, dequeue) and utility commands (version, validate, status, stop, start-all, migrate) appropriately use the ServiceNone default, which loads all config sections. This is a safe and efficient approach.
internal/test/helper.go (4)
130-137: LGTM! Test helper migrated to new loader pattern.The test helper now creates an isolated Viper instance and uses the new
ConfigLoaderpattern. TheCore.*field assignments for timezone settings are correct.
232-238: LGTM! Config file writer usesCore.*paths.The helper config file generation correctly sources values from
Core.Debug,Core.LogFormat,Core.DefaultShell, andCore.TZ.
505-507: LGTM! Consistentstrings.Cutusage in test assertions.The parsing logic correctly uses
strings.Cutand validates that the output is inkey=valueformat before checking the value.
567-568: LGTM! Agent construction usesCore.Peer.The peer configuration is correctly sourced from
Core.Peerfor agent construction in tests.internal/common/config/loader_test.go (6)
15-29: LGTM! Well-designed test helpers.The
testLoadandtestLoadWithErrorhelpers properly uset.Helper()for better stack traces and create isolated Viper instances per test. This aligns with the newConfigLoaderpattern and prevents test pollution.Based on learnings, using
stretchr/testify/requireis the preferred approach.
142-161: LGTM! Test expectations updated forCorenamespace.The expected config structure correctly uses
Coreinstead ofGlobal, with all relevant fields (Debug,LogFormat,TZ,Location,DefaultShell,SkipExamples,Peer,BaseEnv) properly referenced.
248-256: LGTM! Path test usesCore.BaseEnv.The assertion correctly accesses
cfg.Core.BaseEnv.AsSlice()instead of the oldGlobalpath.
355-370: LGTM! YAML test expectations updated.The expected
Corestruct is correctly populated with all fields including thePeerconfiguration.
540-591: LGTM! Error case tests use new helper.All error-expecting tests now use
testLoadWithError, which provides cleaner test code and consistent error handling.
789-800: LGTM!TestBindEnv_AsPathuses explicit loader.The test now creates a
ConfigLoaderinstance and callsbindEnvironmentVariablesdirectly, aligning with the new explicit Viper instance pattern.internal/common/config/loader.go (5)
960-967: Good use ofstrings.Cutfor parsing.The refactor from manual string splitting to
strings.Cutis cleaner and more robust. The handling of empty values and whitespace trimming is appropriate.
188-242: Well-structured service-aware configuration loading.The
buildConfigmethod cleanly separates core/paths loading (always needed) from service-specific sections, with proper validation gating. The modular approach improves maintainability.
112-119: Correct bit-flag checking with sensible fallback.The
requiresmethod properly uses bitwise AND for section checking and safely falls back toSectionAllfor unknown services.
131-186: Clean configuration loading flow with isolated viper instance.The
Loadmethod properly uses the isolated viper instance (l.v) throughout, handles missing config files gracefully, and maintains backward compatibility withadmin.yamlmerging.
49-57: ConfigLoader struct with isolated viper instance is well-designed.The introduction of an isolated viper instance (
v *viper.Viper) in theConfigLoaderstruct enables better testability and avoids global state issues. The service field enables selective configuration loading.
| // validateUIConfig validates the UI configuration. | ||
| func (l *ConfigLoader) validateUIConfig(cfg *Config) error { | ||
| if cfg.UI.MaxDashboardPageLimit < 1 { | ||
| return fmt.Errorf("invalid max dashboard page limit: %d", cfg.UI.MaxDashboardPageLimit) | ||
| } | ||
| return nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validation may fail for default configurations.
validateUIConfig requires MaxDashboardPageLimit >= 1, but loadUIConfig only sets this field when def.UI != nil. If the UI section is absent from the config file, cfg.UI.MaxDashboardPageLimit remains 0 (the zero value), causing validation to fail despite a viper default of 100 being set.
Consider setting the default directly on cfg.UI.MaxDashboardPageLimit before or after the if def.UI != nil block in loadUIConfig, or use l.v.GetInt("ui.maxDashboardPageLimit") to retrieve the defaulted value.
// loadUIConfig loads the UI configuration.
func (l *ConfigLoader) loadUIConfig(cfg *Config, def Definition) {
+ // Apply defaults from viper (these include the configured defaults)
+ cfg.UI.MaxDashboardPageLimit = l.v.GetInt("ui.maxDashboardPageLimit")
+ cfg.UI.NavbarTitle = l.v.GetString("ui.navbarTitle")
+ cfg.UI.LogEncodingCharset = l.v.GetString("ui.logEncodingCharset")
+
if def.UI != nil {
cfg.UI.NavbarColor = def.UI.NavbarColor
- cfg.UI.NavbarTitle = def.UI.NavbarTitle
- cfg.UI.MaxDashboardPageLimit = def.UI.MaxDashboardPageLimit
- cfg.UI.LogEncodingCharset = def.UI.LogEncodingCharset
+ if def.UI.NavbarTitle != "" {
+ cfg.UI.NavbarTitle = def.UI.NavbarTitle
+ }
+ if def.UI.MaxDashboardPageLimit > 0 {
+ cfg.UI.MaxDashboardPageLimit = def.UI.MaxDashboardPageLimit
+ }
+ if def.UI.LogEncodingCharset != "" {
+ cfg.UI.LogEncodingCharset = def.UI.LogEncodingCharset
+ }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
internal/common/config/loader.go around lines 431-437: validateUIConfig fails
when cfg.UI is nil because cfg.UI.MaxDashboardPageLimit stays at the Go zero
value (0) even though viper has a default; fix loadUIConfig to ensure cfg.UI is
non-nil and assign the defaulted value into cfg.UI.MaxDashboardPageLimit (e.g.,
if cfg.UI == nil { cfg.UI = &UIConfig{} } and set cfg.UI.MaxDashboardPageLimit =
l.v.GetInt("ui.maxDashboardPageLimit") or set it after the def.UI block), so
validation no longer rejects configs that rely on the viper default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/common/config/loader.go (1)
516-559: ZombieDetectionInterval default is skipped on invalid user valuesIn
loadSchedulerConfig, the default forcfg.Scheduler.ZombieDetectionIntervalis only applied when the value is zero and!l.v.IsSet("scheduler.zombieDetectionInterval"). If the user sets an invalid duration (parse error),IsSetwill be true, the field will stay at its zero value, and the 45s default will never be applied, unlike the other scheduler durations which always fall back when<=0.To make behavior consistent and more forgiving of invalid values, consider aligning this with the other scheduler fields, e.g.:
- if cfg.Scheduler.ZombieDetectionInterval == 0 && !l.v.IsSet("scheduler.zombieDetectionInterval") { - cfg.Scheduler.ZombieDetectionInterval = 45 * time.Second - } + if cfg.Scheduler.ZombieDetectionInterval <= 0 { + cfg.Scheduler.ZombieDetectionInterval = 45 * time.Second + }This way, parse failures or explicitly zero values both get a sane default instead of silently leaving the interval at 0.
🧹 Nitpick comments (2)
internal/common/config/loader.go (2)
18-47: Service/section modeling and gating look solidThe
Serviceenum,ConfigSectionbitflags,serviceRequirementsmap, andrequireshelper form a clean, understandable way to gate which sections load per service; comments match the actual masks, and defaulting unknown services toSectionAllis a safe fallback for CLI-style entrypoints.One minor robustness tweak you might consider: guard against a nil
*viper.ViperinNewConfigLoader(e.g., instantiate a new one or panic with a clear message), to avoid a potential nil dereference if a caller misuses the constructor.Also applies to: 76-83, 85-120, 121-129
614-675: Legacy handling and env binding are well-scoped; minor consistency nit on path envsThe combination of
LoadLegacyFields,loadLegacyEnv,envBindings, andbindEnvironmentVariablesgives a clear, service-aware story for both legacy and current config inputs, and the default seeding insetViperDefaultValuesmatches how the section loaders consume values.One small consistency gap: the legacy path env mappings (e.g.
DAGU__DATA,DAGU__SUSPEND_FLAGS_DIR,DAGU__ADMIN_LOGS_DIR) inloadLegacyEnvassign raw strings intocfg.Paths.*, whereas the newer env bindings for file paths go through absolute-path normalization. If you want fully uniform behavior, you could optionally wrap those legacy setters with the same normalization (or reusefileutil.ResolvePathOrBlank), while keeping the existing deprecation warnings.Also applies to: 677-741, 743-760, 762-813, 815-928, 930-948, 950-962
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
internal/common/config/loader.go(15 hunks)internal/runtime/env.go(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- internal/runtime/env.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Backend entrypoint incmd/orchestrates the scheduler and CLI; runtime, persistence, and service layers sit underinternal/*(for exampleinternal/runtime,internal/persistence)
Keep Go filesgofmt/goimportsclean; use tabs, PascalCase for exported symbols (SchedulerClient), lowerCamelCase for locals, andErr...names for package-level errors
Repository linting relies ongolangci-lint; prefer idiomatic Go patterns, minimal global state, and structured logging helpers ininternal/common
Files:
internal/common/config/loader.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Test on ubuntu-latest
🔇 Additional comments (4)
internal/common/config/loader.go (4)
131-186: Config loading pipeline is cohesive and service-awareThe
Load→buildConfigflow is well-structured: viper setup, config file/admin merge, unmarshal intoDefinition, then per-section loaders gated viarequires(), followed by legacy handling, path finalization, and targeted validation. Always loading core+paths while gating the rest aligns with theService/ConfigSectionmodel, and timezone initialization errors are surfaced clearly.No functional issues stand out in this part.
Also applies to: 188-242, 244-275, 277-293
295-401: Server and auth configuration handling is thoroughThe server loader and validator cover the main edge cases (permissions overrides, optional TLS, legacy vs. new auth settings, TTL parsing with warnings, OIDC auto-detection) and normalize
BasePathviacleanServerBasePathin a predictable way. The validation checks are appropriate and avoid over-constraining the config.No changes needed here from a correctness perspective.
Also applies to: 403-415, 990-1008
416-454: Section-specific loaders and defaults are generally well-behavedUI, queues, coordinator, worker, monitoring, and path finalization logic all look consistent and robust. In particular, seeding
cfg.UIfrom viper defaults before applyingdef.UIfixes the prior default/validation mismatch, andparseWorkerLabelsplus the map-based cases give good flexibility for worker labels while ignoring malformed entries safely.Also applies to: 456-472, 474-514, 516-559, 561-587, 589-612
964-987: Worker label parsing is robust
parseWorkerLabels’ use of trimming, skipping empty segments, andstrings.Cutto only split on the first=yields predictable label maps and tolerates messy input without panicking or mis-parsing values containing=.Looks good as-is.
|
@coderabbitai generate docstrings |
✅ Actions performedInitiated docstring generation; will generate only if new commits exist. |
|
Note Docstrings generation - SUCCESS |
Docstrings generation was requested by @yottahmd. * #1467 (comment) The following files were modified: * `internal/cmd/agent_executor.go` * `internal/cmd/context.go` * `internal/cmd/coordinator.go` * `internal/cmd/dry.go` * `internal/cmd/exec.go` * `internal/cmd/flags.go` * `internal/cmd/restart.go` * `internal/cmd/retry.go` * `internal/cmd/scheduler.go` * `internal/cmd/start.go` * `internal/common/config/context.go` * `internal/common/config/env.go` * `internal/common/config/loader.go` * `internal/common/config/timzone.go` * `internal/common/masking/masker.go` * `internal/common/stringutil/kv.go` * `internal/core/spec/variables.go` * `internal/runtime/env.go` * `internal/runtime/subcmd.go` * `internal/service/frontend/server.go` * `internal/service/scheduler/scheduler.go` * `internal/test/helper.go`
Docstrings generation was requested by @yottahmd. * #1467 (comment) The following files were modified: * `internal/cmd/agent_executor.go` * `internal/cmd/context.go` * `internal/cmd/coordinator.go` * `internal/cmd/dry.go` * `internal/cmd/exec.go` * `internal/cmd/flags.go` * `internal/cmd/restart.go` * `internal/cmd/retry.go` * `internal/cmd/scheduler.go` * `internal/cmd/start.go` * `internal/common/config/context.go` * `internal/common/config/env.go` * `internal/common/config/loader.go` * `internal/common/config/timzone.go` * `internal/common/masking/masker.go` * `internal/common/stringutil/kv.go` * `internal/core/spec/variables.go` * `internal/runtime/env.go` * `internal/runtime/subcmd.go` * `internal/service/frontend/server.go` * `internal/service/scheduler/scheduler.go` * `internal/test/helper.go` <details> <summary>These files were ignored</summary> * `internal/cmd/agent_executor_test.go` * `internal/common/config/context_test.go` * `internal/common/config/env_test.go` * `internal/common/config/loader_test.go` * `internal/common/config/timezone_test.go` * `internal/core/spec/builder_test.go` * `internal/integration/base_dag_test.go` * `internal/integration/parallel_test.go` * `internal/runtime/env_test.go` * `internal/runtime/subcmd_test.go` * `internal/service/worker/handler_test.go` </details> <details> <summary>ℹ️ Note</summary><blockquote> CodeRabbit cannot perform edits on its own pull requests yet. </blockquote></details> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/runtime/env.go (1)
71-71: Update comment to reflect actual precedence.The comment states
Step.Env > Envs > Variables > ..., implying Step.Env has the highest precedence. However, the implementation at lines 98-100 gives Step.Env the lowest precedence—it's only added if the key doesn't already exist. The comment on lines 89-92 correctly clarifies this is intentional to avoid overwriting evaluated values with raw placeholders.Apply this diff to correct the precedence order:
-// Precedence: Step.Env > Envs > Variables > SecretEnvs > DAGContext.Envs > DAG.Env +// Precedence: Envs > Variables > SecretEnvs > DAGContext.Envs > DAG.Env > Step.Env
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
internal/common/config/loader.go(15 hunks)internal/runtime/env.go(4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Backend entrypoint incmd/orchestrates the scheduler and CLI; runtime, persistence, and service layers sit underinternal/*(for exampleinternal/runtime,internal/persistence)
Keep Go filesgofmt/goimportsclean; use tabs, PascalCase for exported symbols (SchedulerClient), lowerCamelCase for locals, andErr...names for package-level errors
Repository linting relies ongolangci-lint; prefer idiomatic Go patterns, minimal global state, and structured logging helpers ininternal/common
Files:
internal/runtime/env.gointernal/common/config/loader.go
🧬 Code graph analysis (2)
internal/runtime/env.go (1)
internal/core/step.go (1)
Step(13-77)
internal/common/config/loader.go (5)
internal/common/config/definition.go (1)
Definition(5-138)internal/common/config/config.go (9)
Config(9-39)Core(53-81)Peer(286-301)Server(84-121)UI(207-213)Coordinator(252-257)Scheduler(267-283)Auth(144-150)AuthToken(177-179)internal/common/config/env.go (1)
BaseEnv(9-11)internal/common/config/path.go (1)
Paths(13-30)internal/common/fileutil/fileutil.go (1)
ResolvePathOrBlank(187-194)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Test on ubuntu-latest
🔇 Additional comments (9)
internal/runtime/env.go (4)
77-80: LGTM: Clean migration tostrings.Cut.The use of
strings.Cutis more idiomatic thanstrings.SplitNfor parsing "key=value" strings. It clearly signals intent with thefoundboolean and handles edge cases correctly (empty values, values containing "=", missing separators).
94-101: LGTM: Correct use ofstrings.Cutwith precedence check.The migration to
strings.Cutis correct, and the exists check (line 98) properly implements the lower precedence for Step.Env as clarified in the comments above.
120-123: LGTM: Consistentstrings.Cutusage for DAG params.The migration is correct. Storing the entire
paramstring (line 122) is consistent with how Variables is used throughout the codebase—values are expected in "key=value" format (see line 63 and line 77).
393-396: LGTM: Cleanstrings.Cutmigration.The migration is correct and follows the same safe pattern as the other changes in this file.
internal/common/config/loader.go (5)
18-119: Excellent service-aware loading architecture!The introduction of
ServiceandConfigSectiontypes with the requirements mapping creates a clean, efficient system for loading only necessary configuration. The bit flag approach forConfigSectionis idiomatic and performant, and therequires()method provides a safe API with sensible fallback toSectionAllfor unknown services.The architecture correctly handles Core and Paths as always-loaded sections (confirmed in
buildConfiglines 193-197), while other sections load conditionally based on service requirements.
188-242: Well-structured configuration pipeline!The refactored
buildConfigmethod implements a clear, maintainable pipeline:
- Always loads Core and Paths (required by all services)
- Conditionally loads service-specific sections using the
requires()API- Applies legacy field and environment overrides
- Finalizes derived paths
- Validates only the loaded sections
This modular approach improves both performance and code clarity.
416-454: UI config loading correctly fixed!The refactored
loadUIConfignow properly handles the case where the UI section is absent from the config file:
- Lines 418-423 explicitly retrieve viper defaults BEFORE checking
def.UI- Lines 427-443 only override defaults when explicit values are provided
- Validation at line 450 now passes even when the UI section is absent, as
MaxDashboardPageLimitcorrectly defaults to 100 (set via viper on line 795)This resolves the previous validation issue mentioned in past reviews.
933-951: Note: Path normalization mutates environment variables.Lines 942-946 normalize relative paths in environment variables to absolute paths and update the environment variables using
os.Setenv:if b.isPath { if val := os.Getenv(fullEnv); val != "" { if abs, err := filepath.Abs(val); err == nil && abs != val { _ = os.Setenv(fullEnv, abs) } } }This ensures consistency but has the side effect that any code reading these environment variables after configuration loading will see the normalized absolute paths rather than the original values. This behavior is acceptable for internal configuration loading but is worth noting for maintainability.
967-991: Excellent use ofstrings.Cutfor label parsing!The refactored
parseWorkerLabelsusesstrings.Cutinstead ofstrings.SplitN, which is cleaner and more idiomatic:key, value, found := strings.Cut(pair, "=") if found { key = strings.TrimSpace(key) value = strings.TrimSpace(value) if key != "" { labels[key] = value } }This correctly handles all edge cases:
"key=value"→labels["key"] = "value""key="→labels["key"] = ""(allows empty values)"key"(no=) → skipped"=value"→ skipped (empty key rejected)- Whitespace trimmed appropriately
The implementation is robust and aligns with the PR objectives of standardizing to
strings.Cut.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/core/spec/variables.go (1)
56-60: Critical: Duplicate parsing ofmap[string]anyentries.This block is redundant and causes a bug. The
switchstatement at lines 42-45 already handlesmap[string]anyentries by callingparseKeyValue. This post-switchifblock then checks the same condition and callsparseKeyValueagain, resulting in every map entry's key-value pairs being added twice to thepairsslice.This will cause duplicate environment variables to be processed.
Remove the redundant block:
pairs = append(pairs, pair{key: key, val: val}) default: return nil, core.NewValidationError("env", &pairs, fmt.Errorf("%w: %s", ErrInvalidEnvValue, v)) } - if aa, ok := v.(map[string]any); ok { - if err := parseKeyValue(aa, &pairs); err != nil { - return nil, core.NewValidationError("env", v, err) - } - } }
🧹 Nitpick comments (6)
internal/cmd/context.go (2)
76-78: Docstring has redundant opening line.Line 76 repeats the function name and purpose already stated on line 75. The multi-line docstring should flow as a single coherent description.
// NewContext initializes the application setup by loading configuration, -// NewContext creates and initializes an application Context for the given Cobra command. -// It binds command flags, loads configuration scoped to the command, configures logging (respecting debug, quiet, and log format settings), logs any configuration warnings, and initializes history, DAG run, proc, queue, and service registry stores and managers used by the application. -// NewContext returns an initialized Context or an error if flag retrieval, configuration loading, or other initialization steps fail. +// binding command flags, loading configuration scoped to the command, configuring logging +// (respecting debug, quiet, and log format settings), logging any configuration warnings, +// and initializing history, DAG run, proc, queue, and service registry stores and managers. +// It returns an initialized Context or an error if any initialization step fails.
183-204: Docstring is redundant and verbose.Lines 183-187 repeat the function name and duplicate what the code already clearly expresses. Consider a concise one-liner docstring.
-// serviceForCommand returns the appropriate config.Service type for a given command name. -// serviceForCommand determines which config.Service to load for a given command name. -// "server" -> ServiceServer, "scheduler" -> ServiceScheduler, "worker" -> ServiceWorker, -// "coordinator" -> ServiceCoordinator, and "start", "restart", "retry", "dry", "exec" -> ServiceAgent. -// For any other command it returns ServiceNone so all configuration sections are loaded. +// serviceForCommand maps a command name to its required config.Service type. func serviceForCommand(cmdName string) config.Service {internal/test/helper.go (2)
78-80: Docstring is verbose; consider trimming.The Setup docstring spans multiple detailed sentences. A shorter summary with key points would improve readability.
229-232: Docstring is overly detailed.Consider a one-liner:
// writeHelperConfigFile writes a minimal YAML config for subprocess use.internal/common/config/loader.go (2)
77-84: Incomplete docstring on line 79.Line 79 appears truncated:
// ConfigLoader to determine which configuration sections to load.This seems like a leftover from editing.// WithService sets the service type for configuration loading. // This allows the loader to only process configuration sections -// ConfigLoader to determine which configuration sections to load. +// relevant to the specific service. func WithService(service Service) ConfigLoaderOption {
122-124: Incomplete docstring on line 123.Line 123 is truncated:
// ConfigLoaderOption values (for example: service, config file path, or app home directory).// NewConfigLoader creates a new ConfigLoader instance with an isolated viper instance -// ConfigLoaderOption values (for example: service, config file path, or app home directory). +// and applies the given options (e.g., service type, config file path, app home directory). func NewConfigLoader(viper *viper.Viper, options ...ConfigLoaderOption) *ConfigLoader {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (22)
internal/cmd/agent_executor.go(1 hunks)internal/cmd/context.go(8 hunks)internal/cmd/coordinator.go(2 hunks)internal/cmd/dry.go(2 hunks)internal/cmd/exec.go(2 hunks)internal/cmd/flags.go(2 hunks)internal/cmd/restart.go(2 hunks)internal/cmd/retry.go(2 hunks)internal/cmd/scheduler.go(1 hunks)internal/cmd/start.go(2 hunks)internal/common/config/context.go(1 hunks)internal/common/config/env.go(1 hunks)internal/common/config/loader.go(15 hunks)internal/common/config/timzone.go(1 hunks)internal/common/masking/masker.go(1 hunks)internal/common/stringutil/kv.go(2 hunks)internal/core/spec/variables.go(2 hunks)internal/runtime/env.go(4 hunks)internal/runtime/subcmd.go(1 hunks)internal/service/frontend/server.go(3 hunks)internal/service/scheduler/scheduler.go(2 hunks)internal/test/helper.go(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (11)
- internal/service/scheduler/scheduler.go
- internal/common/config/timzone.go
- internal/runtime/subcmd.go
- internal/service/frontend/server.go
- internal/common/config/context.go
- internal/cmd/dry.go
- internal/common/config/env.go
- internal/cmd/scheduler.go
- internal/runtime/env.go
- internal/cmd/restart.go
- internal/cmd/coordinator.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Backend entrypoint incmd/orchestrates the scheduler and CLI; runtime, persistence, and service layers sit underinternal/*(for exampleinternal/runtime,internal/persistence)
Keep Go filesgofmt/goimportsclean; use tabs, PascalCase for exported symbols (SchedulerClient), lowerCamelCase for locals, andErr...names for package-level errors
Repository linting relies ongolangci-lint; prefer idiomatic Go patterns, minimal global state, and structured logging helpers ininternal/common
Files:
internal/common/masking/masker.gointernal/cmd/flags.gointernal/test/helper.gointernal/cmd/start.gointernal/cmd/exec.gointernal/cmd/context.gointernal/common/stringutil/kv.gointernal/common/config/loader.gointernal/cmd/retry.gointernal/core/spec/variables.gointernal/cmd/agent_executor.go
🧠 Learnings (2)
📚 Learning: 2025-12-04T10:34:17.051Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.051Z
Learning: Applies to **/*.go : Keep Go files `gofmt`/`goimports` clean; use tabs, PascalCase for exported symbols (`SchedulerClient`), lowerCamelCase for locals, and `Err...` names for package-level errors
Applied to files:
internal/test/helper.go
📚 Learning: 2025-12-04T10:34:17.051Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.051Z
Learning: Applies to **/*.go : Backend entrypoint in `cmd/` orchestrates the scheduler and CLI; runtime, persistence, and service layers sit under `internal/*` (for example `internal/runtime`, `internal/persistence`)
Applied to files:
internal/cmd/context.go
🧬 Code graph analysis (7)
internal/test/helper.go (2)
internal/common/config/loader.go (1)
NewConfigLoader(124-130)internal/common/config/config.go (3)
Core(53-81)Config(9-39)Peer(286-301)
internal/cmd/start.go (1)
internal/common/config/config.go (2)
Core(53-81)Peer(286-301)
internal/cmd/context.go (3)
internal/common/config/config.go (3)
Config(9-39)Core(53-81)Peer(286-301)internal/common/logger/logger.go (3)
Config(45-50)WithFormat(62-66)Option(52-52)internal/common/config/loader.go (3)
WithService(80-84)NewConfigLoader(124-130)Service(21-21)
internal/common/config/loader.go (5)
internal/common/config/definition.go (1)
Definition(5-138)internal/common/config/config.go (9)
Config(9-39)Core(53-81)Peer(286-301)Server(84-121)UI(207-213)Coordinator(252-257)Scheduler(267-283)Auth(144-150)AuthToken(177-179)internal/common/config/env.go (2)
LoadBaseEnv(31-33)BaseEnv(9-11)internal/common/config/path.go (1)
Paths(13-30)internal/common/fileutil/fileutil.go (1)
ResolvePathOrBlank(187-194)
internal/cmd/retry.go (1)
internal/common/config/config.go (2)
Core(53-81)Peer(286-301)
internal/core/spec/variables.go (1)
internal/core/spec/errors.go (1)
ErrInvalidEnvValue(27-27)
internal/cmd/agent_executor.go (3)
internal/cmd/context.go (1)
Context(40-55)internal/common/logger/logger.go (5)
Option(52-52)Config(45-50)WithDebug(55-59)WithQuiet(76-80)WithFormat(62-66)internal/common/config/config.go (2)
Config(9-39)Core(53-81)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Test on ubuntu-latest
🔇 Additional comments (31)
internal/core/spec/variables.go (2)
16-26: LGTM! Comprehensive docstring.The updated docstring clearly documents the function's parameters, behavior (including command substitution and variable expansion), and error conditions.
48-52: LGTM! Clean migration tostrings.Cut.The change from
strings.SplitNtostrings.Cutis correct and more idiomatic. Thefoundboolean properly indicates whether the separator was present.internal/common/masking/masker.go (1)
74-82: LGTM! Clean migration tostrings.Cut.The refactored
splitEnvfunction correctly usesstrings.Cutto split on the first '=' and safely handles entries without '=' by returning two empty strings. The caller at line 27 properly handles this by skipping empty values at line 30.internal/common/stringutil/kv.go (2)
17-20: LGTM! Correct use ofstrings.Cut.The
Key()method correctly usesstrings.Cutto extract the key portion before the first '='.
22-28: LGTM! Proper handling of entries without '='.The
Value()method correctly usesstrings.Cutwith thefoundflag to return an empty string when '=' is not present.internal/cmd/agent_executor.go (1)
72-78: LGTM!The migration from
ctx.Config.Global.Debugandctx.Config.Global.LogFormattoctx.Config.Core.Debugandctx.Config.Core.LogFormatis consistent with the Core struct definition. The logic remains unchanged.internal/cmd/start.go (2)
460-469: Well-documented function.The new docstring for
executeDAGRunis comprehensive—it clearly describes the initialization flow, log file handling, DAG store setup, agent construction, and error scenarios.
500-500: LGTM!The change from
ctx.Config.Global.Peertoctx.Config.Core.Peeris consistent with the Core struct definition and the overall config migration in this PR.internal/cmd/exec.go (2)
65-72: Well-documented function.The new docstring for
runExeccomprehensively describes the function's responsibilities including flag parsing, validation, DAG building, and execution/enqueueing logic.
173-178: LGTM! Improved parsing withstrings.Cut.Using
strings.Cutis more idiomatic for Go 1.18+ and correctly handles edge cases:
- Missing
=separator- Empty key (e.g.,
=value)- Empty value (e.g.,
key=)internal/cmd/retry.go (2)
140-143: Well-documented function.The docstring for
executeRetryclearly describes the setup steps (log file, environment, DAG store, agent configuration) and the delegation to the shared executor.
180-180: LGTM!The change from
ctx.Config.Global.Peertoctx.Config.Core.Peeris consistent with the Core struct definition and aligns with the same change instart.goand other files.internal/cmd/flags.go (2)
279-295: LGTM!The
initFlagsfunction is well-structured with clear separation of concerns:
- Always includes base flags (config, dagu-home, quiet, cpu-profile)
- Properly handles boolean vs string flag registration
- Marks required flags appropriately
297-311: LGTM! Thread-safe explicit Viper binding.The updated
bindFlagsfunction:
- Takes an explicit
*viper.Viperinstance for better testability and per-service config isolation- Uses
config.WithViperLockfor thread-safe registration- Converts kebab-case flag names to camelCase keys via
stringutil.KebabToCamel- Only binds flags with
bindViper: true, which is the correct subsetinternal/cmd/context.go (4)
82-83: Good use of isolated viper instance per context.Creating a dedicated viper instance and binding flags explicitly avoids global state pollution across commands. This aligns well with the refactor goals.
60-68: Core field migration looks correct.References to
c.Config.Core.Debugandc.Config.Core.LogFormatalign with the new Core-based configuration structure.
236-240: Coordinator client config correctly uses Core.Peer.The migration from
Global.PeertoCore.Peerfor TLS/connection settings is consistent with the broader refactor.
188-204: Mapping is intentionally partial with a safe fallback.The switch statement explicitly maps performance-critical services:
server,scheduler,worker,coordinator, and agent commands (start,restart,retry,dry,exec). All other commands—includingstop,status,start-all,migrate,enqueue,dequeue, andversion—fall back toServiceNone, which loads all config sections. This is functionally correct and safe; commands get everything they might need rather than failing on missing configuration.If optimization is desired later, commands like
status,stop, andversioncould benefit from lighter service profiles (e.g.,ServiceMinimalskipping Queues). However, this is not necessary; the current approach is straightforward and maintainable.internal/test/helper.go (5)
132-134: Correct use of isolated viper instance in tests.Creating a fresh viper instance per test avoids cross-test contamination, mirroring the production pattern in
NewContext.
137-139: Core field assignments are correct.Setting
cfg.Core.TZ,cfg.Core.Location, andcfg.Core.TzOffsetInSecaligns with the Core-based config structure.
237-243: Core-based field references in config file writer are correct.The fields
cfg.Core.Debug,cfg.Core.LogFormat,cfg.Core.DefaultShell, andcfg.Core.TZare correctly sourced from the Core struct.
510-512: Good use ofstrings.Cutfor key=value parsing.Using
strings.Cutwith a presence check (found) is cleaner and more idiomatic thanstrings.SplitNwith length checks.
572-572: Agent construction correctly uses Core.Peer.Passing
d.Config.Core.Peeraligns with the Core-based configuration migration.internal/common/config/loader.go (8)
18-47: Service type and constants are well-documented.The Service enum with clear docstrings for each service type improves code clarity. The comments now correctly reference "Core" instead of "Global".
89-101: Bit flag comments are now correct.The inline comments (
// 2,// 4, etc.) now match the actual values afteriotaincrement fromSectionNone = 0. Previous review feedback has been addressed.
417-455: UI config default loading issue addressed.The
loadUIConfignow retrieves defaults vial.v.GetInt("ui.maxDashboardPageLimit")and similar calls before applyingdef.UIoverrides. This addresses the previous review concern about validation failing when the UI section is absent.
557-562: ZombieDetectionInterval silent-disable behavior remains.Per the past review comment: if a user provides an invalid duration string (e.g.,
"invalid"), parsing fails, a warning is logged, butIsSet()returns true, so the default (45s) is not applied. This silently disables zombie detection rather than failing validation.The current behavior is documented in comments (lines 557-559), but consider whether this is the intended UX—invalid config silently disabling a feature could be surprising. The alternative is to return a validation error for unparseable durations.
Is the current "warn but disable" behavior intentional for
zombieDetectionInterval? If so, document this in user-facing config documentation. If not, consider returning an error on parse failure to prevent misconfiguration.
819-824:envBindingstruct is clear and well-documented.The declarative binding approach with
isPathflag for path normalization is clean and maintainable.
934-952: Environment variable binding with path normalization is correct.The loop correctly applies path normalization before binding and uses the loader's isolated viper instance.
968-994:parseWorkerLabelsusesstrings.Cutcorrectly.The function properly handles the
key=valueformat, trims whitespace, and skips empty keys. The use ofstrings.Cutis more idiomatic thanSplitN.
860-863: Duplicate environment bindings for legacy UI keys.Lines 860-863 duplicate bindings for
ui.maxDashboardPageLimit,ui.logEncodingCharset,ui.navbarColor, andui.navbarTitlewith legacy env var names. This is intentional for backward compatibility, but note that viper will use the last bound env var if multiple are set simultaneously. Document this precedence if it matters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
internal/common/stringutil/kv.go (1)
11-16: Implement the documented validation: panic when key contains '='.The documentation on line 12 states "The key must not contain '=' characters" but the implementation doesn't enforce this constraint. The test in
kv_test.go(lines 32-40) expects a panic for this case, which will cause test failures.Apply this diff to add the validation:
func NewKeyValue(key, value string) KeyValue { + if strings.Contains(key, "=") { + panic("stringutil: NewKeyValue: key must not contain '=' character") + } return KeyValue(key + "=" + value) }This aligns with the documented contract and ensures round-trip correctness with
Key()andValue().
🧹 Nitpick comments (1)
internal/common/config/loader.go (1)
77-84: Minor comment wording issue.The comment on lines 78-79 appears to have duplicated or fragmented text: "This allows the loader to only process configuration sections / ConfigLoader to determine which configuration sections to load." Consider clarifying:
Apply this diff to improve clarity:
-// WithService sets the service type for configuration loading. -// This allows the loader to only process configuration sections -// ConfigLoader to determine which configuration sections to load. +// WithService sets the service type for configuration loading, +// allowing the loader to only process configuration sections required by that service. func WithService(service Service) ConfigLoaderOption {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
internal/cmd/agent_executor.go(1 hunks)internal/common/config/loader.go(15 hunks)internal/common/stringutil/kv.go(2 hunks)internal/common/stringutil/kv_test.go(7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Backend entrypoint incmd/orchestrates the scheduler and CLI; runtime, persistence, and service layers sit underinternal/*(for exampleinternal/runtime,internal/persistence)
Keep Go filesgofmt/goimportsclean; use tabs, PascalCase for exported symbols (SchedulerClient), lowerCamelCase for locals, andErr...names for package-level errors
Repository linting relies ongolangci-lint; prefer idiomatic Go patterns, minimal global state, and structured logging helpers ininternal/common
Files:
internal/common/stringutil/kv_test.gointernal/common/stringutil/kv.gointernal/common/config/loader.gointernal/cmd/agent_executor.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Co-locate Go tests as*_test.go; favour table-driven cases and cover failure paths
Usestretchr/testify/requireand shared fixtures frominternal/testinstead of duplicating mocks
Files:
internal/common/stringutil/kv_test.go
🧠 Learnings (3)
📚 Learning: 2025-12-04T10:34:17.051Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.051Z
Learning: Applies to **/*_test.go : Co-locate Go tests as `*_test.go`; favour table-driven cases and cover failure paths
Applied to files:
internal/common/stringutil/kv_test.go
📚 Learning: 2025-12-04T10:34:17.051Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.051Z
Learning: Applies to **/*_test.go : Use `stretchr/testify/require` and shared fixtures from `internal/test` instead of duplicating mocks
Applied to files:
internal/common/stringutil/kv_test.go
📚 Learning: 2025-12-04T10:34:17.051Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.051Z
Learning: `make test` (or `make test-coverage`) executes the Go suite via `gotestsum`; append `TEST_TARGET=./internal/...` to focus packages
Applied to files:
internal/common/stringutil/kv_test.go
🧬 Code graph analysis (3)
internal/common/stringutil/kv_test.go (1)
internal/common/stringutil/kv.go (1)
NewKeyValue(14-16)
internal/common/stringutil/kv.go (1)
internal/common/logger/tag/tag.go (2)
Key(369-371)Value(364-366)
internal/cmd/agent_executor.go (3)
internal/cmd/context.go (1)
Context(40-55)internal/common/logger/logger.go (5)
Option(52-52)Config(45-50)WithDebug(55-59)WithQuiet(76-80)WithFormat(62-66)internal/common/config/config.go (2)
Config(9-39)Core(53-81)
🪛 GitHub Check: Go Linter
internal/common/stringutil/kv_test.go
[failure] 39-39:
SA4017: NewKeyValue doesn't have side effects and its return value is ignored (staticcheck)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Test on ubuntu-latest
🔇 Additional comments (21)
internal/common/stringutil/kv_test.go (3)
11-11: LGTM! Parallelization enhances test performance.The addition of
t.Parallel()to the test functions and subtests follows Go testing best practices and will improve test execution speed.As per coding guidelines, table-driven tests with parallel execution are encouraged.
Also applies to: 14-14, 22-22, 33-33, 43-43, 129-129, 147-147, 183-183, 209-209, 219-219, 303-303
21-30: LGTM! Test correctly validates multi-equals handling in values.This test case properly verifies that when a value contains '=' characters,
Key()andValue()correctly split only on the first '=' separator.
42-53: LGTM! Round-trip test validates correctness.This test confirms that a key-value pair constructed with
NewKeyValuecan be correctly retrieved viaKey()andValue()methods, ensuring round-trip integrity.internal/common/stringutil/kv.go (3)
18-21: LGTM! Cut-based parsing simplifies Key extraction.The refactoring from
strings.SplitNtostrings.Cutcorrectly extracts the key (substring before the first '='). For entries without '=', it returns the entire string, which matches the documented behavior.
23-29: LGTM! Cut-based parsing handles multi-equals correctly.The
strings.Cutapproach properly extracts everything after the first '=' as the value, correctly handling cases where the value itself contains '=' characters (e.g., "foo=bar=baz" returns "bar=baz").
56-69: LGTM! Clear documentation and correct Cut-based implementation.The updated documentation (lines 56-59) accurately describes the behavior:
- Splits at first '='
- Skips entries without '='
- Allows empty values and empty keys
The implementation correctly uses
strings.Cutand thefoundreturn value to skip invalid entries.internal/cmd/agent_executor.go (2)
69-70: Comment properly updated.The function comment now correctly describes the purpose and behavior of
configureLoggerForProgress. Good improvement from the previous truncated version.
73-73: LGTM: Refactored to use Core configuration.The changes correctly update the configuration access from
GlobaltoCore, aligning with the PR's refactoring objectives.Also applies to: 77-78
internal/common/config/loader.go (13)
18-47: LGTM: Well-documented service-aware configuration design.The service type enumeration and associated documentation clearly explain which configuration sections each service requires. This selective loading approach should improve performance and reduce unnecessary processing.
86-101: LGTM: Bit flag values correctly documented.The inline comments now accurately reflect the computed bit flag values. The use of bit flags for configuration sections is appropriate for efficient OR-based membership checks.
103-120: LGTM: Service requirements correctly implemented.The
serviceRequirementsmap andrequires()method correctly implement the service-to-section membership logic using bit flags. The fallback toSectionAllfor unknown services (line 117) is a safe default.
189-243: LGTM: Well-structured configuration building workflow.The
buildConfigmethod correctly orchestrates configuration loading with appropriate service-aware gating. The sequence—core/paths → service-specific sections → legacy overrides → finalization → validation—is logical and ensures only necessary sections are processed.
245-276: LGTM: Core configuration loaded correctly.The function properly initializes the
Coreconfiguration, including base environment and peer settings. The timezone initialization with error handling is appropriate.
417-455: LGTM: UI configuration loading properly defaults and validates.The addition of default value loading from viper (lines 419-424) before checking the definition resolves the previous concern about validation failures when the UI section is absent from the config file. The viper defaults (set on line 795 to 100) ensure
MaxDashboardPageLimitis never 0, allowing validation to pass.
617-678: LGTM: Service-aware legacy field handling.The refactored
LoadLegacyFieldscorrectly applies service-aware gating, ensuring legacy fields are only processed for configuration sections that are being loaded. Path-related legacy fields are correctly applied unconditionally since paths are always loaded.
680-744: LGTM: Service-aware legacy environment variable handling.The
loadLegacyEnvfunction correctly implements service-aware gating for legacy environment variables. The use ofSectionNonefor universally applicable settings (like path fields) is a clear pattern.
967-993: LGTM: Improved label parsing with strings.Cut.The refactor to use
strings.Cut(line 982) instead ofstrings.SplitNis a good modernization. The function correctly handles malformed entries by skipping pairs without an=delimiter, and properly trims whitespace around keys and values.
592-615: LGTM: Path finalization correctly derives subdirectories.The
finalizePathsfunction properly sets derived paths relative toDataDirand handles the executable path with appropriate error handling.
765-816: LGTM: Comprehensive default values configured.The
setViperDefaultValuesfunction properly initializes all configuration defaults using the loader's isolated viper instance. The default values are sensible and align with validation requirements.
933-951: LGTM: Environment variable binding with path normalization.The
bindEnvironmentVariablesfunction correctly binds configuration keys to environment variables using the loader's viper instance. The automatic path normalization for path-type bindings (lines 941-946) is a useful feature.
746-765: LGTM: Viper setup correctly uses isolated instance.Both
setupViperandconfigureViperproperly use the loader's isolated viper instance (l.v), ensuring configuration isolation per loader. The setup sequence is appropriate.Also applies to: 953-965
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1467 +/- ##
==========================================
- Coverage 59.92% 59.88% -0.04%
==========================================
Files 196 196
Lines 21896 21892 -4
==========================================
- Hits 13121 13110 -11
- Misses 7367 7375 +8
+ Partials 1408 1407 -1
... and 2 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.