-
Notifications
You must be signed in to change notification settings - Fork 8
HYPERFLEET-304 | refactor: phase 1 put context to logger parameter and support args and ENV #19
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
HYPERFLEET-304 | refactor: phase 1 put context to logger parameter and support args and ENV #19
Conversation
WalkthroughReplaces legacy glog with a context-aware, structured logger that is bootstrapped before config load and reinitialized after adapter config is loaded. Logger and context fields are threaded through startup, config loading, hyperfleet API client creation, Kubernetes client creation, executor and sub-executors, subscriber/event handling, and shutdown. Many constructors and method signatures now accept context and/or logger (notably pkg/logger, hyperfleet_api.NewClient, evaluator/CELEvaluator, executor and sub-executors). Executor now consumes parsed event data (map) instead of CloudEvent objects. Validator factory was made unexported and tests were updated to the new APIs. Sequence Diagram(s)sequenceDiagram
participant CLI as CLI
participant BootLog as "Bootstrap Logger"
participant Config as "Config Loader"
participant AdapterLog as "Adapter Logger"
participant HFAPI as "Hyperfleet API Client"
participant K8s as "Kubernetes Client"
participant Exec as "Executor"
participant Sub as "Subscriber"
rect rgb(245,247,250)
CLI->>BootLog: build logger from flags/env
BootLog-->>CLI: ctx with bootstrap fields
end
rect rgb(250,240,245)
CLI->>Config: load adapter config (ctx)
Config-->>CLI: adapter config (includes metadata.name)
CLI->>AdapterLog: rebuild logger (component=metadata.name)
AdapterLog-->>CLI: ctx with adapter fields
end
rect rgb(240,255,245)
CLI->>HFAPI: NewClient(adapter logger, apiConfig)
HFAPI-->>CLI: apiClient
CLI->>K8s: NewK8sClient(adapter ctx)
K8s-->>CLI: k8sClient
CLI->>Exec: NewExecutor(config{apiClient,k8sClient,logger})
Exec-->>CLI: executor ready
end
rect rgb(255,250,240)
Sub->>Exec: deliver event (ctx with event_id)
Exec->>Exec: ParseEventData(ctx, data)
Exec->>HFAPI: perform API calls / post-actions (ctx)
Exec->>K8s: apply manifests / resources (ctx)
Exec-->>Sub: ack / result (ctx)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/executor/executor_test.go (1)
312-319: Dead code: unused CloudEvent creation.The CloudEvent
evtis created and data is set, but it's never used after line 319. The test now passeseventDatadirectly toNewExecutionContextat line 372. This CloudEvent creation and the associated import can be removed.func TestParamExtractor(t *testing.T) { t.Setenv("TEST_ENV", "env-value") - evt := event.New() eventData := map[string]interface{}{ "cluster_id": "test-cluster", "nested": map[string]interface{}{ "value": "nested-value", }, } - _ = evt.SetData(event.ApplicationJSON, eventData)Also consider removing the unused import on line 7:
- "github.com/cloudevents/sdk-go/v2/event"
🧹 Nitpick comments (13)
pkg/logger/context.go (1)
119-132: Formatting issue: inconsistent indentation in the for loop.The closing brace on line 128 appears to have inconsistent indentation relative to the for loop structure.
func GetLogFields(ctx context.Context) LogFields { if ctx == nil { return nil } if v, ok := ctx.Value(LogFieldsKey).(LogFields); ok { // Return a copy to avoid mutation fields := make(LogFields, len(v)) for k, val := range v { fields[k] = val - } + } return fields } return nil }internal/config_loader/test_helpers_test.go (1)
7-9: Consider using a singleton pattern for test logger consistency.Unlike
testutil.TestLogger()which usessync.Onceto create a shared logger instance, thistestLog()function creates a new logger on each call. While acceptable for unit tests, this is inconsistent with the integration test utility pattern.For consistency and reduced allocations, consider using a singleton:
package config_loader import ( + "sync" + "github.com/openshift-hyperfleet/hyperfleet-adapter/pkg/logger" ) +var ( + sharedTestLogger logger.Logger + loggerOnce sync.Once +) + func testLog() logger.Logger { - return logger.New(logger.Config{Level: "error", Format: "text", Output: "stdout", Component: "test", Version: "test"}) + loggerOnce.Do(func() { + sharedTestLogger = logger.New(logger.Config{Level: "error", Format: "text", Output: "stdout", Component: "test", Version: "test"}) + }) + return sharedTestLogger }internal/criteria/test_helpers_test.go (1)
7-9: Consider using "debug" or "info" level for test logger.The logger is configured with "error" level, which will suppress debug, info, and warning logs during tests. For test scenarios, more verbose logging (e.g., "debug" or "info") can be helpful for debugging test failures.
test/integration/executor/main_test.go (1)
186-214: Health check implementation looks good.The HTTP-based health check is a reliable approach for detecting API server readiness during startup. The response body is properly closed on success.
Regarding the static analysis warning about missing
MinVersion: while this is test code andInsecureSkipVerify: truealready relaxes security, addingMinVersion: tls.VersionTLS12would silence the warning and add defense-in-depth at minimal cost.Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, //nolint:gosec // Required for envtest self-signed certs + MinVersion: tls.VersionTLS12, }, },internal/config_loader/validator.go (1)
417-419: Consider nil-safety for logger usage.If
NewValidatoris called with anillogger, callingv.log.Debugfwill panic. Consider adding a nil check or documenting that a non-nil logger is required._, issues = v.celEnv.Check(ast) if issues != nil && issues.Err() != nil { // Log at debug level - type check failures are expected for dynamic variables - v.log.Debugf(v.ctx, "CEL type check failed for expression %q (validation continues): %v", expr, issues.Err()) + if v.log != nil { + v.log.Debugf(v.ctx, "CEL type check failed for expression %q (validation continues): %v", expr, issues.Err()) + } }internal/executor/resource_executor_test.go (1)
155-175: Consider renaming test and removing stale references.
TestDeepCopyMap_NilLoggeris now a misleading name sincedeepCopyMapno longer accepts a logger parameter. The test still validates deep copy behavior, but the name/comment should be updated.-func TestDeepCopyMap_NilLogger(t *testing.T) { - // Should not panic when logger is nil +func TestDeepCopyMap_DeepCopyVerification(t *testing.T) { + // Verify deep copy works correctly original := map[string]interface{}{internal/hyperfleet_api/client.go (2)
202-202: Inconsistent indentation on logging statements.The logging calls have extra leading whitespace/tabs that don't match the surrounding code indentation. This appears to be a formatting issue.
Apply this diff to fix the indentation:
- c.log.Warnf(ctx, "HyperFleet API request failed (attempt %d/%d): %v", attempt, retryAttempts, err) + c.log.Warnf(ctx, "HyperFleet API request failed (attempt %d/%d): %v", attempt, retryAttempts, err)- c.log.Warnf(ctx, "HyperFleet API request returned retryable status %d (attempt %d/%d)", - resp.StatusCode, attempt, retryAttempts) + c.log.Warnf(ctx, "HyperFleet API request returned retryable status %d (attempt %d/%d)", + resp.StatusCode, attempt, retryAttempts)- c.log.Infof(ctx, "Retrying in %v...", delay) + c.log.Infof(ctx, "Retrying in %v...", delay)Also applies to: 214-215, 221-221
309-309: Inconsistent indentation on debug logging statements.Same formatting issue as above with extra leading tabs on the debug logging calls.
- c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) + c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL)- c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status) + c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status)Also applies to: 329-329
internal/executor/executor.go (1)
180-189: Consider moving logger before ctx in parameter list.Go convention typically places
context.Contextas the first parameter. The current signature haslog logger.Logger, ctx context.Contextwhich is unconventional.-func (e *Executor) finishWithError(result *ExecutionResult, execCtx *ExecutionContext, err error, reason string, log logger.Logger, ctx context.Context) *ExecutionResult { +func (e *Executor) finishWithError(result *ExecutionResult, execCtx *ExecutionContext, err error, reason string, ctx context.Context, log logger.Logger) *ExecutionResult {Update call site at line 78 accordingly.
internal/executor/resource_executor.go (3)
66-66: Inconsistent indentation on log statements.Several log statements lack proper indentation relative to surrounding code (e.g., lines 66, 80, 86, 91, 100-103, 111, 115, 121, 143). This appears to be a formatting issue that should be corrected for consistency.
Example fix for line 66:
-re.log.Debugf(ctx, "Building manifest from config") + re.log.Debugf(ctx, "Building manifest from config")Apply similar indentation fixes to all affected log statements.
Also applies to: 80-81, 86-86, 91-91, 100-103, 111-111, 115-115, 121-121, 143-143
150-195: Unusedctxparameter in buildManifest.The
ctxparameter is accepted but never used inbuildManifest. Either remove it for clarity or use it for logging template rendering progress.If logging is not needed:
-func (re *ResourceExecutor) buildManifest(ctx context.Context, resource config_loader.Resource, execCtx *ExecutionContext) (*unstructured.Unstructured, error) { +func (re *ResourceExecutor) buildManifest(resource config_loader.Resource, execCtx *ExecutionContext) (*unstructured.Unstructured, error) {Update call site at line 67 accordingly.
391-417: Silent fallback in deepCopyMap hides potential issues.The removal of the logger parameter means failures in deep copy now silently fall back to shallow copy. Consider adding a comment or using a package-level approach to log this, as shallow copy can cause unexpected mutations of nested structures.
At minimum, add a comment clarifying the silent fallback behavior:
copied, err := copystructure.Copy(m) if err != nil { - // Fallback to shallow copy if deep copy fails + // Fallback to shallow copy if deep copy fails. + // WARNING: This is a silent fallback - nested maps/slices will share references. + // Consider passing a logger or using structured error tracking if this becomes problematic. result := make(map[string]interface{})pkg/logger/logger_test.go (1)
355-368: Test only verifies defaults, not actual env var reading.
TestConfigFromEnvtests the default values but doesn't actually set environment variables to verify they're read correctly. Consider adding subtest cases that set and unset env vars.func TestConfigFromEnv(t *testing.T) { - // Test with defaults (no env vars set) - cfg := ConfigFromEnv() - - if cfg.Level != "info" { - t.Errorf("Expected default level 'info', got %s", cfg.Level) - } - if cfg.Format != "text" { - t.Errorf("Expected default format 'text', got %s", cfg.Format) - } - if cfg.Output != "stdout" { - t.Errorf("Expected default output 'stdout', got %s", cfg.Output) - } + t.Run("defaults_without_env_vars", func(t *testing.T) { + cfg := ConfigFromEnv() + if cfg.Level != "info" { + t.Errorf("Expected default level 'info', got %s", cfg.Level) + } + if cfg.Format != "text" { + t.Errorf("Expected default format 'text', got %s", cfg.Format) + } + }) + + t.Run("reads_LOG_LEVEL_env_var", func(t *testing.T) { + t.Setenv("LOG_LEVEL", "DEBUG") + cfg := ConfigFromEnv() + if cfg.Level != "debug" { + t.Errorf("Expected level 'debug', got %s", cfg.Level) + } + }) }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (41)
Makefile(1 hunks)cmd/adapter/main.go(9 hunks)go.mod(0 hunks)internal/config_loader/loader.go(4 hunks)internal/config_loader/loader_test.go(10 hunks)internal/config_loader/test_helpers_test.go(1 hunks)internal/config_loader/validator.go(4 hunks)internal/config_loader/validator_test.go(10 hunks)internal/criteria/cel_evaluator.go(5 hunks)internal/criteria/cel_evaluator_test.go(10 hunks)internal/criteria/evaluator.go(4 hunks)internal/criteria/evaluator_scenarios_test.go(8 hunks)internal/criteria/evaluator_test.go(13 hunks)internal/criteria/evaluator_version_test.go(5 hunks)internal/criteria/test_helpers_test.go(1 hunks)internal/executor/README.md(0 hunks)internal/executor/executor.go(3 hunks)internal/executor/executor_test.go(12 hunks)internal/executor/param_extractor.go(0 hunks)internal/executor/post_action_executor.go(9 hunks)internal/executor/post_action_executor_test.go(8 hunks)internal/executor/precondition_executor.go(10 hunks)internal/executor/resource_executor.go(9 hunks)internal/executor/resource_executor_test.go(11 hunks)internal/executor/types.go(3 hunks)internal/executor/utils.go(10 hunks)internal/executor/utils_test.go(2 hunks)internal/hyperfleet_api/client.go(8 hunks)internal/hyperfleet_api/client_test.go(15 hunks)internal/k8s_client/client.go(13 hunks)internal/k8s_client/discovery.go(1 hunks)pkg/logger/context.go(1 hunks)pkg/logger/logger.go(1 hunks)pkg/logger/logger_test.go(3 hunks)test/integration/config-loader/config_criteria_integration_test.go(10 hunks)test/integration/executor/executor_integration_test.go(16 hunks)test/integration/executor/executor_k8s_integration_test.go(8 hunks)test/integration/executor/main_test.go(4 hunks)test/integration/executor/setup_test.go(2 hunks)test/integration/k8s_client/helper_envtest_prebuilt.go(1 hunks)test/integration/testutil/logger.go(1 hunks)
💤 Files with no reviewable changes (3)
- internal/executor/README.md
- internal/executor/param_extractor.go
- go.mod
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
test/integration/config-loader/config_criteria_integration_test.gointernal/config_loader/loader.gocmd/adapter/main.gointernal/config_loader/validator.gointernal/executor/types.gointernal/config_loader/validator_test.gointernal/hyperfleet_api/client.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.go
🧬 Code graph analysis (24)
test/integration/k8s_client/helper_envtest_prebuilt.go (1)
test/integration/testutil/logger.go (1)
TestLogger(17-28)
internal/k8s_client/client.go (2)
pkg/errors/error.go (1)
KubernetesError(203-205)internal/hyperfleet_api/types.go (1)
Client(216-237)
internal/executor/utils_test.go (1)
internal/executor/utils.go (1)
ExecuteLogAction(39-70)
test/integration/config-loader/config_criteria_integration_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(54-66)test/integration/testutil/logger.go (1)
TestLogger(17-28)
internal/config_loader/loader.go (2)
pkg/logger/logger.go (1)
Logger(15-41)internal/config_loader/validator.go (1)
Validate(519-521)
test/integration/testutil/logger.go (1)
pkg/logger/logger.go (3)
Logger(15-41)New(97-156)Config(55-66)
cmd/adapter/main.go (5)
pkg/logger/logger.go (3)
ConfigFromEnv(80-94)New(97-156)Logger(15-41)internal/config_loader/loader.go (4)
Load(106-129)WithAdapterVersion(59-63)WithLogger(80-84)WithContext(87-91)internal/hyperfleet_api/client.go (1)
NewClient(119-148)internal/k8s_client/client.go (3)
NewClient(60-109)ClientConfig(30-38)Client(24-27)internal/executor/executor.go (1)
NewBuilder(285-289)
internal/executor/resource_executor.go (4)
internal/executor/types.go (6)
ExecutorConfig(63-73)ResourceResult(132-149)OperationUpdate(158-158)OperationCreate(156-156)PhaseResources(25-25)NewExecutorError(380-387)internal/k8s_client/interface.go (1)
K8sClient(13-47)internal/config_loader/types.go (1)
Resource(171-178)internal/k8s_client/discovery.go (1)
Discovery(14-29)
internal/criteria/cel_evaluator_test.go (2)
internal/criteria/cel_evaluator.go (1)
NewCELEvaluator(57-79)internal/criteria/evaluator.go (1)
NewEvaluator(54-66)
test/integration/executor/setup_test.go (2)
pkg/logger/logger.go (1)
Logger(15-41)test/integration/testutil/logger.go (1)
TestLogger(17-28)
internal/config_loader/validator.go (2)
pkg/logger/logger.go (1)
Logger(15-41)internal/config_loader/types.go (1)
AdapterConfig(6-11)
internal/executor/executor.go (7)
internal/executor/precondition_executor.go (1)
NewPreconditionExecutor(22-27)internal/executor/resource_executor.go (1)
NewResourceExecutor(27-32)internal/executor/post_action_executor.go (1)
NewPostActionExecutor(21-26)internal/executor/types.go (11)
Executor(76-81)ExecutionResult(84-107)StatusFailed(43-43)PhaseParamExtraction(21-21)NewExecutionContext(259-270)StatusSuccess(41-41)PhasePreconditions(23-23)PhaseResources(25-25)PhasePostActions(27-27)ExecutionContext(186-201)EventData(54-60)pkg/logger/logger.go (1)
Logger(15-41)pkg/logger/context.go (4)
WithResourceID(95-97)WithResourceType(90-92)WithDynamicResourceID(64-67)WithEventID(80-82)internal/config_loader/types.go (1)
AdapterConfig(6-11)
internal/criteria/evaluator_scenarios_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(54-66)
internal/config_loader/loader_test.go (1)
internal/config_loader/loader.go (3)
Parse(132-148)WithContext(87-91)WithLogger(80-84)
test/integration/executor/main_test.go (4)
test/integration/testutil/logger.go (1)
TestLogger(17-28)pkg/logger/logger.go (1)
Config(55-66)internal/k8s_client/client.go (1)
Client(24-27)internal/config_loader/types.go (1)
Header(119-122)
internal/criteria/evaluator_version_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(54-66)
internal/config_loader/test_helpers_test.go (1)
pkg/logger/logger.go (3)
Logger(15-41)New(97-156)Config(55-66)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (2)
EvaluationContext(64-72)NewEvaluationContext(75-80)pkg/logger/logger.go (1)
Logger(15-41)
internal/config_loader/validator_test.go (2)
internal/config_loader/loader.go (3)
Parse(132-148)WithContext(87-91)WithLogger(80-84)internal/config_loader/validator.go (1)
Validate(519-521)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(55-66)DefaultConfig(69-77)New(97-156)ConfigFromEnv(80-94)pkg/logger/context.go (9)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithTraceID(70-72)
internal/criteria/test_helpers_test.go (1)
pkg/logger/logger.go (3)
Logger(15-41)New(97-156)Config(55-66)
pkg/logger/logger.go (1)
pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
internal/hyperfleet_api/client.go (2)
pkg/logger/logger.go (1)
Logger(15-41)internal/k8s_client/client.go (2)
NewClient(60-109)Client(24-27)
internal/executor/executor_test.go (3)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (4)
NewExecutionContext(259-270)EventData(54-60)StatusSuccess(41-41)ExecutionStatus(37-37)pkg/logger/context.go (1)
WithEventID(80-82)
🪛 ast-grep (0.40.0)
test/integration/executor/main_test.go
[warning] 189-191: MinVersionis missing from this TLS configuration. By default, TLS 1.2 is currently used as the minimum when acting as a client, and TLS 1.0 when acting as a server. General purpose web applications should default to TLS 1.3 with all other protocols disabled. Only where it is known that a web server must support legacy clients with unsupported an insecure browsers (such as Internet Explorer 10), it may be necessary to enable TLS 1.0 to provide support. AddMinVersion: tls.VersionTLS13' to the TLS configuration to bump the minimum version to TLS 1.3.
Context: tls.Config{
InsecureSkipVerify: true, //nolint:gosec // Required for envtest self-signed certs
}
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
https://owasp.org/Top10/A02_2021-Cryptographic_Failures
(missing-ssl-minversion-go)
🔇 Additional comments (72)
Makefile (1)
151-157: Clarify the relationship between this change and the logging refactor.This PR is described as a logging refactor (HYPERFLEET-304), but this Makefile change adds an
installtarget that doesn't relate to logging. While the implementation itself is fine, it's unclear why this change is included in this PR.Is this change intentionally bundled with the logging refactor, or should it be in a separate PR?
internal/executor/utils_test.go (1)
4-4: LGTM!The test correctly adapts to the new context-aware
ExecuteLogActionsignature by:
- Adding the
contextimport- Passing
context.Background()as the first argumentThis aligns with the broader logging refactor tracked in HYPERFLEET-304. Based on learnings from the retrieved context, this change is part of the planned logger refactor.
Also applies to: 778-778
internal/k8s_client/discovery.go (1)
85-86: LGTM!The logging call now correctly passes the
ctxparameter toInfof, enabling context-aware structured logging. The context is already available from the function signature, making this a clean adaptation to the new logger API.pkg/logger/context.go (2)
40-47: Consider documenting the field accumulation behavior.The
WithLogFieldfunction correctly retrieves existing fields (as a copy fromGetLogFields), adds the new field, and stores the updated map. This creates a new context value on each call, which is the expected immutable context pattern.However, note that
GetLogFieldsreturns a copy, so eachWithLogFieldcall allocates a new map. For high-frequency field additions, consider a builder pattern or batching withWithLogFieldsinstead.
11-29: Good use of typed context keys to avoid collisions.The
contextKeytype prevents key collisions with other packages usingcontext.Value. The predefined keys for tracing, resource, and adapter fields provide a clear, organized structure for observability data.test/integration/k8s_client/helper_envtest_prebuilt.go (1)
100-100: LGTM!Switching to
testutil.TestLogger()provides a consistent, shared logger instance across integration tests. This aligns with the test utility pattern established intest/integration/testutil/logger.goand reduces test log noise by using the "error" log level.test/integration/executor/setup_test.go (1)
25-28: LGTM!The
testLog()helper provides a package-local convenience wrapper aroundtestutil.TestLogger(). This pattern is consistent with similar helpers in other test packages (e.g.,internal/config_loader/test_helpers_test.go).test/integration/testutil/logger.go (1)
1-28: LGTM! Well-structured test utility.The singleton pattern using
sync.Onceensures thread-safe, efficient logger sharing across all integration tests. The "error" log level appropriately reduces test output noise while still capturing important error messages.internal/k8s_client/client.go (1)
76-367: LGTM! Context-aware logging consistently applied.All logging statements have been updated to pass context as the first parameter, aligning with the new context-aware logger interface. The changes are mechanical and consistent throughout the file.
test/integration/config-loader/config_criteria_integration_test.go (2)
6-6: LGTM! Imports added for context and test logger.The imports support the updated evaluator constructor signature that requires context and logger parameters.
Also applies to: 17-17
73-409: LGTM! Evaluator initialization consistently updated.All
NewEvaluatorcalls have been updated to passcontext.Background()as the first parameter andtestutil.TestLogger()as the third parameter, matching the new constructor signature.internal/criteria/evaluator_version_test.go (2)
4-4: LGTM! Context import added.The import supports the updated evaluator constructor signature.
17-146: LGTM! Evaluator initialization consistently updated.All
NewEvaluatorcalls have been updated to passcontext.Background()andtestLog(), matching the new constructor signature.test/integration/executor/executor_integration_test.go (1)
91-1338: LGTM! API client and logger interface consistently updated.All changes properly reflect the updated API signatures:
hyperfleet_api.NewClient()now receives logger as first parameterlogCaptureLoggermethods updated to accept context as first parameterThe changes are consistent throughout the file.
internal/criteria/evaluator_scenarios_test.go (2)
4-4: LGTM! Context import added.
46-341: LGTM! Evaluator initialization consistently updated.All
NewEvaluatorcalls properly updated withcontext.Background()andtestLog()parameters.internal/criteria/evaluator_test.go (2)
4-4: LGTM! Context import added.
524-1073: LGTM! Evaluator initialization consistently updated.All
NewEvaluatorcalls throughout the test file have been properly updated withcontext.Background()andtestLog()parameters, matching the new constructor signature.test/integration/executor/executor_k8s_integration_test.go (1)
318-321:testLog()helper is properly defined and accessible.The
testLog()function is defined insetup_test.gowithin the same test package (test/integration/executor/) and is correctly available for use inexecutor_k8s_integration_test.go. No changes needed.test/integration/executor/main_test.go (1)
103-106: Good integration of test logger.The shared test logger from
testutil.TestLogger()is correctly used here and passed tok8s_client.NewClientFromConfig, aligning with the PR's dependency injection pattern.internal/config_loader/loader.go (1)
79-91: Clean functional options implementation.The
WithLoggerandWithContextoptions follow idiomatic Go patterns for configuration injection.internal/config_loader/validator_test.go (1)
271-284: Consistent test updates for context and logger injection.All
ParseandValidatecalls have been correctly updated to useWithContext(context.Background())andWithLogger(testLog()). The pattern is uniform across all test functions.internal/config_loader/loader_test.go (1)
162-177: Test updates are consistent and correct.The
Parsecalls in table-driven tests are correctly updated to passWithContext(context.Background())andWithLogger(testLog()). TheLoad()call at line 63 intentionally omits these options to test default behavior, which is appropriate.internal/executor/post_action_executor_test.go (3)
17-28: Test helpers are well-structured.The
testLog()andtestPAE()helpers provide clean test setup. Since this test file is in theexecutorpackage (same package as the implementation), accessingpae.logdirectly is valid.Note: Similar
testLog()helpers exist in other test packages (config_loader,testutil). This duplication is acceptable for test isolation, but you could consider consolidating to a shared test utility if desired.
96-115: Test correctly uses context-aware evaluator and payload builder.The test properly creates the evaluator with
context.Background()andpae.log, then callspae.buildPayloadwith context. This aligns with the refactored API.
423-446: ExecuteAll test correctly wired with new ExecutorConfig.The test properly constructs
PostActionExecutorwithExecutorConfigcontaining bothAPIClientandLogger, and usesNewExecutionContextwithcontext.Background().internal/hyperfleet_api/client_test.go (2)
21-23: LGTM! Test logger helper follows best practices.The
testLog()helper correctly configures a test logger with error level to minimize noise during test runs while still capturing critical issues.
25-30: Consistent logger injection across all test cases.All
NewClientinvocations have been updated to use the test logger. The pattern is applied uniformly throughout the test file.internal/config_loader/validator.go (2)
65-76: LGTM! Validator correctly stores context and logger.The Validator struct now properly carries logging context, and the constructor initializes both fields. This aligns with the HYPERFLEET-304 logging refactor objective.
519-521: Clean public API for validation.The
Validatefunction provides a simple entry point that properly delegates toNewValidator. This maintains a clean separation between the stateless public API and the statefulValidatorinstance.internal/executor/utils.go (3)
39-69: LGTM! ExecuteLogAction properly propagates context.The function correctly:
- Accepts context as the first parameter
- Uses context-aware logging methods (
log.Debugf(ctx, ...), etc.)- Handles all log levels with the
[config]prefix for traceability
76-206: LGTM! ExecuteAPICall correctly uses context-aware logging.The function properly:
- Threads context through all logging calls
- Uses appropriate log levels (Info for normal flow, Warn for recoverable failures, Error for POST body on failure)
- Maintains the existing error handling with APIError wrapping
264-266: Minor formatting adjustment.Cosmetic alignment change with no functional impact.
internal/executor/resource_executor_test.go (1)
18-31: LGTM! deepCopyMap calls updated to match new signature.The test correctly uses the simplified
deepCopyMap(original)signature without the logger parameter.internal/criteria/evaluator.go (2)
54-66: LGTM! Defensive nil handling for context parameters.The constructor properly handles nil inputs:
evalCtxdefaults to a newEvaluationContextgoCtxdefaults tocontext.Background()This prevents nil pointer panics in downstream code.
72-89: LGTM! CEL evaluator correctly uses stored Go context.The
getCELEvaluatormethod properly passese.goCtxtoNewCELEvaluator, ensuring context propagation for logging and potential cancellation support in CEL evaluation.internal/hyperfleet_api/client.go (1)
119-148: LGTM!The logger injection pattern via
NewClient(log logger.Logger, opts ...ClientOption)is consistent with the Kubernetes client pattern shown ininternal/k8s_client/client.goand follows good dependency injection practices.internal/criteria/cel_evaluator_test.go (2)
17-17: LGTM!Test constructor calls are consistently updated to use the new signature with
context.Background()andtestLog().Also applies to: 29-29, 133-133, 249-249, 268-268
444-444: LGTM!The
NewEvaluatorandNewCELEvaluatorcalls in integration tests are correctly updated to pass context and logger parameters.Also applies to: 473-473, 536-536
internal/executor/types.go (2)
46-60: LGTM!The new
ResourceRefandEventDatastructs are well-designed with appropriate JSON tags andomitemptyfor optional fields. Using*ResourceRefforOwnedReferencecorrectly allows nil values for events without owned references.
259-270: LGTM!The simplified
NewExecutionContextsignature that acceptseventData map[string]interface{}directly (instead of*event.Event) reduces coupling to the CloudEvents library and aligns with the broader refactoring to decouple event handling.internal/criteria/cel_evaluator.go (2)
57-79: LGTM!The separation of
goCtx context.Context(for cancellation/logging) fromevalCtx *EvaluationContext(for CEL variable bindings) is a clean design. The nil-safety with sensible defaults (context.Background(),NewEvaluationContext()) ensures robustness.
168-182: LGTM!The evaluation error handling correctly captures errors in
CELResultrather than returning them, enabling callers to decide how to handle missing fields. The debug logging usinge.goCtxprovides proper context propagation.Based on learnings, this aligns with HYPERFLEET-304 tracking how CEL evaluation failures are handled and logged.
cmd/adapter/main.go (4)
116-132: LGTM!The logger configuration pattern correctly prioritizes command-line flags over environment variables, following the standard precedence (flags > env > defaults). The bootstrap logger with a temporary component name is a good pattern for early startup logging.
144-153: LGTM!Recreating the logger with the adapter's configured component name after loading the config is a clean approach that ensures all subsequent logs include the proper component identifier.
300-328: LGTM!The
createAPIClientfunction correctly threads the logger through tohyperfleet_api.NewClient, consistent with the updated API client signature.
193-205: LGTM!The signal handling with graceful shutdown on first signal and forced exit on second signal is a well-established pattern. Context cancellation properly propagates through the application.
internal/executor/precondition_executor.go (4)
16-27: LGTM: Config-based initialization aligns with executor pattern.The
PreconditionExecutornow correctly receives its dependencies viaExecutorConfig, consistent withResourceExecutorandPostActionExecutorconstructors shown in the relevant snippets.
31-69: LGTM: Context-aware logging in ExecuteAll.The logging is properly updated to use
pe.logwith context propagation. The flow handles execution errors, unmet preconditions, and success cases with appropriate log levels.
72-199: LGTM: executePrecondition correctly uses instance logger.The method properly threads
ctxthrough all logging calls and delegates tope.log. The evaluator creation at line 143 correctly passes context and logger.
202-211: LGTM: executeAPICall signature and implementation.Clean delegation to
ExecuteAPICallutility with proper logger injection.internal/executor/executor.go (3)
16-36: LGTM: Unified config-based executor wiring.The validation guards and consistent use of
ExecutorConfigfor all sub-executors is clean. Error messages are clear and identify the missing dependency.
38-85: LGTM: Generalized Execute entry point with context enrichment.The refactor from
*event.Eventtointerface{}withParseEventDataprovides flexibility. Context enrichment with resource IDs (lines 56-62) enables proper log correlation using the helpers frompkg/logger/context.go.
233-277: Consider handling empty JSON object{}case.
ParseEventDatareturns empty structs forniland empty[]byte, but an empty JSON object{}would parse successfully and return anEventDatawith zero values. If upstream code depends on distinguishing "no data" from "empty object", this may need clarification in documentation or a validity check.internal/executor/resource_executor.go (1)
26-32: LGTM: Consistent config-based initialization.Aligns with the pattern established in
PreconditionExecutorandPostActionExecutor.pkg/logger/logger.go (5)
13-41: LGTM: Clean context-aware Logger interface.The interface properly follows the context-as-first-parameter convention and provides both plain and formatted variants. The
With*methods enable fluent field chaining.
54-66: LGTM: Well-structured Config type.The configuration options cover the essential logging concerns (level, format, output, component identification).
233-237: Fatal exits immediately without cleanup.
os.Exit(1)bypasses deferred functions, which could leave resources (like the file handle from line 111) in an inconsistent state. This is standard Go behavior forFatal-style methods, but worth noting given the file handle concern.Ensure callers understand that
Fatalis a hard exit. Consider adding a comment:// Fatal logs at error level and exits +// WARNING: This calls os.Exit(1) which bypasses deferred functions. func (l *logger) Fatal(ctx context.Context, message string) {
172-191: LGTM: Context field extraction.The
buildArgsmethod correctly extracts fields from both the logger instance and the context, enabling rich structured logging with request-scoped fields.
251-293: LGTM: Immutable field chaining.The
With*methods correctly copy fields before modification, ensuring the original logger remains unchanged.WithError(nil)correctly returns the same logger instance.pkg/logger/logger_test.go (4)
8-52: LGTM: Logger creation tests.Tests cover default config, JSON format, and text format configurations. Type assertions verify the concrete implementation is returned.
126-150: LGTM: WithError tests including nil case.Good coverage of both the error case and the nil optimization.
160-242: LGTM: Smoke tests for logging methods.The panic-recovery pattern ensures all log methods are exercised without crashing.
327-353: LGTM: Context helper tests.Good coverage of
WithEventID,WithClusterID, andWithTraceIDwith field verification viaGetLogFields.internal/executor/post_action_executor.go (4)
30-76: LGTM!The
ExecuteAllmethod correctly propagates context through all logging calls and execution paths. Error handling withExecutionErrormetadata is well-structured.
80-115: LGTM!Context is correctly threaded through to the evaluator construction and payload building calls.
119-196: LGTM!Context is properly propagated through the recursive payload building and value processing methods.
199-248: LGTM!The
executePostActionandexecuteAPICallmethods correctly pass context to all logging and external API calls.internal/executor/executor_test.go (4)
24-40: LGTM!The
mockLoggercorrectly implements the updatedLoggerinterface with all context-aware methods. TheWith,WithFields, andWithErrormethods properly returnmto support chaining.
119-131: LGTM!The test correctly uses the updated
NewExecutionContextsignature with map-based event data, validating the refactored API.
288-307: LGTM!Good use of
logger.WithEventIDto attach event IDs to the context, demonstrating the new context-aware logging pattern.
386-386: No issues found. The third parameter toextractConfigParamsisk8sClient, not a logger. The function and its callees (extractFromSecretandextractFromConfigMap) already include nil checks that return appropriate errors if the Kubernetes client is needed but not provided. Passingnilis safe for test cases that don't require secret or configmap parameter extraction.Likely an incorrect or invalid review comment.
8b8dbc8 to
c40b141
Compare
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 (2)
internal/executor/resource_executor.go (2)
81-104: Fix inconsistent indentation in log statements.Several log statements are not properly indented to align with the surrounding code blocks. This affects readability.
🔎 Apply this diff to fix indentation:
-re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)", + re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)", gvk.Group, gvk.Kind, manifest.GetName(), manifest.GetNamespace()) // Step 2: Check for existing resource using discovery var existingResource *unstructured.Unstructured if resource.Discovery != nil { -re.log.Debugf(ctx, "Discovering existing resource...") + re.log.Debugf(ctx, "Discovering existing resource...") existingResource, err = re.discoverExistingResource(ctx, gvk, resource.Discovery, execCtx) if err != nil && !apierrors.IsNotFound(err) { if apperrors.IsRetryableDiscoveryError(err) { // Transient/network error - log and continue, we'll try to create - re.log.Warnf(ctx, " Transient discovery error (continuing): %v", err) + re.log.Warnf(ctx, " Transient discovery error (continuing): %v", err) } else {Similar fixes needed for lines 101-103, 112, 116, 122.
Also applies to: 112-112, 116-116, 122-122
296-351: Fix inconsistent indentation in recreateResource and waitForDeletion.Log statements in these methods have the same indentation issues as noted above.
🔎 Apply this diff to fix indentation:
// Delete the existing resource -re.log.Infof(ctx, "Deleting resource for recreation: %s/%s", gvk.Kind, name) + re.log.Infof(ctx, "Deleting resource for recreation: %s/%s", gvk.Kind, name) if err := re.k8sClient.DeleteResource(ctx, gvk, namespace, name); err != nil { return nil, fmt.Errorf("failed to delete resource for recreation: %w", err) } // Wait for the resource to be fully deleted -re.log.Infof(ctx, "Waiting for resource deletion to complete: %s/%s", gvk.Kind, name) + re.log.Infof(ctx, "Waiting for resource deletion to complete: %s/%s", gvk.Kind, name)Similar fixes needed throughout
waitForDeletion.
♻️ Duplicate comments (3)
internal/criteria/cel_evaluator_test.go (1)
156-158: Test semantics still broken:nullValueshould benil.The test case at line 182-188 is named "access field on null returns error in result (safe)" but
nullValueis set totestLog()instead ofnil. This changes the test from validating null field access to testing field access on a logger object.🔎 Apply this fix:
- ctx.Set("nullValue", testLog()) + ctx.Set("nullValue", nil)internal/executor/executor.go (1)
244-262: Indentation issue from previous review appears to be fixed.The
case []byte:block now has correct indentation with the closing brace properly aligned. The code parses the byte slice correctly and assigns tojsonBytes.internal/executor/post_action_executor.go (1)
20-27: Nil check delegation is documented but could be fragile.The comment on line 21 states "Caller (NewExecutor) is responsible for config validation", which is a valid design choice. However, this creates a tight coupling where
newPostActionExecutorcan panic if called incorrectly from any other location.Since this is now a private function (
newPostActionExecutorvsNewPostActionExecutor), the risk is mitigated as internal callers can be trusted. The comment documents the contract clearly.
🧹 Nitpick comments (6)
test/integration/testutil/logger.go (1)
20-26: Consider the test log level setting.The logger is configured with
Level: "error", which means debug, info, and warning logs will be suppressed during test execution. While this keeps test output clean, it might make debugging test failures more difficult.Consider using
"debug"or"info"level, or making it configurable via an environment variable to allow developers to adjust verbosity when troubleshooting.🔎 Example: Make log level configurable
func TestLogger() logger.Logger { loggerOnce.Do(func() { var err error + level := os.Getenv("TEST_LOG_LEVEL") + if level == "" { + level = "error" + } sharedTestLogger, err = logger.NewLogger(logger.Config{ - Level: "error", + Level: level, Format: "text", Output: "stdout", Component: "test", Version: "test", }) if err != nil { panic(err) } }) return sharedTestLogger }internal/executor/post_action_executor_test.go (1)
23-33: Consider extracting test logger to a shared test utilities package.The
testLog()helper is likely duplicated across multiple test packages (e.g.,internal/criteria/test_helpers_test.go). While Go's package isolation requires each package to have access to test helpers, you could create a sharedinternal/testutilpackage to centralize this pattern and reduce duplication.internal/executor/executor.go (1)
180-188: Consider movingctxparameter to the front offinishWithError.Go convention is to place
context.Contextas the first parameter. While this is an internal method, maintaining consistency improves readability.🔎 Suggested signature change:
-func (e *Executor) finishWithError(result *ExecutionResult, execCtx *ExecutionContext, err error, reason string, ctx context.Context) *ExecutionResult { +func (e *Executor) finishWithError(ctx context.Context, result *ExecutionResult, execCtx *ExecutionContext, err error, reason string) *ExecutionResult {This would require updating the call site at line 78 accordingly.
internal/executor/executor_test.go (1)
312-319: Remove unused CloudEvent creation.The
evtvariable is created and populated but never used. The test only uses theeventDatamap directly. This appears to be leftover code from the CloudEvent-based approach.🔎 Apply this diff to remove dead code:
func TestParamExtractor(t *testing.T) { t.Setenv("TEST_ENV", "env-value") - evt := event.New() eventData := map[string]interface{}{ "cluster_id": "test-cluster", "nested": map[string]interface{}{ "value": "nested-value", }, } - _ = evt.SetData(event.ApplicationJSON, eventData)After removing this code, the
github.com/cloudevents/sdk-go/v2/eventimport on line 7 can also be removed.pkg/logger/logger_test.go (2)
185-270: Consider adding a Fatal method test.The test covers
Debug,Debugf,Info,Infof,Warn,Warnf,Error, andErrorf, but theLoggerinterface (as shown bymockLoggerinexecutor_test.go) also includes aFatalmethod. Consider adding a test forFatalfor completeness.Note: If
Fatalcallsos.Exit, you may need to skip this test or handle it specially.
451-452: Minor: Remove duplicate blank line.There are two consecutive blank lines at lines 451-452.
🔎 Apply this diff:
} } - func TestLoggerContextExtraction(t *testing.T) {
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (40)
Makefile(1 hunks)cmd/adapter/main.go(9 hunks)go.mod(0 hunks)internal/config_loader/loader.go(1 hunks)internal/config_loader/test_helpers_test.go(1 hunks)internal/config_loader/validator.go(3 hunks)internal/config_loader/validator_test.go(2 hunks)internal/criteria/cel_evaluator.go(5 hunks)internal/criteria/cel_evaluator_test.go(10 hunks)internal/criteria/evaluator.go(4 hunks)internal/criteria/evaluator_scenarios_test.go(8 hunks)internal/criteria/evaluator_test.go(13 hunks)internal/criteria/evaluator_version_test.go(5 hunks)internal/criteria/test_helpers_test.go(1 hunks)internal/executor/README.md(0 hunks)internal/executor/executor.go(3 hunks)internal/executor/executor_test.go(12 hunks)internal/executor/param_extractor.go(0 hunks)internal/executor/post_action_executor.go(9 hunks)internal/executor/post_action_executor_test.go(9 hunks)internal/executor/precondition_executor.go(10 hunks)internal/executor/resource_executor.go(9 hunks)internal/executor/resource_executor_test.go(10 hunks)internal/executor/types.go(4 hunks)internal/executor/utils.go(10 hunks)internal/executor/utils_test.go(2 hunks)internal/hyperfleet_api/client.go(8 hunks)internal/hyperfleet_api/client_test.go(15 hunks)internal/k8s_client/client.go(13 hunks)internal/k8s_client/discovery.go(1 hunks)pkg/logger/context.go(1 hunks)pkg/logger/logger.go(1 hunks)pkg/logger/logger_test.go(3 hunks)test/integration/config-loader/config_criteria_integration_test.go(10 hunks)test/integration/executor/executor_integration_test.go(16 hunks)test/integration/executor/executor_k8s_integration_test.go(8 hunks)test/integration/executor/main_test.go(4 hunks)test/integration/executor/setup_test.go(2 hunks)test/integration/k8s_client/helper_envtest_prebuilt.go(1 hunks)test/integration/testutil/logger.go(1 hunks)
💤 Files with no reviewable changes (3)
- internal/executor/param_extractor.go
- internal/executor/README.md
- go.mod
🚧 Files skipped from review as they are similar to previous changes (8)
- test/integration/config-loader/config_criteria_integration_test.go
- internal/criteria/test_helpers_test.go
- test/integration/executor/executor_k8s_integration_test.go
- internal/executor/utils_test.go
- internal/config_loader/loader.go
- internal/config_loader/test_helpers_test.go
- internal/hyperfleet_api/client_test.go
- internal/k8s_client/client.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/config_loader/validator.gointernal/executor/types.gointernal/hyperfleet_api/client.gocmd/adapter/main.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.go
🧬 Code graph analysis (20)
test/integration/k8s_client/helper_envtest_prebuilt.go (1)
test/integration/testutil/logger.go (1)
TestLogger(17-32)
test/integration/executor/main_test.go (3)
test/integration/testutil/logger.go (1)
TestLogger(17-32)pkg/logger/logger.go (1)
Config(55-66)internal/k8s_client/client.go (1)
Client(24-27)
internal/criteria/evaluator_scenarios_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(54-66)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (2)
EvaluationContext(64-72)NewEvaluationContext(75-80)pkg/logger/logger.go (1)
Logger(15-41)
internal/criteria/evaluator_version_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(54-66)
internal/criteria/evaluator.go (3)
internal/criteria/types.go (2)
EvaluationContext(64-72)NewEvaluationContext(75-80)pkg/logger/logger.go (1)
Logger(15-41)internal/criteria/cel_evaluator.go (1)
NewCELEvaluator(57-79)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(114-130)
internal/executor/types.go (2)
pkg/errors/error.go (1)
Href(150-153)pkg/logger/logger.go (1)
Logger(15-41)
internal/criteria/evaluator_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(54-66)
test/integration/executor/executor_integration_test.go (3)
internal/hyperfleet_api/client.go (2)
NewClient(119-148)WithRetryAttempts(74-78)internal/k8s_client/client.go (1)
NewClient(60-109)pkg/logger/logger.go (1)
Logger(15-41)
internal/hyperfleet_api/client.go (2)
pkg/logger/logger.go (1)
Logger(15-41)internal/k8s_client/client.go (2)
NewClient(60-109)Client(24-27)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(55-66)DefaultConfig(69-77)NewLogger(98-151)ConfigFromEnv(80-94)pkg/logger/context.go (10)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithClusterID(85-87)WithTraceID(70-72)
test/integration/executor/setup_test.go (2)
pkg/logger/logger.go (1)
Logger(15-41)test/integration/testutil/logger.go (1)
TestLogger(17-32)
internal/criteria/cel_evaluator_test.go (2)
internal/criteria/cel_evaluator.go (1)
NewCELEvaluator(57-79)internal/criteria/evaluator.go (1)
NewEvaluator(54-66)
internal/executor/executor_test.go (2)
internal/executor/types.go (4)
NewExecutionContext(260-271)EventData(54-60)StatusSuccess(41-41)ExecutionStatus(37-37)pkg/logger/context.go (1)
WithEventID(80-82)
internal/executor/post_action_executor_test.go (5)
pkg/logger/logger.go (3)
Logger(15-41)NewLogger(98-151)Config(55-66)internal/executor/post_action_executor.go (1)
PostActionExecutor(15-18)internal/executor/types.go (2)
ExecutorConfig(63-73)NewExecutionContext(260-271)internal/criteria/evaluator.go (1)
NewEvaluator(54-66)internal/executor/utils.go (1)
ExecuteAPICall(76-206)
internal/executor/executor.go (3)
internal/executor/types.go (4)
NewExecutionContext(260-271)StatusSuccess(41-41)ExecutionContext(187-202)EventData(54-60)pkg/logger/context.go (4)
WithResourceID(95-97)WithResourceType(90-92)WithDynamicResourceID(64-67)WithEventID(80-82)internal/config_loader/types.go (1)
AdapterConfig(6-11)
cmd/adapter/main.go (4)
pkg/logger/logger.go (3)
ConfigFromEnv(80-94)NewLogger(98-151)Logger(15-41)internal/config_loader/loader.go (2)
Load(88-111)WithAdapterVersion(55-59)internal/hyperfleet_api/client.go (1)
NewClient(119-148)internal/k8s_client/client.go (3)
NewClient(60-109)ClientConfig(30-38)Client(24-27)
internal/executor/resource_executor.go (3)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (3)
ExecutorConfig(63-73)ExecutionContext(187-202)ResourceResult(133-150)internal/config_loader/types.go (1)
Resource(171-178)
internal/executor/post_action_executor.go (5)
internal/executor/types.go (2)
ExecutorConfig(63-73)ExecutionContext(187-202)internal/config_loader/types.go (4)
PostConfig(193-196)Payload(67-78)PostAction(199-203)APICall(108-116)internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (2)
NewEvaluator(54-66)Evaluator(41-51)internal/executor/utils.go (1)
ExecuteLogAction(39-70)
🪛 checkmake (0.2.2)
Makefile
[warning] 152-152: Target body for "install" exceeds allowed length of 5 (10).
(maxbodylength)
🔇 Additional comments (64)
test/integration/k8s_client/helper_envtest_prebuilt.go (1)
100-100: LGTM! Logger initialization updated correctly.The change from
logger.NewLogger(ctx)totestutil.TestLogger()aligns with the new test logger singleton pattern, ensuring consistent logging across integration tests.Makefile (1)
151-163: LGTM! GOPATH validation implemented correctly.The
installtarget now includes proper GOPATH validation (lines 153-157) and directory creation (line 160), addressing the previous review feedback. The implementation ensures the binary is installed to a valid location with clear error messaging if GOPATH is unset.internal/config_loader/validator.go (2)
65-66: LGTM! Constructor visibility updated correctly.The change from exported
NewValidatorto unexportednewValidatoraligns with the loader refactoring where validation is now invoked internally vianewValidator(config).Validate()inloader.go.
391-407: LGTM! CEL validation simplified to syntax-only.The change to perform only syntax validation (via
Parse) instead of type-checking is appropriate. As the comment explains (lines 391-393), variables are dynamically typed (DynType) and their actual types are only known at runtime. Type-checking at config load time would produce false positives or require overly complex type inference.internal/config_loader/validator_test.go (2)
792-792: LGTM! Test updated to use new validator API.The change from
Validate(config)tonewValidator(config).Validate()correctly reflects the updated validator construction pattern where the constructor is now unexported.
828-828: LGTM! Consistent with the validator API update.Same pattern as line 792, ensuring consistent usage of the new
newValidatorconstructor across all test cases.internal/executor/types.go (2)
46-61: LGTM! New types support structured event data.The introduction of
ResourceRefandEventDatatypes provides a clean, structured representation of HyperFleet resources and event payloads, replacing the CloudEvents dependency with domain-specific types.
260-260: LGTM! Simplified event data handling.The updated
NewExecutionContextsignature removes the CloudEvents dependency, accepting a plaineventDatamap instead of a*event.Event. This simplification aligns with the PR's objective to refactor event handling from CloudEvents objects to map-based data, making the code more flexible and testable.pkg/logger/context.go (1)
1-132: LGTM! Well-designed context-aware logging infrastructure.The implementation provides a robust foundation for structured, contextual logging:
- Type-safe context keys prevent collisions (lines 8-29)
- Defensive copying in
GetLogFields(lines 124-129) prevents external mutation- Nil-safe context handling (lines 120-122)
WithDynamicResourceIDcleverly derives field names from resource types (lines 64-67)- Consistent API patterns across all
WithXxxfunctionsThe design enables rich, context-driven observability throughout the adapter.
pkg/logger/logger.go (4)
96-151: LGTM! File handle leak concern resolved by design.The previous review raised concerns about file handle leaks when
Outputis a file path. This implementation addresses that concern by explicitly rejecting file paths (lines 101-108), supporting onlystdoutandstderr. This is the recommended approach for containerized applications, where logs should be written to standard streams and collected by the container runtime.The logger initialization is clean and well-structured:
- Config-driven construction with sensible defaults
- Environment variable support via
ConfigFromEnv- Proper level parsing and handler selection
- Base metadata (component, version, hostname) embedded at construction
168-186: LGTM! Efficient context field extraction.The
buildArgsmethod cleanly merges logger-scoped fields (lines 172-174) with context-scoped fields (lines 177-183), enabling both static logger fields (viaWith/WithFields) and dynamic per-call fields (via context) to be included in log entries.
189-232: LGTM! Consistent context-aware logging interface.All logging methods (
Debug,Info,Warn,Error,Fatal) consistently require acontext.Contextas the first parameter, enabling automatic extraction of contextual fields for every log entry. This design aligns with best practices for distributed tracing and structured logging.
247-288: LGTM! Proper immutability via defensive copying.The
With,WithFields, andWithErrormethods create new logger instances with copied field maps (viacopyFields), ensuring that modifications don't affect the original logger. This enables safe logger derivation and chaining.internal/k8s_client/discovery.go (1)
85-86: LGTM! Updated to context-aware logging.The addition of
ctxas the first parameter toInfofaligns with the new context-aware logging interface, enabling automatic extraction of contextual fields for this log entry.test/integration/executor/setup_test.go (1)
25-28: LGTM!The new
testLog()helper provides a consistent way to access the shared test logger. This aligns well with the project-wide shift to context-aware logging.internal/criteria/evaluator_version_test.go (1)
17-17: LGTM!The test has been correctly updated to use the new constructor signature with
context.Background()andtestLog(). This ensures proper context propagation and logging throughout the evaluation flow.internal/criteria/evaluator_scenarios_test.go (1)
46-46: LGTM!The evaluator constructor calls have been consistently updated throughout all test scenarios to use the new context-aware signature. This ensures proper context propagation and logging in all test cases.
test/integration/executor/main_test.go (1)
184-219: Improved API server readiness check.The new implementation using HTTP health checks is more reliable than the previous approach. The use of
InsecureSkipVerifyis properly justified for envtest with self-signed certificates, and theMinVersion: tls.VersionTLS12provides reasonable security baseline for test environments.The response body is properly closed, and the retry logic with timeout is well-implemented.
internal/criteria/evaluator_test.go (1)
524-524: LGTM!The evaluator constructor calls have been systematically updated across all test cases to incorporate context-aware logging. The consistent use of
context.Background()andtestLog()ensures proper test coverage of the new logging infrastructure.internal/executor/utils.go (2)
39-69: Context-aware logging properly implemented.The
ExecuteLogActionfunction has been correctly updated to accept and propagate context throughout all logging calls. All log levels (debug, info, warn, error) now use the context-aware logging methods.
76-206: Context-aware logging properly implemented in ExecuteAPICall.The function correctly propagates context through all logging calls, enabling proper context tracking for API operations. The error handling paths properly maintain context in log messages.
internal/criteria/cel_evaluator.go (2)
57-79: Context-aware constructor properly implemented.The updated
NewCELEvaluatorconstructor correctly:
- Accepts
goCtxas the first parameter for context propagation- Provides sensible defaults (context.Background() and NewEvaluationContext()) when nil
- Stores the context for use in logging operations
- Maintains backward compatibility through nil parameter handling
174-174: Context-aware logging properly implemented.The logging call now correctly uses
e.goCtxto propagate context through the logging infrastructure, enabling better traceability of CEL evaluation operations.internal/criteria/cel_evaluator_test.go (1)
17-17: Context-aware constructor usage looks correct.The updated
NewCELEvaluatorandNewEvaluatorcalls consistently usecontext.Background()andtestLog(), aligning with the new signatures that accept(goCtx context.Context, evalCtx *EvaluationContext, log logger.Logger).internal/executor/post_action_executor_test.go (2)
18-33: Test logger singleton pattern is well-implemented.The
sync.Oncepattern ensures thread-safe lazy initialization of the shared test logger. UsingLevel: "error"appropriately suppresses verbose output during tests while still capturing errors.
36-42: Clean factory pattern for test setup.The
testPAE()factory encapsulates test setup nicely, providing a consistent way to createPostActionExecutorinstances with test dependencies.internal/criteria/evaluator.go (2)
54-66: Context integration is well-designed with appropriate defaults.The constructor properly handles nil inputs by defaulting
goCtxtocontext.Background()andevalCtxto a newEvaluationContext. This defensive approach prevents nil pointer dereferences while allowing callers flexibility.
72-89: CEL evaluator recreation logic correctly propagates context.The lazy-initialization pattern with version tracking ensures the CEL environment stays synchronized with context data, and the
goCtxis correctly passed through for context-aware logging.internal/executor/resource_executor_test.go (1)
19-19: Consistent context-aware signature usage across alldeepCopyMaptests.All test cases have been updated to pass
context.Background()andtestLog()to the refactoreddeepCopyMapfunction. The tests maintain their original coverage of deep copy semantics.internal/hyperfleet_api/client.go (2)
119-148: Clean refactor ofNewClientto require logger dependency.The signature change from
NewClient(opts ...ClientOption)toNewClient(log logger.Logger, opts ...ClientOption)makes the logger dependency explicit. The BaseURL resolution with environment variable fallback is well-documented and provides clear error messaging.
202-221: Appropriate log levels for retry scenarios.The logging strategy is well-thought-out:
Warnffor failures and retryable responses alerts operators to issuesInfoffor retry delays provides visibility into the retry flowDebugf(lines 309, 329) for request/response details keeps verbose info at debug levelcmd/adapter/main.go (4)
31-36: Well-structured logging configuration with proper flag/env precedence.The logging configuration follows proper precedence: environment variables are loaded first via
ConfigFromEnv(), then CLI flags override them. This allows flexible configuration for different deployment scenarios.Also applies to: 79-85, 116-129
131-156: Good bootstrap logger pattern with component name update after config load.The two-phase logger initialization (bootstrap → config-aware) is a clean approach. The bootstrap logger uses a generic component name, then gets recreated with the adapter's configured name from
adapterConfig.Metadata.Name.
162-189: Logger correctly propagated to all dependent components.The logger is properly threaded through API client, K8s client, and executor creation, enabling consistent context-aware logging throughout the application.
306-334: API client creation correctly passes logger.The
createAPIClientfunction signature and implementation properly pass the logger tohyperfleet_api.NewClient, aligning with the new logger-first constructor pattern.internal/executor/executor.go (4)
16-37: Config validation and sub-executor creation look correct.The
NewExecutorfunction properly validates all required config fields (AdapterConfig, APIClient, Logger) and creates sub-executors using the config-driven pattern. K8sClient validation is intentionally omitted since it may be nil in some configurations.
56-64: Context enrichment for logging correlation is well-designed.The context is enriched with resource metadata (type, ID, owned reference) using the appropriate logger context helpers. This enables consistent log correlation across all execution phases.
233-277: ParseEventData handles multiple input formats correctly.The function correctly handles nil data, empty byte slices,
map[string]interface{}, and other JSON-serializable types. Both structuredEventDataand raw map are returned for flexible access patterns.
204-231: CreateHandler properly adds event ID to context for log correlation.The handler enriches the context with the event ID using
logger.WithEventID()before processing, enabling log correlation across the entire execution flow. The ACK-on-error strategy is clearly documented.test/integration/executor/executor_integration_test.go (3)
91-94: API client creation correctly updated to pass logger as first argument.All
hyperfleet_api.NewClientcalls have been updated to pass a logger (testLog()ork8sEnv.Log) as the first argument, aligning with the new constructor signature.Also applies to: 230-230, 332-334, 445-445, 493-493, 546-546, 597-597, 630-630, 664-664, 728-728, 780-780, 911-911, 1023-1023, 1200-1200, 1338-1338
986-1006: logCaptureLogger correctly implements context-aware Logger interface.The test logger implementation properly accepts
context.Contextas the first parameter for all logging methods, matching the newlogger.Loggerinterface. TheFatalmethod correctly usest.Fatalfinstead ofos.Exitfor test compatibility.
91-94: The review comment is incorrect. ThetestLog()function is properly defined insetup_test.go(line 26) within the same package (executor_integration_test), and it correctly calls the exportedtestutil.TestLogger()function. Since both test files are in the same directory and package, they can access each other's package-scoped functions. No changes are required.Likely an incorrect or invalid review comment.
internal/executor/precondition_executor.go (4)
16-28: Clean config-driven constructor pattern.The
PreconditionExecutornow takesExecutorConfigand extracts only what it needs (apiClient, log). The comment clearly documents that config validation is the caller's responsibility.
30-70: ExecuteAll properly uses internal logger with context.All logging in
ExecuteAllcorrectly usespe.logwith context-aware methods. The precondition index logging ([Precondition %d/%d]) provides good operational visibility.
72-200: executePrecondition comprehensively refactored for context-aware logging.The method properly:
- Uses
pe.logfor all log statements- Sets
ExecutionErrorwith phase and step info on failures- Passes
pe.logtoExecuteLogActionandcriteria.NewEvaluator- Logs capture operations, condition evaluations, and CEL results at appropriate levels
203-212: executeAPICall correctly passes logger to ExecuteAPICall.The API call execution path properly passes both the API client and logger to the shared
ExecuteAPICallhelper, enabling consistent logging during HTTP operations.internal/executor/resource_executor.go (3)
20-33: Config-driven constructor pattern correctly implemented.The
ResourceExecutornow uses the same pattern as other executors, takingExecutorConfigand extracting k8sClient and logger.
35-57: ExecuteAll correctly uses internal logger with context.Resource processing logging properly uses
re.logwith context-aware methods, providing clear operational visibility with resource index and status.
386-419: deepCopyMap correctly updated with context-aware logging.The function now accepts
ctxandlogparameters for context-aware warning logging when deep copy fails. The fallback to shallow copy with a warning is appropriate.internal/executor/executor_test.go (5)
28-39: LGTM on mockLogger implementation.The mockLogger correctly implements the context-aware Logger interface with all required methods. The fluent methods (
With,WithFields,WithError) properly returnlogger.Loggerto support method chaining, and theWarnmethod captures warnings for test assertions.
41-42: Orphaned comment has been addressed.The previous orphaned comment about
testEventWithDatahas been removed. The current comment appropriately describes theTestNewExecutorfunction.
119-131: LGTM on TestExecutionContext.The test correctly exercises the new
NewExecutionContextAPI with context and map-based event data, and properly verifies theEventDatafield access pattern.
288-295: LGTM on context-aware event ID propagation.The test correctly demonstrates the new pattern where event IDs are propagated via
logger.WithEventID(context.Background(), "test-event-123")instead of being embedded in CloudEvent objects.
541-542: Consistent test patterns across sequential execution tests.All the sequential execution tests (
TestSequentialExecution_Preconditions,TestSequentialExecution_Resources,TestSequentialExecution_PostActions,TestSequentialExecution_SkipReasonCapture) consistently use thelogger.WithEventIDpattern and pass map-based event data toExecute.pkg/logger/logger_test.go (6)
8-55: LGTM on TestNewLogger.The test cases comprehensively cover logger creation with default config, JSON format, and text format with different outputs (stdout/stderr). Error handling for the
NewLoggercall is properly checked.
57-68: LGTM on invalid output validation test.Good negative test case that verifies
NewLoggerproperly rejects invalid output configurations.
148-175: LGTM on WithError tests.Good test coverage including the edge case where
WithError(nil)should return the same logger instance without adding an error field.
358-384: LGTM on context helper tests.The tests properly verify that
WithEventID,WithClusterID, andWithTraceIDcorrectly store values in the context that can be retrieved viaGetLogFields.
386-423: LGTM on ConfigFromEnv tests.Good coverage of environment variable configuration including defaults and case normalization (e.g.,
DEBUG→debug).
453-479: LGTM on context extraction test.Good integration test that verifies logging with a context containing multiple log fields (
trace_id,event_id,cluster_id) doesn't cause panics.internal/executor/post_action_executor.go (4)
31-77: LGTM on ExecuteAll refactor.The method correctly uses the internal
pae.loglogger with context propagation. The sequential execution pattern (stop on first failure) is preserved, and error context is properly captured inexecCtx.Adapter.ExecutionError.
81-116: LGTM on buildPostPayloads refactor.The method correctly creates the evaluator with context and the internal logger (
pae.log), enabling context-aware CEL evaluation. The payload building delegations use the receiver pattern consistently.
156-197: LGTM on processValue refactor.The recursive value processing correctly propagates context through all code paths (nested maps, arrays, type conversions). The receiver pattern ensures consistent access to the internal logger.
224-248: LGTM on executeAPICall refactor.The method correctly uses the internal
apiClientandlogdependencies. Error handling withNewExecutorErrorprovides proper phase/step context, and response details are captured even when validation fails.
c40b141 to
3b3c199
Compare
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
♻️ Duplicate comments (4)
internal/config_loader/loader.go (1)
180-184: Critical: Unresolved nil logger issue from previous review.The previous review comment flagged that
newValidator(config)can receive a nil logger (whenWithLoggeris not called), which causes a nil pointer panic when the validator tries to log viav.log.Debugf().This issue remains unresolved. The validator must receive a valid logger instance. Consider one of these approaches:
- Pass a logger to
newValidator(config, logger)- obtain it from a loader option or create a default no-op logger- Ensure
newValidatorinternally handles nil logger by providing a default no-op implementation- Add validation that fails fast if logger is missing rather than panicking later
Based on learnings, this was tracked in a previous review and requires resolution before the logging refactor is complete.
internal/criteria/cel_evaluator_test.go (1)
156-158: Test semantics changed:nullValueis no longer null.The test case "access field on null returns error in result (safe)" at lines 182-188 expects
nullValueto be null, but it's now set totestLog()(a logger instance). This changes the test semantics—you're testing field access on a logger object rather than null value access.🔎 Apply this fix to restore null semantics:
- ctx.Set("nullValue", testLog()) + ctx.Set("nullValue", nil)internal/hyperfleet_api/client.go (1)
309-309: Fix inconsistent indentation.This line has extra leading whitespace (double-indented). The same issue appears on line 329.
🔎 Apply this fix:
// Execute request - c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) + c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL)And for line 329:
- c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status) + c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status)internal/executor/post_action_executor.go (1)
20-27: Constructor follows same validation pattern as other executors.The comment indicates caller responsibility for validation, which is consistent with
newResourceExecutor. This is acceptable ifNewExecutorcentralizes validation.Note: A past review flagged the missing nil check here. The comment now clarifies the design intent, but ensure
NewExecutorvalidatesconfig.APIClientandconfig.Loggerare non-nil.#!/bin/bash # Verify NewExecutor validates APIClient and Logger before calling newPostActionExecutor rg -n -A 30 'func NewExecutor' internal/executor/executor.go
🧹 Nitpick comments (9)
pkg/logger/context.go (1)
62-67: Consider handling empty resourceType in WithDynamicResourceID.If
resourceTypeis empty, this will create a field named_id. Consider adding validation or documenting this behavior.🔎 Optional: Add validation for empty resourceType
func WithDynamicResourceID(ctx context.Context, resourceType string, resourceID string) context.Context { + if resourceType == "" { + return WithLogField(ctx, "resource_id", resourceID) + } fieldName := strings.ToLower(resourceType) + "_id" return WithLogField(ctx, fieldName, resourceID) }test/integration/executor/executor_integration_test.go (1)
230-230: Inconsistent error handling for NewClient across tests.This test and several others (lines 332, 445, 493, 546, 597, 630, 664, 728, 780, 911, 1023, 1200, 1338) ignore the error from
NewClient. While test environments are typically configured correctly, handling these errors would make tests more robust and provide clearer failure messages.Consider creating a test helper function to reduce boilerplate:
func mustNewClient(t *testing.T, log logger.Logger, opts ...hyperfleet_api.ClientOption) hyperfleet_api.Client { t.Helper() client, err := hyperfleet_api.NewClient(log, opts...) if err != nil { t.Fatalf("Failed to create API client: %v", err) } return client }internal/executor/executor.go (1)
233-277: ParseEventData performs double JSON unmarshal.The function unmarshals
jsonBytestwice: once intoEventDatastruct (line 266) and once intorawDatamap (line 272). This is slightly inefficient but acceptable for correctness. The structuredEventDataprovides type safety for known fields, whilerawDataallows flexible access to any fields.For optimization, you could unmarshal once and use type assertions or reflection, but the current approach is clearer and the overhead is negligible for typical event sizes.
pkg/logger/logger.go (2)
167-186: Consider documenting field precedence when context and logger fields collide.When both the logger's
fieldsmap and the context'sLogFieldscontain the same key, context fields will overwrite logger fields due to the append order. This behavior might be intentional (context takes precedence), but it's not documented.Suggested documentation:
// buildArgs builds the slog args from fields and context +// Note: Context fields take precedence over logger fields when keys collide func (l *logger) buildArgs(ctx context.Context) []any {
228-232: Fatal bypasses deferred cleanup.
os.Exit(1)terminates immediately without running deferred functions. This is standard behavior for fatal logging, but callers should be aware that resources won't be cleaned up. Consider documenting this in the interface comment.internal/executor/resource_executor.go (1)
81-104: Inconsistent indentation in log statements.Several log statements have inconsistent leading whitespace/indentation. While this doesn't affect functionality, it impacts readability and log output consistency.
Suggested fix:
-re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)", + re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)", gvk.Group, gvk.Kind, manifest.GetName(), manifest.GetNamespace()) // Step 2: Check for existing resource using discovery var existingResource *unstructured.Unstructured if resource.Discovery != nil { -re.log.Debugf(ctx, "Discovering existing resource...") + re.log.Debugf(ctx, "Discovering existing resource...") existingResource, err = re.discoverExistingResource(ctx, gvk, resource.Discovery, execCtx) if err != nil && !apierrors.IsNotFound(err) { if apperrors.IsRetryableDiscoveryError(err) { // Transient/network error - log and continue, we'll try to create - re.log.Warnf(ctx, " Transient discovery error (continuing): %v", err) + re.log.Warnf(ctx, " Transient discovery error (continuing): %v", err) } else {internal/executor/executor_test.go (2)
28-39: mockLogger.Warnf doesn't capture warnings.
Warnappends tom.warnings, butWarnfdoes not. If tests rely on capturing formatted warnings, they won't be recorded. Consider aligning the behavior.Suggested fix:
func (m *mockLogger) Warn(ctx context.Context, message string) { m.warnings = append(m.warnings, message) } -func (m *mockLogger) Warnf(ctx context.Context, format string, args ...interface{}) {} +func (m *mockLogger) Warnf(ctx context.Context, format string, args ...interface{}) { m.warnings = append(m.warnings, fmt.Sprintf(format, args...)) }
312-319: Unused import: cloudevents/sdk-go/v2/event.Line 7 imports
github.com/cloudevents/sdk-go/v2/event, but it's only used inTestParamExtractor(line 312) to create an event that's not actually used after setting data. Theevtvariable is assigned but the test useseventDatamap directly.Suggested fix:
- evt := event.New() eventData := map[string]interface{}{ "cluster_id": "test-cluster", "nested": map[string]interface{}{ "value": "nested-value", }, } - _ = evt.SetData(event.ApplicationJSON, eventData)And remove the import if no longer needed.
pkg/logger/logger_test.go (1)
451-452: Minor: Extra blank lines.There are consecutive blank lines that could be cleaned up.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (39)
Makefile(1 hunks)cmd/adapter/main.go(9 hunks)go.mod(0 hunks)internal/config_loader/loader.go(1 hunks)internal/config_loader/validator.go(3 hunks)internal/config_loader/validator_test.go(2 hunks)internal/criteria/cel_evaluator.go(5 hunks)internal/criteria/cel_evaluator_test.go(9 hunks)internal/criteria/evaluator.go(7 hunks)internal/criteria/evaluator_scenarios_test.go(8 hunks)internal/criteria/evaluator_test.go(13 hunks)internal/criteria/evaluator_version_test.go(5 hunks)internal/criteria/test_helpers_test.go(1 hunks)internal/executor/README.md(0 hunks)internal/executor/executor.go(3 hunks)internal/executor/executor_test.go(12 hunks)internal/executor/param_extractor.go(0 hunks)internal/executor/post_action_executor.go(9 hunks)internal/executor/post_action_executor_test.go(9 hunks)internal/executor/precondition_executor.go(10 hunks)internal/executor/resource_executor.go(9 hunks)internal/executor/resource_executor_test.go(10 hunks)internal/executor/types.go(4 hunks)internal/executor/utils.go(10 hunks)internal/executor/utils_test.go(2 hunks)internal/hyperfleet_api/client.go(8 hunks)internal/hyperfleet_api/client_test.go(15 hunks)internal/k8s_client/client.go(13 hunks)internal/k8s_client/discovery.go(1 hunks)pkg/logger/context.go(1 hunks)pkg/logger/logger.go(1 hunks)pkg/logger/logger_test.go(3 hunks)test/integration/config-loader/config_criteria_integration_test.go(10 hunks)test/integration/executor/executor_integration_test.go(16 hunks)test/integration/executor/executor_k8s_integration_test.go(8 hunks)test/integration/executor/main_test.go(4 hunks)test/integration/executor/setup_test.go(2 hunks)test/integration/k8s_client/helper_envtest_prebuilt.go(1 hunks)test/integration/testutil/logger.go(1 hunks)
💤 Files with no reviewable changes (3)
- go.mod
- internal/executor/README.md
- internal/executor/param_extractor.go
🚧 Files skipped from review as they are similar to previous changes (6)
- test/integration/testutil/logger.go
- internal/executor/post_action_executor_test.go
- test/integration/executor/setup_test.go
- internal/k8s_client/discovery.go
- internal/criteria/cel_evaluator.go
- internal/executor/resource_executor_test.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.go
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
cmd/adapter/main.gointernal/config_loader/loader.gointernal/hyperfleet_api/client.gointernal/config_loader/validator.gotest/integration/config-loader/config_criteria_integration_test.gointernal/executor/types.go
🧬 Code graph analysis (23)
test/integration/executor/executor_k8s_integration_test.go (2)
internal/hyperfleet_api/client.go (1)
NewClient(119-148)internal/k8s_client/client.go (1)
NewClient(60-109)
internal/criteria/evaluator_version_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
internal/criteria/evaluator_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
cmd/adapter/main.go (6)
pkg/logger/logger.go (2)
NewLogger(98-151)Logger(15-41)internal/config_loader/loader.go (1)
Load(88-111)internal/config_loader/types.go (2)
Metadata(14-18)HyperfleetAPIConfig(37-42)internal/hyperfleet_api/client.go (1)
NewClient(119-148)internal/k8s_client/client.go (3)
NewClient(60-109)ClientConfig(30-38)Client(24-27)internal/hyperfleet_api/types.go (2)
ClientConfig(38-54)Client(216-237)
test/integration/k8s_client/helper_envtest_prebuilt.go (1)
test/integration/testutil/logger.go (1)
TestLogger(17-32)
internal/criteria/evaluator_scenarios_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
test/integration/executor/main_test.go (3)
test/integration/testutil/logger.go (1)
TestLogger(17-32)pkg/logger/logger.go (1)
Config(55-66)internal/k8s_client/client.go (1)
Client(24-27)
internal/executor/utils_test.go (1)
internal/executor/utils.go (1)
ExecuteLogAction(39-70)
internal/criteria/evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-41)
internal/hyperfleet_api/client.go (2)
pkg/logger/logger.go (1)
Logger(15-41)internal/k8s_client/client.go (2)
NewClient(60-109)Client(24-27)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(114-130)
internal/executor/executor.go (2)
internal/executor/types.go (2)
ExecutionContext(187-202)EventData(54-60)pkg/logger/context.go (3)
WithResourceType(90-92)WithDynamicResourceID(64-67)WithEventID(80-82)
internal/executor/utils.go (3)
internal/config_loader/types.go (1)
LogAction(206-209)internal/executor/types.go (2)
ExecutionContext(187-202)ExecutionStatus(37-37)pkg/logger/logger.go (1)
Logger(15-41)
internal/hyperfleet_api/client_test.go (1)
internal/hyperfleet_api/client.go (4)
NewClient(119-148)WithBaseURL(102-106)WithDefaultHeader(57-64)WithConfig(48-54)
pkg/logger/logger.go (1)
pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
internal/executor/precondition_executor.go (3)
internal/executor/types.go (2)
ExecutorConfig(63-73)ExecutionContext(187-202)internal/executor/utils.go (1)
ExecuteLogAction(39-70)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
test/integration/config-loader/config_criteria_integration_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)test/integration/testutil/logger.go (1)
TestLogger(17-32)
internal/criteria/cel_evaluator_test.go (2)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
internal/executor/resource_executor.go (6)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (9)
ExecutorConfig(63-73)ExecutionContext(187-202)ResourceResult(133-150)StatusSuccess(41-41)OperationUpdate(159-159)OperationCreate(157-157)StatusFailed(43-43)PhaseResources(25-25)NewExecutorError(381-388)internal/k8s_client/interface.go (1)
K8sClient(13-47)internal/config_loader/types.go (1)
Resource(171-178)internal/k8s_client/discovery.go (1)
Discovery(14-29)pkg/errors/k8s_error.go (1)
IsRetryableDiscoveryError(160-192)
internal/executor/post_action_executor.go (5)
pkg/logger/logger.go (1)
Logger(15-41)internal/config_loader/types.go (4)
PostConfig(193-196)Payload(67-78)PostAction(199-203)APICall(108-116)internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (2)
NewEvaluator(55-70)Evaluator(41-51)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)
test/integration/executor/executor_integration_test.go (2)
internal/hyperfleet_api/client.go (2)
NewClient(119-148)WithRetryAttempts(74-78)pkg/logger/logger.go (1)
Logger(15-41)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(55-66)DefaultConfig(69-77)NewLogger(98-151)ConfigFromEnv(80-94)pkg/logger/context.go (10)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithClusterID(85-87)WithTraceID(70-72)
internal/criteria/test_helpers_test.go (1)
pkg/logger/logger.go (3)
Logger(15-41)NewLogger(98-151)Config(55-66)
🪛 checkmake (0.2.2)
Makefile
[warning] 152-152: Target body for "install" exceeds allowed length of 5 (10).
(maxbodylength)
🔇 Additional comments (63)
test/integration/k8s_client/helper_envtest_prebuilt.go (1)
100-100: LGTM! Clean refactor to centralized test logging.This change aligns with the broader logger refactor by using the shared
testutil.TestLogger()helper. Benefits include:
- Consistent logger configuration across all integration tests
- Singleton pattern reduces setup overhead
- Centralized configuration makes test logging easier to maintain
test/integration/executor/main_test.go (1)
184-219: LGTM! Well-implemented health check for envtest.The HTTP-based health check is more reliable during envtest startup than attempting to create a Kubernetes client immediately. The implementation correctly:
- Disables TLS verification for self-signed certificates (with appropriate
nolintannotation)- Sets a minimum TLS version (1.2)
- Includes the Authorization header
- Properly closes the response body
- Implements retry logic with a timeout
internal/config_loader/validator_test.go (1)
792-793: Test updates will be needed when logger issue is resolved.These test calls to
newValidator(config).Validate()are consistent with the current implementation inloader.go. However, once the nil logger issue is fixed (by passing a logger tonewValidator), these test calls will also need to be updated to provide a test logger instance.Consider adding a test case that explicitly verifies validator behavior with a nil logger (should either handle gracefully or fail fast with a clear error) to prevent regressions.
Also applies to: 828-829
internal/executor/utils_test.go (1)
778-778: LGTM! Context parameter correctly added.The test properly calls
ExecuteLogActionwithcontext.Background()as the first parameter, aligning with the new context-aware signature.internal/criteria/evaluator_version_test.go (1)
17-17: LGTM! Evaluator instantiation correctly updated.All test cases properly instantiate the evaluator with the new signature:
NewEvaluator(context.Background(), ctx, testLog()). This correctly provides:
- Context as the first parameter
- EvaluationContext as the second parameter
- Logger from testLog() helper as the third parameter
The changes align with the context-aware refactoring across the codebase.
Also applies to: 52-52, 79-79, 146-146
internal/criteria/test_helpers_test.go (1)
1-23: LGTM! Clean test helper implementation.The
testLog()helper follows best practices:
- Uses
sync.Oncefor thread-safe single initialization- Panics on error, which is appropriate for test infrastructure setup
- Returns a shared logger instance to avoid redundant initialization
- Configuration (debug level, text format) is suitable for testing
This pattern is consistent with the similar helper in
test/integration/testutil/logger.go.test/integration/executor/executor_k8s_integration_test.go (1)
318-321: LGTM! API client instantiation correctly updated.All calls to
hyperfleet_api.NewClient()have been updated to includetestLog()as the first parameter, matching the new signature that requires a logger. The changes are applied consistently across all test cases.Also applies to: 470-470, 576-576, 646-646, 703-703, 751-751, 906-906, 969-969
internal/k8s_client/client.go (1)
76-76: LGTM! Context-aware logging correctly implemented.All logging calls in the Kubernetes client methods have been updated to include
ctxas the first parameter (e.g.,log.Infof(ctx, ...)instead oflog.Infof(...)). This enables:
- Request correlation across distributed operations
- Trace propagation for observability
- Context cancellation awareness
The changes are applied consistently across all CRUD operations (Create, Get, List, Update, Delete, Patch) without altering the underlying functional behavior.
Also applies to: 83-83, 131-131, 148-148, 154-154, 180-180, 193-193, 226-226, 256-256, 273-273, 279-279, 289-289, 302-302, 332-332, 366-366
internal/criteria/evaluator_scenarios_test.go (1)
4-4: LGTM! Context import and evaluator instantiation correctly updated.The
contextimport and allNewEvaluatorcalls are properly updated to use the new three-parameter signature(context.Context, *EvaluationContext, Logger). Usingcontext.Background()is appropriate for unit tests.Also applies to: 46-46
test/integration/config-loader/config_criteria_integration_test.go (2)
6-6: LGTM! Imports correctly added for context-aware evaluator initialization.The
contextandtestutilimports are properly added to support the newNewEvaluatorsignature.Also applies to: 17-17
73-73: LGTM! Evaluator instantiation correctly updated.All
NewEvaluatorcalls throughout this integration test file are properly updated to use the new three-parameter signature withcontext.Background()andtestutil.TestLogger().internal/hyperfleet_api/client_test.go (2)
22-36: LGTM! Test logger helper correctly implemented.The
testLog()helper usessync.Oncefor thread-safe singleton initialization, which is a good practice for shared test resources. The "error" log level appropriately minimizes test output noise.
40-40: LGTM! NewClient calls correctly updated with logger parameter.All
NewClientcalls throughout the test file are properly updated to passtestLog()as the first argument, aligning with the new signatureNewClient(log logger.Logger, opts ...ClientOption).internal/executor/utils.go (3)
39-69: LGTM! ExecuteLogAction correctly updated for context-aware logging.The function signature properly accepts
ctx context.Contextas the first parameter, and all log calls (Debugf,Infof,Warnf,Errorf) correctly pass the context. This aligns with the newLoggerinterface requirements.
87-87: LGTM! ExecuteAPICall logging correctly updated to use context.All log statements in
ExecuteAPICallnow properly pass thectxparameter to the context-aware logging methods, ensuring request-scoped context is propagated through the logging infrastructure.Also applies to: 111-111, 140-140, 170-170, 184-184, 204-204
264-266: Minor formatting change - no semantic impact.These are formatting-only changes to the
templateFuncsmap entries with no functional impact.internal/criteria/evaluator_test.go (2)
4-4: LGTM! Context import and evaluator instantiation correctly updated.The
contextimport is added and allNewEvaluatorcalls are properly updated to use the new three-parameter signature throughout the test file.Also applies to: 524-524
772-788: LGTM! Comprehensive panic tests for constructor validation.These tests correctly verify that
NewEvaluatorpanics when any of its required parameters (ctx,evalCtx, orlog) is nil. This provides good coverage for the constructor's defensive checks. The//nolint:staticcheckcomment on line 775 is appropriate since passing a nil context is intentional for testing the panic behavior.internal/criteria/cel_evaluator_test.go (2)
12-20: LGTM!The test function rename from
TestNewCELEvaluatortoTest_newCELEvaluatorcorrectly reflects the unexported constructor, and the context/logger propagation is properly implemented.
438-488: LGTM!The
NewEvaluatorcalls are correctly updated to use the three-parameter signature withcontext.Background(),ctx, andtestLog(). The test logic remains sound.internal/config_loader/validator.go (3)
65-71: LGTM!The constructor is correctly made unexported (
newValidator) since validation is now invoked internally via the loader's pipeline. The initialization remains appropriate.
391-407: LGTM!Simplifying CEL validation to syntax-only parsing is appropriate since variables use
DynTypeand actual types are only known at runtime. The comment clearly explains the rationale.
409-431: LGTM!The
validateBuildExpressionsfunction correctly handles recursive validation of CEL expressions within nested build structures, checking for theexpressionkey at each level.cmd/adapter/main.go (4)
116-135: LGTM!The bootstrap logger pattern is well-designed: configuration is built from environment variables first, overridden by command-line flags, and the logger is created before any operations that require logging. The component name is appropriately set to a bootstrap value initially.
148-153: LGTM!Recreating the logger with the adapter's component name from configuration ensures log entries are properly attributed after the config is loaded. This is a clean approach for dynamic component naming.
278-298: LGTM!The graceful shutdown implementation with a 30-second timeout and proper channel-based coordination is robust. The timeout prevents indefinite hangs during shutdown.
306-334: LGTM!The
createAPIClientfunction correctly propagates the logger tohyperfleet_api.NewClient, aligning with the new signature that requires a logger parameter.internal/hyperfleet_api/client.go (2)
119-148: LGTM!The
NewClientsignature correctly requires a logger as the first parameter, following the same pattern ask8s_client.NewClient. The base URL resolution order (option → env var → error) is well-documented and implemented.
202-221: LGTM!The retry logging provides useful context with attempt counts and delays, using appropriate log levels (Warn for failures, Info for retry delays).
internal/criteria/evaluator.go (4)
40-51: LGTM!The separation of
ctx(for logging correlation and cancellation) fromevalCtx(for CEL evaluation data) is a clean design. The CEL evaluator caching with version tracking ensures the environment stays synchronized with context data changes.
54-70: LGTM!Using panics for nil required parameters is appropriate for a constructor where all three parameters (
ctx,evalCtx,log) are essential. This follows the Go convention of panicking for programmer errors rather than runtime conditions.
76-93: LGTM!The lazy CEL evaluator initialization with version-based cache invalidation is well-implemented. This ensures the CEL environment is recreated when the evaluation context changes, preventing "undeclared reference" errors.
95-119: LGTM!All field accessor methods correctly delegate to
e.evalCtx.GetNestedField, maintaining consistency with the new dual-context design.internal/executor/types.go (4)
46-60: Well-structured event data types.The
ResourceRefandEventDatatypes are cleanly designed with appropriate JSON tags andomitemptyfor optional fields. TheOwnedReferencepointer allows for proper nil handling when no owned reference exists.
81-81: Logger field added to Executor struct.Adding the
logfield to theExecutorstruct centralizes logging and aligns with the PR objective to make logging context-aware. This is consistent with the pattern applied to other sub-executors.
190-191: Comment clarification for EventData field.The comment update clarifies that
EventDatanow holds the parsed event data payload directly as a map, which aligns with the removal of CloudEvent coupling.
259-271: NewExecutionContext signature simplified.The constructor now directly accepts
eventData map[string]interface{}instead of a CloudEvent, making it more flexible and decoupled from the CloudEvents SDK. The initialization is clean with proper map allocations.pkg/logger/context.go (3)
8-29: Well-designed context key constants.Using a custom
contextKeytype prevents collisions with other packages that might use string keys. The categorization of keys (correlation, resource, adapter-specific) improves code organization.
40-47: Potential mutation issue with WithLogField.
GetLogFieldsreturns a copy, butWithLogFieldcallsGetLogFieldsand then mutates that copy before storing it back. While this works correctly, ifGetLogFieldsis called between the get and thecontext.WithValue, another goroutine could see stale data. However, since contexts are typically used in a single goroutine flow, this is acceptable for the logging use case.
118-132: Good defensive copy in GetLogFields.Returning a copy of the map prevents callers from accidentally mutating the context's internal state. The nil context check is a good safety measure.
test/integration/executor/executor_integration_test.go (2)
986-1006: logCaptureLogger correctly implements updated Logger interface.The mock logger properly implements all context-aware methods. The
With*methods returnlto maintain the fluent interface pattern while keeping the same capture behavior.
1003-1003: No issue found. The Flush method is not part of the Logger interface.The
Loggerinterface inpkg/logger/logger.godoes not define aFlushmethod. SincelogCaptureLogger.Flush()is not implementing an interface requirement, it is not subject to any interface signature constraints. The implementation is correct.Likely an incorrect or invalid review comment.
internal/executor/precondition_executor.go (5)
16-28: Clean refactor to config-based constructor.The
PreconditionExecutornow receives its dependencies viaExecutorConfig, which is a cleaner pattern than passing individual dependencies. The lowercasenewPreconditionExecutorindicates internal use, which is appropriate since it's constructed byNewExecutor.
30-70: ExecuteAll properly uses context-aware logging.The method cleanly logs precondition evaluation progress with context. The outcome handling (error vs not matched vs matched) is well-structured with appropriate log levels.
92-100: Good error context propagation for API failures.Setting
ExecutionErrorwith phase, step, and message provides valuable debugging information. The structured error is available for CEL expressions in post-actions, as tested inTestExecutor_ExecutionError_CELAccess.
141-144: Evaluator correctly receives context and logger.The
criteria.NewEvaluatoris called with all required parameters (ctx, evalCtx, pe.log), matching the signature shown in the relevant code snippet frominternal/criteria/evaluator.go.
203-212: executeAPICall properly delegates to shared utility.The method delegates to
ExecuteAPICallutility and validates the response. The error handling throughValidateAPIResponseprovides consistent API error reporting.internal/executor/executor.go (6)
30-36: Sub-executors correctly wired via config.All sub-executors are created using the shared
ExecutorConfig, ensuring consistent dependency injection. Thelogfield is properly assigned fromconfig.Logger.
39-54: Execute method signature change and initial error handling.The signature change from accepting
*event.Eventtodata interface{}decouples from CloudEvents SDK at the API boundary. The error handling for parse failures properly sets the phase and returns early.
56-62: Context enrichment for logging correlation.The context is properly enriched with resource identifiers for logging. The
OwnedReferencehandling allows hierarchical resource tracking (e.g., NodePool owned by Cluster).
244-262: ParseEventData handles edge cases well.The function correctly handles:
nildata (returns empty structs)- Empty
[]byte(returns empty structs)map[string]interface{}(marshals then unmarshals)- Any other JSON-serializable type
This flexibility supports various calling patterns while maintaining a consistent return type.
210-230: CreateHandler properly enriches context with event ID.The handler adds the event ID to context for logging correlation before calling
Execute. The ACK-on-error strategy is well-documented and prevents infinite retry loops for non-recoverable errors.
179-188: finishWithError signature includes context for logging.The context parameter enables proper logging with correlation data. The method correctly sets all error-related fields on the result.
pkg/logger/logger.go (2)
96-108: Good validation for output destination.The previous concern about file handle leaks has been addressed by restricting output to
stdout,stderr, or empty string only. This is a clean approach for containerized applications where logging to stdout/stderr is the standard pattern.
234-244: copyFields performs shallow copy of map values.While the map itself is copied, complex values (nested maps, slices, pointers) will still share references with the original. This is typically acceptable for logging fields (usually primitives or strings), but worth noting if complex types are used.
internal/executor/resource_executor.go (1)
386-419: deepCopyMap signature and fallback behavior are well-documented.The function clearly documents the fallback to shallow copy and the associated risks. The warning log on fallback is appropriate for debugging unexpected copy failures.
internal/executor/executor_test.go (1)
119-131: Test correctly validates new ExecutionContext API.The test properly validates that
NewExecutionContextinitializesEventDatafrom the provided map and sets appropriate defaults forParams,Resources, andAdapter.ExecutionStatus.pkg/logger/logger_test.go (3)
8-55: Comprehensive test coverage for NewLogger.Tests cover default config, JSON format, and text format with stderr output. The validation of the returned type ensures the implementation matches the interface.
57-68: Good validation test for invalid output.This test ensures that
NewLoggerproperly rejects invalid output destinations, which aligns with the decision to restrict output to stdout/stderr only.
358-384: Context helper tests validate field propagation.Tests verify that
WithEventID,WithClusterID, andWithTraceIDproperly store values that can be retrieved viaGetLogFields. This ensures the context-aware logging pipeline works end-to-end.internal/executor/post_action_executor.go (3)
81-86: Evaluator creation correctly passes context and logger.The evaluator is properly initialized with
ctxandpae.log, aligning with theNewEvaluatorsignature that requires both parameters. Per the external snippet,NewEvaluatorwill panic if either is nil, so this depends on proper upstream validation.
156-197: processValue handles recursive structures correctly.The method properly handles nested maps, slices, and type conversions while threading context through recursive calls. The expression evaluation via
evaluator.EvaluateExpressionDefis correctly placed before recursive processing.
224-249: executeAPICall properly captures response details even on error.The implementation correctly populates
result.APIResponseandresult.HTTPStatusbefore checking for errors, ensuring response details are available for debugging failed calls.
3b3c199 to
4ca8360
Compare
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: 8
♻️ Duplicate comments (13)
internal/executor/resource_executor.go (1)
24-31: Incomplete validation inNewExecutorleavesK8sClientunchecked.The comment states the caller is responsible for config validation, but per the past review comment,
NewExecutoronly validatesLoggerandAPIClient, notK8sClient. This could lead to nil pointer dereference in methods likecreateResource,updateResource, etc., that checkre.k8sClient == nilbut only after attempting operations.internal/criteria/cel_evaluator_test.go (1)
156-156: Test semantics changed:nullValueis no longer null.The test case "access field on null returns error in result (safe)" at lines 182-188 expects
nullValueto be null, but it's now set totestLog()(a logger instance). This changes the test semantics - you're no longer testing null value access, but rather testing field access on a logger object.🔎 Proposed fix to restore original semantics
- ctx.Set("nullValue", testLog()) + ctx.Set("nullValue", nil)internal/hyperfleet_api/client.go (1)
309-309: Inconsistent indentation (duplicate issue).Line 309 has double indentation (two tabs) instead of single indentation to match surrounding code. The same issue appears on line 329. This was flagged in a previous review and marked as addressed, but the extra whitespace is still present in this diff.
🔎 Apply this diff to fix the indentation:
// Execute request - c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) + c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) httpResp, err := c.client.Do(httpReq)And for line 329:
- c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status) + c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status)test/integration/executor/executor_integration_test.go (10)
599-599: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog()) + apiClient, err := hyperfleet_api.NewClient(testLog()) + require.NoError(t, err, "failed to create API client")
548-548: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog()) + apiClient, err := hyperfleet_api.NewClient(testLog()) + require.NoError(t, err, "failed to create API client")
913-913: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog()) + apiClient, err := hyperfleet_api.NewClient(testLog()) + require.NoError(t, err, "failed to create API client")
1025-1027: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog(), + apiClient, err := hyperfleet_api.NewClient(testLog(), hyperfleet_api.WithRetryAttempts(1), ) + require.NoError(t, err, "failed to create API client")
334-336: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog(), + apiClient, err := hyperfleet_api.NewClient(testLog(), hyperfleet_api.WithRetryAttempts(1), ) + require.NoError(t, err, "failed to create API client")
666-666: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog()) + apiClient, err := hyperfleet_api.NewClient(testLog()) + require.NoError(t, err, "failed to create API client")
1340-1340: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog()) + apiClient, err := hyperfleet_api.NewClient(testLog()) + require.NoError(t, err, "failed to create API client")
447-447: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog()) + apiClient, err := hyperfleet_api.NewClient(testLog()) + require.NoError(t, err, "failed to create API client")
782-782: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog()) + apiClient, err := hyperfleet_api.NewClient(testLog()) + require.NoError(t, err, "failed to create API client")
495-495: Handle the error returned by NewClient.The error from
hyperfleet_api.NewClientis being ignored, which could cause a nil pointer panic if client creation fails.🔎 Apply this diff:
- apiClient, _ := hyperfleet_api.NewClient(testLog()) + apiClient, err := hyperfleet_api.NewClient(testLog()) + require.NoError(t, err, "failed to create API client")
🧹 Nitpick comments (9)
internal/executor/resource_executor.go (1)
79-80: Consider fixing indentation alignment for log statements.Several log statements have inconsistent indentation (e.g., lines 79-80, 85, 90, 99, 101, 115, 121, 132, 154). While not affecting functionality, aligning them with the surrounding code would improve readability.
🔎 Example fix for line 79-80
-re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)", + re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)", gvk.Group, gvk.Kind, manifest.GetName(), manifest.GetNamespace())Also applies to: 85-85, 90-90, 99-99, 101-101, 115-115, 121-121, 132-132, 154-154
test/integration/executor/executor_k8s_integration_test.go (1)
470-470: Consider handling the error return fromNewClient.Throughout the tests, the error return from
hyperfleet_api.NewClient(testLog())is ignored with_. While unlikely to fail in tests (logger is valid, no options that could error), usingrequire.NoError(t, err)would make tests more robust and provide clearer failure messages if the API changes.🔎 Example fix
- apiClient, _ := hyperfleet_api.NewClient(testLog()) + apiClient, err := hyperfleet_api.NewClient(testLog()) + require.NoError(t, err)Also applies to: 576-576, 646-646, 703-703, 751-751, 906-906, 969-969
pkg/logger/logger.go (4)
30-31: Consider addingFatalffor consistency with other formatted methods.The interface provides
Debugf,Infof,Warnf,Errorfbut lacksFatalf. WhileFatalis rarely used with formatting, adding it would make the API symmetric.Also applies to: 37-39
96-108: Output validation now rejects file paths - verify this is intentional.Per the past review about file handle leaks, the code now returns an error for any output other than
stdout,stderr, or empty string. The docstring at line 97 should be updated to match this stricter validation (it currently says "or empty" but doesn't mention file paths are rejected).🔎 Suggested docstring update
// NewLogger creates a new Logger with the given configuration -// Returns error if output is invalid (must be "stdout", "stderr", or empty) +// Returns error if output is invalid. +// Supported outputs: "stdout" (default), "stderr", or empty (defaults to stdout). +// File paths are not supported to avoid resource leaks. func NewLogger(cfg Config) (Logger, error) {
228-232:Fatalcallsos.Exit(1)which is not testable.The
Fatalmethod directly callsos.Exit(1), making it impossible to test without terminating the test process. Consider accepting an exit function via config or providing a way to override this behavior in tests.🔎 Suggested approach
// In Config struct: type Config struct { // ... existing fields // ExitFunc is called by Fatal. Defaults to os.Exit. ExitFunc func(int) } // In NewLogger: exitFunc := cfg.ExitFunc if exitFunc == nil { exitFunc = os.Exit } // Store in logger struct and use in Fatal
290-305:GetStackTraceis exported but appears unused in this PR.Consider whether this utility needs to be public. If it's intended for future use or external consumers, adding a brief doc comment explaining typical use cases would be helpful.
internal/executor/executor_test.go (1)
312-319: Unnecessary CloudEvent creation in test.These lines create a
CloudEventand set data on it, but onlyeventData(the map) is used in the actual test at line 372. Theevtvariable is unused after line 319. This is likely leftover from the previous CloudEvent-based implementation.🔎 Suggested cleanup
func TestParamExtractor(t *testing.T) { t.Setenv("TEST_ENV", "env-value") - evt := event.New() eventData := map[string]interface{}{ "cluster_id": "test-cluster", "nested": map[string]interface{}{ "value": "nested-value", }, } - _ = evt.SetData(event.ApplicationJSON, eventData)internal/executor/executor.go (1)
256-261: Double serialization when input is already a map.When
dataismap[string]interface{}, it's marshaled to JSON and then unmarshaled twice (toEventDataand back tomap[string]interface{}). This is inefficient - the raw map could be returned directly.🔎 Suggested optimization
case map[string]interface{}: - // Already a map, marshal to JSON for struct conversion - jsonBytes, err = json.Marshal(v) - if err != nil { - return nil, nil, fmt.Errorf("failed to marshal map data: %w", err) - } + // Already a map - marshal only for struct conversion + jsonBytes, err = json.Marshal(v) + if err != nil { + return nil, nil, fmt.Errorf("failed to marshal map data: %w", err) + } + // Parse into structured EventData + var eventData EventData + if err := json.Unmarshal(jsonBytes, &eventData); err != nil { + return nil, nil, fmt.Errorf("failed to unmarshal to EventData: %w", err) + } + return &eventData, v, nil // Return original map directlypkg/logger/logger_test.go (1)
451-452: Remove extra blank line.Minor formatting issue - there are two consecutive blank lines.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (38)
cmd/adapter/main.gogo.modinternal/config_loader/loader.gointernal/config_loader/validator.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/criteria/test_helpers_test.gointernal/executor/README.mdinternal/executor/executor.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/k8s_client/client.gointernal/k8s_client/discovery.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.gotest/integration/testutil/logger.go
💤 Files with no reviewable changes (3)
- internal/executor/param_extractor.go
- internal/executor/README.md
- go.mod
🚧 Files skipped from review as they are similar to previous changes (7)
- internal/criteria/evaluator_scenarios_test.go
- internal/criteria/evaluator.go
- internal/config_loader/validator_test.go
- test/integration/testutil/logger.go
- test/integration/config-loader/config_criteria_integration_test.go
- internal/k8s_client/discovery.go
- test/integration/k8s_client/helper_envtest_prebuilt.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.go
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
cmd/adapter/main.gointernal/hyperfleet_api/client.gointernal/config_loader/validator.gointernal/executor/types.gointernal/executor/executor.gointernal/config_loader/loader.gotest/integration/executor/executor_integration_test.go
🧬 Code graph analysis (17)
internal/executor/utils_test.go (1)
internal/executor/utils.go (1)
ExecuteLogAction(39-70)
test/integration/executor/main_test.go (3)
test/integration/testutil/logger.go (1)
TestLogger(17-32)pkg/logger/logger.go (1)
Config(55-66)internal/k8s_client/client.go (1)
Client(29-32)
internal/criteria/evaluator_version_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
internal/executor/post_action_executor_test.go (5)
pkg/logger/logger.go (3)
Logger(15-41)NewLogger(98-151)Config(55-66)internal/executor/post_action_executor.go (1)
PostActionExecutor(15-18)internal/executor/types.go (1)
ExecutorConfig(57-67)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)internal/executor/utils.go (1)
ExecuteAPICall(76-206)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(105-121)
internal/executor/precondition_executor.go (5)
internal/executor/types.go (2)
ExecutorConfig(57-67)ExecutionContext(181-196)internal/config_loader/types.go (2)
Precondition(98-105)APICall(108-116)internal/executor/utils.go (1)
ExecuteLogAction(39-70)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)internal/config_loader/constants.go (1)
FieldValue(72-72)
internal/criteria/evaluator_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
internal/criteria/test_helpers_test.go (1)
pkg/logger/logger.go (3)
Logger(15-41)NewLogger(98-151)Config(55-66)
internal/executor/utils.go (3)
internal/config_loader/types.go (1)
LogAction(206-209)internal/executor/types.go (1)
ExecutionContext(181-196)pkg/logger/logger.go (1)
Logger(15-41)
internal/executor/executor.go (2)
internal/executor/types.go (6)
Executor(70-76)ExecutorConfig(57-67)NewExecutionContext(254-265)StatusSuccess(35-35)ExecutionContext(181-196)EventData(48-54)pkg/logger/context.go (4)
WithResourceID(95-97)WithResourceType(90-92)WithDynamicResourceID(64-67)WithEventID(80-82)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-41)
internal/criteria/cel_evaluator_test.go (2)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
pkg/logger/logger.go (1)
pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
internal/executor/resource_executor.go (4)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (10)
ExecutorConfig(57-67)ExecutionContext(181-196)ResourceResult(127-144)StatusSuccess(35-35)OperationRecreate(155-155)OperationUpdate(153-153)OperationCreate(151-151)StatusFailed(37-37)PhaseResources(25-25)NewExecutorError(375-382)internal/k8s_client/interface.go (1)
K8sClient(13-47)internal/config_loader/types.go (1)
Resource(171-178)
internal/hyperfleet_api/client_test.go (3)
pkg/logger/logger.go (3)
Logger(15-41)NewLogger(98-151)Config(55-66)internal/hyperfleet_api/client.go (4)
NewClient(119-148)WithBaseURL(102-106)WithDefaultHeader(57-64)WithConfig(48-54)internal/k8s_client/client.go (1)
NewClient(65-114)
internal/executor/executor_test.go (3)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (4)
NewExecutionContext(254-265)EventData(48-54)StatusSuccess(35-35)ExecutionStatus(31-31)pkg/logger/context.go (1)
WithEventID(80-82)
test/integration/executor/executor_integration_test.go (3)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)internal/k8s_client/client.go (1)
NewClient(65-114)pkg/logger/logger.go (1)
Logger(15-41)
🔇 Additional comments (39)
internal/config_loader/loader.go (1)
172-174: LGTM!The refactor to use
newValidator(config).Validate()correctly aligns with the new internal validator API. The previous concern about nil logger is no longer applicable since logging has been removed from the validator entirely.internal/config_loader/validator.go (2)
65-71: LGTM!The constructor is now unexported (
newValidator) which correctly reflects its internal-only usage fromloader.go. Removing the logger dependency simplifies the validation flow.
391-407: LGTM!The shift to syntax-only CEL validation is appropriate given that variables are declared with
DynType. Full type-checking would be meaningless since actual types are only known at runtime. The comments clearly document this design decision.internal/executor/precondition_executor.go (3)
32-70: LGTM!The
ExecuteAllmethod correctly uses the internal logger with context-aware logging. The structured logging with precondition index/count provides good observability.
73-200: LGTM!The
executePreconditionmethod properly:
- Uses context-aware logging throughout
- Sets
ExecutionErroron failures for downstream error reporting- Correctly passes
pe.logtoExecuteLogActionandcriteria.NewEvaluator- Maintains clear separation between execution errors and business outcomes (precondition not met)
21-28: Logger validation is properly implemented.
NewExecutorvalidates thatconfig.Loggeris non-nil viavalidateExecutorConfig()(lines 30-43), which checks "Logger" as a required field beforenewPreconditionExecutoris instantiated. The validation occurs at line 18 before line 24 where the constructor is called, ensuring no nil logger can reachcriteria.NewEvaluator. No action required.internal/executor/resource_executor.go (2)
35-55: LGTM!The
ExecuteAllmethod correctly uses context-aware logging with resource index/count for observability.
404-431: LGTM!The
deepCopyMapfunction now accepts context and logger for proper warning logging when fallback to shallow copy occurs. The warning message clearly communicates the potential risk of shared references.internal/executor/post_action_executor.go (4)
31-77: LGTM!The
ExecuteAllmethod properly:
- Builds payloads with context-aware logging
- Sets
ExecutionErroron failures for error reporting- Stops execution on first failure (fail-fast behavior)
- Uses structured logging with action index/count
81-116: LGTM!Converting
buildPostPayloadsto a method and adding context propagation improves consistency. The evaluator is correctly initialized withpae.log.
156-197: LGTM!The
processValuemethod correctly handles recursive payload building with proper context propagation through all nested structures (maps, slices, expression definitions).
20-27: Design is sound—config validation occurs at the entry point.The constructor's reliance on caller validation is correctly implemented.
NewExecutorcallsvalidateExecutorConfig(config)before creating sub-executors, explicitly validating that "Logger" and other required fields are non-nil. The comment accurately describes the design pattern: validation at the boundary ensures sub-executors can safely assume valid config.test/integration/executor/setup_test.go (1)
25-28: LGTM!The
testLog()helper provides a clean way to obtain a shared logger for tests that don't require the full K8s environment, complementingK8sTestEnv.Logfor K8s-specific tests.internal/criteria/test_helpers_test.go (1)
1-23: LGTM!Well-structured test helper with:
- Thread-safe singleton initialization via
sync.Once- Appropriate test configuration (debug level for visibility, text format for readability)
- Fail-fast behavior (panic) if logger creation fails during test setup
This pattern is consistent with the project's test utilities.
test/integration/executor/executor_k8s_integration_test.go (1)
318-321: LGTM!The
NewClientcall correctly passestestLog()as the first argument, aligning with the API change. The additional options for timeout and retry are appropriately configured for integration tests.internal/criteria/evaluator_version_test.go (1)
4-4: LGTM!The context import and updated
NewEvaluatorcalls correctly align with the new signatureNewEvaluator(ctx context.Context, evalCtx *EvaluationContext, log logger.Logger). Usingcontext.Background()is appropriate for unit tests.Also applies to: 17-17, 52-52, 79-79, 146-146
internal/executor/utils_test.go (1)
4-4: LGTM!The
ExecuteLogActioncall correctly includescontext.Background()as the first argument, matching the updated function signature.Also applies to: 778-778
internal/k8s_client/client.go (1)
81-81: LGTM!All logging calls are consistently updated to pass
ctxas the first parameter, enabling context-aware structured logging throughout the Kubernetes client operations.Also applies to: 88-88, 136-136, 153-153, 159-159, 185-185, 198-198, 231-231, 261-261, 278-278, 284-284, 294-294, 307-307, 337-337, 371-372
internal/hyperfleet_api/client_test.go (2)
22-36: LGTM!The shared test logger pattern using
sync.Onceis idiomatic Go for test utilities. UsingLevel: "error"appropriately reduces test output noise while still capturing errors. The panic on logger creation failure is acceptable for test setup since it indicates a fundamental configuration issue.
40-40: LGTM!All
NewClientcalls consistently passtestLog()as the first argument, correctly matching the updated signatureNewClient(log logger.Logger, opts ...ClientOption).Also applies to: 63-63, 137-137, 162-162, 195-195, 227-227, 266-266, 301-301, 332-332, 362-362, 377-377, 480-480, 501-501, 522-522, 652-652
test/integration/executor/main_test.go (2)
105-105: LGTM!Using
testutil.TestLogger()for integration tests ensures consistent logger configuration across the test suite.
186-213: Response body not closed on non-200 status codes.When the HTTP response returns a non-200 status code, the response body is not closed before the next iteration. This can lead to resource leaks during the retry loop.
🔎 Proposed fix
resp, err := client.Do(req) if err == nil { - _ = resp.Body.Close() if resp.StatusCode == http.StatusOK { + _ = resp.Body.Close() return nil // API server is ready } + _ = resp.Body.Close() }Likely an incorrect or invalid review comment.
internal/criteria/cel_evaluator_test.go (1)
4-4: LGTM!The context import and updated constructor calls correctly align with the new context-aware API. The test function rename to
Test_newCELEvaluatorappropriately reflects testing the unexportednewCELEvaluatorfunction.Also applies to: 12-12, 17-17, 29-29, 133-133, 158-158, 249-249, 268-268, 444-444, 473-473, 536-536
internal/executor/resource_executor_test.go (1)
19-19: LGTM!All
deepCopyMapcalls are correctly updated to includecontext.Background()andtestLog()as parameters, matching the new function signature.Also applies to: 45-45, 69-69, 90-90, 112-112, 134-134, 150-150, 166-166, 180-180, 204-204, 230-230
internal/executor/post_action_executor_test.go (2)
18-42: LGTM!The shared test logger pattern and
testPAE()helper reduce boilerplate and ensure consistent test setup. Usingsync.Oncefor the logger is idiomatic and thread-safe.
45-45: LGTM!Test cases are correctly updated to use the new helpers (
testPAE(),testLog()) and properly pass context and logger to constructors and methods. TheNewExecutionContextcalls correctly includecontext.Background().Also applies to: 117-119, 133-133, 222-224, 238-238, 348-350, 437-444, 654-662
pkg/logger/logger.go (2)
13-41: Well-designed context-aware Logger interface.The interface cleanly separates concerns with context as the first parameter for all log methods, enabling structured logging with request-scoped fields. The fluent API (
With,WithFields,WithError) follows idiomatic Go patterns.
167-186: Potential field key collision between logger fields and context fields.When
buildArgsmergesl.fieldsand contextLogFields, if both contain the same key, the context value will silently overwrite the logger field value (since context fields are appended after). This may be intentional (context takes precedence), but could cause unexpected behavior.Consider documenting this precedence or detecting/logging collisions in debug mode.
internal/executor/executor_test.go (4)
22-40: Mock logger implementation looks correct.The
mockLoggerproperly implements the updatedLoggerinterface with context-aware methods. Capturing warnings at line 32 is useful for specific test assertions.
119-131: Test correctly validates newExecutionContextAPI.The test properly exercises the updated
NewExecutionContextsignature withmap[string]interface{}and validates field access viaEventData.
541-542: Good use of context-based event ID correlation.Tests consistently use
logger.WithEventID(context.Background(), ...)before callingExecute, demonstrating proper adoption of the new context-aware logging pattern.Also applies to: 646-647, 720-721, 790-791
7-7: Remove unused import:cloudevents/sdk-go/v2/event.The
eventpackage is only used at lines 312 and 319 to create aCloudEventand set its data viaevt.SetData(event.ApplicationJSON, eventData), but theevtvariable is never referenced afterward. SinceeventDatais already defined as a map with the necessary test data, the CloudEvent creation is unnecessary and can be removed along with this import.internal/executor/executor.go (2)
62-68: Context enrichment logic handles both owned and direct resources well.The branching correctly distinguishes between events with
OwnedReference(adding both resource and owner IDs) and direct events. This provides good traceability in logs.
239-283:ParseEventDatais well-structured with comprehensive input handling.The function cleanly handles multiple input types (nil, []byte, map, generic) and provides clear error messages. The dual return of structured
EventDataand raw map enables both typed and flexible access patterns.pkg/logger/logger_test.go (5)
8-55: Good test coverage for logger initialization.Tests cover default config, JSON format, and text format with stderr output. The type assertion check ensures the correct implementation is returned.
57-68: Good negative test for invalid output.This test validates the error path when an invalid output is provided, ensuring the validation logic works correctly.
148-175: Thorough testing ofWithErrorincluding nil handling.The test validates both the happy path (error message extracted) and edge case (nil error returns same logger). This is important for preventing nil pointer issues.
386-423: Environment variable tests properly uset.Setenv.Using
t.Setenvensures automatic cleanup after each test, preventing test pollution. Good practice.
453-480: Good integration test for context extraction.This test validates end-to-end context propagation through the logger without panicking, which is crucial for the context-aware logging refactor.
4ca8360 to
20ef0c6
Compare
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
♻️ Duplicate comments (5)
internal/criteria/cel_evaluator_test.go (1)
156-158: Test semantics changed:nullValueis no longer null.The test case "access field on null returns error in result (safe)" at lines 182-188 expects
nullValueto be null, but it's set totestLog()(a logger instance). This changes the test semantics - the test still passes because accessing.fieldon a logger object fails, but for different reasons than null access.internal/executor/executor.go (2)
30-47: Remove K8sClient from required fields validation.Past review comment flagged this:
K8sClientis documented as optional intypes.go(line 62: "optional, can be nil if not needed"), butvalidateExecutorConfigincludes it inrequiredFieldsand rejectsnilvalues. Remove"K8sClient"from therequiredFieldsslice to align with the documentation, or update the documentation if it's truly required.Based on learnings, ...
190-199: Parameter order inconsistency: context should be first.Past review comment flagged this: The
finishWithErrormethod hasctxas the last parameter (line 190), which violates Go conventions wherecontext.Contextshould always be the first parameter. This is inconsistent with all other methods in the file.🔎 Suggested fix
-func (e *Executor) finishWithError(result *ExecutionResult, execCtx *ExecutionContext, err error, reason string, ctx context.Context) *ExecutionResult { +func (e *Executor) finishWithError(ctx context.Context, result *ExecutionResult, execCtx *ExecutionContext, err error, reason string) *ExecutionResult {Update call site at line 88:
- return e.finishWithError(result, execCtx, err, fmt.Sprintf("parameter extraction failed: %v", err), ctx) + return e.finishWithError(ctx, result, execCtx, err, fmt.Sprintf("parameter extraction failed: %v", err))pkg/logger/logger.go (1)
234-244: Fix comment: copyFields performs shallow copy, not deep copy.Past review comment flagged this: The comment states "deep copy" but the implementation only copies top-level map entries. If any value is a map, slice, or pointer, modifications would affect both loggers.
🔎 Suggested fix
-// copyFields creates a deep copy of the fields map +// copyFields creates a shallow copy of the fields map func copyFields(f map[string]interface{}) map[string]interface{} {test/integration/executor/executor_integration_test.go (1)
232-232: Handle errors from hyperfleet_api.NewClient.Multiple past review comments flagged that errors from
hyperfleet_api.NewClientare being ignored with_. This can cause nil pointer panics if client creation fails. While line 92-96 was fixed, these instances remain:
- Line 232
- Line 334
- Line 447
- Line 495
- Line 548
- Line 599
- Line 632
- Line 666
- Line 730
- Line 782
- Line 913
- Line 1025
- Line 1202
- Line 1340
🔎 Suggested fix (apply to all instances)
- apiClient, _ := hyperfleet_api.NewClient(...) + apiClient, err := hyperfleet_api.NewClient(...) + require.NoError(t, err, "failed to create API client")Also applies to: 334-334, 447-447, 495-495, 548-548, 599-599, 632-632, 666-666, 730-730, 782-782, 913-913, 1025-1025, 1202-1202, 1340-1340
🧹 Nitpick comments (3)
test/integration/executor/executor_k8s_integration_test.go (1)
318-321: Error fromNewClientis discarded.Multiple test functions ignore the error returned by
hyperfleet_api.NewClient. While test setup failures would likely cause subsequent test failures anyway, explicitly checking the error provides clearer diagnostics.🔎 Proposed fix
- apiClient, _ := hyperfleet_api.NewClient(testLog(), + apiClient, err := hyperfleet_api.NewClient(testLog(), hyperfleet_api.WithTimeout(10*time.Second), hyperfleet_api.WithRetryAttempts(1), ) + require.NoError(t, err, "failed to create API client")This pattern repeats at lines 470, 576, 646, 703, 751, 906, and 969.
internal/hyperfleet_api/client_test.go (1)
22-36: Consider using the sharedlogger.NewTestLogger()instead of duplicating the pattern.This
testLog()helper duplicates the pattern frompkg/logger/test_support.gowith a minor difference (stdout vs stderr). Using the shared helper would reduce duplication and ensure consistent test logger configuration across the codebase.🔎 Proposed fix
-var ( - sharedTestLogger logger.Logger - loggerOnce sync.Once -) - -func testLog() logger.Logger { - loggerOnce.Do(func() { - var err error - sharedTestLogger, err = logger.NewLogger(logger.Config{Level: "error", Format: "text", Output: "stdout", Component: "test", Version: "test"}) - if err != nil { - panic(err) - } - }) - return sharedTestLogger -} +func testLog() logger.Logger { + return logger.NewTestLogger() +}internal/executor/executor_test.go (1)
294-301: Consider removing unused CloudEvent creation.The
evtvariable is created andSetDatais called, but onlyeventDatais used afterward. The CloudEvent object itself appears unused in this test.🔎 Proposed simplification
- evt := event.New() eventData := map[string]interface{}{ "cluster_id": "test-cluster", "nested": map[string]interface{}{ "value": "nested-value", }, } - _ = evt.SetData(event.ApplicationJSON, eventData)
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (38)
cmd/adapter/main.gogo.modinternal/config_loader/loader.gointernal/config_loader/validator.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/criteria/test_helpers_test.gointernal/executor/README.mdinternal/executor/executor.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/k8s_client/client.gointernal/k8s_client/discovery.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/test_support.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.go
💤 Files with no reviewable changes (3)
- internal/executor/README.md
- internal/executor/param_extractor.go
- go.mod
🚧 Files skipped from review as they are similar to previous changes (5)
- internal/k8s_client/discovery.go
- internal/criteria/test_helpers_test.go
- internal/executor/post_action_executor_test.go
- internal/k8s_client/client.go
- internal/criteria/evaluator_scenarios_test.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
test/integration/config-loader/config_criteria_integration_test.gointernal/config_loader/validator.gocmd/adapter/main.gointernal/executor/executor.gointernal/executor/utils_test.gointernal/config_loader/loader.gointernal/executor/types.gointernal/hyperfleet_api/client.gotest/integration/executor/executor_integration_test.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.go
🧬 Code graph analysis (20)
test/integration/config-loader/config_criteria_integration_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(13-28)
test/integration/executor/main_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(13-28)pkg/logger/logger.go (1)
Config(55-66)internal/k8s_client/client.go (1)
Client(29-32)
internal/criteria/evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-41)
internal/criteria/evaluator_version_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
test/integration/executor/executor_k8s_integration_test.go (1)
internal/hyperfleet_api/client.go (1)
NewClient(119-148)
internal/executor/executor_test.go (4)
pkg/logger/logger.go (1)
Logger(15-41)pkg/logger/test_support.go (1)
NewTestLogger(13-28)internal/executor/types.go (4)
NewExecutionContext(254-265)EventData(48-54)StatusSuccess(35-35)ExecutionStatus(31-31)pkg/logger/context.go (1)
WithEventID(80-82)
internal/criteria/evaluator_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
internal/criteria/cel_evaluator_test.go (2)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(105-121)
internal/executor/executor.go (2)
internal/executor/types.go (6)
Executor(70-76)ExecutorConfig(57-67)NewExecutionContext(254-265)StatusSuccess(35-35)ExecutionContext(181-196)EventData(48-54)pkg/logger/context.go (4)
WithResourceID(95-97)WithResourceType(90-92)WithDynamicResourceID(64-67)WithEventID(80-82)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-41)
internal/executor/utils_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(13-28)internal/executor/types.go (1)
ExecutionContext(181-196)internal/executor/utils.go (1)
ExecuteLogAction(39-70)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(55-66)DefaultConfig(69-77)NewLogger(98-151)ConfigFromEnv(80-94)pkg/logger/context.go (10)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithClusterID(85-87)WithTraceID(70-72)
internal/executor/precondition_executor.go (5)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (5)
ExecutorConfig(57-67)ExecutionContext(181-196)PreconditionsOutcome(385-395)PreconditionResult(105-124)StatusFailed(37-37)internal/config_loader/types.go (2)
Precondition(98-105)APICall(108-116)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
pkg/logger/logger.go (1)
pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
test/integration/k8s_client/helper_envtest_prebuilt.go (1)
pkg/logger/test_support.go (1)
NewTestLogger(13-28)
internal/executor/post_action_executor.go (5)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (2)
ExecutorConfig(57-67)ExecutionContext(181-196)internal/config_loader/types.go (4)
PostConfig(193-196)Payload(67-78)PostAction(199-203)APICall(108-116)internal/criteria/evaluator.go (2)
NewEvaluator(55-70)Evaluator(41-51)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)
internal/hyperfleet_api/client.go (2)
pkg/logger/logger.go (1)
Logger(15-41)internal/hyperfleet_api/types.go (2)
Client(216-237)DefaultClientConfig(57-66)
test/integration/executor/setup_test.go (2)
pkg/logger/logger.go (1)
Logger(15-41)pkg/logger/test_support.go (1)
NewTestLogger(13-28)
test/integration/executor/executor_integration_test.go (3)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)internal/k8s_client/client.go (1)
NewClient(65-114)pkg/logger/logger.go (1)
Logger(15-41)
🔇 Additional comments (59)
test/integration/k8s_client/helper_envtest_prebuilt.go (1)
100-100: LGTM!The switch to
logger.NewTestLogger()aligns with the PR's standardized test logging approach. The singleton pattern inNewTestLogger()ensures consistent logger instances across tests while reducing noise with the "error" log level.test/integration/executor/main_test.go (2)
106-106: LGTM!Consistent with the PR's standardized test logging approach using the singleton test logger.
185-220: LGTM! HTTP-based health check is more reliable during startup.The refactored
waitForAPIServerReadyfunction uses a direct HTTP health check which is more reliable than Kubernetes client operations during API server initialization. Good security practice to setMinVersion: tls.VersionTLS12alongside the necessaryInsecureSkipVerifyfor self-signed certs.pkg/logger/context.go (1)
1-132: LGTM! Well-designed context-based logging facility.The implementation follows Go best practices for context values:
- Custom
contextKeytype prevents collisions- Defensive copy in
GetLogFieldsprevents external mutation- Typed setters provide a clean API for common fields
WithDynamicResourceIDoffers flexible resource ID namingThe copy-on-write approach in
WithLogField/WithLogFieldsensures immutability at the cost of some allocation, which is acceptable for logging contexts.pkg/logger/logger_test.go (1)
8-480: LGTM! Comprehensive test coverage for the logger package.The test suite thoroughly covers:
- Logger creation with various configurations
- Error handling for invalid outputs
- Fluent API methods (
With,WithFields,WithError)- Nil error handling in
WithError- Context key constants and helpers
- Environment variable configuration
- Log level parsing
Good use of table-driven tests and
t.Setenvfor environment variable testing.internal/config_loader/loader.go (1)
171-175: LGTM! Simplified validation API.The refactored call to
newValidator(config).Validate()removes the logger dependency from validation, which resolves the previously flagged nil logger issue. The error wrapping is preserved for proper error context.internal/config_loader/validator_test.go (2)
792-793: LGTM!Test updated to use the new internal validator API pattern
newValidator(config).Validate().
828-832: LGTM!Consistent with the validator API migration. The test continues to properly verify that invalid
ManifestItemsare rejected with appropriate error messages.pkg/logger/test_support.go (1)
1-29: LGTM! Well-implemented test logger singleton.The implementation correctly uses
sync.Oncefor thread-safe lazy initialization. Configuration choices are appropriate:
- "error" level minimizes noise during test runs
- "stderr" output is standard for test logging
- Panic on initialization failure ensures fast failure in tests
The singleton pattern ensures consistent logger instances across all tests in the codebase.
test/integration/executor/setup_test.go (1)
24-27: LGTM!The
testLog()helper provides a convenient wrapper for tests that need a logger independently of the K8s environment, and it's actively used throughout the test suite for API client initialization. This follows the PR's standardized test logging pattern.internal/criteria/evaluator_version_test.go (1)
13-17: LGTM!The test correctly updates to the new three-parameter
NewEvaluatorsignature withcontext.Background(), the evaluation context, andtestLog(). This pattern is consistently applied across all test functions in this file.test/integration/config-loader/config_criteria_integration_test.go (1)
73-73: LGTM!The integration tests correctly use
logger.NewTestLogger()(the public API) since they're in a different package. AllNewEvaluatorcalls are properly updated to the new three-parameter signature.internal/hyperfleet_api/client_test.go (1)
38-43: LGTM!The
NewClientcalls are correctly updated to passtestLog()as the first parameter, aligning with the new constructor signature.internal/executor/utils_test.go (1)
773-783: LGTM!The test correctly adapts to the new
ExecuteLogActionsignature by passingcontext.Background()and usinglogger.NewTestLogger()for the logger parameter.internal/criteria/cel_evaluator_test.go (2)
12-20: LGTM!The test function is correctly renamed to
Test_newCELEvaluatorto reflect the now-private constructor, and the signature update to passcontext.Background(), evaluation context, andtestLog()is correct.
438-444: LGTM!The
NewEvaluatorcall in the integration test correctly uses the three-parameter signature.internal/criteria/evaluator.go (3)
54-70: LGTM!The updated
NewEvaluatorconstructor with explicit nil-checks that panic is a solid defensive design choice. It ensures fail-fast behavior during initialization rather than cryptic nil-pointer dereferences later. The three-parameter signature (ctx,evalCtx,log) clearly separates concerns.
72-93: LGTM!The
getCELEvaluatormethod correctly handles version tracking to detect when the evaluation context has changed, triggering recreation of the CEL evaluator. This prevents "undeclared reference" errors when variables are added after the first evaluation.
95-119: LGTM!The field access methods (
GetField,GetFieldOrDefault,GetFieldSafe,HasField) are correctly refactored to delegate toevalCtx.GetNestedField, maintaining the same public API while using the new internal structure.internal/executor/resource_executor_test.go (2)
10-19: LGTM!The test correctly updates to the new
deepCopyMapsignature that acceptscontext.Contextandlogger.Loggerparameters. The patterndeepCopyMap(context.Background(), original, testLog())is consistently applied across all test cases.
156-176: LGTM!The test function and comments are appropriately updated to reflect the deep copy verification purpose. The test correctly validates that mutations to the copied map don't affect the original.
internal/executor/utils.go (3)
39-68: LGTM! Context-aware logging properly integrated.The
ExecuteLogActionfunction now correctly accepts and propagatescontext.Contextto all log calls. The log level mapping (debug, info, warn, error) is preserved and consistently applied.
76-206: LGTM! API call logging updated consistently.All logging points in
ExecuteAPICallnow properly pass the context parameter. The log levels are appropriate:
Infoffor operation start/completionWarnffor timeout parsing issues and retryable failuresErrorffor POST body logging on failure
264-266: Minor formatting alignment - no functional change.These are cosmetic whitespace adjustments for map entry alignment. No review concerns.
Also applies to: 381-381
internal/criteria/evaluator_test.go (2)
772-788: LGTM! Comprehensive nil parameter panic tests.The test correctly covers all three panic conditions for
NewEvaluator:
- nil
ctx(with//nolint:staticcheckfor intentional nil context)- nil
evalCtx- nil
logThis aligns with the implementation in
internal/criteria/evaluator.go(lines 54-69) that panics on nil parameters.
524-524: LGTM! Evaluator instantiation updated consistently.All
NewEvaluatorcalls now use the three-parameter signatureNewEvaluator(context.Background(), ctx, testLog()), consistent with the updated constructor contract.Also applies to: 611-611, 801-801, 826-826, 847-847, 883-883, 934-934, 960-960, 985-985, 1031-1031, 1085-1085
internal/criteria/cel_evaluator.go (3)
56-73: LGTM! CEL evaluator constructor appropriately unexported.The constructor
newCELEvaluatoris correctly made unexported since it's only created internally byEvaluator. The comment on lines 57-58 clearly documents that parameter validation is the caller's responsibility, which aligns withNewEvaluator's panic behavior for nil params.
18-23: LGTM! CELEvaluator struct updated for context-aware logging.The struct now properly separates:
evalCtxfor evaluation data contextctxfor Go context (used in logging)logfor the logger instance
164-176: LGTM! Safe evaluation with context-aware debug logging.The evaluation correctly uses
e.evalCtx.Data()for CEL evaluation data ande.ctxwithe.log.Debugffor logging evaluation failures. Debug level is appropriate here since evaluation errors are expected when data fields don't exist yet.internal/executor/types.go (3)
40-54: LGTM! New event data types well-structured.The
ResourceRefandEventDatatypes provide clear, typed representations of HyperFleet CloudEvent payloads. JSON tags are correctly defined withomitemptyfor optional fields.
75-76: LGTM! Logger field added to Executor.The
logfield enables context-aware logging throughout the executor's lifecycle.
253-265: LGTM! Simplified ExecutionContext constructor.The constructor now accepts
eventData map[string]interface{}directly instead of a CloudEvent object, aligning with the decoupling from the CloudEvents SDK for event data handling.internal/executor/executor_test.go (3)
22-23: LGTM! Test setup consistently uses NewTestLogger.All test cases properly use
logger.NewTestLogger()for the Logger field, and the orphaned comment from the past review has been addressed.Also applies to: 38-39, 46-47, 63-65, 94-95
103-113: LGTM! ExecutionContext test updated for new constructor.The test correctly verifies the new constructor behavior with map-based event data and properly asserts on
execCtx.EventData["cluster_id"].
270-278: LGTM! Execute test uses context-aware event ID injection.The test properly uses
logger.WithEventID(context.Background(), "test-event-123")to inject the event ID into the context, which aligns with the new logging approach where event IDs are propagated via context rather than extracted from CloudEvent objects.cmd/adapter/main.go (3)
116-156: LGTM! Two-phase logger initialization is well-designed.The bootstrap logger is created first with a generic component name, then recreated after config load with the adapter's actual name from
adapterConfig.Metadata.Name. This provides proper traceability from the start while ensuring the final logger reflects the adapter identity.The flag precedence (CLI > env) is correctly implemented.
79-85: LGTM! Logging flags properly documented.The flags include helpful environment variable hints in their descriptions, making it clear that both CLI and env-based configuration are supported.
306-334: LGTM! API client creation updated for logger injection.The
createAPIClientfunction now accepts and propagates the logger tohyperfleet_api.NewClient, enabling context-aware logging throughout the API client lifecycle.internal/config_loader/validator.go (3)
65-71: LGTM! Constructor appropriately unexported.The
newValidatorfunction is now unexported since validation is invoked internally throughrunValidationPipelinein the loader (as shown in the relevant code snippet frominternal/config_loader/loader.go:104-120). This reduces the public API surface appropriately.
391-407: LGTM! CEL validation simplified to syntax-only.The comment clearly explains why type-checking is skipped: variables are registered as
DynTypesince actual types are only known at runtime. Syntax validation viaParse()is sufficient to catch malformed expressions during config loading.
409-431: LGTM! Recursive build expression validation.The
validateBuildExpressionshelper correctly traverses nested build structures to find and validate any field named "expression" as CEL. The recursion handles maps, arrays, and string values appropriately.internal/hyperfleet_api/client.go (3)
119-148: LGTM! Client constructor updated with logger dependency.The
NewClientfunction now requires a logger as the first parameter, enabling context-aware logging throughout the HTTP client. The base URL validation with clear error messaging is helpful for debugging configuration issues.
150-153: LGTM! BaseURLFromEnv properly exported.Exporting this function allows callers to check the environment variable value if needed, while
NewClienthandles the fallback logic internally.
202-221: LGTM! Retry logging with appropriate levels.The retry loop correctly uses:
Warnffor failed attempts and retryable status codesInfoffor retry delay notificationsinternal/executor/precondition_executor.go (3)
21-28: LGTM - Clean config-driven initialization.The constructor properly defers validation to the caller (
NewExecutor) and cleanly wires the API client and logger from the config. This pattern is consistent across all executor types in this refactor.
32-70: LGTM - Context-aware logging well integrated.The
ExecuteAllmethod properly uses the internal logger (pe.log) with context throughout. Error handling correctly populatesExecutionErrorand returns structured errors. The logging messages are clear and informative.
144-144: LGTM - Evaluator creation follows new pattern.The evaluator is correctly instantiated with context, evaluation context, and the internal logger, aligning with the new context-aware API.
internal/executor/executor.go (2)
243-287: LGTM - ParseEventData handles multiple input types correctly.The function properly handles
nil, empty byte slices, maps, and generic types with appropriate JSON marshaling/unmarshaling. Error messages are clear and the dual return (EventData + raw map) supports both structured and flexible access patterns.
66-72: Good use of dynamic resource context enrichment.The code properly attaches resource IDs to the logging context, handling both single resources and owned references. This enables automatic correlation of log entries with specific resources throughout the execution pipeline.
pkg/logger/logger.go (2)
96-108: LGTM - File output restriction prevents resource leaks.By restricting output to
stdoutandstderronly and returning an error for file paths, the previous file handle leak issue (noted in past reviews) is properly addressed. This is the correct approach for containerized applications.
167-186: LGTM - Context field extraction well implemented.The
buildArgsmethod properly merges logger instance fields with context-derived fields, enabling flexible field attachment at both logger creation and call site. The flat structure extracted fromLogFieldsKeyaligns with the context helpers inpkg/logger/context.go.test/integration/executor/executor_integration_test.go (2)
92-96: LGTM - Error handling added as requested.Past review comments flagged that the error from
NewClientwas being ignored. This has been correctly fixed withrequire.NoError.
988-1008: LGTM - Test logger properly implements context-aware interface.The
logCaptureLoggercorrectly implements all Logger interface methods with context as the first parameter, aligning with the new context-aware logging API.internal/executor/resource_executor.go (3)
24-31: LGTM - Config-driven initialization is clean.The constructor properly delegates validation to
NewExecutorand wires the K8s client and logger from config. This is consistent with the pattern used across all executors.
35-55: LGTM - Context-aware logging throughout resource execution.The
ExecuteAllmethod properly uses the internal logger with context for all resource processing. Error handling and logging messages are clear and informative.
404-431: LGTM - deepCopyMap signature updated correctly.The function now accepts
ctxandlogparameters and uses context-aware warning logging when falling back to shallow copy. The fallback behavior is properly documented in the comment.internal/executor/post_action_executor.go (3)
20-27: LGTM - Config-driven initialization matches pattern.The constructor properly delegates validation to
NewExecutorand cleanly wires the API client and logger from config, consistent with other executors.
31-77: LGTM - Well-structured post-action execution with proper error handling.The
ExecuteAllmethod correctly:
- Builds payloads first with proper error handling
- Executes actions sequentially with context-aware logging
- Populates
ExecutionErroron failures- Stops on first failure (as documented)
The logging is clear and the error propagation is correct.
81-116: LGTM - Payload building properly integrated with evaluator.The
buildPostPayloadsmethod correctly creates a context-aware evaluator with the internal logger and processes payloads with proper error handling. The JSON marshaling for template rendering is appropriate.
6c0e49c to
0e0f0d0
Compare
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
♻️ Duplicate comments (6)
internal/criteria/cel_evaluator_test.go (1)
150-160: Test semantics issue persists:nullValueis not null.Setting
nullValuetologger.NewTestLogger()(line 157) breaks the test case at lines 183-189 which tests "access field on null returns error in result (safe)". The test is now testing field access on a logger object, not null value access.🔎 Proposed fix
- ctx.Set("nullValue", logger.NewTestLogger()) + ctx.Set("nullValue", nil)internal/executor/executor.go (2)
189-199: Parameter order inconsistency:ctxshould be first.The
finishWithErrormethod hasctx context.Contextas the last parameter, which is unconventional in Go. This was flagged in a previous review. Consider movingctxto the first position for consistency with other methods.🔎 Suggested signature change
-func (e *Executor) finishWithError(result *ExecutionResult, execCtx *ExecutionContext, err error, reason string, ctx context.Context) *ExecutionResult { +func (e *Executor) finishWithError(ctx context.Context, result *ExecutionResult, execCtx *ExecutionContext, err error, reason string) *ExecutionResult {And update the call site at line 88:
- return e.finishWithError(result, execCtx, err, fmt.Sprintf("parameter extraction failed: %v", err), ctx) + return e.finishWithError(ctx, result, execCtx, err, fmt.Sprintf("parameter extraction failed: %v", err))
30-47: K8sClient in required fields conflicts with documentation.In
types.go(line 62),K8sClientis documented as "optional, can be nil if not needed", but this validation rejects nil values. Either update the documentation to indicate K8sClient is required, or remove it fromrequiredFields.🔎 Suggested fix - remove from required fields
requiredFields := []string{ "AdapterConfig", "APIClient", - "Logger", - "K8sClient"} + "Logger"}internal/hyperfleet_api/client.go (2)
309-309: Fix inconsistent indentation on debug log statement.This line has extra leading whitespace (double-indented), which was flagged in a previous review.
🔎 Proposed fix
// Execute request - c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) + c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL)
329-329: Fix inconsistent indentation on debug log statement.Same indentation issue as line 309.
🔎 Proposed fix
- c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status) + c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status)pkg/logger/logger.go (1)
244-254:copyFieldscomment still says "deep copy" but performs shallow copy.This was flagged in a previous review. The function only copies top-level map entries; nested maps/slices would share references. Update the comment to accurately reflect the behavior.
🔎 Suggested fix
-// copyFields creates a deep copy of the fields map +// copyFields creates a shallow copy of the fields map func copyFields(f map[string]interface{}) map[string]interface{} {
🧹 Nitpick comments (7)
pkg/logger/context.go (1)
62-67: Consider validating resource type naming.
WithDynamicResourceIDderives field names by converting to lowercase and appending "_id". For resource types with spaces or special characters, this could produce unexpected field names (e.g., "My Resource" → "my resource_id").Optional: Add sanitization for field names
func WithDynamicResourceID(ctx context.Context, resourceType string, resourceID string) context.Context { - fieldName := strings.ToLower(resourceType) + "_id" + // Sanitize resource type: replace spaces/special chars with underscores + sanitized := strings.Map(func(r rune) rune { + if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' { + return r + } + return '_' + }, resourceType) + fieldName := strings.ToLower(sanitized) + "_id" return WithLogField(ctx, fieldName, resourceID) }REFACTORING_PLAN.md (1)
733-733: Minor: Add language identifier to fenced code block.The fenced code block at line 733 is missing a language identifier. Add
textorlogafter the opening backticks for better rendering.Suggested fix
-``` +```text time=2025-01-15T10:30:00.123Z level=INFO msg="Creating resource" component=adapter-validation version=v1.2.3 hostname=adapter-pod-xyz trace_id=4bf92f3577b34da6a3ce929d0e0e4736 event_id=evt-123 cluster_id=cls-456</details> </blockquote></details> <details> <summary>internal/hyperfleet_api/client_test.go (1)</summary><blockquote> `22-36`: **Consider using the centralized `logger.NewTestLogger()` instead of local `testLog()`.** This local `testLog()` implementation duplicates the functionality already provided by `logger.NewTestLogger()` in `pkg/logger/test_support.go`. The only difference is the output destination (`stdout` vs `stderr`). Using the centralized utility would: 1. Reduce code duplication 2. Ensure consistent test logger configuration across the codebase 3. Simplify maintenance <details> <summary>🔎 Proposed fix</summary> ```diff -var ( - sharedTestLogger logger.Logger - loggerOnce sync.Once -) - -func testLog() logger.Logger { - loggerOnce.Do(func() { - var err error - sharedTestLogger, err = logger.NewLogger(logger.Config{Level: "error", Format: "text", Output: "stdout", Component: "test", Version: "test"}) - if err != nil { - panic(err) - } - }) - return sharedTestLogger -}Then replace all
testLog()calls withlogger.NewTestLogger().internal/criteria/evaluator.go (1)
41-51: Minor formatting inconsistency in struct field declaration.Line 44 has inconsistent indentation compared to other fields. Consider aligning the fields for better readability.
type Evaluator struct { evalCtx *EvaluationContext log logger.Logger - ctx context.Context + ctx context.Context // Lazily cached CEL evaluator for repeated CEL evaluationspkg/logger/logger.go (1)
238-242: Consider addingFatalffor API consistency.Other log levels have both plain and formatted variants (Debug/Debugf, Info/Infof, etc.), but Fatal lacks a Fatalf variant. This could be intentional to discourage complex fatal messages, but it creates an inconsistency in the API surface.
test/integration/executor/executor_integration_test.go (1)
231-232: Consider usingrequire.NoErrorinstead ofassert.NoErrorfor critical setup.When API client creation fails, subsequent code will panic on nil pointer dereference. Using
require.NoError(which fails the test immediately) is more appropriate thanassert.NoError(which continues execution) for critical setup steps.This pattern is inconsistent across the file - some places use
require.NoError(line 95) while others useassert.NoError.🔎 Suggested fix
apiClient, err := hyperfleet_api.NewClient(k8sEnv.Log) - assert.NoError(t, err) + require.NoError(t, err, "failed to create API client")internal/executor/resource_executor.go (1)
79-80: Inconsistent indentation on log statements.Several log statements have inconsistent leading whitespace compared to surrounding code. This appears to be a formatting artifact. The
re.logcalls should be indented consistently with the surrounding code block.For example, lines 79-80, 85-86, 99-102 have
re.logat column 0 or with non-standard indentation while inside nested blocks.🔎 Suggested fix (representative example)
-re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)", + re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)", gvk.Group, gvk.Kind, manifest.GetName(), manifest.GetNamespace())Also applies to: 85-86, 90-91, 99-102, 115-116, 121-122, 125-126, 132-133
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (38)
REFACTORING_PLAN.mdcmd/adapter/main.gogo.modinternal/config_loader/loader.gointernal/config_loader/validator.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/executor/README.mdinternal/executor/executor.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/k8s_client/client.gointernal/k8s_client/discovery.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/test_support.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.go
💤 Files with no reviewable changes (3)
- go.mod
- internal/executor/param_extractor.go
- internal/executor/README.md
🚧 Files skipped from review as they are similar to previous changes (5)
- internal/config_loader/loader.go
- test/integration/executor/setup_test.go
- internal/executor/post_action_executor_test.go
- test/integration/config-loader/config_criteria_integration_test.go
- internal/config_loader/validator_test.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/criteria/evaluator_version_test.gointernal/executor/utils_test.gointernal/criteria/evaluator_scenarios_test.gointernal/config_loader/validator.gointernal/criteria/evaluator_test.gointernal/hyperfleet_api/client.gointernal/executor/executor.gocmd/adapter/main.gotest/integration/executor/executor_integration_test.gointernal/executor/types.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.go
🧬 Code graph analysis (19)
test/integration/k8s_client/helper_envtest_prebuilt.go (1)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-41)
internal/criteria/evaluator_version_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/executor/utils.go (3)
internal/config_loader/types.go (1)
LogAction(206-209)internal/executor/types.go (1)
ExecutionContext(181-196)pkg/logger/logger.go (1)
Logger(15-41)
internal/executor/executor_test.go (4)
pkg/logger/logger.go (1)
Logger(15-41)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/executor/types.go (4)
NewExecutionContext(254-265)EventData(48-54)StatusSuccess(35-35)ExecutionStatus(31-31)pkg/logger/context.go (1)
WithEventID(80-82)
internal/criteria/evaluator_scenarios_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
test/integration/executor/main_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)pkg/logger/logger.go (1)
Config(55-70)internal/k8s_client/client.go (1)
Client(29-32)
internal/hyperfleet_api/client_test.go (1)
internal/hyperfleet_api/client.go (4)
NewClient(119-148)WithBaseURL(102-106)WithDefaultHeader(57-64)WithConfig(48-54)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(105-121)
internal/criteria/cel_evaluator_test.go (3)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(55-70)DefaultConfig(73-81)NewLogger(102-161)ConfigFromEnv(84-98)pkg/logger/context.go (10)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithClusterID(85-87)WithTraceID(70-72)
internal/criteria/evaluator_test.go (3)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
internal/hyperfleet_api/client.go (3)
pkg/logger/logger.go (1)
Logger(15-41)internal/k8s_client/client.go (2)
NewClient(65-114)Client(29-32)internal/hyperfleet_api/types.go (2)
Client(216-237)DefaultClientConfig(57-66)
internal/executor/executor.go (5)
internal/executor/types.go (8)
Executor(70-76)ExecutorConfig(57-67)ExecutionResult(79-102)StatusFailed(37-37)NewExecutionContext(254-265)StatusSuccess(35-35)ExecutionContext(181-196)EventData(48-54)pkg/logger/logger.go (1)
Logger(15-41)internal/config_loader/constants.go (1)
FieldByName(93-93)pkg/logger/context.go (4)
WithResourceID(95-97)WithResourceType(90-92)WithDynamicResourceID(64-67)WithEventID(80-82)internal/config_loader/types.go (1)
AdapterConfig(6-11)
pkg/logger/test_support.go (1)
pkg/logger/logger.go (3)
Logger(15-41)NewLogger(102-161)Config(55-70)
test/integration/executor/executor_integration_test.go (4)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)internal/k8s_client/client.go (1)
NewClient(65-114)pkg/logger/test_support.go (1)
NewCaptureLogger(67-83)internal/executor/executor.go (1)
NewBuilder(295-299)
internal/executor/post_action_executor.go (5)
internal/executor/types.go (2)
ExecutorConfig(57-67)ExecutionContext(181-196)internal/config_loader/types.go (4)
PostConfig(193-196)Payload(67-78)PostAction(199-203)APICall(108-116)internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (2)
NewEvaluator(55-70)Evaluator(41-51)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)
pkg/logger/logger.go (1)
pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
internal/executor/types.go (2)
pkg/errors/error.go (1)
Href(150-153)pkg/logger/logger.go (1)
Logger(15-41)
🪛 markdownlint-cli2 (0.18.1)
REFACTORING_PLAN.md
733-733: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (85)
internal/k8s_client/client.go (1)
81-81: LGTM! Context-aware logging implemented consistently.All logging calls have been updated to pass the context as the first argument, aligning with the new logger interface. The changes are consistent throughout the file and maintain the existing logic.
Also applies to: 88-88, 136-136, 153-153, 159-159, 185-185, 198-198, 231-231, 261-261, 278-278, 284-284, 294-294, 307-307, 337-337, 371-371
internal/executor/types.go (2)
40-55: LGTM! New types for event data representation.The new
ResourceRefandEventDatatypes provide a cleaner abstraction for representing HyperFleet resources, decoupling from CloudEvents types. The JSON tags are properly defined.
254-254: All call sites properly updated to new signature.
NewExecutionContextsignature changed from acceptingevt *event.EventtoeventData map[string]interface{}. All 9 call sites throughout the codebase have been updated to use the new signature (internal/executor/executor.go:74, post_action_executor_test.go:444/654, and executor_test.go:107/117/127/179/201/354).pkg/logger/context.go (1)
119-132: LGTM! Defensive copy prevents mutation.The
GetLogFieldsfunction returns a defensive copy of the log fields map (lines 124-129), preventing external mutation of the context's internal state. The nil context check (lines 120-122) is also appropriate.pkg/logger/logger_test.go (4)
8-55: LGTM! Comprehensive logger initialization tests.The tests cover various configuration scenarios (default, JSON format, text format) and now properly handle the error return from
NewLogger. The test structure is clear and follows good practices.
57-68: LGTM! Error handling verification added.Good addition of
TestNewLoggerInvalidOutputto verify that invalid output configurations are properly rejected with errors.
70-175: LGTM! Fluent API tests are thorough.The tests for
With,WithFields, andWithErrorverify both the fluent API behavior and proper field handling, including the nil error case (lines 168-174).
358-384: LGTM! Context helper tests verify proper integration.The tests verify that context helper functions (
WithEventID,WithClusterID,WithTraceID) properly store and retrieve values viaGetLogFields.test/integration/k8s_client/helper_envtest_prebuilt.go (1)
100-100: LGTM! Updated to use test logger utility.The change from
logger.NewLogger(ctx)tologger.NewTestLogger()correctly uses the new test logger utility, which is designed for test environments.internal/executor/utils_test.go (1)
775-779: LGTM! Test updated for context-aware logging.The test correctly:
- Uses
logger.NewTestLogger()for test logging (line 775)- Passes
context.Background()as the first argument toExecuteLogAction(line 779)This aligns with the new context-aware logging API.
internal/config_loader/validator.go (2)
65-71: No breaking change to public API - package is internal.The package is located in
internal/config_loader/, which by Go convention is not part of the public API. External consumers cannot import internal packages, so changingNewValidatortonewValidatordoes not affect external API contracts. This is an internal refactoring with no impact on consumers.Likely an incorrect or invalid review comment.
391-407: Type checking is intentionally deferred to runtime where it is already caught and tested.The decision to skip type checking during validation is documented and intentional. Variables use DynType because actual types are only known at runtime. However, type errors are caught during evaluation via
EvaluateSafe(), which explicitly handles "type mismatch" errors and captures them in the result. Integration tests includingTestExecutor_CELExpressionEvaluationandTestCELEvaluatorEvaluatealready cover CEL evaluation scenarios with type-related failures.internal/k8s_client/discovery.go (1)
85-86: LGTM!The logging call correctly passes the context as the first parameter, aligning with the project-wide context-aware logging refactor.
internal/criteria/evaluator_version_test.go (5)
4-10: LGTM!The imports are correctly added to support the new context-aware logging pattern.
18-18: LGTM!The test correctly uses the three-parameter
NewEvaluatorsignature withcontext.Background()andlogger.NewTestLogger(), following the new API contract.
53-53: LGTM!Consistent usage of the updated
NewEvaluatorAPI.
80-80: LGTM!Consistent usage of the updated
NewEvaluatorAPI.
147-147: LGTM!Consistent usage of the updated
NewEvaluatorAPI.internal/criteria/evaluator_scenarios_test.go (8)
4-10: LGTM!The imports are correctly added to support the context-aware logging pattern.
47-47: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
121-121: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
134-138: LGTM!Good practice to create isolated
EvaluationContextandEvaluatorper subtest to avoid shared state mutation issues.
171-171: LGTM!Consistent usage of the updated
NewEvaluatorAPI.
211-211: LGTM!Consistent usage of the updated
NewEvaluatorAPI.
262-262: LGTM!Consistent usage of the updated
NewEvaluatorAPI.
342-342: LGTM!Consistent usage of the updated
NewEvaluatorAPI.internal/hyperfleet_api/client_test.go (1)
40-43: LGTM!The
NewClientcall correctly passes the logger as the first parameter, aligning with the updated API signature.test/integration/executor/main_test.go (2)
106-106: LGTM!Good use of the centralized
logger.NewTestLogger()instead of a local implementation.
185-220: LGTM!The HTTP-based health check implementation is well-structured:
- TLS configuration properly disables certificate verification for self-signed envtest certs with appropriate nolint comment
MinVersion: tls.VersionTLS12ensures minimum TLS security- Response body is properly closed to prevent resource leaks
- 5-second timeout and 500ms polling interval are reasonable for health checks
pkg/logger/test_support.go (1)
1-83: LGTM!Well-designed test utilities for the logging package:
NewTestLogger()correctly usessync.Oncefor thread-safe singleton initialization with "error" level to minimize test noiseLogCaptureprovides proper mutex protection for concurrent accessNewCaptureLogger()uses "debug" level to capture all log messages for assertions- The
Contains()method correctly delegates toMessages()for thread-safe accesstest/integration/executor/executor_k8s_integration_test.go (8)
318-322: LGTM!The
NewClientcall correctly passes the logger as the first parameter and properly handles the error return withrequire.NoError(t, err).
471-472: LGTM!Consistent usage of the updated
NewClientAPI with proper error handling.
578-579: LGTM!Consistent usage of the updated
NewClientAPI with proper error handling.
649-650: LGTM!Consistent usage of the updated
NewClientAPI with proper error handling.
707-708: LGTM!Consistent usage of the updated
NewClientAPI with proper error handling.
755-756: LGTM!Consistent usage of the updated
NewClientAPI with proper error handling.
910-911: LGTM!Consistent usage of the updated
NewClientAPI with proper error handling.
974-975: LGTM!Consistent usage of the updated
NewClientAPI with proper error handling.internal/criteria/evaluator_test.go (13)
4-11: LGTM!The imports are correctly added to support the context-aware logging pattern.
525-525: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
612-612: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
773-789: LGTM!Comprehensive panic tests for all three nil parameter cases. The
nolint:staticcheckcomment is appropriate since passingnilcontext is intentional to verify the panic behavior.
802-802: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
827-827: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
848-848: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
884-884: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
935-935: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
961-961: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
986-986: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
1032-1032: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.
1086-1086: LGTM!Correctly updated to use the three-parameter
NewEvaluatorsignature.internal/executor/utils.go (3)
36-70: LGTM! Context-aware logging properly threaded throughExecuteLogAction.The addition of
ctx context.Contextas the first parameter and its consistent use in all log calls (lines 47, 59, 61, 63, 65, 67) follows the new logging pattern correctly. This aligns with the HYPERFLEET-304 logger refactor.
76-206: LGTM! Context-aware logging consistently applied toExecuteAPICall.All logging statements properly pass
ctxas the first parameter, maintaining consistency with the newlogger.Loggerinterface. The changes cover all logging scenarios: info, warn, error, and debug levels.
264-266: Minor formatting alignment - no functional change.These alignment adjustments to
trim,replace, andcontainsare cosmetic only.internal/executor/resource_executor_test.go (2)
10-33: LGTM! Tests correctly updated to newdeepCopyMapsignature.All test functions consistently pass
context.Background()andtestLog()to match the updated function signature. Test assertions remain valid.
156-176: Test renamed appropriately to reflect verification purpose.The renamed test
TestDeepCopyMap_DeepCopyVerificationwith updated comments accurately describes its purpose. The function signature update is correctly applied.internal/criteria/cel_evaluator.go (3)
17-23: LGTM! CELEvaluator struct properly updated for context-aware logging.The struct now holds both:
evalCtx *EvaluationContextfor CEL evaluation datactx context.Contextfor logging contextThis separation is appropriate - Go context for request lifecycle/logging, EvaluationContext for CEL variables.
56-73: Constructor correctly wires context and evaluation context.The
newCELEvaluatorfunction properly initializes all fields. The function is now unexported (lowercasen), which is appropriate since it's called internally byNewEvaluator.
163-176: Context-aware logging inEvaluateSafeis correct.Line 164 properly uses
e.evalCtx.Data()for evaluation, and line 168 usese.ctxfor the logging call, correctly separating concerns.internal/criteria/cel_evaluator_test.go (2)
13-21: LGTM! Test function renamed and signature updated correctly.The test function name change to
Test_newCELEvaluatorfollows Go conventions for testing unexported functions, and the constructor call properly includes the new parameters.
439-470: LGTM! Integration tests correctly updated to new signatures.
NewEvaluatorcalls properly includecontext.Background()andlogger.NewTestLogger()as required by the updated public API.cmd/adapter/main.go (5)
31-36: LGTM! Logging flags properly declared.The new CLI flags for
log-level,log-format, andlog-outputprovide runtime configuration flexibility while maintaining environment variable fallback.
116-135: Good bootstrap logger pattern with config override.The approach of building config from environment first, then applying CLI flag overrides, is correct. This ensures flags take precedence over environment variables.
147-156: Logger recreation after config load is appropriate.Recreating the logger with the adapter's component name from config provides better log context for debugging. The pattern is clean.
251-265: Non-blocking error handling for subscription errors is correct.The goroutine monitors errors and signals shutdown via
fatalErrChwith a non-blocking send. This prevents the goroutine from blocking if an error was already sent.
305-334: LGTM!createAPIClientproperly accepts and propagates logger.The signature update and passing
logtohyperfleet_api.NewClientcompletes the logging integration for the API client.internal/executor/executor_test.go (4)
22-23: Orphaned comment removed as per previous review.The stale comment about
testEventWithDatahas been addressed.
101-113: LGTM! Test correctly uses map-based event data.
NewExecutionContextis properly called witheventDatamap, and assertions checkexecCtx.EventData["cluster_id"]which aligns with the new API.
270-289: LGTM! Event ID propagation via context is correct.Using
logger.WithEventID(context.Background(), "test-event-123")to attach the event ID to context, then passingeventDatamap toExecutefollows the new contract where the caller is responsible for context enrichment.
291-384: Test still creates CloudEvent but only uses its data.
TestParamExtractorcreates a CloudEvent and callsevt.SetData()(line 301), but then only passeseventDatamap toNewExecutionContext(line 354). This works correctly - the CloudEvent is just used to simulate incoming broker messages in the test setup.internal/hyperfleet_api/client.go (2)
30-35: LGTM! Logger field added to httpClient struct.The
log logger.Loggerfield enables context-aware logging throughout the HTTP client lifecycle.
119-148: LGTM! NewClient properly accepts and stores logger.The signature change to
NewClient(log logger.Logger, opts ...ClientOption)is a breaking change but correctly documented in the PR summary. The logger is stored in the client struct for use in request/response logging.internal/executor/executor.go (4)
17-29: LGTM! NewExecutor properly delegates to config-based constructors.The executor initialization correctly creates sub-executors using the config and stores the logger for use throughout execution.
49-95: LGTM! Execute method properly handles new data flow.The method correctly:
- Parses event data via
ParseEventData- Enriches context with resource IDs for logging
- Creates execution context with raw data
- Logs each phase appropriately
243-287: LGTM!ParseEventDatahandles multiple input types correctly.The function properly handles:
nilinput (returns empty data)[]byte(JSON bytes)map[string]interface{}(already parsed)- Other types (attempts JSON marshaling)
Both structured
EventDataand raw map are returned for flexible access.
220-240: LGTM! CreateHandler correctly enriches context with event ID.The handler:
- Attaches event ID to context via
logger.WithEventID- Logs event metadata
- Passes event data to
Execute- ACKs all messages to prevent retry loops (intentional design for non-recoverable errors)
internal/criteria/evaluator.go (1)
53-70: LGTM - Constructor with defensive nil checks.The panic-based validation for required parameters is appropriate for an internal API where callers are expected to provide valid dependencies. This ensures fail-fast behavior during development.
pkg/logger/logger.go (1)
100-161: LGTM - Clean logger initialization with proper validation.The
NewLoggerfunction properly validates the output configuration and returns clear errors for invalid values. The removal of file path support (now only stdout/stderr) addresses the previous review concern about file handle leaks.test/integration/executor/executor_integration_test.go (1)
841-843: LGTM - Good use of capture logger for test assertions.Using
logger.NewCaptureLogger()to verify log output in tests is a clean pattern that allows asserting on logged messages without coupling to implementation details.internal/executor/precondition_executor.go (2)
20-28: LGTM - Config-driven constructor with documented validation responsibility.The constructor correctly documents that the caller (
NewExecutor) is responsible for config validation. This is consistent with the pattern used in other executors and avoids duplicate validation.
30-70: LGTM - Well-structured logging with appropriate levels.The logging follows a consistent pattern:
- Info level for business outcomes (precondition met/not met)
- Error level for execution failures
- Debug level for detailed tracing
The checkmark notation (✓) and numbered progress indicators improve log readability.
internal/executor/resource_executor.go (1)
398-431: LGTM - Proper deep copy with fallback and warning.The
deepCopyMapfunction appropriately:
- Uses
copystructure.Copyfor proper deep copying- Falls back to shallow copy on error with a warning log
- Documents the shallow copy limitation in comments
The context parameter enables consistent logging throughout the call chain.
internal/executor/post_action_executor.go (3)
20-27: Constructor delegates validation to caller - consistent with pattern.The comment documents that
NewExecutoris responsible for config validation. This is the same pattern used inprecondition_executor.goandresource_executor.go, maintaining consistency across the executor package.The past review concern about nil config is addressed by this documented responsibility delegation.
29-77: LGTM - Well-structured post-action execution with proper error handling.The
ExecuteAllmethod correctly:
- Builds payloads first, failing fast on errors
- Executes actions sequentially, stopping on first failure
- Sets
ExecutionErrorwith phase/step context for debugging- Propagates context through the entire call chain
The logging provides good visibility into execution progress.
156-197: LGTM - Recursive payload value processing handles all cases.The
processValuemethod correctly handles:
- CEL expression definitions (
EvaluateExpressionDef)- Simple value definitions (
GetValueDef)- Nested maps (recursive processing)
- Arrays (element-by-element processing)
- Template strings (rendering)
- Pass-through for other types
This covers all expected payload definition patterns.
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 (5)
pkg/logger/logger.go (1)
244-254: Update comment to accurately reflect shallow copy behavior.The function comment says "deep copy" but the implementation only copies top-level map entries. If any value is itself a map, slice, or pointer, modifications to nested structures would affect both the original and copied logger.
🔎 Suggested fix
-// copyFields creates a deep copy of the fields map +// copyFields creates a shallow copy of the fields map func copyFields(f map[string]interface{}) map[string]interface{} {internal/criteria/cel_evaluator_test.go (1)
157-157: Fix test semantics:nullValueshould benil, not a logger instance.Line 157 sets
nullValuetologger.NewTestLogger(), but the test case at lines 183-189 named "access field on null returns error in result (safe)" expectsnullValueto be null. This changes the test from verifying null-access error handling to testing field access on a logger object.🔎 Restore the original test semantics
- ctx.Set("nullValue", logger.NewTestLogger()) + ctx.Set("nullValue", nil)Alternatively, if you intended to test field access on a non-map object, rename the variable (e.g.,
loggerValue) and update the test name and assertions to match the new semantics.internal/executor/executor.go (2)
190-199: Parameter order:ctxshould be first.Go convention places
context.Contextas the first parameter. Having it last infinishWithErroris inconsistent with the rest of the codebase and Go idioms.🔎 Suggested fix
-func (e *Executor) finishWithError(result *ExecutionResult, execCtx *ExecutionContext, err error, reason string, ctx context.Context) *ExecutionResult { +func (e *Executor) finishWithError(ctx context.Context, result *ExecutionResult, execCtx *ExecutionContext, err error, reason string) *ExecutionResult {Update call site at line 88:
- return e.finishWithError(result, execCtx, err, fmt.Sprintf("parameter extraction failed: %v", err), ctx) + return e.finishWithError(ctx, result, execCtx, err, fmt.Sprintf("parameter extraction failed: %v", err))
30-47: Resolve K8sClient requirement inconsistency.The validation requires
K8sClientto be non-nil (line 39), buttypes.go(line 62-63) documents it as "optional, can be nil if not needed". Either:
- Remove
K8sClientfromrequiredFieldsto match the documentation, or- Update the documentation in
types.goto indicate it's now required.internal/hyperfleet_api/client.go (1)
309-309: Fix inconsistent indentation.These log lines have extra leading whitespace (extra tab/spaces). This appears to be a formatting issue that should be corrected.
🔎 Apply this fix
// Execute request - c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) + c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) httpResp, err := c.client.Do(httpReq)And for line 329:
- c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status) + c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status)Also applies to: 329-329
🧹 Nitpick comments (6)
cmd/adapter/main.go (1)
272-300: Context usage during shutdown is safe but consider clarity.After
cancel()is called (line 275),ctxis technically cancelled, but you continue using it for logging. This works because the logger likely just extracts fields from context and doesn't check cancellation. However, for clarity and future-proofing, you might consider usingcontext.Background()for shutdown logging.pkg/logger/context.go (1)
38-60: Consider performance for high-frequency logging paths.
WithLogFieldandWithLogFieldscreate a copy of the existing fields map on every call viaGetLogFields. While this provides immutability, chaining multipleWithLogFieldcalls results in O(n) copies per addition. For typical usage this is fine, but if you expect high-frequency field additions in hot paths, consider whether a more efficient approach (e.g., linked structure or builder pattern) would be beneficial.internal/executor/executor.go (1)
260-265: Optimization opportunity: avoid round-trip marshaling for map input.When input is already
map[string]interface{}, marshaling to JSON then unmarshaling back is inefficient. Consider direct struct population or using a library likemapstructurefor this case.🔎 Alternative approach
case map[string]interface{}: // Directly use the map for rawData rawData := v // For EventData, manually extract known fields or use mapstructure eventData := &EventData{ ID: getStringField(v, "id"), Kind: getStringField(v, "kind"), Href: getStringField(v, "href"), Generation: getInt64Field(v, "generation"), // Handle OwnedReference similarly } return eventData, rawData, nilThis avoids the JSON round-trip overhead, though it requires manual field extraction or a library dependency.
internal/criteria/evaluator.go (1)
54-70: Constructor with panic on nil parameters.Using
panicfor nil parameters is a valid design choice for catching programming errors early. However, returning an error would be more idiomatic for Go libraries and allows callers to handle gracefully. Consider if this is an internal-only API where panics are acceptable, or if it might be called with potentially nil values from dynamic sources.🔎 Alternative approach with error return
func NewEvaluator(ctx context.Context, evalCtx *EvaluationContext, log logger.Logger) (*Evaluator, error) { if ctx == nil { return nil, errors.New("ctx is required for Evaluator") } if evalCtx == nil { return nil, errors.New("evalCtx is required for Evaluator") } if log == nil { return nil, errors.New("log is required for Evaluator") } return &Evaluator{ evalCtx: evalCtx, log: log, ctx: ctx, }, nil }This would require updating all call sites to handle the error, but provides more flexibility.
test/integration/executor/executor_integration_test.go (2)
231-232: Consider usingrequire.NoErrorfor critical setup failures.Using
assert.NoErrorhere means the test will continue executing even if client creation fails, potentially causing nil pointer panics later. Consider usingrequire.NoErrorfor consistency with other tests and to fail fast on setup errors.🔎 Suggested fix
apiClient, err := hyperfleet_api.NewClient(k8sEnv.Log) - assert.NoError(t, err) + require.NoError(t, err, "failed to create API client")
447-449: Inconsistent error assertion pattern across tests.Multiple tests in this file use
assert.NoErrorforhyperfleet_api.NewClienterror checking (lines 232, 336, 449, 498, 551, 602, 635, 669, 734, 787, 918, 988, 1163, 1301), while others userequire.NoError(line 95). For setup code that would cause nil pointer panics if it fails,require.NoErroris preferred to fail fast with a clear error message.Consider standardizing on
require.NoErrorfor all client creation error checks.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (37)
cmd/adapter/main.gogo.modinternal/config_loader/loader.gointernal/config_loader/validator.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/executor/README.mdinternal/executor/executor.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/k8s_client/client.gointernal/k8s_client/discovery.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/test_support.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.go
💤 Files with no reviewable changes (3)
- internal/executor/param_extractor.go
- go.mod
- internal/executor/README.md
🚧 Files skipped from review as they are similar to previous changes (6)
- internal/k8s_client/discovery.go
- test/integration/executor/setup_test.go
- test/integration/k8s_client/helper_envtest_prebuilt.go
- pkg/logger/test_support.go
- internal/config_loader/validator_test.go
- internal/executor/utils.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
test/integration/config-loader/config_criteria_integration_test.gocmd/adapter/main.gointernal/criteria/evaluator_test.gointernal/executor/utils_test.gointernal/config_loader/loader.gointernal/hyperfleet_api/client.gointernal/executor/executor.gointernal/config_loader/validator.gointernal/criteria/evaluator_version_test.gointernal/executor/types.gointernal/criteria/evaluator_scenarios_test.gotest/integration/executor/executor_integration_test.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.go
🧬 Code graph analysis (19)
test/integration/config-loader/config_criteria_integration_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/criteria/evaluator_test.go (3)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
internal/executor/utils_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/executor/types.go (1)
ExecutionContext(181-196)internal/executor/utils.go (1)
ExecuteLogAction(39-70)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-41)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(55-70)DefaultConfig(73-81)NewLogger(102-161)ConfigFromEnv(84-98)pkg/logger/context.go (10)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithClusterID(85-87)WithTraceID(70-72)
internal/hyperfleet_api/client.go (3)
pkg/logger/logger.go (1)
Logger(15-41)internal/k8s_client/client.go (2)
NewClient(65-114)Client(29-32)internal/hyperfleet_api/types.go (2)
Client(216-237)DefaultClientConfig(57-66)
internal/criteria/evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-41)
internal/criteria/cel_evaluator_test.go (3)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
internal/executor/executor_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/executor/types.go (5)
ExecutorConfig(57-67)NewExecutionContext(254-265)EventData(48-54)StatusSuccess(35-35)ExecutionStatus(31-31)pkg/logger/context.go (1)
WithEventID(80-82)
internal/executor/executor.go (4)
internal/executor/types.go (2)
ExecutionContext(181-196)EventData(48-54)pkg/logger/logger.go (1)
Logger(15-41)pkg/logger/context.go (4)
WithResourceID(95-97)WithResourceType(90-92)WithDynamicResourceID(64-67)WithEventID(80-82)internal/config_loader/types.go (1)
AdapterConfig(6-11)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(105-121)
test/integration/executor/executor_k8s_integration_test.go (1)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)
pkg/logger/logger.go (2)
pkg/errors/error.go (1)
New(107-123)pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
internal/executor/post_action_executor_test.go (4)
internal/executor/post_action_executor.go (1)
PostActionExecutor(15-18)internal/executor/types.go (2)
ExecutorConfig(57-67)NewExecutionContext(254-265)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)internal/executor/utils.go (1)
ExecuteAPICall(76-206)
internal/executor/precondition_executor.go (3)
internal/executor/types.go (2)
ExecutorConfig(57-67)ExecutionContext(181-196)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
internal/criteria/evaluator_version_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
test/integration/executor/main_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)pkg/logger/logger.go (1)
Config(55-70)internal/k8s_client/client.go (1)
Client(29-32)
test/integration/executor/executor_integration_test.go (2)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)pkg/logger/test_support.go (1)
NewCaptureLogger(67-83)
internal/k8s_client/client.go (2)
pkg/errors/error.go (1)
KubernetesError(203-205)internal/hyperfleet_api/types.go (1)
Client(216-237)
🔇 Additional comments (64)
test/integration/executor/main_test.go (3)
5-8: LGTM!The addition of
crypto/tlsandnet/httpimports is appropriate to support the new HTTP health check implementation for API server readiness verification.
106-106: LGTM!Correct usage of the new test logger helper from
pkg/logger/test_support.go.
185-220: LGTM!The HTTP health check implementation is well-designed for envtest scenarios. The TLS configuration properly handles self-signed certificates while maintaining minimum security standards with TLS 1.2, and the polling mechanism with timeout is appropriate for startup readiness verification.
pkg/logger/logger.go (2)
100-161: LGTM!The
NewLoggerimplementation properly validates configuration and handles output selection. By restricting outputs tostdoutandstderr(or customio.Writer), the previously flagged file handle leak concern is avoided by design.
177-196: LGTM!The
buildArgsmethod correctly merges fields from both the logger instance and the context, with appropriate nil checking for the context parameter.pkg/logger/logger_test.go (2)
8-68: LGTM!Test coverage for
NewLoggeris comprehensive, including success cases with various configurations and error cases for invalid output.
148-175: LGTM!The
TestLoggerWithErrorfunction correctly validates both the error field setting and the nil error optimization where the same logger instance is returned.internal/executor/utils_test.go (1)
4-4: LGTM!The test updates correctly adopt the context-aware logging pattern, using
logger.NewTestLogger()and passingcontext.Background()toExecuteLogAction, consistent with the broader refactoring.Also applies to: 14-14, 775-779
internal/k8s_client/client.go (1)
81-81: LGTM!All logging calls have been consistently updated to include the context parameter as the first argument, aligning with the context-aware logging API migration.
Also applies to: 88-88, 136-136, 153-153, 159-159, 185-185, 198-198, 231-231, 261-261, 278-278, 284-284, 294-294, 307-307, 337-337, 371-371
test/integration/config-loader/config_criteria_integration_test.go (1)
6-6: LGTM!Test updates consistently adopt the new three-parameter
NewEvaluatorsignature withcontext.Background()andlogger.NewTestLogger(), aligning with the context-aware API refactoring.Also applies to: 17-17, 73-73, 158-158, 189-189, 210-210, 230-230, 317-317, 379-379, 409-409
internal/criteria/evaluator_version_test.go (1)
4-4: LGTM!Test updates consistently use the new
NewEvaluatorsignature with appropriate context and test logger, matching the pattern used across the codebase.Also applies to: 7-7, 18-18, 53-53, 80-80, 147-147
internal/config_loader/loader.go (1)
172-172: No issues found. The refactored validation pattern is safe and actually eliminates the previous concern about nil logger usage. ThenewValidator(config)approach removes the logger dependency entirely—the Validator struct contains no logger field, and theValidate()method does not use or require one. This is a safer design than the previous pattern.Likely an incorrect or invalid review comment.
internal/criteria/evaluator_scenarios_test.go (2)
4-10: LGTM! Test imports updated correctly.The addition of
contextandloggerimports aligns with the new API requirements.
47-47: LGTM! Evaluator initialization updated consistently.All
NewEvaluatorcalls have been correctly updated to the new three-parameter signature:NewEvaluator(context.Background(), ctx, logger.NewTestLogger()). The pattern is consistent across all test cases.Also applies to: 121-121, 138-138, 171-171, 211-211, 262-262, 342-342
test/integration/executor/executor_k8s_integration_test.go (1)
318-322: LGTM! API client creation updated with proper error handling.The
NewClientcalls have been correctly updated to:
- Pass
testLog()as the first parameter- Capture the error return value
- Assert no error with
require.NoError(t, err)This pattern is consistently applied across all test cases in this file.
internal/hyperfleet_api/client_test.go (2)
22-36: LGTM! Test logger singleton implemented correctly.The shared test logger with
sync.Onceinitialization is a good pattern that:
- Prevents repeated logger creation across tests
- Ensures thread-safe initialization
- Provides consistent logging configuration for all tests
40-40: LGTM! All NewClient calls updated consistently.All test cases have been updated to pass
testLog()as the first parameter toNewClient, aligning with the new API signature.Also applies to: 63-63, 137-137, 162-162, 195-195, 227-227, 266-266, 301-301, 332-332, 362-362, 377-377, 480-480, 501-501, 522-522
internal/executor/post_action_executor_test.go (3)
18-33: LGTM! Test logger singleton implemented correctly.Consistent with the pattern used in other test files.
36-42: LGTM! Test helper factory is a good pattern.The
testPAE()helper centralizesPostActionExecutorcreation for tests, making the test setup more maintainable and consistent.
45-45: LGTM! Test refactoring applied consistently.Tests now use the
testPAE()factory and call methods on thepaeinstance (e.g.,pae.buildPayload,pae.log), aligning with the updated API where these are receiver methods onPostActionExecutor.Also applies to: 117-119, 133-133, 222-224, 238-238, 348-350
internal/criteria/cel_evaluator_test.go (2)
13-21: LGTM! Test function renamed to reflect unexported constructor.The test name
Test_newCELEvaluatorcorrectly reflects thatnewCELEvaluatoris now an unexported constructor.
18-18: LGTM! Evaluator initialization updated consistently.All evaluator instantiations have been correctly updated to use the new three-parameter constructor:
newCELEvaluator(context.Background(), ctx, logger.NewTestLogger())orNewEvaluator(context.Background(), ctx, logger.NewTestLogger()).Also applies to: 30-30, 134-134, 159-159, 250-250, 269-269, 445-445, 474-474, 537-537
internal/config_loader/validator.go (2)
65-71: LGTM! Validator constructor correctly made private.The change from
NewValidatortonewValidator(unexported) is consistent with the broader API refactoring where validators are constructed internally by the loader.
391-407: LGTM! CEL validation simplified to syntax-only checks.The updated documentation clearly explains that type checking is skipped because variables are registered as
DynTypeand their actual types are only known at runtime. This is a reasonable trade-off that catches syntax errors at validation time while allowing runtime type flexibility.internal/criteria/evaluator_test.go (2)
773-789: LGTM! Comprehensive nil-parameter validation tests.The renamed test
TestNewEvaluatorPanicsWithNilParamsnow covers all three nil-parameter cases:
nilctxnilevalCtxnillogThis provides better coverage of the constructor's parameter validation.
525-525: LGTM! All evaluator instantiations updated consistently.All
NewEvaluatorcalls have been updated to the new three-parameter signature throughout the test file.Also applies to: 612-612, 802-802, 827-827, 848-848, 884-884, 935-935, 961-961, 986-986, 1032-1032, 1086-1086
internal/criteria/cel_evaluator.go (3)
18-23: LGTM! CELEvaluator structure refactored correctly.The struct now properly separates concerns:
evalCtxholds evaluation datactxprovides context for propagation (cancellation, tracing, etc.)logis the logger instanceThis is a cleaner design that aligns with Go best practices.
56-73: LGTM! Constructor refactored with proper parameter usage.The constructor
newCELEvaluator(now unexported) correctly:
- Accepts
ctx,evalCtx, andlogparameters- Uses
evalCtxto build CEL options (line 60)- Initializes all struct fields appropriately
The comment noting that parameter validation is the caller's responsibility is helpful.
164-168: LGTM! Evaluation and logging use the correct context sources.
- Line 164: Uses
e.evalCtx.Data()for evaluation data (correct)- Line 168: Uses
e.ctxfor logging context propagation (correct)This properly separates data context from request context.
internal/executor/types.go (3)
40-54: Well-structured types for event data handling.The
ResourceRefandEventDatatypes are cleanly defined with appropriate JSON tags andomitemptydirectives. This aligns well with the PR's goal of reducing CloudEvent dependency by parsing event data into a generic map structure.
75-75: LGTM - Logger field addition.Adding the
logfield to theExecutorstruct enables context-aware logging throughout the executor lifecycle.
254-265: Simplified constructor aligns with data-driven approach.The
NewExecutionContextsignature change from accepting*event.Eventto justmap[string]interface{}cleanly decouples the execution context from CloudEvents, enabling more flexible data sources.internal/hyperfleet_api/client.go (2)
119-148: Well-designed logger injection with environment fallback.The
NewClientconstructor properly:
- Accepts a logger as the first parameter for dependency injection
- Falls back to environment variable for base URL when not provided via options
- Validates that base URL is configured before returning
This follows the established pattern seen in
k8s_client.NewClient.
150-153: Good addition of environment helper.
BaseURLFromEnv()provides a clean, reusable way to retrieve the base URL from environment variables, following the pattern ofAPIVersionFromEnv().cmd/adapter/main.go (3)
116-135: Clean logging configuration with proper precedence.The logging configuration follows a sensible precedence: environment variables as defaults, CLI flags as overrides. The bootstrap component name is appropriately set before config loading.
147-153: Good pattern: Recreate logger with adapter identity.Recreating the logger after config load to include the adapter's name as the component is a solid pattern for operational clarity - logs will now be tagged with the specific adapter identity.
306-334: LGTM - API client creation with logger injection.The
createAPIClientfunction properly accepts and forwards the logger tohyperfleet_api.NewClient, completing the logging chain.internal/executor/executor_test.go (4)
22-80: Comprehensive test coverage for executor configuration validation.Tests properly cover all validation scenarios: nil config, missing required fields (AdapterConfig, APIClient, Logger), and valid configuration. The use of
logger.NewTestLogger()is consistent throughout.
101-113: Test properly validates new ExecutionContext API.The test correctly demonstrates the new
NewExecutionContextsignature acceptingeventDataas a map, and validates thatEventDatais properly accessible from the context.
270-289: Good test pattern for context-based event correlation.Using
logger.WithEventID(context.Background(), "test-event-123")before callingExecutedemonstrates the expected pattern for callers to add event IDs to context for logging correlation.
291-384: Thorough param extraction test coverage.The
TestParamExtractortests comprehensively cover various parameter sources (env, event, nested event) and edge cases (defaults, missing required). TheNewExecutionContextcall at line 354 correctly uses the new signature.pkg/logger/context.go (3)
8-29: Well-designed context key structure.Using a custom
contextKeytype prevents collisions with other packages that might use the same string keys. The organized grouping of keys (correlation, resource, adapter-specific) improves readability.
62-67: Clever dynamic field name derivation.
WithDynamicResourceIDnicely derives the field name from the resource type (e.g., "Cluster" → "cluster_id"), reducing boilerplate when logging different resource types.
118-131: Defensive copy prevents mutation bugs.Returning a copy of the
LogFieldsmap inGetLogFieldsis the right choice - it prevents callers from accidentally mutating the context's fields. The nil-context guard is also good defensive programming.internal/executor/executor.go (2)
49-94: Clean data-driven execution flow.The
Executemethod now:
- Parses event data into both structured and raw forms
- Enriches context with resource IDs for logging correlation
- Follows a clear phase-by-phase execution pattern
The context enrichment logic (lines 66-72) correctly handles both owned and non-owned resources.
220-240: Event handler properly sets up logging correlation.
CreateHandlercorrectly adds the event ID to context usinglogger.WithEventIDbefore callingExecute, ensuring all downstream logs are correlated with the event.internal/criteria/evaluator.go (3)
40-51: Clear struct field organization.The
Evaluatorstruct now cleanly separates:
evalCtx: the data context for field lookupsctx: the request context for logging correlationlog: the logger instanceThis separation of concerns is well-designed.
72-93: Lazy CEL evaluator with version tracking.The
getCELEvaluatormethod properly:
- Uses mutex for thread safety
- Checks context version to detect modifications
- Recreates the CEL evaluator when data changes
This ensures CEL environment stays in sync with context data.
95-119: Field accessors consistently use evalCtx.All field accessor methods (
GetField,GetFieldOrDefault,GetFieldSafe,HasField) now consistently delegate toevalCtx.GetNestedField, maintaining a clean separation between request context and data context.internal/executor/resource_executor_test.go (1)
19-19: LGTM - Consistent test updates for newdeepCopyMapsignature.All test functions correctly updated to pass
context.Background()andtestLog()to match the new context-awaredeepCopyMapsignature. The test coverage remains comprehensive across various data types and edge cases.internal/executor/resource_executor.go (2)
24-31: LGTM on config-driven constructor pattern.The constructor correctly delegates validation to
NewExecutoras noted in the comment. This aligns with the centralized validation approach documented in the past review (now resolved). Based on learnings, this PR (HYPERFLEET-304) addresses the logger refactor tracked for this repository.
404-431: LGTM on deepCopyMap context-aware logging.The function correctly accepts context and logger parameters, and the fallback behavior with warning logging is preserved.
test/integration/executor/executor_integration_test.go (3)
91-95: LGTM on NewClient error handling.The error from
hyperfleet_api.NewClientis now properly captured and validated withrequire.NoError, addressing the previously identified critical issue.
841-843: LGTM on capture logger usage.The
logger.NewCaptureLogger()pattern is correctly used to capture and verify log messages during test execution.
1300-1308: LGTM on payload build failure test setup.The test correctly uses both
NewClienterror handling andNewCaptureLoggerto verify error logging behavior.internal/executor/precondition_executor.go (4)
21-28: LGTM on config-driven constructor.The constructor follows the same pattern as other executors, delegating validation to
NewExecutoras documented in the NOTE comment.
30-70: LGTM on ExecuteAll logging refactor.The method correctly uses the internal logger with context propagation for all log statements. The outcome-based return pattern cleanly separates execution errors from business logic (precondition not met).
73-200: LGTM on executePrecondition implementation.The method correctly:
- Propagates context through all operations
- Uses internal logger consistently
- Sets
ExecutionErrorfor API and parse failures- Integrates with
criteria.NewEvaluatorwith proper context and logger
203-212: LGTM on executeAPICall delegation.The method correctly delegates to the shared
ExecuteAPICallutility with all required parameters including context and logger.internal/executor/post_action_executor.go (5)
31-77: LGTM on ExecuteAll implementation.The method correctly:
- Handles nil
postConfiggracefully- Logs and propagates payload build failures
- Sets
ExecutionErrorwith appropriate phase/step context- Stops execution on first post-action failure
81-116: LGTM on buildPostPayloads context propagation.The method correctly creates the evaluator with context and logger, and propagates context through to
buildPayload.
156-197: LGTM on processValue recursive context propagation.Context is correctly propagated through all recursive paths (nested maps, arrays, type conversions).
224-249: LGTM on executeAPICall implementation.The method correctly:
- Delegates to the shared
ExecuteAPICallutility- Captures response details even on error for debugging
- Creates appropriate
ExecutorErrorwith phase/step context
20-27: Constructor design is correct - validation is enforced at the entry point.
NewExecutorexplicitly validates the config viavalidateExecutorConfigbefore calling any sub-executor constructors (line 18 of executor.go). This checks for nil config and required fields includingAPIClientandLogger. The NOTE comment is accurate: the caller (NewExecutor) is responsible for validation, and this responsibility is fulfilled. No defensive nil checks are needed in the sub-executor constructors, and the design is consistent withnewResourceExecutorandnewPreconditionExecutor.
0e0f0d0 to
a546970
Compare
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
♻️ Duplicate comments (3)
internal/criteria/cel_evaluator_test.go (1)
157-157: Test semantics broken:nullValueshould be nil, not a logger.The test case "access field on null returns error in result (safe)" (lines 183-189) expects
nullValueto be null to verify null-safe error handling. Setting it totestLog()changes the test to check field access on a logger object instead.🔎 Restore the test semantics
- ctx.Set("nullValue", logger.NewTestLogger()) + ctx.Set("nullValue", nil)If the intent is to test field access on a non-map value, consider renaming the variable (e.g.,
loggerValue) and updating the test name/assertions accordingly.internal/hyperfleet_api/client.go (1)
309-309: Fix inconsistent indentation (still present).These log lines have extra leading whitespace (double-indented). This issue was flagged in a previous review and marked as addressed, but the extra indentation persists in the current diff.
🔎 Apply this fix
- c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) + c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL)And for line 329:
- c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status) + c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status)internal/executor/resource_executor.go (1)
79-80: Indentation inconsistency on log statements.Multiple log statements throughout the file (lines 79, 85, 90, 99, 101, 115, 121, 125, 132, 154, 318, 324, 330, 345, 352, 356, 360) appear to have inconsistent indentation. They should be aligned with surrounding code in their respective blocks.
Please run
gofmtorgo fmton this file to fix the indentation issues. For example, line 79 should be indented with a tab:- re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)", + re.log.Infof(ctx, " Manifest: %s/%s %s (namespace: %s)",This appears to be the same issue noted in the past review comment, suggesting it may not have been fully addressed.
Also applies to: 85-85, 90-90, 99-99, 101-101, 115-115
🧹 Nitpick comments (8)
test/integration/executor/main_test.go (2)
202-214: Drain response body before closing for proper connection reuse.The response body should be read and discarded before closing, even for non-200 responses, to allow the HTTP client to reuse connections efficiently.
🔎 Proposed fix for response body handling
req, err := http.NewRequest(http.MethodGet, healthURL, nil) if err != nil { return fmt.Errorf("failed to create request: %w", err) } req.Header.Set("Authorization", "Bearer "+config.BearerToken) resp, err := client.Do(req) - if err == nil { - _ = resp.Body.Close() - if resp.StatusCode == http.StatusOK { + if err == nil && resp != nil { + // Drain and close body to allow connection reuse + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + if resp.StatusCode == http.StatusOK { return nil // API server is ready } }Note: You'll need to import
"io"at the top of the file.
219-219: Consider including last error in timeout message for better debugging.The timeout error message could include the last error encountered during the health check attempts, which would help with troubleshooting failed test runs.
🔎 Proposed enhancement for error context
+ var lastErr error healthURL := config.Host + "/healthz" deadline := time.Now().Add(timeout) for time.Now().Before(deadline) { req, err := http.NewRequest(http.MethodGet, healthURL, nil) if err != nil { return fmt.Errorf("failed to create request: %w", err) } req.Header.Set("Authorization", "Bearer "+config.BearerToken) resp, err := client.Do(req) if err == nil { _ = resp.Body.Close() if resp.StatusCode == http.StatusOK { return nil // API server is ready } + lastErr = fmt.Errorf("unexpected status: %d", resp.StatusCode) + } else { + lastErr = err } time.Sleep(500 * time.Millisecond) } - return fmt.Errorf("timeout waiting for API server to be ready") + if lastErr != nil { + return fmt.Errorf("timeout waiting for API server to be ready: %w", lastErr) + } + return fmt.Errorf("timeout waiting for API server to be ready") }pkg/logger/logger.go (1)
238-242:Fatalcallsos.Exit(1)which is difficult to test.This is a common pattern for fatal logging. Consider documenting that tests should not exercise
Fataldirectly, or optionally inject an exit function for testability.internal/hyperfleet_api/client_test.go (1)
22-36: Consider usinglogger.NewTestLogger()for consistency.The
testLog()helper duplicates the singleton pattern already provided bylogger.NewTestLogger()inpkg/logger/test_support.go. Using the shared test logger would reduce code duplication and ensure consistent test logging behavior across the codebase.🔎 Suggested simplification
-var ( - sharedTestLogger logger.Logger - loggerOnce sync.Once -) - -func testLog() logger.Logger { - loggerOnce.Do(func() { - var err error - sharedTestLogger, err = logger.NewLogger(logger.Config{Level: "error", Format: "text", Output: "stdout", Component: "test", Version: "test"}) - if err != nil { - panic(err) - } - }) - return sharedTestLogger -} +func testLog() logger.Logger { + return logger.NewTestLogger() +}This also removes the need for the
syncimport at line 11.internal/executor/executor.go (1)
66-72: Context enrichment logic may need clarification.The logic adds resource IDs to context differently based on whether
OwnedReferenceexists:
- With OwnedReference: Sets both static (Kind, ID) and dynamic (OwnedReference.Kind, OwnedReference.ID) resource IDs
- Without OwnedReference: Only sets dynamic resource ID (eventData.Kind, eventData.ID)
Verify this is the intended behavior. Consider adding a comment explaining why both static and dynamic IDs are set when OwnedReference exists.
// Context enrichment: // - If OwnedReference exists: track both the primary resource and owned resource // - Otherwise: track only the primary resource dynamically if eventData.OwnedReference != nil { ctx = logger.WithResourceID( logger.WithResourceType(ctx, eventData.Kind), eventData.ID) ctx = logger.WithDynamicResourceID(ctx, eventData.OwnedReference.Kind, eventData.OwnedReference.ID) } else { ctx = logger.WithDynamicResourceID(ctx, eventData.Kind, eventData.ID) }test/integration/executor/executor_integration_test.go (1)
1346-1350: Log format assertion may be fragile.The test checks for
"level=ERROR"in the captured logs, which assumes slog's text format. If the log format changes (e.g., to JSON), this assertion will break. Consider checking for log content rather than format-specific strings, or document the dependency on text format.- // slog uses "level=ERROR" format capturedLogs := logCapture.Messages() t.Logf("Captured logs:\n%s", capturedLogs) - foundErrorLog := logCapture.Contains("level=ERROR") && logCapture.Contains("failed to build") + // Check for error-level log containing the expected message + foundErrorLog := logCapture.Contains("failed to build") assert.True(t, foundErrorLog, "Expected to find error log for payload build failure")internal/criteria/evaluator.go (1)
54-70: Consider returning error instead of panic for nil parameters.While panicking on nil parameters catches programming errors early, it may be more idiomatic in Go to return an error, especially for a public constructor. This allows callers to handle the error gracefully rather than crashing the program.
func NewEvaluator(ctx context.Context, evalCtx *EvaluationContext, log logger.Logger) *Evaluator { if ctx == nil { - panic("ctx is required for Evaluator") + return nil, fmt.Errorf("ctx is required for Evaluator") } if evalCtx == nil { - panic("evalCtx is required for Evaluator") + return nil, fmt.Errorf("evalCtx is required for Evaluator") } if log == nil { - panic("log is required for Evaluator") + return nil, fmt.Errorf("log is required for Evaluator") } return &Evaluator{ evalCtx: evalCtx, log: log, ctx: ctx, - } + }, nil }Alternatively, if panic is intentional for programming errors, add a comment explaining this design choice.
pkg/logger/context.go (1)
1-132: Solid context-based logging implementation.The implementation follows Go best practices:
- Custom
contextKeytype prevents collisions- Consistent pattern across all
With*functions- Defensive copy in
GetLogFieldsprevents external mutation of the mapMinor observation:
GetLogFieldsperforms a shallow copy (lines 125-129), which means nested mutable values (e.g., maps or slices stored as field values) could still be mutated externally. For typical logging use cases with primitive values (strings, ints, bools), this is an acceptable tradeoff. If nested mutable values become common, consider implementing a deep copy.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (37)
cmd/adapter/main.gogo.modinternal/config_loader/loader.gointernal/config_loader/validator.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/executor/README.mdinternal/executor/executor.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/k8s_client/client.gointernal/k8s_client/discovery.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/test_support.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.go
💤 Files with no reviewable changes (3)
- internal/executor/README.md
- go.mod
- internal/executor/param_extractor.go
🚧 Files skipped from review as they are similar to previous changes (7)
- internal/k8s_client/client.go
- test/integration/executor/setup_test.go
- pkg/logger/test_support.go
- internal/k8s_client/discovery.go
- internal/config_loader/loader.go
- test/integration/k8s_client/helper_envtest_prebuilt.go
- internal/config_loader/validator_test.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/criteria/evaluator_version_test.gocmd/adapter/main.gointernal/config_loader/validator.gotest/integration/config-loader/config_criteria_integration_test.gointernal/criteria/evaluator_scenarios_test.gointernal/executor/executor.gointernal/executor/utils_test.gotest/integration/executor/executor_integration_test.gointernal/criteria/evaluator_test.gointernal/executor/types.gointernal/hyperfleet_api/client.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.go
🧬 Code graph analysis (19)
internal/criteria/evaluator_version_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(105-121)
test/integration/config-loader/config_criteria_integration_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/criteria/evaluator_scenarios_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
test/integration/executor/executor_k8s_integration_test.go (1)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)
internal/executor/utils.go (3)
internal/config_loader/types.go (1)
LogAction(206-209)internal/executor/types.go (2)
ExecutionContext(180-195)ExecutionStatus(31-31)pkg/logger/logger.go (1)
Logger(15-41)
internal/executor/utils_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/executor/types.go (1)
ExecutionContext(180-195)internal/executor/utils.go (1)
ExecuteLogAction(39-70)
internal/executor/precondition_executor.go (6)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (2)
ExecutorConfig(57-66)ExecutionContext(180-195)internal/config_loader/types.go (2)
Precondition(98-105)APICall(108-116)internal/executor/utils.go (1)
ExecuteLogAction(39-70)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)internal/criteria/types.go (1)
Operator(10-10)
internal/criteria/evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-41)
internal/criteria/cel_evaluator_test.go (3)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(55-70)
internal/executor/post_action_executor.go (6)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (1)
ExecutorConfig(57-66)internal/config_loader/types.go (4)
PostConfig(193-196)Payload(67-78)PostAction(199-203)APICall(108-116)internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (2)
NewEvaluator(55-70)Evaluator(41-51)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-41)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(55-70)DefaultConfig(73-81)NewLogger(102-161)ConfigFromEnv(84-98)pkg/logger/context.go (10)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithClusterID(85-87)WithTraceID(70-72)
pkg/logger/logger.go (2)
pkg/errors/error.go (1)
New(107-123)pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
internal/criteria/evaluator_test.go (3)
internal/criteria/evaluator.go (1)
NewEvaluator(55-70)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
internal/executor/types.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)pkg/logger/logger.go (1)
Logger(15-41)
internal/hyperfleet_api/client.go (3)
pkg/logger/logger.go (1)
Logger(15-41)internal/k8s_client/client.go (2)
NewClient(65-114)Client(29-32)internal/hyperfleet_api/types.go (2)
Client(216-237)DefaultClientConfig(57-66)
internal/executor/resource_executor.go (5)
pkg/logger/logger.go (1)
Logger(15-41)internal/executor/types.go (9)
ExecutorConfig(57-66)ResourceResult(126-143)StatusSuccess(35-35)OperationRecreate(154-154)OperationUpdate(152-152)OperationCreate(150-150)StatusFailed(37-37)ExecutionError(243-250)NewExecutorError(374-381)internal/k8s_client/interface.go (1)
K8sClient(13-47)internal/config_loader/types.go (1)
Resource(171-178)internal/k8s_client/discovery.go (1)
Discovery(14-29)
internal/hyperfleet_api/client_test.go (1)
internal/hyperfleet_api/client.go (4)
NewClient(119-148)WithBaseURL(102-106)WithDefaultHeader(57-64)WithConfig(48-54)
🔇 Additional comments (60)
test/integration/executor/main_test.go (4)
5-5: LGTM! Necessary imports for HTTP health check.The
crypto/tlsandnet/httpimports are required for the new health check implementation.Also applies to: 8-8
106-106: LGTM! Aligns with the logging refactor.The switch to
logger.NewTestLogger()is consistent with the project-wide logging changes tracked in HYPERFLEET-304. Based on learnings, this is the expected pattern for test code.
142-142: LGTM! Clear readiness messaging.The updated messages provide clear feedback about the API server readiness state.
Also applies to: 147-147
188-196: LGTM! Appropriate TLS configuration for test environment.The use of
InsecureSkipVerifyis correctly documented and necessary for envtest self-signed certificates. SettingMinVersionto TLS 1.2 is a good security practice.internal/criteria/evaluator_scenarios_test.go (3)
4-10: LGTM!The imports are correctly updated to include
contextand theloggerpackage to support the newNewEvaluatorsignature.
47-47: LGTM!The
NewEvaluatorcall correctly uses the new 3-parameter signature withcontext.Background(), the evaluation context, and the test logger.
121-121: Consistent API usage across all test functions.All
NewEvaluatorinstantiations follow the same pattern, correctly passingcontext.Background(), the evaluation context, andlogger.NewTestLogger(). The pattern is consistent and aligns with the new public API.Also applies to: 138-138, 171-171, 211-211, 262-262, 342-342
internal/config_loader/validator.go (3)
65-71: LGTM!The constructor is correctly made unexported (
newValidator) since it's only used internally by the loader. The implementation remains unchanged.
391-407: LGTM!The CEL validation correctly performs syntax-only checks using
Parse()instead ofCheck(). This is the right approach since variables are declared asDynTypeand their actual types are only known at runtime. The documentation clearly explains this design decision.
409-431: LGTM!The
validateBuildExpressionshelper correctly recursively traverses the build structure to find and validate CEL expressions. It handles nested maps and arrays appropriately.internal/executor/resource_executor_test.go (2)
156-176: LGTM!The test correctly verifies deep copy behavior with the new context-aware signature. The test name and comments are updated to reflect the verification focus.
19-19: LGTM!The
deepCopyMapcall correctly includescontext.Background()andtestLog()as the new signature requires. ThetestLog()helper is defined in the executor package and is accessible to this test file.pkg/logger/logger.go (5)
13-41: LGTM!The
Loggerinterface is well-designed with context-aware logging methods and chainable field manipulation methods (With,WithFields,WithError). The interface aligns with the sentinel pattern for context propagation.
54-70: LGTM!The
Configstruct provides good flexibility with the optionalWriterfield for testing scenarios while maintaining simple defaults for production use.
100-161: LGTM!The
NewLoggerconstructor correctly:
- Validates output options and returns an error for invalid values
- Supports custom
io.Writerfor testing- Builds hostname from multiple sources with sensible fallbacks
- Creates the underlying
slog.Loggerwith base fields
177-196: LGTM!The
buildArgsmethod correctly merges fields from both the logger instance and the context'sLogFields. The capacity pre-allocation is a nice optimization.
244-254: LGTM!The
copyFieldsfunction correctly performs a shallow copy, and the comment accurately describes this behavior (addressing the past review comment).pkg/logger/logger_test.go (5)
8-55: LGTM!Good coverage of
NewLoggerwith various configuration options including default config, JSON format, and text format with different outputs.
57-68: LGTM!Correctly validates that
NewLoggerreturns an error for invalid output values.
70-175: LGTM!Comprehensive tests for
With,WithFields, andWithErrormethods including the edge case ofWithError(nil)returning the same logger instance.
386-423: LGTM!Good test coverage for
ConfigFromEnvusingt.Setenvwhich properly restores environment variables after each test. Tests verify case-insensitive handling of environment variable values.
425-450: LGTM!The
parseLeveltests cover all expected inputs including case variations and invalid values with proper fallback to INFO.test/integration/config-loader/config_criteria_integration_test.go (3)
6-17: LGTM!The imports are correctly updated to include
contextandloggerpackages to support the newNewEvaluatorsignature.
73-73: LGTM!The
NewEvaluatorcall correctly uses the new 3-parameter signature withcontext.Background(), the evaluation context, and the test logger.
158-158: Consistent API usage across all integration tests.All
NewEvaluatorinstantiations follow the same pattern throughout the integration tests, correctly aligning with the updated public API.Also applies to: 189-189, 210-210, 230-230, 317-317, 379-379, 409-409
internal/criteria/evaluator_version_test.go (2)
4-10: LGTM!The imports are correctly updated for the new
NewEvaluatorsignature requirements.
18-18: Consistent API usage across version tracking tests.All
NewEvaluatorinstantiations correctly usecontext.Background(), the evaluation context, andlogger.NewTestLogger(). The version tracking tests are valuable for ensuring CEL environment recreation works correctly.Also applies to: 53-53, 80-80, 147-147
internal/hyperfleet_api/client_test.go (2)
40-40: LGTM!The
NewClientcall correctly passes the test logger as the first argument, aligning with the updated API signature.
63-63: Consistent API usage across all client tests.All
NewClientinstantiations correctly passtestLog()as the first parameter, maintaining consistency with the updatedNewClient(log logger.Logger, opts ...ClientOption)signature.Also applies to: 137-137, 162-162, 195-195, 227-227, 266-266, 301-301, 332-332, 362-362, 377-377, 480-480, 501-501, 522-522, 652-652
internal/executor/utils_test.go (1)
775-779: LGTM! Test updated correctly for context-aware logging.The test has been properly updated to use the new
ExecuteLogActionsignature that requires a context parameter. The use oflogger.NewTestLogger()andcontext.Background()is appropriate for test scenarios.test/integration/executor/executor_k8s_integration_test.go (1)
318-322: LGTM! NewClient API updated consistently.All
NewClientinvocations throughout the test file have been correctly updated to:
- Pass
testLog()as the first parameter (new logger requirement)- Capture and check the error return value with
require.NoError(t, err)This change is consistently applied across all 8 call sites in the file.
internal/executor/utils.go (1)
39-69: LGTM! Context-aware logging properly implemented.The function signature and all internal logging calls have been correctly updated to thread context through the logging API. This change:
- Adds
ctx context.Contextas the first parameter (breaking API change noted in PR objectives)- Consistently passes
ctxto all log methods (Errorf,Debugf,Infof,Warnf)- Maintains the same logging behavior with added context propagation
internal/criteria/cel_evaluator_test.go (1)
18-21: LGTM! Constructor updated correctly.All test invocations of
newCELEvaluatorhave been correctly updated to pass:
context.Background()as the first parameter- The evaluation context as the second parameter
logger.NewTestLogger()as the third parameterThis aligns with the new private constructor signature.
internal/criteria/evaluator_test.go (2)
773-789: LGTM! Comprehensive panic tests for nil parameters.The test has been properly expanded to verify that
NewEvaluatorpanics when any of the three required parameters (ctx, evalCtx, log) is nil. This provides good coverage of the validation logic in the constructor.
525-525: LGTM! NewEvaluator calls updated consistently.All invocations of
NewEvaluatorthroughout the test file have been correctly updated to pass the three required parameters:
context.Background()for the context- The evaluation context (
ctx)logger.NewTestLogger()for the loggerThis change is consistently applied across all 11 call sites in the file.
internal/executor/post_action_executor_test.go (2)
18-33: LGTM! Well-designed test logger factory.The shared test logger with
sync.Onceinitialization is a good pattern that:
- Eliminates duplication across tests
- Ensures thread-safe initialization
- Provides consistent error-level logging for all tests
- Follows the singleton pattern appropriately for test utilities
36-42: LGTM! Consistent test executor factory.The
testPAE()factory provides a clean way to createPostActionExecutorinstances with proper configuration for tests. This reduces boilerplate and ensures consistent test setup.internal/criteria/cel_evaluator.go (2)
56-72: LGTM! Constructor properly refactored for context-aware logging.The private constructor correctly:
- Accepts three required parameters:
ctx context.Context,evalCtx *EvaluationContext, andlog logger.Logger- Stores both the Go context (for logging) and evaluation context (for CEL data) separately
- Builds CEL environment from the evaluation context
- Returns proper error handling for CEL environment creation
The separation of concerns between operational context (
ctx) and evaluation data (evalCtx) is clean.
164-168: LGTM! Evaluation correctly uses separated contexts.The evaluation properly:
- Uses
e.evalCtx.Data()for CEL evaluation data (evaluation context)- Uses
e.ctxfor logging context (operational context)This separation ensures thread-safe access to evaluation data while maintaining proper context propagation for observability.
internal/hyperfleet_api/client.go (1)
119-147: LGTM! NewClient API correctly updated.The constructor properly:
- Accepts
log logger.Loggeras the first required parameter- Returns
(Client, error)for proper error handling- Stores the logger in the httpClient for use throughout the request lifecycle
- Validates base URL configuration and returns clear error messages
- Falls back to environment variable when base URL not provided via options
This is a breaking API change that enables proper structured logging throughout the client.
internal/executor/types.go (2)
40-54: LGTM! Well-structured event data types.The new
ResourceRefandEventDatatypes provide a clean abstraction for CloudEvent payloads, replacing direct CloudEvent dependencies. The JSON tags are properly defined for serialization.
253-264: All call sites forNewExecutionContexthave been properly updated to use the new signature. Verified 9 call sites acrossexecutor_test.go,executor.go, andpost_action_executor_test.go, and all correctly pass onlyctxandeventDataparameters.cmd/adapter/main.go (2)
116-154: LGTM! Well-designed bootstrap logger pattern.The approach of creating a bootstrap logger before config load, then recreating it with the adapter component name from the loaded config, is a solid pattern. Error handling for logger creation is properly implemented.
306-335: No changes required. Thehyperfleet_api.NewClientsignature correctly acceptslogger.Loggeras the first parameter, and the implementation incmd/adapter/main.go:334uses it correctly. All 30+ call sites across the codebase consistently pass the logger as the first argument.internal/executor/executor_test.go (2)
103-113: LGTM! Test data construction properly simplified.The test correctly uses a simple map for event data instead of constructing CloudEvent objects, aligning with the new data-driven approach. The assertions verify
execCtx.EventData["cluster_id"]instead ofexecCtx.Event.ID().
275-278: Good use of logger.WithEventID for test context enrichment.The test properly adds event ID to context using
logger.WithEventID(context.Background(), "test-event-123")before calling Execute. This ensures logging correlation works correctly in tests.internal/executor/executor.go (2)
30-47: LGTM! Proper validation with nil check.The
validateExecutorConfigfunction correctly checks for nil config first (addressing past review comment), then uses reflection to verify required fields. The approach prevents nil pointer panics.
243-287: ParseEventData handles multiple input types correctly.The function properly handles:
nildata → returns empty EventData and map[]byte→ parses JSONmap[string]interface{}→ marshals and unmarshals for consistency- Other types → attempts JSON marshaling
The dual return of structured
EventDataand rawmap[string]interface{}provides flexibility for different use cases.test/integration/executor/executor_integration_test.go (2)
91-95: LGTM! API client error handling properly added.The error from
hyperfleet_api.NewClientis now captured and checked withrequire.NoError, addressing the past review comment. This prevents nil pointer panics if client creation fails.
841-854: Good use of capture logger for test assertions.The test correctly uses
logger.NewCaptureLogger()to create a logger with a capture handle, then verifies log messages usinglogCapture.Contains(). This provides better test coverage for logging behavior.internal/criteria/evaluator.go (1)
76-93: LGTM! Lazy CEL evaluator creation with version tracking.The
getCELEvaluatormethod correctly caches the CEL evaluator and recreates it when the context version changes. This ensures the CEL environment stays in sync with variable changes while avoiding unnecessary recreations.internal/executor/precondition_executor.go (3)
21-28: LGTM! Clean constructor with config-based wiring.The
newPreconditionExecutorconstructor properly extracts the API client and logger from theExecutorConfig. The comment correctly notes that the caller (NewExecutor) is responsible for config validation.
87-119: Good error handling with ExecutionError population.The API call and JSON parsing error paths correctly populate
execCtx.Adapter.ExecutionErrorwith phase, step, and message. This provides structured error information for downstream processing and reporting.
144-144: Verify criteria.NewEvaluator call site matches new signature.The call to
criteria.NewEvaluator(ctx, evalCtx, pe.log)should match the updated signature that now requirescontext.Contextas the first parameter. This looks correct based on the evaluator.go changes.internal/executor/resource_executor.go (3)
24-31: LGTM! Constructor properly wired with config.The
newResourceExecutorconstructor correctly extracts the K8s client and logger from theExecutorConfig. The comment notes thatNewExecutorhandles config validation, which addresses past review concerns about K8sClient validation.
404-431: LGTM! deepCopyMap properly handles edge cases.The function correctly:
- Returns nil for nil input
- Uses
copystructure.Copyfor deep copying (preserves types)- Falls back to shallow copy with warning if deep copy fails
- Logs the fallback with context for debugging
The warning message helpfully explains the implications of the shallow copy fallback.
336-363: waitForDeletion polling logic looks correct.The function properly:
- Uses a ticker for polling
- Checks context cancellation
- Returns nil on NotFound (success case)
- Logs status at appropriate log levels
- Returns errors for unexpected conditions
The polling approach with context cancellation support is a good pattern for waiting on asynchronous Kubernetes operations.
internal/executor/post_action_executor.go (3)
31-77: Excellent context propagation in ExecuteAll.The refactor correctly:
- Converts to receiver method with context parameter
- Propagates
ctxto all logging calls (lines 38, 40, 49, 56, 61, 73)- Passes
ctxto downstream methods (buildPostPayloads,executePostAction)- Maintains the original logic flow while adding context awareness
The implementation is clean and consistent with the context-aware logging pattern.
81-249: Context propagation is correct throughout all methods.All methods have been properly refactored to:
- Accept
context.Contextas a parameter- Propagate
ctxthrough all recursive calls:
buildPostPayloads→buildPayload→buildMapPayload/processValue(lines 100, 123, 126, 144, 174, 178, 183)executePostAction→executeAPICall(lines 214, 225)- Pass
ctxto evaluator creation (line 86)- Pass
ctxto utility functions likeExecuteLogActionandExecuteAPICall(lines 208, 225)- Use
pae.logwithctxfor all loggingThe refactor is thorough, consistent, and maintains the original logic while adding context awareness throughout the execution flow.
20-27: No action required — config validation is properly handled by the caller.The
NewExecutorfunction validates theExecutorConfigparameter viavalidateExecutorConfig()before callingnewPostActionExecutor(config)at line 26 of executor.go. The validation checks thatconfigis not nil and that all required fields (APIClient,Logger,AdapterConfig,K8sClient) are non-nil. This design correctly delegates validation to the public API, allowing internal functions to safely assume a valid config. The inline comment documenting this responsibility is accurate.Likely an incorrect or invalid review comment.
a546970 to
a9035f3
Compare
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
♻️ Duplicate comments (2)
internal/hyperfleet_api/client.go (1)
309-309: Fix inconsistent indentation (duplicate concern).Line 309 has extra leading whitespace (double-indented). This was flagged in a previous review and marked as addressed in commit 6c0e49c, but the issue persists in the current diff.
🔎 Apply this fix
// Execute request - c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) + c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) httpResp, err := c.client.Do(httpReq)Also applies to line 329:
- c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status) + c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status)internal/criteria/cel_evaluator_test.go (1)
157-157: Test semantics changed:nullValueis no longer null.The test case at lines 183-189 ("access field on null returns error in result (safe)") expects
nullValueto benilto test null value access behavior. Setting it tologger.NewTestLogger()changes the test semantics - you're now testing field access on a logger object instead of null access.- ctx.Set("nullValue", logger.NewTestLogger()) + ctx.Set("nullValue", nil)
🧹 Nitpick comments (4)
pkg/logger/context.go (1)
64-66: Consider validating empty resourceType.Line 65 converts
resourceTypeto lowercase and appends "_id", but ifresourceTypeis empty, this produces a field named "_id". Consider adding a guard:🔎 Suggested validation
func WithDynamicResourceID(ctx context.Context, resourceType string, resourceID string) context.Context { + if resourceType == "" { + return ctx + } fieldName := strings.ToLower(resourceType) + "_id" return WithLogField(ctx, fieldName, resourceID) }pkg/logger/logger.go (1)
180-198: Context fields override logger fields by key.Lines 184-195 append logger fields first, then context fields. If a context field has the same key as a logger field, slog will use the later (context) value. This override behavior may be intentional but should be documented if it's part of the design.
Consider adding a comment documenting this behavior:
🔎 Documentation suggestion
// buildArgs builds the slog args from fields and context +// Context fields with the same key as logger fields will override logger fields. func (l *logger) buildArgs(ctx context.Context) []any {internal/executor/post_action_executor_test.go (1)
18-33: Consider usinglogger.NewTestLogger()instead of defining a localtestLog().This local
testLog()duplicates the functionality oflogger.NewTestLogger()frompkg/logger/test_support.go. The implementations differ slightly (this uses"stdout", the central one uses"stderr"). For consistency across the test suite, consider using the centralized helper.🔎 Proposed refactor
-var ( - sharedTestLogger logger.Logger - loggerOnce sync.Once -) - -// testLog creates a logger for tests -func testLog() logger.Logger { - loggerOnce.Do(func() { - var err error - sharedTestLogger, err = logger.NewLogger(logger.Config{Level: "error", Format: "text", Output: "stdout", Component: "test", Version: "test"}) - if err != nil { - panic(err) - } - }) - return sharedTestLogger -} +// testLog returns a shared test logger +func testLog() logger.Logger { + return logger.NewTestLogger() +}internal/executor/executor.go (1)
30-47: Consider compile-time validation instead of reflection.The reflection-based validation at line 42 uses hardcoded field names (
"AdapterConfig","APIClient","Logger","K8sClient"). This approach is brittle because:
- Field renames won't be caught at compile time
- Typos in field names will only surface at runtime
- IDEs can't assist with refactoring
Consider replacing this with explicit nil checks:
func validateExecutorConfig(config *ExecutorConfig) error { if config == nil { return fmt.Errorf("config is required") } if config.AdapterConfig == nil { return fmt.Errorf("field AdapterConfig is required") } if config.APIClient == nil { return fmt.Errorf("field APIClient is required") } if config.Logger == nil { return fmt.Errorf("field Logger is required") } if config.K8sClient == nil { return fmt.Errorf("field K8sClient is required") } return nil }This provides better compile-time safety and is easier to maintain.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (37)
cmd/adapter/main.gogo.modinternal/config_loader/loader.gointernal/config_loader/validator.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/executor/README.mdinternal/executor/executor.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/k8s_client/client.gointernal/k8s_client/discovery.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/test_support.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.go
💤 Files with no reviewable changes (3)
- go.mod
- internal/executor/param_extractor.go
- internal/executor/README.md
🚧 Files skipped from review as they are similar to previous changes (9)
- test/integration/k8s_client/helper_envtest_prebuilt.go
- internal/config_loader/validator_test.go
- internal/config_loader/loader.go
- internal/executor/utils.go
- internal/executor/types.go
- test/integration/executor/setup_test.go
- internal/k8s_client/discovery.go
- internal/criteria/cel_evaluator.go
- internal/config_loader/validator.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
test/integration/config-loader/config_criteria_integration_test.gointernal/criteria/evaluator_version_test.gointernal/criteria/evaluator_scenarios_test.gocmd/adapter/main.gointernal/executor/utils_test.gointernal/executor/executor.gointernal/criteria/evaluator_test.gotest/integration/executor/executor_integration_test.gointernal/hyperfleet_api/client.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.gopkg/logger/logger_test.go
🧬 Code graph analysis (16)
internal/hyperfleet_api/client_test.go (2)
pkg/logger/logger.go (3)
Logger(15-43)NewLogger(104-163)Config(57-72)internal/hyperfleet_api/client.go (4)
NewClient(119-148)WithBaseURL(102-106)WithDefaultHeader(57-64)WithConfig(48-54)
test/integration/config-loader/config_criteria_integration_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/criteria/evaluator_version_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/criteria/evaluator_scenarios_test.go (1)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
cmd/adapter/main.go (6)
pkg/logger/logger.go (3)
ConfigFromEnv(86-100)NewLogger(104-163)Logger(15-43)internal/config_loader/loader.go (2)
Load(79-102)WithAdapterVersion(46-50)internal/config_loader/types.go (2)
Metadata(14-18)HyperfleetAPIConfig(37-42)internal/hyperfleet_api/client.go (1)
NewClient(119-148)internal/k8s_client/client.go (3)
NewClient(65-114)ClientConfig(35-43)Client(29-32)internal/executor/executor.go (1)
NewBuilder(299-303)
internal/executor/utils_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/executor/types.go (1)
ExecutionContext(180-195)internal/executor/utils.go (1)
ExecuteLogAction(39-70)
internal/criteria/evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-43)
test/integration/executor/executor_k8s_integration_test.go (2)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)internal/k8s_client/client.go (1)
NewClient(65-114)
internal/executor/executor.go (5)
internal/executor/types.go (8)
Executor(69-75)ExecutorConfig(57-66)ExecutionResult(78-101)StatusFailed(37-37)NewExecutionContext(253-264)StatusSuccess(35-35)ExecutionContext(180-195)EventData(48-54)pkg/logger/logger.go (1)
Logger(15-43)internal/config_loader/constants.go (1)
FieldByName(93-93)pkg/logger/context.go (4)
WithResourceID(95-97)WithResourceType(90-92)WithDynamicResourceID(64-67)WithEventID(80-82)internal/config_loader/types.go (1)
AdapterConfig(6-11)
internal/criteria/evaluator_test.go (3)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
internal/executor/post_action_executor_test.go (5)
pkg/logger/logger.go (3)
Logger(15-43)NewLogger(104-163)Config(57-72)internal/executor/post_action_executor.go (1)
PostActionExecutor(15-18)internal/executor/types.go (2)
ExecutorConfig(57-66)NewExecutionContext(253-264)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)internal/executor/utils.go (1)
ExecuteAPICall(76-206)
internal/executor/precondition_executor.go (4)
internal/executor/types.go (2)
ExecutorConfig(57-66)ExecutionContext(180-195)internal/config_loader/types.go (2)
Precondition(98-105)APICall(108-116)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
internal/hyperfleet_api/client.go (2)
pkg/logger/logger.go (1)
Logger(15-43)internal/k8s_client/client.go (2)
NewClient(65-114)Client(29-32)
test/integration/executor/main_test.go (2)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)pkg/logger/logger.go (1)
Config(57-72)
internal/criteria/cel_evaluator_test.go (3)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
pkg/logger/logger.go (1)
pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
🔇 Additional comments (40)
pkg/logger/context.go (1)
119-132: LGTM: Defensive copy protects context fields.The defensive copy on lines 125-128 correctly prevents callers from mutating the stored LogFields. The implementation follows best practices for context value retrieval.
pkg/logger/logger.go (1)
128-130: AddSource disabled for all log levels.Line 129 sets
AddSource: false, meaning source file/line information is not included in any log entries. This can make debugging difficult, especially for error-level logs.Is this intentional? Consider enabling source information at least for error level:
🔎 Optional: Enable source for errors
opts := &slog.HandlerOptions{ Level: level, - // Add source location for error level only - AddSource: false, + // Add source location for error level + AddSource: level == slog.LevelError, }Or enable for all levels if the comment on line 128 reflects the original intent.
internal/k8s_client/client.go (1)
81-88: LGTM: Context-aware logging properly integrated.The logging calls throughout this file have been correctly updated to accept context as the first parameter, enabling context-based field propagation for all Kubernetes client operations.
cmd/adapter/main.go (3)
116-136: LGTM: Bootstrap logger correctly configured.The bootstrap logger creation properly merges CLI flags with environment variables and returns early on error. The component name "hyperfleet-adapter" is appropriate for the bootstrap phase before the adapter config is loaded.
148-154: Logger recreation correctly uses adapter component name.The logger is properly recreated with the adapter's component name from the loaded configuration. The error handling ensures that logger creation failures are surfaced immediately.
306-334: LGTM: Logger correctly threaded through API client creation.The updated signature and implementation correctly pass the logger to
hyperfleet_api.NewClient, enabling context-aware logging throughout API client operations.internal/hyperfleet_api/client_test.go (2)
27-36: LGTM: Test logger properly implemented with sync.Once.The
testLog()helper correctly usessync.Oncefor thread-safe lazy initialization, which is appropriate for parallel tests. The panic on logger creation failure is acceptable for test setup.
38-43: LGTM: All test calls updated to provide logger.All
NewClientinvocations throughout the test file have been correctly updated to passtestLog()as the first parameter, maintaining test coverage and aligning with the new API signature.internal/criteria/evaluator_scenarios_test.go (1)
47-49: LGTM: Evaluator tests correctly updated for context-aware API.All
NewEvaluatorcalls throughout the test file have been properly updated to:
- Pass
context.Background()as the first parameter- Pass the evaluation context
- Pass
logger.NewTestLogger()for test logging- Check for errors via
require.NoErrorThis aligns with the broader context-aware logging refactor and ensures consistent test patterns.
internal/executor/utils_test.go (1)
775-779: LGTM: ExecuteLogAction test correctly updated.The test correctly instantiates a test logger via
logger.NewTestLogger()and passescontext.Background()as the first parameter toExecuteLogAction, aligning with the updated function signature.internal/criteria/evaluator_version_test.go (1)
18-20: LGTM!The test correctly migrates to the new
NewEvaluator(ctx, evalCtx, log)signature with proper error assertion. Usinglogger.NewTestLogger()aligns with the shared test logger pattern inpkg/logger/test_support.go.test/integration/config-loader/config_criteria_integration_test.go (1)
73-74: LGTM!Integration tests correctly updated to use the new
NewEvaluatorsignature with context, evaluation context, and test logger. Error handling is properly added across all call sites.test/integration/executor/executor_k8s_integration_test.go (1)
318-322: LGTM!The
hyperfleet_api.NewClientcalls are correctly updated to pass the logger as the first argument and handle the returned error. This aligns with the new client signature shown ininternal/hyperfleet_api/client.go.test/integration/executor/main_test.go (2)
106-106: LGTM!Using
logger.NewTestLogger()is the correct approach for test setup, consistent with the centralized test logger inpkg/logger/test_support.go.
208-214: Response body leak on non-200 status codes.When
resp.StatusCode != http.StatusOK, the response body is not closed before continuing the loop. This can lead to connection leaks over the retry period.🔎 Proposed fix
resp, err := client.Do(req) if err == nil { - _ = resp.Body.Close() if resp.StatusCode == http.StatusOK { + _ = resp.Body.Close() return nil // API server is ready } + _ = resp.Body.Close() }Likely an incorrect or invalid review comment.
internal/executor/resource_executor_test.go (1)
19-19: LGTM!The
deepCopyMapcalls are correctly updated to includecontext.Background()andtestLog(), aligning with the context-aware logging refactor. Test semantics are preserved.internal/criteria/cel_evaluator_test.go (1)
13-21: LGTM!The test function rename to
Test_newCELEvaluatorcorrectly reflects that it's testing the unexportednewCELEvaluatorfunction. The signature update with context and logger is correct.internal/executor/post_action_executor_test.go (1)
36-42: LGTM!The
testPAE()helper provides a clean factory for constructingPostActionExecutorinstances in tests, properly wiring the logger and a mock API client.internal/criteria/evaluator_test.go (2)
775-791: LGTM!Excellent test coverage for the new
NewEvaluatorerror cases. Testing all three nil parameter scenarios (ctx, evalCtx, log) ensures the constructor's validation logic is properly verified. Thenolint:staticcheckcomment appropriately documents the intentional nil context for testing.
525-526: LGTM!The migration to the new
NewEvaluator(ctx, evalCtx, log)signature is consistent throughout the file, with proper error handling usingrequire.NoError(t, err).pkg/logger/test_support.go (1)
1-83: LGTM! Clean test utility implementation.The test support utilities are well-designed:
NewTestLogger()uses a singleton pattern withsync.Onceto avoid creating multiple instancesLogCaptureis thread-safe with proper mutex usageNewCaptureLogger()provides a clean API for inspecting logs in tests- Good documentation with example usage
These utilities align well with the broader logger refactor and will improve test clarity across the codebase.
internal/executor/executor.go (1)
247-291: LGTM! Robust input handling in ParseEventData.The
ParseEventDatafunction correctly handles multiple input types:
- Empty/nil inputs return empty structures
[]byte(JSON) is parsed directlymap[string]interface{}is marshaled then parsed- Other types are marshaled as JSON
The dual return of both structured
EventDataand rawmap[string]interface{}provides flexibility for different use cases. Error handling is appropriate throughout.test/integration/executor/executor_integration_test.go (2)
833-967: LGTM! Clean log capture pattern in tests.The test correctly uses
logger.NewCaptureLogger()to:
- Create a logger that writes to a buffer (line 842)
- Wire it into the executor (line 922)
- Inspect captured logs using
logCapture.Contains()andlogCapture.Messages()(lines 939-951)This pattern provides better isolation than intercepting global output and aligns well with the context-aware logging refactor.
1236-1361: LGTM! Comprehensive verification of error logging.The test properly verifies that:
- Payload build failures are logged as errors (lines 1346-1350)
- Post actions are blocked when payload building fails (line 1332)
- ExecutionError is populated correctly (lines 1335-1343)
- The error is logged with appropriate context
The log inspection correctly checks for both
level=ERRORandfailed to buildpatterns in the captured logs.internal/executor/executor_test.go (2)
23-99: LGTM! Clean migration to new test utilities.The tests correctly use
logger.NewTestLogger()throughout (lines 38, 46, 64, 94), which:
- Provides a consistent test logger across all tests
- Uses the singleton pattern to avoid creating multiple instances
- Reduces test boilerplate
The test structure and assertions remain clear and maintainable.
234-289: LGTM! Proper migration to data-centric API.The test correctly:
- Creates event data as a map (lines 271-273) instead of a CloudEvent
- Passes context with event ID via
logger.WithEventID()(line 276)- Calls
Execute()with the data map (line 277)This aligns with the new data-centric API and removes the dependency on CloudEvent structures in the executor.
internal/criteria/evaluator.go (2)
53-71: LGTM! Robust parameter validation in NewEvaluator.The updated constructor correctly:
- Requires all parameters (ctx, evalCtx, log) and validates they're non-nil
- Returns an error instead of panicking, allowing graceful handling
- Documents the purpose of each parameter in the error messages
This prevents runtime panics and provides clear feedback when the evaluator is misconfigured.
73-94: LGTM! Correct CEL evaluator cache invalidation.The
getCELEvaluator()method properly:
- Checks if the evaluation context version has changed (line 81)
- Recreates the CEL evaluator when the context is modified (lines 84-90)
- Uses mutex protection for thread safety (lines 78-79)
This ensures the CEL environment stays in sync with the context data and prevents "undeclared reference" errors when variables are added after the first evaluation.
internal/executor/precondition_executor.go (2)
21-28: LGTM! Clean config-based wiring.The constructor correctly:
- Accepts
ExecutorConfiginstead of individual parameters- Wires the logger from the centralized config (line 26)
- Documents that the caller (NewExecutor) handles validation (line 22)
This aligns with the broader refactor to centralize configuration and logging, as noted in the learning from HYPERFLEET-304.
Based on learnings, logger refactor tracked in HYPERFLEET-304.
144-149: LGTM! Proper error handling for evaluator creation.The code correctly:
- Calls
criteria.NewEvaluator(ctx, evalCtx, pe.log)with all required parameters- Checks for errors from the constructor (lines 145-149)
- Returns a wrapped error with phase and step context via
NewExecutorError()This prevents potential panics and provides clear error context when evaluator creation fails.
pkg/logger/logger_test.go (2)
8-55: LGTM! Comprehensive constructor testing.The tests properly verify:
- Logger creation with default config
- Logger creation with JSON format
- Logger creation with text format
- Error handling for invalid output (lines 57-68)
Type assertions confirm the correct implementation is returned, providing good coverage of the NewLogger API surface.
358-424: LGTM! Thorough context helpers and config testing.The tests comprehensively verify:
- Context helper functions (
WithEventID,WithClusterID,WithTraceID) properly add fields to context (lines 361-383)ConfigFromEnv()respects environment variables and provides sensible defaults (lines 386-423)- Field propagation through context is correct
This ensures the context-aware logging infrastructure works as expected.
internal/executor/post_action_executor.go (2)
20-27: LGTM! Config validation properly delegated.The constructor comment (line 22) correctly documents that the caller (
NewExecutor) is responsible for config validation. This is verified inexecutor.gowherevalidateExecutorConfig()checks all required fields includingLoggerandAPIClient.This design centralizes validation logic and avoids duplication across executor constructors.
81-89: LGTM! Proper error handling for evaluator creation.The code correctly:
- Calls
criteria.NewEvaluator(ctx, evalCtx, pae.log)with the new signature- Handles the error return (lines 87-89)
- Returns a wrapped error with clear context
This prevents panics and aligns with the broader refactor to require explicit error handling for evaluator creation.
internal/executor/resource_executor.go (6)
21-31: LGTM! Constructor refactor aligns with config-based wiring.The addition of the internal logger field and the shift to a private constructor using
ExecutorConfigproperly centralizes initialization and enables context-aware logging throughout the executor.
35-55: LGTM! Context-aware logging properly integrated.The
ExecuteAllmethod correctly threads context through toexecuteResourceand uses the internal logger with context for all logging statements.
161-200: LGTM! Context and logger properly propagated.The
buildManifestmethod correctly passes context and the internal logger todeepCopyMap, enabling context-aware logging for copy failures.
308-332: LGTM! Recreate flow properly context-aware.The
recreateResourcemethod correctly threads context through the delete-wait-create sequence and uses context-aware logging throughout.
336-363: LGTM! Context properly used for cancellation and logging.The
waitForDeletionmethod correctly uses context for both cancellation detection and logging, ensuring the polling loop respects context deadlines.
404-431: LGTM! Standalone function properly parameterized for context-aware logging.The
deepCopyMapfunction correctly accepts context and logger parameters, enabling context-aware warning logs when deep copy falls back to shallow copy.
b29668b to
1442108
Compare
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
♻️ Duplicate comments (2)
internal/criteria/cel_evaluator_test.go (1)
157-157: Test semantics broken:nullValueshould benil, not a logger instance.The test case at lines 183-189 ("access field on null returns error in result (safe)") expects
nullValueto be null to verify null-access handling, but line 157 sets it tologger.NewTestLogger(). This changes the test from verifying null behavior to testing field access on a non-map object.Restore the original semantics:
- ctx.Set("nullValue", logger.NewTestLogger()) + ctx.Set("nullValue", nil)internal/hyperfleet_api/client.go (1)
309-309: Fix inconsistent indentation on log statements.Lines 309 and 329 have extra leading whitespace (double-indented), which is inconsistent with the surrounding code. This appears to persist from a previous review.
🔎 Proposed fix
// Execute request - c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) + c.log.Debugf(ctx, "HyperFleet API request: %s %s", req.Method, req.URL) httpResp, err := c.client.Do(httpReq)And for line 329:
- c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status) + c.log.Debugf(ctx, "HyperFleet API response: %d %s", response.StatusCode, response.Status)
🧹 Nitpick comments (4)
pkg/logger/context.go (1)
40-47: Consider nil context guard for consistency.
GetLogFieldshandles nil context (line 120-122), butWithLogFieldwill panic ifctxis nil due tocontext.WithValue. Consider adding a nil check or documenting that nil context is not supported.🔎 Optional: Add nil context guard
func WithLogField(ctx context.Context, key string, value interface{}) context.Context { + if ctx == nil { + return nil + } fields := GetLogFields(ctx) if fields == nil { fields = make(LogFields) } fields[key] = value return context.WithValue(ctx, LogFieldsKey, fields) }internal/executor/post_action_executor_test.go (1)
23-33: ReplacetestLog()withlogger.NewTestLogger()to eliminate duplication.The
testLog()function duplicates the test logger pattern already provided bylogger.NewTestLogger()inpkg/logger/test_support.go. The only difference is the output destination (stdoutvsstderr), which is not significant for tests.🔎 Refactor to use the shared test logger
-var ( - sharedTestLogger logger.Logger - loggerOnce sync.Once -) - -// testLog creates a logger for tests -func testLog() logger.Logger { - loggerOnce.Do(func() { - var err error - sharedTestLogger, err = logger.NewLogger(logger.Config{Level: "error", Format: "text", Output: "stdout", Component: "test", Version: "test"}) - if err != nil { - panic(err) - } - }) - return sharedTestLogger -} - // testPAE creates a PostActionExecutor for tests func testPAE() *PostActionExecutor { return newPostActionExecutor(&ExecutorConfig{ - Logger: testLog(), + Logger: logger.NewTestLogger(), APIClient: newMockAPIClient(), }) }Then update line 663:
- testLog(), + logger.NewTestLogger(),internal/executor/executor.go (1)
30-47: Consider using explicit nil checks instead of reflection.While the reflection-based validation works, it's brittle - renaming a field in
ExecutorConfigwithout updating the string list here will cause silent failures. Consider explicit nil checks for type safety and better compile-time guarantees.🔎 Alternative approach
func validateExecutorConfig(config *ExecutorConfig) error { if config == nil { return fmt.Errorf("config is required") } if config.AdapterConfig == nil { return fmt.Errorf("AdapterConfig is required") } if config.APIClient == nil { return fmt.Errorf("APIClient is required") } if config.Logger == nil { return fmt.Errorf("Logger is required") } if config.K8sClient == nil { return fmt.Errorf("K8sClient is required") } return nil }internal/executor/post_action_executor.go (1)
62-62: Remove extraneous blank lines.Lines 62, 69, 241, and 247 contain unnecessary blank lines that disrupt code flow between error handling logic and subsequent statements.
🔎 Proposed fix
if err != nil { pae.log.Errorf(ctx, " [PostAction %d/%d] %s: FAILED - %v", i+1, len(postConfig.PostActions), action.Name, err) - // Set ExecutionError for failed post action execCtx.Adapter.ExecutionError = &ExecutionError{Similar cleanup applies to lines 69, 241, and 247.
Also applies to: 69-69, 241-241, 247-247
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (37)
cmd/adapter/main.gogo.modinternal/config_loader/loader.gointernal/config_loader/validator.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/executor/README.mdinternal/executor/executor.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/k8s_client/client.gointernal/k8s_client/discovery.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/test_support.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.go
💤 Files with no reviewable changes (3)
- go.mod
- internal/executor/README.md
- internal/executor/param_extractor.go
🚧 Files skipped from review as they are similar to previous changes (8)
- internal/k8s_client/client.go
- internal/executor/utils_test.go
- internal/config_loader/loader.go
- test/integration/executor/setup_test.go
- test/integration/k8s_client/helper_envtest_prebuilt.go
- test/integration/config-loader/config_criteria_integration_test.go
- internal/hyperfleet_api/client_test.go
- internal/config_loader/validator_test.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/criteria/evaluator_scenarios_test.gointernal/executor/types.gointernal/criteria/evaluator_test.gocmd/adapter/main.gointernal/hyperfleet_api/client.gointernal/executor/executor.gointernal/config_loader/validator.gotest/integration/executor/executor_integration_test.gointernal/criteria/evaluator_version_test.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.gopkg/logger/logger_test.gointernal/executor/resource_executor.go
🧬 Code graph analysis (18)
internal/criteria/evaluator_scenarios_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/executor/types.go (2)
internal/k8s_client/client.go (1)
Client(29-32)pkg/logger/logger.go (1)
Logger(15-43)
internal/criteria/evaluator_test.go (3)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
internal/criteria/evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-43)
internal/hyperfleet_api/client.go (2)
pkg/logger/logger.go (1)
Logger(15-43)internal/hyperfleet_api/types.go (1)
Client(216-237)
internal/executor/post_action_executor_test.go (4)
internal/executor/post_action_executor.go (1)
PostActionExecutor(15-18)internal/executor/types.go (1)
ExecutorConfig(57-66)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)internal/executor/utils.go (1)
ExecuteAPICall(76-206)
internal/criteria/cel_evaluator_test.go (3)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
pkg/logger/logger.go (1)
pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
internal/executor/executor_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/executor/types.go (4)
NewExecutionContext(253-264)EventData(48-54)StatusSuccess(35-35)ExecutionStatus(31-31)pkg/logger/context.go (1)
WithEventID(80-82)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(57-72)DefaultConfig(75-83)NewLogger(104-163)ConfigFromEnv(86-100)pkg/logger/context.go (10)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithClusterID(85-87)WithTraceID(70-72)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(105-121)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-43)
pkg/logger/test_support.go (1)
pkg/logger/logger.go (3)
Logger(15-43)NewLogger(104-163)Config(57-72)
internal/executor/post_action_executor.go (5)
internal/executor/types.go (2)
ExecutorConfig(57-66)ExecutionContext(180-195)internal/config_loader/types.go (3)
Payload(67-78)PostAction(199-203)APICall(108-116)internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (2)
NewEvaluator(56-71)Evaluator(41-51)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)
test/integration/executor/executor_integration_test.go (4)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)internal/k8s_client/client.go (1)
NewClient(65-114)pkg/logger/test_support.go (1)
NewCaptureLogger(67-83)internal/executor/executor.go (1)
NewBuilder(299-303)
test/integration/executor/executor_k8s_integration_test.go (1)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)
internal/executor/precondition_executor.go (5)
pkg/logger/logger.go (1)
Logger(15-43)internal/executor/types.go (2)
ExecutorConfig(57-66)ExecutionContext(180-195)internal/config_loader/types.go (2)
Precondition(98-105)APICall(108-116)internal/executor/utils.go (1)
ExecuteAPICall(76-206)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
internal/criteria/evaluator_version_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
🔇 Additional comments (54)
internal/k8s_client/discovery.go (1)
85-86: LGTM!The context-aware logging change is consistent with the PR's objective to propagate context through logger calls. This enables contextual log fields (trace IDs, cluster IDs, etc.) to be automatically included in log output.
internal/criteria/evaluator_scenarios_test.go (1)
47-48: LGTM!Test correctly updated to use the new
NewEvaluatorsignature with proper error handling. The patternNewEvaluator(context.Background(), ctx, logger.NewTestLogger())withrequire.NoError(t, err)is consistent throughout the file.internal/config_loader/validator.go (3)
391-406: Syntax-only CEL validation is appropriate.The decision to skip type checking makes sense given that all variables are declared as
DynType. Type mismatches will surface at runtime evaluation. The comments at lines 391-393 properly document this design choice.
409-431: LGTM on recursive expression validator.
validateBuildExpressionscorrectly traverses nested structures to find and validate CEL expressions. The recursion handles maps, slices, and string values appropriately.
65-71: Constructor is now unexported.Making
NewValidatorunexported is safe; no external packages depend on it. Callers usenewValidator(config).Validate()internally.pkg/logger/context.go (2)
119-131: LGTM on defensive copy.
GetLogFieldscorrectly returns a copy of the fields map to prevent external mutation of context-stored data. The nil context check at line 120-122 is good defensive programming.
64-67:WithDynamicResourceIDfield naming looks good.The dynamic field naming pattern (
strings.ToLower(resourceType) + "_id") produces consistent field names likecluster_id,nodepool_id. This is a clean approach for varying resource types.internal/criteria/evaluator_version_test.go (1)
18-19: LGTM!Test updates are consistent with the new
NewEvaluatorAPI. Error handling is properly added throughout all test functions in this file.test/integration/executor/executor_k8s_integration_test.go (1)
318-322: LGTM!API client creation correctly updated to pass
testLog()as the first argument with proper error handling. This pattern is consistently applied across all test functions in this file.test/integration/executor/main_test.go (2)
106-106: LGTM on test logger usage.Using
logger.NewTestLogger()is the correct approach for test environments, consistent with the pattern established across other test files in this PR.
186-220: Health check approach is more reliable.The refactored
waitForAPIServerReadyusing HTTP health checks against/healthzis more reliable during startup than the previous approach. The TLS configuration withInsecureSkipVerifyis appropriate for envtest's self-signed certificates, and thenolint:gosecannotation properly documents this intentional choice.internal/executor/resource_executor_test.go (2)
19-19: LGTM!All
deepCopyMapcalls correctly updated to includecontext.Background()as the first argument. The test coverage for deep copy behavior remains comprehensive, verifying mutation isolation for basic types, nested maps, slices, channels, functions, and Kubernetes manifests.
156-176: Test renamed appropriately.The test
TestDeepCopyMap_DeepCopyVerificationproperly verifies that deep copy works correctly and that the function doesn't panic. This is a cleaner test name reflecting its actual purpose.internal/executor/utils.go (2)
39-70: LGTM! Context propagation is correct.The refactor to context-aware logging in
ExecuteLogActionproperly threads the context through all logging calls. The signature change is backward-compatible at the call-site level since callers are updated in parallel.
76-206: LGTM! Context propagation is correct in API call execution.All logging calls within
ExecuteAPICallnow correctly use the context parameter. The changes maintain consistent error handling and logging patterns throughout the function.internal/criteria/evaluator_test.go (2)
525-526: LGTM! Tests correctly updated for three-parameter API.All test invocations of
NewEvaluatornow properly passcontext.Background(), the evaluation context, andlogger.NewTestLogger(). This aligns with the refactored constructor signature and enables context-aware logging throughout the evaluator tests.Also applies to: 613-614, 804-805, 830-831, 852-853, 889-890, 941-942, 967-968, 993-994, 1040-1041, 1095-1096
775-791: LGTM! Comprehensive nil-parameter validation tests.The expanded test now covers all three nil-parameter cases (ctx, evalCtx, log) with appropriate error message assertions. This ensures the constructor properly validates its inputs and provides clear error messages.
pkg/logger/test_support.go (3)
17-32: LGTM! Singleton pattern is appropriate for test logger.The singleton pattern with
sync.Onceensures that a single shared logger instance is used across tests, which is efficient and appropriate for test scenarios. The "error" level minimizes noise during test runs.
34-57: LGTM! Thread-safe log capture implementation.The
LogCapturetype provides thread-safe access to captured log output with helpful utility methods. The mutex correctly protects concurrent access to the buffer.
67-83: LGTM! Capture logger configured correctly for testing.
NewCaptureLoggerappropriately uses "debug" level to capture all log levels during testing. The custom writer pattern enables inspection of log output for assertions.internal/executor/types.go (3)
40-54: LGTM! New event data structures align with data-centric approach.The
ResourceRefandEventDatastructs properly capture the essential event payload information without requiring full CloudEvent objects. JSON tags are correctly specified.
74-74: LGTM! Logger field enables context-aware logging in Executor.Adding the
logfield to theExecutorstruct supports the broader refactor to context-aware logging throughout the executor components.
253-264: LGTM! Simplified constructor signature aligns with data-centric design.Removing the Event parameter from
NewExecutionContextand accepting event data as a map simplifies the API and removes the CloudEvent dependency. The function correctly initializes all fields with appropriate defaults.internal/criteria/cel_evaluator.go (3)
19-23: LGTM! Field updates support context-aware operations.The addition of the
ctxfield and renaming toevalCtxproperly separates concerns:ctxfor Go context propagation andevalCtxfor CEL evaluation data. This enables context-aware logging and aligns with the broader refactor.
56-73: LGTM! Constructor correctly initializes with context and logger.The updated
newCELEvaluatorsignature properly accepts and stores the context and logger for downstream use. The comment correctly notes that parameter validation is the caller's responsibility.
164-168: LGTM! Evaluation uses correct context references.The changes correctly use
e.evalCtx.Data()for CEL evaluation data ande.log.Debugf(e.ctx, ...)for context-aware logging on evaluation failure.internal/executor/executor_test.go (3)
38-65: LGTM! Tests correctly uselogger.NewTestLogger().All test cases properly utilize the shared test logger utility, ensuring consistent logging configuration across tests.
103-113: LGTM! Test correctly uses data-centric event handling.The test properly constructs event data as a map and verifies access through
execCtx.EventData["cluster_id"], aligning with the refactored data-centric approach.
270-278: LGTM! Event ID propagation via context is correct.The test properly uses
logger.WithEventID(context.Background(), "test-event-123")to attach the event ID to the context, demonstrating the new pattern for event ID propagation without requiring a full CloudEvent object.cmd/adapter/main.go (4)
31-36: LGTM: Well-structured flag variables for logging configuration.The separation of logging configuration flags (level, format, output) from the config path is clean and allows for flexible configuration through both CLI and environment variables.
116-138: LGTM: Bootstrap logger pattern with proper precedence.The configuration properly follows the precedence order: CLI flags override environment variables, which override defaults. Creating a bootstrap logger before config load ensures logging is available during the initialization phase.
147-156: LGTM: Logger recreation with adapter component name.Recreating the logger after config load to include the adapter's actual component name from configuration is a good pattern for meaningful log attribution.
306-334: LGTM: Updated createAPIClient to pass logger.The function signature change aligns with the updated
hyperfleet_api.NewClientAPI that now requires a logger as the first parameter.internal/hyperfleet_api/client.go (1)
119-148: LGTM: Clean logger injection with proper validation.The updated
NewClientsignature accepting a logger as the first parameter follows Go conventions. The base URL resolution with environment variable fallback and clear error messages provides good DX.internal/executor/executor.go (2)
66-77: LGTM: Well-designed context enrichment for logging.The logic to set owner reference and resource ID based on event data structure provides good traceability. The branching for owned vs. non-owned resources is clear and handles both cluster and nodepool scenarios appropriately.
247-291: LGTM: Flexible event data parsing with good error handling.
ParseEventDatahandles multiple input types ([]byte, map, arbitrary types) gracefully, with clear error messages for each failure path. The dual return of structuredEventDataand raw map provides flexibility for different use cases.internal/criteria/evaluator.go (2)
53-71: LGTM: Well-designed constructor with proper parameter validation.The updated
NewEvaluatorsignature with explicit error returns for nil parameters follows Go best practices. The separation ofctx(for logging correlation) andevalCtx(for CEL data) is clear and well-documented.
77-94: LGTM: CEL evaluator caching with version tracking.The lazy CEL evaluator creation with version-based cache invalidation ensures the CEL environment stays synchronized with context data changes, preventing stale variable references.
pkg/logger/logger.go (4)
13-43: LGTM: Clean Logger interface design.The interface provides a comprehensive set of context-aware logging methods with formatting variants. The
With,WithFields,WithError, andWithoutmethods enable fluent field management without mutation.
102-163: LGTM: Robust logger construction with slog backend.The constructor properly handles configuration with sensible defaults, validates output options, and initializes the slog handler with appropriate format. The hostname fallback chain (os.Hostname → POD_NAME → "unknown") is practical for containerized environments.
179-198: LGTM: Context-aware field extraction.The
buildArgsmethod correctly merges logger-level fields with context-carried log fields, enabling rich structured logging with correlation IDs propagated through context.
286-306: LGTM: Efficient nil-error handling in WithError.Returning the same logger instance when
erris nil is a smart optimization that avoids unnecessary allocations in common "log if error" patterns.pkg/logger/logger_test.go (3)
8-55: LGTM: Comprehensive NewLogger test coverage.The table-driven tests cover default config, JSON format, and text format with stderr output. Error handling verification is included.
168-175: LGTM: Correct nil-error test assertion.The test correctly verifies that
WithError(nil)returns the same logger instance (identity check withresult != log), validating the optimization behavior.
386-423: LGTM: Environment variable tests with proper isolation.Using
t.Setenvensures environment variables are properly cleaned up after each test, preventing test pollution.internal/executor/precondition_executor.go (3)
21-28: LGTM: Clean dependency injection through config.The constructor properly extracts dependencies from
ExecutorConfig, maintaining a single source of truth for configuration while keeping the executor struct focused.
144-149: LGTM: Proper error handling for evaluator creation.The updated
NewEvaluatorcall now handles the error return, propagating failures appropriately with a descriptive error message.
73-205: LGTM: Comprehensive context-aware logging throughout execution.The precondition execution flow has detailed logging at each step (API call, capture, conditions, CEL evaluation) with appropriate log levels (Info for progress, Debug for details, Warn/Error for issues).
test/integration/executor/executor_integration_test.go (4)
91-95: LGTM: Proper error handling for API client creation.The test now correctly captures and asserts the error from
NewClient, preventing potential nil pointer panics.
841-843: LGTM: Clean log capture pattern for test assertions.Using
logger.NewCaptureLogger()provides a clean way to capture and assert on log output without coupling to internal implementation details.
939-954: LGTM: Log assertion pattern using capture methods.The use of
logCapture.Messages()andlogCapture.Contains()provides readable assertions for verifying expected log messages were emitted.
1346-1350: LGTM: Error log verification with slog format awareness.The test correctly accounts for slog's
level=ERRORformat when verifying error logs were captured.internal/executor/resource_executor.go (1)
21-21: Logger refactor implemented correctly.The transition to internal logger with context propagation is well-executed. Key improvements:
- Internal
logfield eliminates parameter passing- All logging calls now include context for better observability
deepCopyMapsignature enhanced with context and logger for diagnostic fallback warnings- Constructor properly wired via
ExecutorConfigThe refactor maintains consistency with the broader HYPERFLEET-304 effort.
Also applies to: 24-31, 35-55, 58-156, 159-198, 306-330, 334-361, 402-429
internal/executor/post_action_executor.go (1)
17-17: Logger refactor implemented correctly.The context-aware logging integration is well-structured:
- Internal
logfield eliminates redundant parameter threadingNewEvaluatornow correctly receives context and logger (lines 86-89)- All payload building and action execution properly propagate context
- API call execution routes through internal logger
The changes align with the HYPERFLEET-304 refactor objectives.
Also applies to: 20-31, 31-77, 81-119, 123-133, 136-156, 159-200, 203-224, 227-252
1442108 to
1ca3777
Compare
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
🧹 Nitpick comments (7)
pkg/logger/test_support.go (1)
34-50: Potential race condition inContainsmethod.The
Containsmethod callsc.Messages()which acquires the lock, butstrings.Containsoperates on the returned string after the lock is released. If another goroutine writes to the buffer betweenMessages()returning and theContainscheck completing, the result could be stale. While this is unlikely to cause issues in most test scenarios, consider holding the lock for the entire operation for stricter thread-safety.🔎 Proposed fix
// Contains checks if the captured log output contains the given substring. func (c *LogCapture) Contains(substr string) bool { - return strings.Contains(c.Messages(), substr) + c.mu.Lock() + defer c.mu.Unlock() + return strings.Contains(c.buf.String(), substr) }internal/criteria/cel_evaluator.go (1)
17-23: Consider reordering struct fields for consistency.The struct fields have an inconsistent ordering -
ctxis placed afterloginstead of grouping context-related fields together. Consider reordering for better readability.🔎 Suggested field ordering
type CELEvaluator struct { + ctx context.Context env *cel.Env evalCtx *EvaluationContext log logger.Logger - ctx context.Context }internal/executor/executor_test.go (2)
294-301: Remove unused CloudEvent creation.The test creates a CloudEvent
evtand callsevt.SetData(), butevtis never used - the test only useseventDatamap. This appears to be leftover code from the CloudEvent-based approach.🔎 Proposed fix
func TestParamExtractor(t *testing.T) { t.Setenv("TEST_ENV", "env-value") - evt := event.New() eventData := map[string]interface{}{ "cluster_id": "test-cluster", "nested": map[string]interface{}{ "value": "nested-value", }, } - _ = evt.SetData(event.ApplicationJSON, eventData)
3-15: Unused import:github.com/cloudevents/sdk-go/v2/event.The CloudEvents import at line 7 is only used in
TestParamExtractorto create an unused event object. After removing that dead code, this import can also be removed.🔎 Proposed fix
import ( "context" "testing" - "github.com/cloudevents/sdk-go/v2/event" "github.com/openshift-hyperfleet/hyperfleet-adapter/internal/config_loader"internal/hyperfleet_api/client.go (1)
119-148: Consider nil logger validation.The
NewClientfunction accepts a logger but doesn't validate if it's nil. A nil logger would cause panics when logging is attempted. Consider adding validation similar to how base URL is validated.🔎 Proposed fix
func NewClient(log logger.Logger, opts ...ClientOption) (Client, error) { + if log == nil { + return nil, fmt.Errorf("logger is required for HyperFleet API client") + } + c := &httpClient{ config: DefaultClientConfig(), log: log, }internal/executor/executor.go (1)
30-47: Reflection-based validation works but is fragile.The validation correctly checks required fields, and past review concerns about nil config and K8sClient have been addressed. However, using reflection with string field names creates coupling that can silently break if struct fields are renamed.
Consider using direct nil checks for compile-time safety:
🔎 Alternative approach (optional)
func validateExecutorConfig(config *ExecutorConfig) error { if config == nil { return fmt.Errorf("config is required") } if config.AdapterConfig == nil { return fmt.Errorf("AdapterConfig is required") } if config.APIClient == nil { return fmt.Errorf("APIClient is required") } if config.Logger == nil { return fmt.Errorf("Logger is required") } if config.K8sClient == nil { return fmt.Errorf("K8sClient is required") } return nil }pkg/logger/logger.go (1)
240-244: Fatal calls os.Exit(1) directly - consider testability.Calling
os.Exit(1)directly makes this method difficult to test. For improved testability, consider injecting an exit function or using a package-level variable that tests can override.This is a minor concern since Fatal is rarely called and typically indicates unrecoverable errors.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (37)
cmd/adapter/main.gogo.modinternal/config_loader/loader.gointernal/config_loader/validator.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/executor/README.mdinternal/executor/executor.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/k8s_client/client.gointernal/k8s_client/discovery.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/test_support.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.go
💤 Files with no reviewable changes (3)
- internal/executor/param_extractor.go
- internal/executor/README.md
- go.mod
🚧 Files skipped from review as they are similar to previous changes (2)
- internal/config_loader/loader.go
- test/integration/k8s_client/helper_envtest_prebuilt.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/executor/utils_test.gotest/integration/config-loader/config_criteria_integration_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gocmd/adapter/main.gotest/integration/executor/executor_integration_test.gointernal/config_loader/validator.gointernal/executor/executor.gointernal/executor/types.gointernal/hyperfleet_api/client.gointernal/criteria/evaluator_scenarios_test.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.gointernal/executor/resource_executor.gopkg/logger/logger_test.go
🧬 Code graph analysis (23)
internal/executor/utils_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/executor/types.go (1)
ExecutionContext(180-195)internal/executor/utils.go (1)
ExecuteLogAction(39-70)
test/integration/config-loader/config_criteria_integration_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/criteria/evaluator_test.go (3)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
internal/executor/post_action_executor_test.go (5)
pkg/logger/logger.go (3)
Logger(15-43)NewLogger(104-163)Config(57-72)internal/executor/post_action_executor.go (1)
PostActionExecutor(15-18)internal/executor/types.go (1)
ExecutorConfig(57-66)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)internal/executor/utils.go (1)
ExecuteAPICall(76-206)
pkg/logger/test_support.go (1)
pkg/logger/logger.go (3)
Logger(15-43)NewLogger(104-163)Config(57-72)
internal/hyperfleet_api/client_test.go (3)
pkg/logger/logger.go (3)
Logger(15-43)NewLogger(104-163)Config(57-72)internal/hyperfleet_api/client.go (4)
NewClient(119-148)WithBaseURL(102-106)WithDefaultHeader(57-64)WithConfig(48-54)internal/k8s_client/client.go (1)
NewClient(65-114)
cmd/adapter/main.go (3)
pkg/logger/logger.go (3)
ConfigFromEnv(86-100)NewLogger(104-163)Logger(15-43)internal/hyperfleet_api/client.go (1)
NewClient(119-148)internal/k8s_client/client.go (3)
NewClient(65-114)ClientConfig(35-43)Client(29-32)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-43)
test/integration/executor/main_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)pkg/logger/logger.go (1)
Config(57-72)internal/k8s_client/client.go (1)
Client(29-32)
internal/criteria/evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-43)
internal/executor/resource_executor.go (6)
pkg/logger/logger.go (1)
Logger(15-43)internal/executor/types.go (6)
ExecutorConfig(57-66)ExecutionContext(180-195)ResourceResult(126-143)StatusFailed(37-37)ExecutionError(243-250)PhaseResources(25-25)internal/k8s_client/interface.go (1)
K8sClient(13-47)internal/config_loader/types.go (1)
Resource(171-178)internal/k8s_client/discovery.go (1)
Discovery(14-29)pkg/errors/k8s_error.go (1)
IsRetryableDiscoveryError(160-192)
test/integration/executor/executor_integration_test.go (2)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)pkg/logger/test_support.go (1)
NewCaptureLogger(67-83)
test/integration/executor/setup_test.go (2)
pkg/logger/logger.go (1)
Logger(15-43)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(105-121)
test/integration/executor/executor_k8s_integration_test.go (1)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)
pkg/logger/logger.go (1)
pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
internal/executor/utils.go (3)
internal/config_loader/types.go (1)
LogAction(206-209)internal/executor/types.go (1)
ExecutionContext(180-195)pkg/logger/logger.go (1)
Logger(15-43)
internal/executor/types.go (1)
internal/k8s_client/client.go (1)
Client(29-32)
internal/hyperfleet_api/client.go (3)
pkg/logger/logger.go (1)
Logger(15-43)internal/k8s_client/client.go (2)
NewClient(65-114)Client(29-32)internal/hyperfleet_api/types.go (2)
Client(216-237)DefaultClientConfig(57-66)
internal/executor/post_action_executor.go (5)
internal/executor/types.go (2)
ExecutorConfig(57-66)ExecutionContext(180-195)internal/config_loader/types.go (3)
Payload(67-78)PostAction(199-203)APICall(108-116)internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (2)
NewEvaluator(56-71)Evaluator(41-51)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)
internal/criteria/evaluator_scenarios_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/criteria/cel_evaluator_test.go (3)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
internal/executor/precondition_executor.go (5)
pkg/logger/logger.go (1)
Logger(15-43)internal/executor/types.go (2)
ExecutorConfig(57-66)ExecutionContext(180-195)internal/config_loader/types.go (2)
Precondition(98-105)APICall(108-116)internal/executor/utils.go (1)
ExecuteLogAction(39-70)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
🔇 Additional comments (70)
internal/k8s_client/discovery.go (1)
85-86: LGTM! Context correctly added to logging call.The change properly updates the logging call to include the context parameter, aligning with the context-aware logging migration. The context is available from the function parameter and is correctly passed as the first argument to
Infof.internal/config_loader/validator_test.go (1)
792-792: LGTM! Clean migration to internal validator API.The test updates correctly reflect the validator API changes where the public
Validate(config)wrapper was removed in favor of direct instantiation vianewValidator(config).Validate(). The test coverage remains intact.Also applies to: 828-828
internal/config_loader/validator.go (3)
65-66: LGTM! Validator constructor made internal.Making
newValidatorunexported is consistent with the refactored validation flow where callers useParse()for config loading with validation, rather than directly instantiating validators. The related test updates invalidator_test.goconfirm this is an intentional API change.
391-407: LGTM! CEL validation appropriately scoped to syntax checking.The explicit documentation that validation is "syntax only" is accurate given that CEL variables are declared as
DynType(their actual types are only known at runtime). This is a reasonable design tradeoff - catching syntax errors at config load time while deferring type validation to runtime when actual values are available.
409-431: LGTM! Comprehensive recursive validation for build expressions.The
validateBuildExpressionshelper correctly handles nested structures (maps, slices) to find and validate CEL expressions embedded in build payloads. The recursive approach ensures all expression fields are validated regardless of nesting depth.pkg/logger/logger_test.go (1)
8-450: LGTM! Comprehensive test coverage for logger package.The test suite thoroughly covers all aspects of the new logger implementation:
- Configuration and initialization (default, JSON/text formats, env vars)
- Field attachment and chaining (With, WithFields, WithError)
- All log levels and formatted variants
- Context key propagation and extraction
- Level parsing and defaults
The tests are well-structured and provide strong confidence in the logger's correctness.
pkg/logger/context.go (1)
38-132: LGTM! Context field management follows Go best practices.The implementation correctly uses defensive copying to prevent external mutation:
GetLogFieldsreturns a copy of the fields map (lines 125-128)WithLogFieldretrieves the copy, modifies it, and stores in a new context (lines 40-46)- All helper functions properly delegate through
WithLogFieldThis ensures thread-safety and follows the immutability principle for context values.
test/integration/executor/setup_test.go (1)
24-27: LGTM! Useful test helper for consistent logging.The
testLog()helper provides a clean, reusable way for integration tests to obtain a properly configured test logger, promoting consistency across the test suite.internal/k8s_client/client.go (1)
81-81: LGTM! Consistent migration to context-aware logging.All logging calls have been properly updated to pass
ctxas the first parameter, enabling context propagation through the logging layer. This allows trace IDs, event IDs, and other contextual fields to be automatically included in log entries.Also applies to: 88-88, 136-136, 153-153, 159-159, 185-185, 198-198, 231-231, 261-261, 278-278, 284-284, 294-294, 307-307, 337-337, 371-371
internal/executor/utils_test.go (1)
4-4: LGTM! Test updated for context-aware logging API.The test properly exercises the updated
ExecuteLogActionsignature with:
- Real test logger from
logger.NewTestLogger()context.Background()as the first parameter (appropriate for unit tests)This ensures the logging actions work correctly with the refactored API.
Also applies to: 14-14, 775-779
internal/criteria/evaluator_version_test.go (1)
4-4: LGTM! Evaluator tests updated for context-aware API.The test calls to
NewEvaluatorhave been properly updated to pass:
context.Background()as the first parameterlogger.NewTestLogger()as the logger parameterThis aligns with the broader refactor while preserving the test logic for context version tracking.
Also applies to: 7-7, 18-20, 54-56, 82-84, 150-152
test/integration/executor/executor_k8s_integration_test.go (3)
318-322: LGTM! Correctly updated to newNewClientsignature.The client creation now passes
testLog()as the first argument and properly handles the returned error withrequire.NoError. This aligns with the API change whereNewClientnow requires a logger parameter.
471-472: LGTM!Consistent update to the new API signature with proper error handling.
578-579: LGTM! All remainingNewClientcall sites correctly updated.All test functions consistently:
- Pass
testLog()as the first argument- Capture the error return value
- Assert no error with
require.NoError(t, err)Also applies to: 649-650, 707-708, 755-756, 910-911, 974-975
internal/hyperfleet_api/client_test.go (3)
22-36: LGTM! Well-implemented test logger singleton.The
sync.Oncepattern ensures thread-safe, single initialization of the shared test logger. Using "error" level reduces test output noise while still capturing important messages. The panic on initialization failure is appropriate for test setup code.
40-43: LGTM! AllNewClientcalls correctly updated.The test functions properly pass the test logger and handle the error return value consistently.
Also applies to: 63-63, 137-137
162-162: LGTM! Remaining test updates are consistent.All HTTP method tests (GET, POST, PUT, PATCH, DELETE) and retry/timeout tests correctly updated to the new API pattern.
Also applies to: 195-195, 227-227, 266-266, 301-301, 332-332, 362-362, 377-377, 480-480, 501-501, 522-522, 652-652
internal/executor/resource_executor_test.go (1)
156-157: Test rename and comments updated appropriately.The test function and comments now accurately describe that the test verifies deep copy works correctly, removing any reference to deprecated fallback behavior.
internal/criteria/evaluator_scenarios_test.go (2)
4-4: LGTM! Required imports added.The
contextandloggerimports are necessary for the updatedNewEvaluatorconstructor signature.Also applies to: 7-7
47-48: LGTM! All evaluator instantiations correctly updated.Each
NewEvaluatorcall now:
- Passes
context.Background()as the first argument- Uses
logger.NewTestLogger()for the logger parameter- Captures and asserts no error with
require.NoError(err)The pattern is consistent across all test scenarios and aligns with the new constructor signature.
Also applies to: 122-123, 140-141, 173-174, 214-215, 266-267, 347-348
test/integration/config-loader/config_criteria_integration_test.go (2)
6-6: LGTM! Required imports added for integration tests.The
contextandloggerimports enable the updatedNewEvaluatorconstructor calls.Also applies to: 17-17
73-74: LGTM! Integration test evaluator calls correctly updated.All
NewEvaluatorinstantiations in the integration tests follow the same consistent pattern with proper context, logger, and error handling.Also applies to: 159-160, 190-191, 211-212, 231-232, 318-319, 380-381, 410-411
test/integration/executor/main_test.go (3)
106-106: LGTM! Simplified to use test logger utility.Using
logger.NewTestLogger()instead of manually constructing a logger is cleaner and ensures consistent test logger configuration across the codebase.
142-142: LGTM! Improved readiness messaging.The updated log messages ("fully ready" and success indicator) provide clearer feedback about API server state.
Also applies to: 147-147
185-220: LGTM! Robust health check implementation.The rewritten
waitForAPIServerReadyfunction is well-implemented:
- HTTP client with appropriate timeout (5s per request)
- TLS 1.2 minimum version for security
InsecureSkipVerifyis necessary for envtest self-signed certs (correctly annotated withnolint)- Proper Authorization header with Bearer token
- Response body closed on success to prevent resource leaks
- Clear timeout error message
internal/executor/post_action_executor_test.go (4)
18-33: LGTM! Test logger singleton pattern.Same
sync.Oncepattern as other test files, ensuring consistent logger initialization.
36-42: LGTM! Clean test factory forPostActionExecutor.The
testPAE()helper encapsulates the executor construction with proper config, making tests cleaner and more maintainable. UsingnewMockAPIClient()as the default is appropriate for unit tests.
45-45: LGTM! Payload and value processing tests updated.Tests now:
- Use
testPAE()to get a configured executor- Pass
pae.logtoNewEvaluator, ensuring consistent logging- Call executor methods (
buildPayload,buildMapPayload,processValue) via thepaeinstanceAlso applies to: 117-120, 134-134, 223-225, 239-239, 349-351
438-441: LGTM! ExecuteAll and ExecuteAPICall tests updated.The tests correctly:
- Create executors via
newPostActionExecutorwith proper config- Use
testLog()where standalone logger is needed- Pass context to
NewExecutionContextAlso applies to: 445-445, 655-655, 663-663
internal/criteria/evaluator_test.go (3)
4-4: LGTM! Required imports added.The
contextandloggerimports enable the updated constructor signature usage.Also applies to: 8-8
525-526: LGTM! All evaluator test instantiations updated.Consistent pattern across all tests:
context.Background()as first argumentlogger.NewTestLogger()for logger parameterrequire.NoError(t, err)for error handlingAlso applies to: 613-614, 804-805, 830-831, 852-853, 889-890, 941-942, 967-968, 993-994, 1040-1041, 1095-1096, 1099-1099
775-791: LGTM! Comprehensive nil parameter validation tests.Excellent test coverage for the constructor's input validation:
- Tests all three nil parameter cases (ctx, evalCtx, log)
- Verifies specific error messages to document the API contract
- The
nolint:staticcheckcomment appropriately suppresses the intentional nil context warningThis ensures callers get clear error messages when providing invalid inputs.
pkg/logger/test_support.go (2)
17-32: LGTM - Well-designed singleton pattern for test logger.The singleton implementation using
sync.Onceensures thread-safe initialization across concurrent test runs. Using "error" level minimizes noise while still allowing critical issues to surface during tests.
67-82: LGTM - Good test utility for log capture.
NewCaptureLoggerproperly configures a debug-level logger to capture all log output, which is useful for integration tests that need to verify logging behavior.internal/executor/utils.go (3)
36-70: LGTM - Properly updated to context-aware logging.The
ExecuteLogActionfunction correctly accepts a context parameter and propagates it to all logging calls. The log level switch statement handles all valid levels with a sensible default fallback.
72-206: LGTM - Context propagation in ExecuteAPICall is correct.The function properly threads context through all logging paths including success, timeout parsing warnings, POST body failures, API call failures, and completion logging. Error handling is comprehensive with proper APIError wrapping.
264-266: Minor formatting alignment.These are whitespace-only changes for alignment consistency. No functional impact.
internal/criteria/cel_evaluator.go (2)
56-73: LGTM - Constructor properly validates and initializes CEL evaluator.The
newCELEvaluatorfunction correctly:
- Builds CEL options from the evaluation context
- Creates the CEL environment with proper error handling
- Initializes all struct fields including the new context fields
Note: The comment indicates caller is responsible for parameter validation, which aligns with the pattern in
NewEvaluator(from relevant snippets) that performs nil checks before calling this.
163-176: LGTM - Thread-safe evaluation with proper error capture.The evaluation correctly:
- Uses
e.evalCtx.Data()to get a thread-safe snapshot of the data- Captures evaluation errors in the result rather than returning them (safe mode)
- Uses the stored context for debug logging
internal/executor/types.go (3)
40-54: LGTM - Well-defined event data types.The new
ResourceRefandEventDatastructs provide a clean internal representation of CloudEvent payloads, decoupling the executor from the CloudEvents SDK. JSON tags are properly configured withomitemptyfor optional fields.
68-75: LGTM - Logger integration in Executor.Adding the
logfield to theExecutorstruct aligns with the broader refactor to use injected, context-aware loggers instead of global glog calls.
252-264: LGTM - Simplified NewExecutionContext signature.The removal of the
*event.Eventparameter simplifies the API. Event data is now passed directly as a map, and event IDs are propagated via context (usinglogger.WithEventIDas seen in tests). This is a cleaner approach that decouples execution from CloudEvents specifics.internal/executor/executor_test.go (3)
22-80: LGTM - Tests properly updated for new logger API.Test cases correctly use
logger.NewTestLogger()for the Logger field in ExecutorConfig, ensuring consistency with the new logging approach.
101-113: LGTM - ExecutionContext tests updated correctly.The test now uses the simplified
NewExecutionContext(ctx, eventData)signature and correctly asserts onexecCtx.EventDatainstead of the removedEventfield.
270-288: LGTM - Event ID propagation via context.The test correctly demonstrates the new pattern: event IDs are propagated via
logger.WithEventID(context.Background(), "test-event-123")instead of being extracted from CloudEvent objects.internal/hyperfleet_api/client.go (3)
150-153: LGTM - Clean extraction of BaseURLFromEnv.Exposing
BaseURLFromEnv()as a public function allows callers to inspect the environment variable value if needed, while keeping the fallback logic internal toNewClient.
193-230: LGTM - Retry loop logging properly updated.The retry logic correctly uses context-aware logging for:
- Request failures with attempt counts
- Retryable status codes
- Backoff delay notifications
All log calls receive the context parameter for proper correlation.
308-331: LGTM - Request/response logging fixed.The indentation issues flagged in the past review have been addressed. The debug logging for request initiation and response handling is properly indented and uses context-aware logging.
cmd/adapter/main.go (4)
116-135: LGTM - Well-structured logger initialization.The two-phase logger initialization is a good pattern:
- Bootstrap logger for early startup (before config is loaded)
- Rebuild with adapter component name after config load
CLI flags properly override environment variables, following standard precedence.
147-156: LGTM - Logger rebuild with component context.Rebuilding the logger after loading adapter config allows logs to include the adapter's component name from configuration, improving log correlation in multi-adapter deployments.
161-176: LGTM - Client creation properly passes logger.Both the HyperFleet API client and Kubernetes client are created with the logger instance, enabling context-aware logging throughout the client lifecycle.
305-334: LGTM - createAPIClient updated for new NewClient signature.The function correctly passes the logger to
hyperfleet_api.NewClient()as the first parameter, aligning with the updated client API.internal/criteria/cel_evaluator_test.go (3)
13-21: LGTM - Test renamed to match unexported function.The test function correctly renamed from
TestNewCELEvaluatortoTest_newCELEvaluatorto follow Go conventions for testing unexported functions (using underscore prefix).
150-160: LGTM - nullValue test case is correct.The past review flagged that
nullValuewas incorrectly set totestLog(). This has been properly fixed - line 157 now correctly setsctx.Set("nullValue", nil), which is the intended value for testing null value access behavior.
439-470: LGTM - Integration tests updated for new Evaluator API.Tests correctly use the new
NewEvaluator(context.Background(), ctx, logger.NewTestLogger())signature and properly handle the returned error from the constructor.internal/executor/precondition_executor.go (2)
21-28: LGTM - Config-based constructor with internal logging.The constructor properly initializes the executor from the shared
ExecutorConfig, delegating validation toNewExecutor. This aligns with the consistent pattern across all sub-executors in this PR. Based on retrieved learnings, this is part of the HYPERFLEET-304 logger refactor.
144-149: Good addition of error handling for evaluator creation.The previous implementation likely panicked or had undefined behavior if evaluator creation failed. This now properly captures and propagates the error with appropriate phase context.
internal/criteria/evaluator.go (2)
40-51: Clean separation of context types.The struct now properly distinguishes between
ctx(Go context for request lifecycle/correlation) andevalCtx(CEL evaluation data context). This separation improves clarity and aligns with the broader context-aware logging strategy.
53-71: Good defensive validation with clear error messages.The explicit nil checks with descriptive error messages enable fail-fast behavior and provide clear diagnostics when misconfigured.
internal/executor/executor.go (2)
66-76: Good context enrichment for logging correlation.The owner reference handling properly distinguishes between owned resources (e.g., NodePool with Cluster owner) and root resources (e.g., Cluster), ensuring appropriate correlation IDs are attached to the context for structured logging.
247-291: ParseEventData handles multiple input types correctly.The function properly handles
[]byte,map[string]interface{}, and arbitrary JSON-serializable types. The double unmarshal approach (to EventData struct and raw map) provides both typed access and flexible field access.test/integration/executor/executor_integration_test.go (2)
91-95: Past review concern addressed - error handling added.The error from
hyperfleet_api.NewClientis now properly captured and asserted withrequire.NoError, preventing nil pointer panics if client creation fails.
841-843: Good use of capture logger for test assertions.The
NewCaptureLogger()pattern provides a clean way to verify log output in tests. ThelogCapture.Contains()method enables readable assertions without brittle exact-match comparisons.Also applies to: 939-954
pkg/logger/logger.go (3)
13-43: Well-designed context-aware Logger interface.The interface follows Go conventions with
context.Contextas the first parameter. The fluent builder methods (With,WithFields,WithError,Without) enable clean field manipulation without mutation.
102-163: Clean logger construction with proper validation.The constructor validates the output destination, supports both stdout/stderr and custom writers (for testing), and properly initializes base fields (component, version, hostname). The hostname fallback chain handles both local development and Kubernetes pod environments.
286-306: Smart nil-check optimization in WithError.Returning
l(same instance) whenerr == nilavoids unnecessary allocations for the common case where errors are conditionally attached. The doc comment clearly explains this behavior.internal/executor/post_action_executor.go (2)
20-27: Constructor delegates validation to caller - consistent pattern.The comment clarifies that
NewExecutoris responsible for config validation. This is consistent withnewPreconditionExecutorandnewResourceExecutor, creating a uniform pattern across all sub-executors. The past review concern about nil config is addressed by centralized validation invalidateExecutorConfig.
81-89: Good error handling for evaluator creation.The evaluator creation now properly handles errors and propagates them with context, aligning with the updated
NewEvaluatorsignature that returns(*Evaluator, error).internal/executor/resource_executor.go (2)
24-31: Constructor follows consistent config-based pattern.The comment clarifies validation responsibility, consistent with other sub-executors. Past review concerns about K8sClient validation have been addressed in
validateExecutorConfig.
402-429: Good fallback strategy for deep copy failure.The function properly logs a warning when deep copy fails and falls back to shallow copy. The warning is appropriate since shallow copy could lead to unexpected mutations of nested structures.
…d support args and ENV
1ca3777 to
1f522a1
Compare
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
♻️ Duplicate comments (4)
internal/criteria/cel_evaluator_test.go (1)
157-157: Past review concern is resolved.The past review comment flagged that
nullValuewas incorrectly set totestLog()instead ofnil. The current code correctly setsnullValuetonil, which properly tests the "access field on null returns error in result (safe)" scenario at lines 183-189.internal/executor/post_action_executor.go (1)
20-27: LGTM - Constructor validation documented.The explicit comment stating "Caller (NewExecutor) is responsible for config validation" clearly documents the validation contract. This is an acceptable pattern for internal constructors where validation is centralized at the factory level.
Based on learnings, this logger refactor is part of HYPERFLEET-304.
internal/executor/resource_executor.go (2)
79-80: Fix indentation: rungofmt -won this file.Several
re.log.*statements appear to lack proper leading indentation, causing them to start at column 0 instead of being indented within their function bodies. This formatting issue was flagged in a previous review and acknowledged, but appears to persist.Run the following command to fix:
gofmt -w internal/executor/resource_executor.goAlso applies to: 85-85, 90-90, 99-99, 101-101, 115-115, 121-121, 125-125, 132-132
316-316: Fix indentation: same issue in recreateResource and waitForDeletion.The
re.log.*statements in these methods also lack proper indentation. The samegofmtfix will address these lines as well.Also applies to: 322-323, 328-328, 343-343, 350-350, 354-354, 358-358
🧹 Nitpick comments (5)
test/integration/executor/main_test.go (1)
208-214: Consider using defer for response body closing.The current implementation closes the response body only in the success path (line 210). If
client.Doreturns a non-nil response with an error, the body won't be closed, potentially causing a resource leak.🔎 Suggested improvement
resp, err := client.Do(req) - if err == nil { - _ = resp.Body.Close() - if resp.StatusCode == http.StatusOK { + if err == nil && resp != nil { + defer resp.Body.Close() + if resp.StatusCode == http.StatusOK { return nil // API server is ready } }Alternatively, check and close the body regardless of error:
resp, err := client.Do(req) + if resp != nil { + defer resp.Body.Close() + } if err == nil { - _ = resp.Body.Close() if resp.StatusCode == http.StatusOK { return nil // API server is ready } }pkg/logger/test_support.go (1)
47-50: Minor: Contains() acquires lock twice.The
Contains()method callsMessages(), which acquires the lock, thenstrings.Contains()acquires it again implicitly. While this works correctly and is unlikely to cause issues in tests, it could be optimized to lock once.🔎 Optional optimization
func (c *LogCapture) Contains(substr string) bool { - return strings.Contains(c.Messages(), substr) + c.mu.Lock() + defer c.mu.Unlock() + return strings.Contains(c.buf.String(), substr) }internal/executor/executor.go (1)
247-291: Consider validating JSON structure in ParseEventData.The function handles nil/empty inputs gracefully and supports multiple input types. However, when
datais already amap[string]interface{}, you marshal then immediately unmarshal it, which is inefficient. Consider a direct approach for the map case.🔎 Suggested optimization for map case
case map[string]interface{}: - // Already a map, marshal to JSON for struct conversion - jsonBytes, err = json.Marshal(v) - if err != nil { - return nil, nil, fmt.Errorf("failed to marshal map data: %w", err) + // Already a map - use it directly for rawData + rawData := v + // Marshal only for struct conversion + jsonBytes, err := json.Marshal(v) + if err != nil { + return nil, nil, fmt.Errorf("failed to marshal map data: %w", err) + } + var eventData EventData + if err := json.Unmarshal(jsonBytes, &eventData); err != nil { + return nil, nil, fmt.Errorf("failed to unmarshal to EventData: %w", err) } + return &eventData, rawData, nilpkg/logger/logger.go (1)
179-198: Potential field key collision between logger fields and context fields.When both
l.fieldsand context'sLogFieldscontain the same key, the context value will overwrite the logger field due to iteration order. This might be intentional (context takes precedence), but it's worth documenting.Consider adding a comment to document the precedence behavior:
// buildArgs builds the slog args from fields and context // Context fields take precedence over logger fields if keys collide func (l *logger) buildArgs(ctx context.Context) []any {pkg/logger/context.go (1)
118-132: GetLogFields returns a shallow copy - document this behavior.The function creates a new map and copies key-value pairs, but if any value is itself a map/slice/pointer, the copy will reference the same underlying data. This is likely fine for the expected use case (primitive values), but should be documented.
Consider adding a clarifying comment:
// GetLogFields returns the dynamic log fields from the context, or nil if not set. // Returns a shallow copy to prevent external mutation of the original map. // Note: Complex values (maps, slices, pointers) are not deep-copied. func GetLogFields(ctx context.Context) LogFields {
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (37)
cmd/adapter/main.gogo.modinternal/config_loader/loader.gointernal/config_loader/validator.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/executor/README.mdinternal/executor/executor.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor.gointernal/executor/post_action_executor_test.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/k8s_client/client.gointernal/k8s_client/discovery.gopkg/logger/context.gopkg/logger/logger.gopkg/logger/logger_test.gopkg/logger/test_support.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.go
💤 Files with no reviewable changes (3)
- go.mod
- internal/executor/param_extractor.go
- internal/executor/README.md
🚧 Files skipped from review as they are similar to previous changes (7)
- internal/config_loader/loader.go
- internal/executor/resource_executor_test.go
- internal/executor/utils_test.go
- test/integration/k8s_client/helper_envtest_prebuilt.go
- internal/k8s_client/discovery.go
- internal/hyperfleet_api/client.go
- internal/config_loader/validator_test.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
test/integration/config-loader/config_criteria_integration_test.gointernal/criteria/evaluator_version_test.gointernal/criteria/evaluator_test.gointernal/config_loader/validator.gointernal/criteria/evaluator_scenarios_test.gointernal/executor/executor.gocmd/adapter/main.gointernal/executor/types.gotest/integration/executor/executor_integration_test.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.gointernal/executor/resource_executor.gopkg/logger/logger_test.go
🧬 Code graph analysis (22)
internal/k8s_client/client.go (2)
pkg/errors/error.go (1)
KubernetesError(203-205)internal/hyperfleet_api/types.go (1)
Client(216-237)
test/integration/config-loader/config_criteria_integration_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/criteria/evaluator_test.go (3)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
test/integration/executor/main_test.go (2)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/k8s_client/client.go (1)
Client(29-32)
internal/config_loader/validator.go (2)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/config_loader/loader.go (1)
Parse(105-121)
test/integration/executor/executor_k8s_integration_test.go (2)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)internal/k8s_client/client.go (1)
NewClient(65-114)
internal/hyperfleet_api/client_test.go (1)
internal/hyperfleet_api/client.go (4)
NewClient(119-148)WithBaseURL(102-106)WithDefaultHeader(57-64)WithConfig(48-54)
internal/criteria/evaluator_scenarios_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
internal/criteria/evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-43)
internal/executor/executor.go (3)
internal/executor/types.go (1)
EventData(48-54)pkg/logger/context.go (3)
WithResourceType(90-92)WithDynamicResourceID(64-67)WithEventID(80-82)internal/config_loader/types.go (1)
AdapterConfig(6-11)
cmd/adapter/main.go (5)
pkg/logger/logger.go (3)
ConfigFromEnv(86-100)NewLogger(104-163)Logger(15-43)internal/config_loader/loader.go (2)
Load(79-102)WithAdapterVersion(46-50)internal/hyperfleet_api/client.go (1)
NewClient(119-148)internal/k8s_client/client.go (3)
NewClient(65-114)ClientConfig(35-43)Client(29-32)internal/hyperfleet_api/types.go (2)
ClientConfig(38-54)Client(216-237)
internal/executor/types.go (4)
pkg/errors/error.go (1)
Href(150-153)internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/k8s_client/client.go (1)
Client(29-32)pkg/logger/logger.go (1)
Logger(15-43)
internal/executor/post_action_executor.go (5)
pkg/logger/logger.go (1)
Logger(15-43)internal/executor/types.go (2)
ExecutorConfig(57-66)ExecutionContext(180-195)internal/config_loader/types.go (2)
PostAction(199-203)APICall(108-116)internal/criteria/evaluator.go (2)
NewEvaluator(56-71)Evaluator(41-51)internal/executor/utils.go (1)
ExecuteLogAction(39-70)
internal/executor/post_action_executor_test.go (4)
internal/executor/post_action_executor.go (1)
PostActionExecutor(15-18)internal/executor/types.go (2)
ExecutorConfig(57-66)NewExecutionContext(253-264)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
pkg/logger/test_support.go (1)
pkg/logger/logger.go (3)
Logger(15-43)NewLogger(104-163)Config(57-72)
pkg/logger/logger.go (2)
pkg/errors/error.go (1)
New(107-123)pkg/logger/context.go (2)
LogFieldsKey(28-28)LogFields(32-32)
internal/criteria/cel_evaluator_test.go (3)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
internal/executor/utils.go (3)
internal/config_loader/types.go (1)
LogAction(206-209)internal/executor/types.go (1)
ExecutionContext(180-195)pkg/logger/logger.go (1)
Logger(15-43)
internal/executor/resource_executor.go (3)
internal/executor/types.go (8)
ExecutorConfig(57-66)ExecutionContext(180-195)ResourceResult(126-143)StatusSuccess(35-35)OperationRecreate(154-154)OperationUpdate(152-152)OperationCreate(150-150)StatusFailed(37-37)internal/k8s_client/interface.go (1)
K8sClient(13-47)internal/config_loader/types.go (1)
Resource(171-178)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-43)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(57-72)DefaultConfig(75-83)NewLogger(104-163)ConfigFromEnv(86-100)pkg/logger/context.go (10)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithClusterID(85-87)WithTraceID(70-72)
test/integration/executor/executor_integration_test.go (3)
internal/hyperfleet_api/client.go (3)
NewClient(119-148)WithTimeout(67-71)WithRetryAttempts(74-78)pkg/logger/test_support.go (1)
NewCaptureLogger(67-83)internal/executor/executor.go (1)
NewBuilder(299-303)
🔇 Additional comments (46)
internal/config_loader/validator.go (2)
65-66: LGTM - Validator factory correctly made internal.The constructor is now unexported as intended, with callers updated accordingly in
internal/config_loader/loader.go.
391-407: Well-documented validation change.The shift to syntax-only validation is appropriate given that variables use
DynTypeat validation time. The comments clearly explain the rationale, which will help future maintainers understand why type checking was removed.test/integration/executor/setup_test.go (1)
24-27: LGTM - Clean test logger helper.The
testLog()helper provides a straightforward way to obtain a test logger for integration tests.internal/k8s_client/client.go (1)
81-88: LGTM - Context-aware logging correctly applied.The logging calls now properly pass context as the first argument, enabling structured logging with request context. This pattern is consistently applied throughout all client operations.
internal/criteria/evaluator_version_test.go (1)
18-20: LGTM - Test updated for new evaluator API.The test correctly uses the updated
NewEvaluatorsignature with context, evaluation context, and test logger, with proper error handling. This pattern is consistently applied across all test cases in this file.internal/hyperfleet_api/client_test.go (1)
22-36: LGTM - Efficient test logger implementation.The singleton pattern using
sync.Onceensures the test logger is initialized only once, improving test performance. The logger configuration (error level, text format) is appropriate for testing.test/integration/executor/executor_k8s_integration_test.go (1)
318-322: LGTM - API client initialization updated correctly.All
hyperfleet_api.NewClientcalls throughout the test file correctly pass the test logger as the first argument and handle the returned error. The pattern is consistently applied across all test cases.test/integration/config-loader/config_criteria_integration_test.go (1)
73-74: LGTM - Evaluator initialization updated consistently.The test correctly initializes evaluators with the new three-parameter signature (context, evaluation context, logger) and handles errors appropriately. This pattern is consistently applied throughout the entire test suite.
internal/criteria/evaluator_scenarios_test.go (1)
47-49: LGTM - Test scenarios updated for context-aware evaluator.All test scenarios correctly use the updated
NewEvaluatorAPI with context, evaluation context, and test logger. Error handling is properly implemented throughout the file.internal/executor/post_action_executor_test.go (1)
17-23: Clean test helper pattern.The
testPAE()factory function provides a consistent way to create test executors with proper logger and mock client setup, improving test maintainability.internal/criteria/evaluator_test.go (1)
775-791: Comprehensive nil parameter validation tests.The new test function properly validates that
NewEvaluatorrejects nil parameters with appropriate error messages. Thenolint:staticcheckcomment at line 777 is correctly used for the intentional nil context test.internal/executor/utils.go (2)
39-70: Context-aware logging properly implemented.The updates to
ExecuteLogActionconsistently thread the context parameter through all logging calls, aligning with the broader refactor to support context-aware structured logging.
76-206: Context propagation in ExecuteAPICall is correct.All logging calls within
ExecuteAPICallhave been updated to use the context parameter, maintaining consistency with the context-aware logging pattern throughout the codebase.internal/criteria/cel_evaluator.go (1)
56-73: Well-structured context separation.The refactored
newCELEvaluatorcleanly separates concerns by usingctxfor control flow (logging) andevalCtxfor evaluation data. The note that "Caller (NewEvaluator) is responsible for parameter validation" appropriately documents the validation contract.pkg/logger/test_support.go (1)
17-32: Clean singleton pattern for test logger.The use of
sync.Onceensures thread-safe initialization of a single test logger instance, and the "error" log level appropriately reduces noise during test runs.internal/executor/types.go (2)
40-54: New event data types support structured event handling.The
ResourceRefandEventDatatypes provide a structured way to represent HyperFleet event payloads, improving type safety and removing the dependency on CloudEvent objects in the execution context.
253-264: All callers ofNewExecutionContexthave been correctly updated to use the new signature(ctx, eventData). The verification found 9 call sites acrossexecutor.goand test files, and all of them correctly pass exactly two arguments without the removed CloudEvent parameter.internal/executor/executor_test.go (3)
22-23: LGTM!The orphaned comment about
testEventWithDatahas been removed as noted in the past review, and the test file is properly updated to use the new data-centric API.
101-113: LGTM!The
TestExecutionContexttest correctly validates the newNewExecutionContext(ctx, eventData)signature and verifies thatEventDatamap access works as expected.
270-289: LGTM!The
TestExecute_ParamExtractiontest properly demonstrates the new pattern: usinglogger.WithEventIDto attach event ID to context for logging correlation, then passing the map-based event data toExecute. This aligns well with the PR's objective of context-aware logging.internal/executor/executor.go (2)
30-47: LGTM!The
validateExecutorConfigfunction properly handles the nil config case first (addressing the past review), then uses reflection to validate required fields. The required fields list aligns with the updated documentation thatK8sClientis now required.
66-76: Context enrichment logic is well-documented and handles ownership correctly.The conditional logic for owned vs. non-owned resources is clear:
- For owned resources (e.g., NodePool owned by Cluster): logs both resource_id and owner's dynamic ID
- For non-owned resources (e.g., Cluster): logs just the dynamic resource ID
This aligns with the documented intent in the comments.
cmd/adapter/main.go (3)
116-135: LGTM!The bootstrap logger pattern is well-implemented:
- Create initial config from environment variables
- Override with command-line flags if provided
- Create bootstrap logger before config load
- Recreate logger after config load with adapter-specific component name
This ensures logging is available throughout startup while allowing adapter-specific context after config is loaded.
147-156: Logger recreation with component name is a good practice.Recreating the logger with the adapter's metadata name ensures all subsequent logs are properly attributed to the specific adapter instance. This is especially useful in multi-adapter deployments.
306-334: LGTM!The
createAPIClientfunction signature correctly updated to accept the logger parameter, which is then passed tohyperfleet_api.NewClient. This aligns with the new client constructor signature shown in the relevant code snippets.internal/criteria/evaluator.go (3)
41-51: LGTM!The
Evaluatorstruct field renaming fromcontexttoevalCtxclarifies the purpose (evaluation data context vs. Go context). The newctxfield for Go context propagation enables context-aware logging in CEL evaluation.
53-71: LGTM!The updated
NewEvaluatorconstructor:
- Now requires all three parameters (ctx, evalCtx, log) with explicit validation
- Returns
(*Evaluator, error)for proper error handling- Clear documentation explaining parameter purposes
This is a breaking change but improves reliability by failing fast on invalid inputs.
77-94: CEL evaluator caching with version tracking is well-maintained.The version-based invalidation ensures the CEL environment stays synchronized with context data changes. Using
e.evalCtx.Version()and passing bothe.ctxande.evalCtxtonewCELEvaluatorcorrectly threads both context types through.internal/executor/precondition_executor.go (3)
21-28: LGTM!The
newPreconditionExecutorconstructor is appropriately unexported since validation is handled by the caller (NewExecutor). The config-based initialization centralizes dependency wiring.
144-149: Good addition of error handling for NewEvaluator.The new
NewEvaluatorsignature returns an error, and this is properly handled here. The error case correctly sets the result status and returns an appropriateExecutorError.
32-62: LGTM!The
ExecuteAllmethod properly uses context-aware logging throughout:
- Logs precondition evaluation progress
- Logs errors and results with appropriate levels
- Consistent formatting with precondition index tracking
test/integration/executor/executor_integration_test.go (4)
91-95: LGTM!The
NewClienterror is now properly handled withrequire.NoError, addressing the past review comments about ignored errors.
841-843: LGTM!The use of
logger.NewCaptureLogger()for tests that need to verify log output is a good pattern. This returns both a logger and a capture handle for assertions.
939-954: LGTM!The log verification pattern using
logCapture.Messages()andlogCapture.Contains()is clean and readable. The test properly checks for expected log messages with the[config]prefix.
1300-1350: LGTM!The
TestExecutor_PayloadBuildFailuretest properly uses the capture logger to verify error logging behavior. The assertions checking forlevel=ERRORandfailed to buildensure the logging subsystem correctly reports payload build failures.pkg/logger/logger.go (4)
13-43: LGTM!The
Loggerinterface is well-designed:
- Context as first parameter aligns with Go conventions
- Formatted variants (Debugf, Infof, etc.) for convenience
- Fluent builder methods (With, WithFields, WithError, Without) for field management
WithErroris a no-op for nil errors, avoiding unnecessary allocations
102-163: LGTM!The
NewLoggerfunction:
- Properly validates Output (must be stdout, stderr, or empty)
- Supports custom Writer for testing
- Creates slog handler based on format configuration
- Includes component, version, and hostname as base fields
The removal of file path support addresses the past review about file handle leaks.
240-244: Fatal calls os.Exit(1) directly.The
Fatalmethod logs then callsos.Exit(1). This is standard behavior but makes testing difficult. Consider documenting this or providing a way to override the exit behavior in tests.This is acceptable for production use, but verify that tests don't inadvertently call
Fatalwhich would terminate the test process.
246-256: LGTM!The
copyFieldsfunction is correctly documented as performing a shallow copy (addressing past review). The implementation is correct for the use case since field values are typically primitive types.pkg/logger/context.go (3)
8-29: LGTM!The context key constants are well-organized by category (correlation, resource, adapter-specific). Using a custom
contextKeytype prevents collisions with other packages' context keys.
38-60: LGTM!The
WithLogFieldandWithLogFieldsfunctions properly:
- Retrieve existing fields (or initialize new map)
- Add/update the field(s)
- Return new context with updated fields
This pattern enables incremental field addition throughout the request lifecycle.
62-67: LGTM!
WithDynamicResourceIDis a nice utility that derives the field name from the resource type (e.g., "Cluster" → "cluster_id"). This ensures consistent naming conventions for resource IDs across the logging system.internal/executor/post_action_executor.go (1)
31-77: Well-executed context-aware logging refactor.The ExecuteAll method and its callees now consistently use the internal logger (pae.log) with context threading. The removal of external log parameters in favor of config-driven initialization improves testability and reduces parameter proliferation.
internal/executor/resource_executor.go (2)
24-31: LGTM - Constructor validation documented and previously addressed.The explicit comment about caller responsibility for validation is clear. Per past review comments, the K8sClient validation concern was addressed in earlier commits.
35-55: Excellent context-aware refactoring.The updates to ExecuteAll, buildManifest, and deepCopyMap demonstrate consistent context threading and structured logging. The deepCopyMap function now properly logs fallback warnings with context, which improves observability when deep copy operations fail.
Also applies to: 158-198, 402-429
pkg/logger/logger_test.go (1)
8-480: Comprehensive test coverage for logger refactor.The test suite thoroughly covers:
- Config-based logger construction and error handling
- Fluent API methods (With, WithFields, WithError)
- All log levels (Debug, Info, Warn, Error) with formatting variants
- Method chaining
- Context helper functions (WithEventID, WithClusterID, WithTraceID)
- Environment variable configuration
- Level parsing with edge cases
The tests are well-structured with descriptive names and proper use of subtests. The nil error handling test (lines 168-174) correctly verifies that WithError(nil) returns the same logger instance, which is the expected optimization.
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
🧹 Nitpick comments (5)
internal/hyperfleet_api/client.go (1)
118-122: Consider validating the logger parameter.The
NewClientfunction now requires alogger.Loggeras the first parameter, which is a good design aligned with the k8s_client pattern. However, unlike the validation done forBaseURL, there's no nil check for the logger. If a nil logger is passed, subsequentc.log.Warnf(...)calls will panic.🔎 Suggested fix
func NewClient(log logger.Logger, opts ...ClientOption) (Client, error) { + if log == nil { + return nil, fmt.Errorf("logger is required for HyperFleet API client") + } c := &httpClient{ config: DefaultClientConfig(), log: log, }test/integration/executor/executor_integration_test.go (3)
231-232: Inconsistent error assertion - consider usingrequire.NoErrorinstead ofassert.NoError.This test uses
assert.NoErrorwhich allows the test to continue even if client creation fails, potentially causing nil pointer panics later. Other similar tests in this file (e.g., line 95) userequire.NoErrorfor immediate failure.🔎 Proposed fix for consistency
apiClient, err := hyperfleet_api.NewClient(k8sEnv.Log) - assert.NoError(t, err) + require.NoError(t, err, "failed to create API client")
447-449: Unnecessary blank line between client creation and assertion.Lines 447-449 have an extra blank line between
NewClientand the assertion that disrupts readability. Other occurrences (e.g., lines 497-498) keep them adjacent.🔎 Proposed fix
apiClient, err := hyperfleet_api.NewClient(testLog()) - - assert.NoError(t, err) + assert.NoError(t, err)
1345-1349: Log format verification is fragile.The assertion checks for
"level=ERROR"which assumes a specific log format (text format withlevel=ERRORliteral). If the logger configuration or format changes, this test will break. Consider using a more robust approach or documenting the format dependency.The current approach works but is tightly coupled to the log format. If future changes modify the format, multiple tests could break silently.
internal/executor/resource_executor.go (1)
396-429:deepCopyMapfallback behavior is documented but could silently cause issues.The function logs a warning when deep copy fails and falls back to shallow copy. However, the warning at line 410 may not surface clearly in production logs, and subsequent mutations could cause hard-to-debug issues.
Consider adding a metric or structured log field to make shallow copy fallbacks more visible in monitoring:
if err != nil { // Fallback to shallow copy if deep copy fails - log.Warnf(ctx, "Failed to deep copy map: %v. Falling back to shallow copy.", err) + log.With("fallback", "shallow_copy").Warnf(ctx, "Failed to deep copy map: %v. Falling back to shallow copy - nested structures may share references.", err)
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (47)
internal/config_loader/accessors.gointernal/config_loader/constants.gointernal/config_loader/loader_test.gointernal/config_loader/types.gointernal/config_loader/validator_test.gointernal/criteria/cel_evaluator.gointernal/criteria/cel_evaluator_test.gointernal/criteria/evaluator.gointernal/criteria/evaluator_scenarios_test.gointernal/criteria/evaluator_test.gointernal/criteria/evaluator_version_test.gointernal/criteria/types.gointernal/executor/executor_test.gointernal/executor/param_extractor.gointernal/executor/post_action_executor_test.gointernal/executor/resource_executor.gointernal/executor/resource_executor_test.gointernal/executor/types.gointernal/executor/utils_test.gointernal/hyperfleet_api/client.gointernal/hyperfleet_api/client_test.gointernal/hyperfleet_api/mock.gointernal/hyperfleet_api/types.gointernal/k8s_client/data_extractor.gointernal/k8s_client/discovery.gointernal/k8s_client/interface.gointernal/k8s_client/mock.gointernal/k8s_client/test_helpers_test.gointernal/k8s_client/types.gointernal/k8s_client/types_test.gopkg/errors/cel_error.gopkg/errors/error_test.gopkg/errors/k8s_error.gopkg/errors/k8s_error_test.gopkg/errors/network_error.gopkg/errors/network_error_test.gopkg/logger/logger_test.gotest/integration/config-loader/config_criteria_integration_test.gotest/integration/executor/executor_integration_test.gotest/integration/executor/executor_k8s_integration_test.gotest/integration/executor/main_test.gotest/integration/executor/setup_test.gotest/integration/k8s_client/helper_envtest_prebuilt.gotest/integration/k8s_client/helper_selector.gotest/integration/k8s_client/main_test.gotest/integration/testutil/container.gotest/integration/testutil/mock_api_server.go
💤 Files with no reviewable changes (18)
- pkg/errors/cel_error.go
- internal/executor/param_extractor.go
- internal/config_loader/constants.go
- internal/k8s_client/data_extractor.go
- test/integration/k8s_client/helper_selector.go
- pkg/errors/error_test.go
- internal/k8s_client/mock.go
- test/integration/testutil/mock_api_server.go
- pkg/errors/network_error_test.go
- pkg/errors/network_error.go
- pkg/errors/k8s_error.go
- internal/k8s_client/interface.go
- internal/k8s_client/types_test.go
- internal/config_loader/accessors.go
- test/integration/k8s_client/main_test.go
- internal/hyperfleet_api/types.go
- pkg/errors/k8s_error_test.go
- test/integration/testutil/container.go
✅ Files skipped from review due to trivial changes (5)
- internal/k8s_client/types.go
- internal/criteria/types.go
- internal/config_loader/loader_test.go
- internal/hyperfleet_api/mock.go
- internal/k8s_client/test_helpers_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
- internal/config_loader/validator_test.go
- internal/hyperfleet_api/client_test.go
- internal/executor/utils_test.go
- internal/criteria/evaluator_test.go
- test/integration/executor/setup_test.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/criteria/evaluator_version_test.gotest/integration/config-loader/config_criteria_integration_test.gointernal/criteria/evaluator_scenarios_test.gointernal/hyperfleet_api/client.gointernal/executor/types.gotest/integration/executor/executor_integration_test.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
internal/executor/resource_executor_test.gopkg/logger/logger_test.gointernal/executor/resource_executor.go
🧬 Code graph analysis (17)
internal/criteria/evaluator_version_test.go (3)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/types.go (1)
NewEvaluationContext(75-80)
internal/executor/resource_executor_test.go (1)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)
test/integration/config-loader/config_criteria_integration_test.go (2)
internal/criteria/evaluator.go (1)
NewEvaluator(56-71)pkg/logger/test_support.go (1)
NewTestLogger(17-32)
test/integration/k8s_client/helper_envtest_prebuilt.go (2)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)test/integration/executor/main_test.go (2)
EnvtestAPIServerPort(25-25)EnvtestReadyLog(26-26)
internal/criteria/evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-43)
internal/config_loader/types.go (1)
internal/k8s_client/discovery.go (2)
Discovery(14-29)DiscoveryConfig(32-42)
internal/criteria/cel_evaluator_test.go (3)
internal/criteria/types.go (1)
NewEvaluationContext(75-80)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
internal/criteria/evaluator_scenarios_test.go (3)
internal/criteria/evaluator.go (2)
NewEvaluator(56-71)ConditionDef(358-362)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/types.go (2)
Operator(10-10)NewEvaluationContext(75-80)
internal/hyperfleet_api/client.go (3)
pkg/logger/logger.go (1)
Logger(15-43)internal/k8s_client/client.go (2)
NewClient(65-114)Client(29-32)internal/hyperfleet_api/types.go (2)
Client(216-237)DefaultClientConfig(57-66)
pkg/logger/logger_test.go (2)
pkg/logger/logger.go (4)
Config(57-72)DefaultConfig(75-83)NewLogger(104-163)ConfigFromEnv(86-100)pkg/logger/context.go (10)
TraceIDKey(13-13)SpanIDKey(14-14)EventIDKey(15-15)ClusterIDKey(18-18)AdapterKey(23-23)SubscriptionKey(25-25)WithEventID(80-82)GetLogFields(119-132)WithClusterID(85-87)WithTraceID(70-72)
internal/executor/types.go (4)
internal/config_loader/types.go (1)
AdapterConfig(6-11)internal/hyperfleet_api/types.go (1)
Client(216-237)internal/k8s_client/client.go (1)
Client(29-32)pkg/logger/logger.go (1)
Logger(15-43)
internal/executor/executor_test.go (3)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/executor/types.go (4)
NewExecutionContext(253-264)EventData(48-54)StatusSuccess(35-35)ExecutionStatus(31-31)pkg/logger/context.go (1)
WithEventID(80-82)
internal/executor/post_action_executor_test.go (5)
internal/executor/post_action_executor.go (1)
PostActionExecutor(15-18)internal/executor/types.go (1)
ExecutorConfig(57-66)pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)internal/executor/utils.go (1)
ExecuteAPICall(76-206)
test/integration/executor/executor_k8s_integration_test.go (2)
internal/hyperfleet_api/client.go (3)
NewClient(118-147)WithTimeout(67-71)WithRetryAttempts(74-78)internal/k8s_client/client.go (1)
NewClient(65-114)
test/integration/executor/executor_integration_test.go (4)
internal/hyperfleet_api/client.go (1)
NewClient(118-147)internal/executor/types.go (2)
ExecutionContext(180-195)ExecutionStatus(31-31)pkg/logger/test_support.go (1)
NewCaptureLogger(67-83)internal/executor/executor.go (1)
NewBuilder(299-303)
internal/executor/resource_executor.go (6)
pkg/logger/logger.go (1)
Logger(15-43)internal/executor/types.go (9)
ExecutorConfig(57-66)ExecutionContext(180-195)ResourceResult(126-143)StatusSuccess(35-35)OperationRecreate(154-154)OperationUpdate(152-152)OperationCreate(150-150)StatusFailed(37-37)NewExecutorError(374-381)internal/k8s_client/interface.go (1)
K8sClient(13-47)internal/config_loader/types.go (1)
Resource(171-178)internal/k8s_client/discovery.go (1)
Discovery(14-29)pkg/errors/k8s_error.go (1)
IsRetryableDiscoveryError(160-192)
internal/criteria/cel_evaluator.go (2)
internal/criteria/types.go (1)
EvaluationContext(64-72)pkg/logger/logger.go (1)
Logger(15-43)
🔇 Additional comments (61)
internal/config_loader/types.go (1)
22-28: LGTM! Formatting alignment improvements.The struct tag alignment changes improve readability without affecting functionality. The YAML tags remain consistent with the field names.
Also applies to: 38-41, 172-184
test/integration/k8s_client/helper_envtest_prebuilt.go (2)
100-100: LGTM! Proper test logger integration.Using
logger.NewTestLogger()aligns with the PR's context-aware logging refactor. The singleton test logger is appropriately configured at error level to minimize noise during tests.
124-125: Formatting-only change.The poll interval formatting change (
500*time.Millisecond) is cosmetic and has no behavioral impact.internal/k8s_client/discovery.go (1)
85-86: LGTM! Context-aware logging integration.The logging call now correctly passes
ctxas the first argument, aligning with the newLoggerinterface signature. This enables context-based field propagation (e.g., trace IDs, request metadata) through the logging chain.test/integration/config-loader/config_criteria_integration_test.go (2)
6-6: LGTM! Required imports for updated API.The
contextandloggerimports are necessary to support the newNewEvaluatorsignature.Also applies to: 17-17
73-74: LGTM! Consistent adaptation to new Evaluator API.All
NewEvaluatorcalls are correctly updated to the new signature(context.Context, *EvaluationContext, logger.Logger) (*Evaluator, error)with proper error handling viarequire.NoError. Usingcontext.Background()is appropriate for test contexts.Also applies to: 159-160, 190-191, 211-212, 231-232, 318-319, 380-381, 410-411
internal/criteria/evaluator_scenarios_test.go (2)
4-4: Required imports for updated API.Also applies to: 7-7
47-48: LGTM! Test evaluator instantiation updated consistently.All
NewEvaluatorcalls correctly use the new three-argument signature with proper error handling. The pattern is consistent across all test scenarios.Also applies to: 122-123, 140-141, 173-174, 214-215, 266-267, 347-348
internal/criteria/cel_evaluator_test.go (4)
4-4: Required imports for updated API.Also applies to: 8-8
13-21: LGTM! Test renamed to reflect unexported constructor.The test function
Test_newCELEvaluatorcorrectly reflects thatnewCELEvaluatoris now unexported. The constructor call properly uses the new signature with context and logger.
150-160: LGTM! Null value test semantics preserved.Line 157 correctly sets
ctx.Set("nullValue", nil)to test null access behavior, addressing the previous review concern about test semantics.
445-446: LGTM! Public Evaluator tests updated.The
NewEvaluatorcalls in integration tests correctly use the new signature with proper error handling.Also applies to: 474-475
internal/executor/post_action_executor_test.go (4)
17-23: LGTM! Clean test helper factory.The
testPAE()helper centralizesPostActionExecutorconstruction for tests, reducing boilerplate and ensuring consistent test setup with a test logger and mock API client.
98-101: LGTM! Evaluator creation uses executor's logger.Using
pae.logforNewEvaluatorensures the evaluator shares the same logger instance as the executor, maintaining consistency in test logging behavior.Also applies to: 204-206, 330-332
419-426: LGTM! Test executor setup updated.The test correctly uses
newPostActionExecutorwithExecutorConfigcontaining the mock client and test logger, andNewExecutionContextis called with the updated signature.
636-644: LGTM! ExecuteAPICall tests updated.The test correctly passes
logger.NewTestLogger()as the logger parameter toExecuteAPICall, aligning with the updated function signature.internal/hyperfleet_api/client.go (3)
17-17: LGTM! Logger integration into httpClient.The logger import and new
logfield enable context-aware logging throughout the HTTP client lifecycle.Also applies to: 34-34
201-201: LGTM! Context-aware logging in retry logic.The retry/backoff logging correctly uses
c.logwith context, providing visibility into retry attempts and delays.Also applies to: 213-214, 220-220
308-308: LGTM! Request/response logging with context.The debug logging for request execution and response handling now properly passes context, enabling correlation of logs with request traces.
Also applies to: 328-328
pkg/logger/logger_test.go (8)
8-55: LGTM! Comprehensive coverage for NewLogger constructor.The tests properly validate the new
NewLogger(Config) (Logger, error)signature with various configurations (default, JSON format, text format) and verify both error handling and type assertions.
57-68: LGTM! Good negative test for invalid output.Validates that
NewLoggerreturns an error for unsupported output values.
70-175: LGTM! Fluent API tests are well-designed.The
With,WithFields, andWithErrortests properly verify:
- Field addition and immutability
- Type assertions on returned logger
WithError(nil)returning the same logger instance (optimization)
185-269: LGTM! Log method panic tests provide good coverage.Tests verify all log levels (Debug, Debugf, Info, Infof, Warn, Warnf, Error, Errorf) don't panic when invoked with context.
272-309: LGTM! Chaining tests validate fluent API composition.Tests ensure method chaining (
With().With().Info(),WithFields().With().Info(),WithError().With().Error()) works without panics.
311-384: LGTM! Context key and helper tests are thorough.Tests validate:
- Context key constants map to expected string values
WithEventID,WithClusterID,WithTraceIDhelpers properly attach fields to contextGetLogFieldsretrieves attached fields correctly
386-423: LGTM! ConfigFromEnv tests cover environment variable handling.Tests verify:
- Default values when env vars are unset
- Reading and lowercasing LOG_LEVEL, LOG_FORMAT, LOG_OUTPUT
425-479: LGTM! parseLevel and context extraction tests complete the coverage.
parseLeveltests cover various input formats and default behavior- Context extraction test verifies logging with context values doesn't panic
internal/criteria/evaluator_version_test.go (3)
14-45: LGTM! Context version tracking test properly updated.The test correctly uses the new
NewEvaluator(context.Background(), ctx, logger.NewTestLogger())signature and handles the returned error withrequire.NoError.
47-103: LGTM! Version tracking tests for SetVariablesFromMap and Merge are well-structured.Both tests properly verify that the CEL evaluator recognizes variables added after initial evaluation, demonstrating correct version-based recreation.
105-185: LGTM! Version increment and CEL evaluator recreation tests are comprehensive.
TestVersionIncrementsvalidates all scenarios (new key, same value, different value, merge)TestNoVersionChangeNoRecreateverifies evaluator instance is reused when context unchanged and recreated when modifiedtest/integration/executor/executor_k8s_integration_test.go (3)
318-322: LGTM! API client creation updated to new signature.The test correctly uses the new
hyperfleet_api.NewClient(testLog(), opts...)signature with proper error handling viarequire.NoError.
471-479: LGTM! Consistent API client initialization across all integration tests.All test functions properly use
hyperfleet_api.NewClient(testLog())withrequire.NoError(t, err)error handling, maintaining consistency across the test suite.Also applies to: 578-586, 649-657, 707-715, 755-763, 910-918, 974-982
25-31: Minor: Struct field alignment is cosmetic only.The reformatting of
k8sTestAPIServerfields with consistent spacing is a stylistic improvement with no functional impact.internal/executor/resource_executor_test.go (2)
11-34: LGTM! Deep copy tests properly updated with context and logger.The
deepCopyMapfunction now receivescontext.Background()andlogger.NewTestLogger(), aligning with the context-aware API changes. Test logic correctly verifies value copying and mutation isolation.
36-238: LGTM! Comprehensive deep copy test coverage.All test cases consistently use the updated
deepCopyMap(context.Background(), original, logger.NewTestLogger())signature:
- Nested maps, slices, channels, functions
- Edge cases (nil map, empty map)
- Kubernetes manifest structures
- Real-world context simulation
Mutation isolation is properly verified in each test.
test/integration/executor/main_test.go (2)
103-147: LGTM! Improved test environment setup with proper logger and readiness flow.The changes appropriately:
- Use
logger.NewTestLogger()for shared test environment- Include informative readiness logging
- Wait for API server with explicit health check
184-220: LGTM! Robust HTTP-based health check implementation.The
waitForAPIServerReadyfunction is well-implemented:
- Uses HTTP client with 5s timeout per request
- Properly configures TLS with
InsecureSkipVerifyfor self-signed envtest certs (documented withnolint:gosec)- Enforces TLS 1.2 minimum version
- Includes Bearer token authorization
- Correctly closes response body on success
- Uses reasonable 500ms polling interval
internal/executor/types.go (3)
40-54: LGTM! Well-designed event data types.
ResourceRefandEventDataprovide clean, typed structures for HyperFleet CloudEvent payloads:
- JSON tags with
omitemptyallow flexible serializationOwnedReferencepointer enables optional nested ownership tracking- Fields align with HyperFleet API conventions
68-75: LGTM! Logger field added to Executor.Adding
log logger.Loggerto theExecutorstruct enables context-aware logging throughout the execution lifecycle, aligning with the broader logger refactor goals.
179-195: LGTM! Simplified ExecutionContext with data-centric approach.The changes appropriately:
- Replace
Event *event.EventwithEventData map[string]interface{}- Simplify
NewExecutionContext(ctx, eventData)constructor- Initialize all required fields including the new
EvaluationssliceThis decouples execution context from the CloudEvent SDK, enabling cleaner testing and more flexible event handling.
Also applies to: 252-264
internal/executor/executor_test.go (5)
22-80: LGTM! TestNewExecutor properly updated.Tests correctly validate executor construction with:
logger.NewTestLogger()in configsk8s_client.NewMockK8sClient()for valid config case- Proper error expectations for missing dependencies
82-113: LGTM! Builder and ExecutionContext tests updated.
- Builder test uses
NewTestLogger()andNewMockK8sClient()TestExecutionContextcorrectly uses map-based event data and validatesexecCtx.EventData["cluster_id"]
234-289: LGTM! Param extraction test correctly updated for data-centric API.The test:
- Uses
map[string]interface{}for event data- Propagates event ID via
logger.WithEventID(ctx, "test-event-123")- Calls
exec.Execute(ctx, eventData)with the new signature- Properly verifies extracted params from both env and event sources
291-384: LGTM! ParamExtractor tests properly use new ExecutionContext.Tests correctly:
- Create
NewExecutionContext(context.Background(), eventData)with map-based data- Use CloudEvent only for setting data in the test fixture (line 301)
- Validate parameter extraction logic for env, event, nested, default, and required cases
440-554: LGTM! Sequential execution tests consistently updated.All tests properly:
- Use
logger.NewTestLogger()in builder- Propagate event ID via
logger.WithEventID(ctx, "...")- Call
exec.Execute(ctx, map[string]interface{}{})with data-centric API- Validate precondition, resource, and post-action sequential behavior
Also applies to: 556-645, 647-717, 719-791
internal/criteria/cel_evaluator.go (4)
17-23: LGTM! Clean separation of context types.The
CELEvaluatorstruct now properly distinguishes:
evalCtx *EvaluationContext: Holds CEL evaluation data (variables, version tracking)ctx context.Context: Standard Go context for logging, cancellation, and tracingThis separation improves clarity and enables proper context-aware logging.
56-73: LGTM! Constructor properly wires both contexts.The unexported
newCELEvaluatorfunction correctly:
- Documents that caller (
NewEvaluator) handles validation- Builds CEL options from
evalCtx- Initializes all fields including both
evalCtxandctxMaking this unexported is appropriate since
NewEvaluatoris the intended public API.
163-176: LGTM! Evaluation uses correct context for data and logging.The changes properly:
- Use
e.evalCtx.Data()for thread-safe data snapshot during evaluation- Use
e.log.Debugf(e.ctx, ...)for context-aware debug logging- Maintain the safe error handling pattern (errors captured in result, not returned)
269-272: Minor comment improvement.The updated comment clarifies that boolean values (both true and false) are never considered "empty" for the purpose of CEL result matching.
test/integration/executor/executor_integration_test.go (3)
91-95: LGTM - Error handling correctly implemented.The API client creation now properly captures and checks the error with
require.NoError, which will fail the test immediately if client creation fails. This addresses the previously flagged issue.
841-842: Good use of capture logger for log verification.The
NewCaptureLogger()pattern is correctly used here to create a logger and capture handle for asserting on log output. The subsequent assertions usinglogCapture.Messages()andlogCapture.Contains()properly verify expected log messages.
1299-1307: Correct pattern: separate loggers for API client and executor.The test correctly creates one logger for the API client (
testLog()) and a separate capture logger for the executor to verify error logging. This allows the test to capture only the executor's logs for assertion.internal/criteria/evaluator.go (4)
53-71: Well-structured constructor with clear validation.The updated
NewEvaluatorconstructor properly validates all required parameters (ctx,evalCtx,log) and returns descriptive errors. The approach of requiring all parameters at construction time is cleaner than allowing nil values and handling them later.
77-94: CEL evaluator caching with version tracking is well designed.The
getCELEvaluatormethod correctly handles lazy initialization and cache invalidation when the evaluation context version changes. This prevents "undeclared reference" errors when variables are added after first evaluation, as documented in the comment.
96-120: Consistent migration of field accessors to useevalCtx.All field accessor methods (
GetField,GetFieldOrDefault,GetFieldSafe,HasField) consistently usee.evalCtx.GetNestedField()for data access. This aligns with the architectural change to separate the Go context from the evaluation context.
141-143: Field accessor inEvaluateConditionWithResultalso updated correctly.The change to use
e.evalCtx.GetNestedField(field)is consistent with other field accessor methods.internal/executor/resource_executor.go (5)
35-55: Clean migration to internal logger forExecuteAll.The method now uses
re.loginstead of accepting a log parameter. All log calls are context-aware (re.log.Infof(ctx, ...)) which enables proper correlation. The signature change simplifies the API.
58-156: Context-aware logging consistently applied inexecuteResource.All logging within
executeResourceuses the context-aware pattern (re.log.Debugf(ctx, ...),re.log.Infof(ctx, ...), etc.). This enables log correlation across the resource execution flow.
159-198:buildManifestnow accepts context for logging.The method signature correctly includes
ctx context.Contextwhich is passed todeepCopyMap. This maintains the context-aware logging pattern throughout the call chain.
306-330:recreateResourceuses internal logger consistently.The method no longer requires an explicit log parameter and uses
re.logfor all logging. The context-aware logging is properly applied throughout the delete-wait-create flow.
24-31: Constructor properly validates configuration including K8sClient.The
NewExecutorfunction correctly validates the config by callingvalidateExecutorConfig()before instantiating child executors, includingnewResourceExecutor(). TheK8sClientfield is explicitly included in the required fields validation (line 39), ensuring it cannot be nil when passed tonewResourceExecutor().
2bd9cc6 to
88189ab
Compare
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
♻️ Duplicate comments (2)
internal/executor/post_action_executor.go (1)
20-27: Constructor follows the same validation pattern as other sub-executors.The comment clarifies that
NewExecutoris responsible for config validation. This is consistent with the pattern inprecondition_executor.goandresource_executor.go, which is good for maintainability.The nil check concern raised in a past review on this file has been addressed by documenting that validation is the caller's responsibility. Ensure
NewExecutorperforms the necessary validation.internal/executor/resource_executor.go (1)
24-31: Constructor follows the established validation pattern.Same pattern as other sub-executors. The past review concern about
K8sClientvalidation was marked as addressed in commit 4ca8360.The validation concern was previously raised and addressed. The comment correctly documents that
NewExecutoris responsible for config validation.
🧹 Nitpick comments (2)
internal/criteria/cel_evaluator_test.go (1)
13-21: Rename test to follow Go conventions for unexported functions.The test function name should match the visibility of the function being tested. Since
newCELEvaluatoris unexported, the test should be namedTest_newCELEvaluator(with lowercase after underscore).🔎 Proposed fix
-func TestNewCELEvaluator(t *testing.T) { +func Test_newCELEvaluator(t *testing.T) {Based on past review comment noting naming inconsistency.
internal/executor/resource_executor.go (1)
418-426: Consider logging the type assertion failure for consistency.The first fallback (lines 409-415) logs a warning when deep copy fails, but the second fallback (lines 418-425) for type assertion failure is silent. While this "should not happen" per the comment, logging would help with debugging if it ever does occur.
🔎 Proposed fix
result, ok := copied.(map[string]interface{}) if !ok { // Should not happen, but handle gracefully + log.Warnf(ctx, "Deep copy returned unexpected type %T, falling back to shallow copy", copied) result := make(map[string]interface{}) for k, v := range m { result[k] = v } return result }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
internal/criteria/cel_evaluator_test.gointernal/executor/post_action_executor.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
internal/criteria/cel_evaluator_test.go
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
internal/executor/resource_executor.go
🧬 Code graph analysis (3)
internal/criteria/cel_evaluator_test.go (2)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
internal/executor/precondition_executor.go (5)
pkg/logger/logger.go (1)
Logger(15-43)internal/executor/types.go (2)
ExecutorConfig(57-66)ExecutionContext(180-195)internal/config_loader/types.go (2)
Precondition(98-105)APICall(108-116)internal/executor/utils.go (1)
ExecuteAPICall(76-206)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
internal/executor/post_action_executor.go (5)
pkg/logger/logger.go (1)
Logger(15-43)internal/executor/types.go (2)
ExecutorConfig(57-66)ExecutionContext(180-195)internal/config_loader/types.go (4)
PostConfig(193-196)Payload(67-78)PostAction(199-203)APICall(108-116)internal/criteria/evaluator.go (2)
NewEvaluator(56-71)Evaluator(41-51)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)
🔇 Additional comments (11)
internal/criteria/cel_evaluator_test.go (1)
18-20: LGTM! Test updates correctly reflect the new API.All test cases have been properly updated to use the new constructor signatures with
context.Contextandlogger.Loggerparameters. Error handling has been consistently added, and the changes align with the logger refactoring objectives (HYPERFLEET-304).Also applies to: 30-31, 134-135, 159-160, 250-251, 269-270, 445-446, 474-475, 537-538
internal/executor/precondition_executor.go (3)
30-70: LGTM!The
ExecuteAllmethod properly uses context-aware logging with clear progress indicators (step N/M format) and appropriate log levels (Info for progress, Error for failures).
144-149: Good addition of evaluator creation error handling.The new error handling for
criteria.NewEvaluatorproperly captures and propagates the error, which aligns with the HYPERFLEET-304 objective to improve error handling and logging.
207-217: LGTM!Clean delegation to the shared
ExecuteAPICallutility, properly passing the internal logger and API client.internal/executor/post_action_executor.go (4)
29-77: LGTM!The
ExecuteAllmethod properly handles the two-phase approach (build payloads, then execute actions) with appropriate logging and error propagation. The stop-on-first-failure behavior is clearly implemented.
79-119: LGTM!Proper evaluator creation with error handling, and clean payload building flow with appropriate JSON serialization for template compatibility.
121-200: LGTM!The payload building methods are cleanly refactored as receiver methods with context threading. The recursive processing of nested structures is well-handled.
202-252: LGTM!The post-action execution methods properly delegate to shared utilities while providing action-specific logging and error context. The error context determination (lines 243-246) provides helpful debugging information.
internal/executor/resource_executor.go (3)
33-156: LGTM!The resource execution flow is well-structured with:
- Clear progress logging with step indicators
- Smart differentiation between transient and fatal discovery errors (lines 88-96)
- Proper resource context storage after successful operations
- Consistent context-aware logging throughout
158-198: LGTM!Clean manifest building with proper deep copying and template rendering. The context is properly passed to
deepCopyMapfor potential warning logs.
303-361: LGTM!The recreate and wait-for-deletion logic is well-implemented with:
- Proper resource cleanup via
defer ticker.Stop()- Clear context cancellation handling
- Correct interpretation of
NotFoundas successful deletion- Informative logging at each step
88189ab to
05734f1
Compare
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
♻️ Duplicate comments (1)
internal/executor/post_action_executor.go (1)
20-27: Constructor follows established pattern with caller validation.Similar to
precondition_executor.go, this constructor relies on the caller (NewExecutor) to validate the config parameter. A past review comment suggested adding nil checks here, but the established pattern across all executors is to validate once inNewExecutor. This is acceptable and maintains consistency.Note: This follows the same validation pattern as the precondition executor.
🧹 Nitpick comments (1)
cmd/adapter/main.go (1)
155-159: Verify adapter name is valid before recreating logger.The logger is recreated using
adapterConfig.Metadata.Nameas the component name. If the adapter name is empty or contains unexpected characters, the logger might be created with invalid metadata. Consider adding validation to ensure the adapter name is suitable for use as a component identifier.🔎 Suggested validation
// Recreate logger with component name from adapter config + if adapterConfig.Metadata.Name == "" { + return fmt.Errorf("adapter name is required but empty in config") + } log, err = logger.NewLogger(buildLoggerConfig(adapterConfig.Metadata.Name)) if err != nil { return fmt.Errorf("failed to create logger with adapter config: %w", err) }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
cmd/adapter/main.gointernal/criteria/cel_evaluator_test.gointernal/executor/post_action_executor.gointernal/executor/precondition_executor.gointernal/executor/resource_executor.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
📚 Learning: 2025-12-04T14:06:51.656Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 13
File: internal/executor/post_action_executor.go:198-205
Timestamp: 2025-12-04T14:06:51.656Z
Learning: Logger refactor is tracked in HYPERFLEET-304 for the hyperfleet-adapter repository, which will address how CEL evaluation failures and similar errors are handled and logged.
Applied to files:
cmd/adapter/main.gointernal/executor/resource_executor.go
📚 Learning: 2025-12-11T02:06:33.975Z
Learnt from: xueli181114
Repo: openshift-hyperfleet/hyperfleet-adapter PR: 17
File: internal/config_loader/validator_schema.go:126-133
Timestamp: 2025-12-11T02:06:33.975Z
Learning: In the hyperfleet-adapter repository (Go), environment variable validation for required parameters (those with `env.*` source, `Required=true`, and no default) occurs at config load time in `internal/config_loader/validator_schema.go`. This is intentional design - environment variables must be set before deployment, and the validation ensures fail-fast behavior with clear error messages.
Applied to files:
cmd/adapter/main.gointernal/criteria/cel_evaluator_test.go
🧬 Code graph analysis (3)
cmd/adapter/main.go (4)
internal/config_loader/loader.go (2)
Load(79-102)WithAdapterVersion(46-50)internal/config_loader/types.go (2)
Metadata(14-18)HyperfleetAPIConfig(37-42)internal/hyperfleet_api/client.go (1)
NewClient(118-147)internal/hyperfleet_api/types.go (2)
ClientConfig(38-54)Client(216-237)
internal/executor/post_action_executor.go (6)
pkg/logger/logger.go (1)
Logger(15-43)internal/executor/types.go (1)
ExecutorConfig(57-66)internal/config_loader/types.go (3)
Payload(67-78)PostAction(199-203)APICall(108-116)internal/criteria/types.go (1)
NewEvaluationContext(75-80)internal/criteria/evaluator.go (2)
NewEvaluator(56-71)Evaluator(41-51)internal/executor/utils.go (2)
ExecuteLogAction(39-70)ExecuteAPICall(76-206)
internal/criteria/cel_evaluator_test.go (2)
pkg/logger/test_support.go (1)
NewTestLogger(17-32)internal/criteria/evaluator.go (1)
NewEvaluator(56-71)
🔇 Additional comments (15)
internal/criteria/cel_evaluator_test.go (4)
4-4: LGTM! Imports align with the logger refactor.The addition of
contextandloggerimports correctly supports the new constructor signatures that now require context and logger parameters.Also applies to: 8-8
18-18: LGTM! Constructor calls updated consistently.All
newCELEvaluatorcalls have been correctly updated to the new three-parameter signature withcontext.Background()andlogger.NewTestLogger(). The use ofcontext.Background()is appropriate for test scenarios, andlogger.NewTestLogger()follows the established test helper pattern.Also applies to: 30-30, 134-134, 159-159, 250-250, 269-269, 537-537
445-446: LGTM! NewEvaluator error handling added correctly.The
NewEvaluatorcalls have been properly updated to handle the new error return value. Usingrequire.NoErroris appropriate for test setup, as constructor failures should prevent test execution.Also applies to: 474-475
157-157: LGTM! nullValue correctly set to nil.The
nullValueis properly set tonil, which correctly aligns with the test case at lines 183-189 that validates error handling when accessing a field on a null value. This addresses the issue mentioned in past review comments.cmd/adapter/main.go (2)
138-159: Bootstrap logger pattern is well-designed.The approach of creating an initial "hyperfleet-adapter" logger before config load, then recreating it with the actual adapter name from config, is a solid pattern that ensures logging is available throughout startup while still providing proper component identification once configuration is loaded.
110-130: Logger configuration precedence is correctly implemented.The
buildLoggerConfigfunction properly implements the precedence of command-line flags over environment variables, which aligns with standard configuration patterns. The component name and version are correctly set from build-time variables.internal/executor/precondition_executor.go (3)
144-149: Good: Error handling added for evaluator creation.The error handling for evaluator creation properly captures and returns errors with context. This addresses the known issue tracked in HYPERFLEET-304 regarding CEL evaluation error handling.
Based on learnings, this resolves the CEL evaluation error handling concerns.
32-70: Consistent context-aware logging throughout execution.The
ExecuteAllmethod properly propagates context through all logging calls and sub-operations. The logging provides clear progress indicators with precondition numbers and results, making execution flow easy to trace.
21-28: Constructor validation is properly handled by NewExecutor.The
newPreconditionExecutorconstructor safely assumesconfig.APIClientandconfig.Loggerare non-nil becauseNewExecutorexplicitly validates both fields viavalidateExecutorConfig()using reflection checks (lines 30-47 in executor.go). This delegation of validation to the caller is acceptable and properly implemented.internal/executor/post_action_executor.go (2)
86-89: Evaluator creation properly handles errors.Error handling for evaluator creation is correctly implemented, preventing nil dereference if creation fails. This aligns with the broader error handling improvements in HYPERFLEET-304.
Based on learnings, this addresses CEL evaluation error handling concerns.
123-200: Context properly propagated through recursive payload building.The context is correctly passed through all levels of payload building:
buildPayload→buildMapPayload→processValue, including recursive calls. This ensures proper cancellation propagation and tracing throughout complex payload structures.internal/executor/resource_executor.go (4)
24-31: Constructor consistent with executor pattern.The constructor follows the same config-based initialization pattern as the other executors, with validation delegated to
NewExecutor. Past reviews confirmed thatK8sClientvalidation was added toNewExecutor, making this approach safe.
402-429: deepCopyMap handles failures gracefully with clear warning.The fallback to shallow copy when deep copy fails is good defensive programming. The warning message clearly explains the implications of shallow copy (nested structures will share references), helping developers understand potential mutation issues.
334-361: waitForDeletion properly handles context cancellation.The polling loop correctly handles
ctx.Done()for cancellation and timeout scenarios, preventing indefinite waits. The logging at each stage (waiting, confirmed, timeout) provides good observability for debugging resource lifecycle issues.
58-156: Resource execution flow is well-structured and logged.The
executeResourcemethod provides comprehensive logging at each stage (manifest building, discovery, operation selection, execution). The context-aware logging makes it easy to trace resource lifecycle operations and debug issues.
| // Syntax validation only | ||
| _, issues := v.celEnv.Parse(expr) | ||
| if issues != nil && issues.Err() != nil { | ||
| v.errors.Add(path, fmt.Sprintf("CEL parse error: %v", issues.Err())) |
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.
Since the section below was removed, would it make sense to add the expr info here?
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: 86254860 The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
50a640c
into
openshift-hyperfleet:main
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Tests
✏️ Tip: You can customize this high-level summary in your review settings.