Skip to content

Conversation

@xueli181114
Copy link
Contributor

@xueli181114 xueli181114 commented Dec 17, 2025

Summary by CodeRabbit

  • New Features

    • Configurable CLI logging (level/format/output) and a new context-aware, structured logger; test-friendly log utilities and capture logger.
  • Bug Fixes

    • Improved, consistent propagation of contextual fields (trace, event, cluster, resource, adapter, subscription) across startup, runtime, and shutdown; clearer startup/shutdown logs.
  • Refactor

    • Execution flow moved to data-centric, context-driven APIs with unified, config-driven executors and context-bound logging; legacy logging removed.
  • Tests

    • Tests updated to use context-aware constructors, test loggers, and enhanced log-capture assertions.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Walkthrough

Replaces 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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested labels

lgtm, approved

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.78% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main refactoring objective: migrating context to logger parameters and adding environment variable/CLI flag support for logging configuration.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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 evt is created and data is set, but it's never used after line 319. The test now passes eventData directly to NewExecutionContext at 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 uses sync.Once to create a shared logger instance, this testLog() 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 and InsecureSkipVerify: true already relaxes security, adding MinVersion: tls.VersionTLS12 would 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 NewValidator is called with a nil logger, calling v.log.Debugf will 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_NilLogger is now a misleading name since deepCopyMap no 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.Context as the first parameter. The current signature has log logger.Logger, ctx context.Context which 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: Unused ctx parameter in buildManifest.

The ctx parameter is accepted but never used in buildManifest. 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.

TestConfigFromEnv tests 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

📥 Commits

Reviewing files that changed from the base of the PR and between 370691a and 8b8dbc8.

⛔ Files ignored due to path filters (1)
  • go.sum is 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.go
  • internal/config_loader/loader.go
  • cmd/adapter/main.go
  • internal/config_loader/validator.go
  • internal/executor/types.go
  • internal/config_loader/validator_test.go
  • internal/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 install target 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 ExecuteLogAction signature by:

  1. Adding the context import
  2. Passing context.Background() as the first argument

This 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 ctx parameter to Infof, 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 WithLogField function correctly retrieves existing fields (as a copy from GetLogFields), 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 GetLogFields returns a copy, so each WithLogField call allocates a new map. For high-frequency field additions, consider a builder pattern or batching with WithLogFields instead.


11-29: Good use of typed context keys to avoid collisions.

The contextKey type prevents key collisions with other packages using context.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 in test/integration/testutil/logger.go and 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 around testutil.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.Once ensures 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 NewEvaluator calls have been updated to pass context.Background() as the first parameter and testutil.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 NewEvaluator calls have been updated to pass context.Background() and testLog(), 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 parameter
  • logCaptureLogger methods updated to accept context as first parameter

The 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 NewEvaluator calls properly updated with context.Background() and testLog() parameters.

internal/criteria/evaluator_test.go (2)

4-4: LGTM! Context import added.


524-1073: LGTM! Evaluator initialization consistently updated.

All NewEvaluator calls throughout the test file have been properly updated with context.Background() and testLog() 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 in setup_test.go within the same test package (test/integration/executor/) and is correctly available for use in executor_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 to k8s_client.NewClientFromConfig, aligning with the PR's dependency injection pattern.

internal/config_loader/loader.go (1)

79-91: Clean functional options implementation.

The WithLogger and WithContext options 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 Parse and Validate calls have been correctly updated to use WithContext(context.Background()) and WithLogger(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 Parse calls in table-driven tests are correctly updated to pass WithContext(context.Background()) and WithLogger(testLog()). The Load() 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() and testPAE() helpers provide clean test setup. Since this test file is in the executor package (same package as the implementation), accessing pae.log directly 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() and pae.log, then calls pae.buildPayload with context. This aligns with the refactored API.


423-446: ExecuteAll test correctly wired with new ExecutorConfig.

The test properly constructs PostActionExecutor with ExecutorConfig containing both APIClient and Logger, and uses NewExecutionContext with context.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 NewClient invocations 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 Validate function provides a simple entry point that properly delegates to NewValidator. This maintains a clean separation between the stateless public API and the stateful Validator instance.

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:

  • evalCtx defaults to a new EvaluationContext
  • goCtx defaults to context.Background()

This prevents nil pointer panics in downstream code.


72-89: LGTM! CEL evaluator correctly uses stored Go context.

The getCELEvaluator method properly passes e.goCtx to NewCELEvaluator, 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 in internal/k8s_client/client.go and 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() and testLog().

Also applies to: 29-29, 133-133, 249-249, 268-268


444-444: LGTM!

The NewEvaluator and NewCELEvaluator calls 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 ResourceRef and EventData structs are well-designed with appropriate JSON tags and omitempty for optional fields. Using *ResourceRef for OwnedReference correctly allows nil values for events without owned references.


259-270: LGTM!

The simplified NewExecutionContext signature that accepts eventData 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) from evalCtx *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 CELResult rather than returning them, enabling callers to decide how to handle missing fields. The debug logging using e.goCtx provides 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 createAPIClient function correctly threads the logger through to hyperfleet_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 PreconditionExecutor now correctly receives its dependencies via ExecutorConfig, consistent with ResourceExecutor and PostActionExecutor constructors shown in the relevant snippets.


31-69: LGTM: Context-aware logging in ExecuteAll.

The logging is properly updated to use pe.log with 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 ctx through all logging calls and delegates to pe.log. The evaluator creation at line 143 correctly passes context and logger.


202-211: LGTM: executeAPICall signature and implementation.

Clean delegation to ExecuteAPICall utility with proper logger injection.

internal/executor/executor.go (3)

16-36: LGTM: Unified config-based executor wiring.

The validation guards and consistent use of ExecutorConfig for 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.Event to interface{} with ParseEventData provides flexibility. Context enrichment with resource IDs (lines 56-62) enables proper log correlation using the helpers from pkg/logger/context.go.


233-277: Consider handling empty JSON object {} case.

ParseEventData returns empty structs for nil and empty []byte, but an empty JSON object {} would parse successfully and return an EventData with 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 PreconditionExecutor and PostActionExecutor.

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 for Fatal-style methods, but worth noting given the file handle concern.

Ensure callers understand that Fatal is 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 buildArgs method 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, and WithTraceID with field verification via GetLogFields.

internal/executor/post_action_executor.go (4)

30-76: LGTM!

The ExecuteAll method correctly propagates context through all logging calls and execution paths. Error handling with ExecutionError metadata 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 executePostAction and executeAPICall methods correctly pass context to all logging and external API calls.

internal/executor/executor_test.go (4)

24-40: LGTM!

The mockLogger correctly implements the updated Logger interface with all context-aware methods. The With, WithFields, and WithError methods properly return m to support chaining.


119-131: LGTM!

The test correctly uses the updated NewExecutionContext signature with map-based event data, validating the refactored API.


288-307: LGTM!

Good use of logger.WithEventID to attach event IDs to the context, demonstrating the new context-aware logging pattern.


386-386: No issues found. The third parameter to extractConfigParams is k8sClient, not a logger. The function and its callees (extractFromSecret and extractFromConfigMap) already include nil checks that return appropriate errors if the Kubernetes client is needed but not provided. Passing nil is safe for test cases that don't require secret or configmap parameter extraction.

Likely an incorrect or invalid review comment.

Copy link

@coderabbitai coderabbitai bot left a 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: nullValue should be nil.

The test case at line 182-188 is named "access field on null returns error in result (safe)" but nullValue is set to testLog() instead of nil. 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 to jsonBytes.

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 newPostActionExecutor can panic if called incorrectly from any other location.

Since this is now a private function (newPostActionExecutor vs NewPostActionExecutor), 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 shared internal/testutil package to centralize this pattern and reduce duplication.

internal/executor/executor.go (1)

180-188: Consider moving ctx parameter to the front of finishWithError.

Go convention is to place context.Context as 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 evt variable is created and populated but never used. The test only uses the eventData map 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/event import 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, and Errorf, but the Logger interface (as shown by mockLogger in executor_test.go) also includes a Fatal method. Consider adding a test for Fatal for completeness.

Note: If Fatal calls os.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

📥 Commits

Reviewing files that changed from the base of the PR and between 8b8dbc8 and c40b141.

⛔ Files ignored due to path filters (1)
  • go.sum is 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.go
  • internal/executor/types.go
  • internal/hyperfleet_api/client.go
  • cmd/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) to testutil.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 install target 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 NewValidator to unexported newValidator aligns with the loader refactoring where validation is now invoked internally via newValidator(config).Validate() in loader.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) to newValidator(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 newValidator constructor across all test cases.

internal/executor/types.go (2)

46-61: LGTM! New types support structured event data.

The introduction of ResourceRef and EventData types 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 NewExecutionContext signature removes the CloudEvents dependency, accepting a plain eventData map 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)
  • WithDynamicResourceID cleverly derives field names from resource types (lines 64-67)
  • Consistent API patterns across all WithXxx functions

The 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 Output is a file path. This implementation addresses that concern by explicitly rejecting file paths (lines 101-108), supporting only stdout and stderr. 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 buildArgs method cleanly merges logger-scoped fields (lines 172-174) with context-scoped fields (lines 177-183), enabling both static logger fields (via With/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 a context.Context as 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, and WithError methods create new logger instances with copied field maps (via copyFields), 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 ctx as the first parameter to Infof aligns 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() and testLog(). 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 InsecureSkipVerify is properly justified for envtest with self-signed certificates, and the MinVersion: tls.VersionTLS12 provides 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() and testLog() ensures proper test coverage of the new logging infrastructure.

internal/executor/utils.go (2)

39-69: Context-aware logging properly implemented.

The ExecuteLogAction function 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 NewCELEvaluator constructor correctly:

  • Accepts goCtx as 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.goCtx to 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 NewCELEvaluator and NewEvaluator calls consistently use context.Background() and testLog(), 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.Once pattern ensures thread-safe lazy initialization of the shared test logger. Using Level: "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 create PostActionExecutor instances 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 goCtx to context.Background() and evalCtx to a new EvaluationContext. 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 goCtx is correctly passed through for context-aware logging.

internal/executor/resource_executor_test.go (1)

19-19: Consistent context-aware signature usage across all deepCopyMap tests.

All test cases have been updated to pass context.Background() and testLog() to the refactored deepCopyMap function. The tests maintain their original coverage of deep copy semantics.

internal/hyperfleet_api/client.go (2)

119-148: Clean refactor of NewClient to require logger dependency.

The signature change from NewClient(opts ...ClientOption) to NewClient(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:

  • Warnf for failures and retryable responses alerts operators to issues
  • Infof for retry delays provides visibility into the retry flow
  • Debugf (lines 309, 329) for request/response details keeps verbose info at debug level
cmd/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 createAPIClient function signature and implementation properly pass the logger to hyperfleet_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 NewExecutor function 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 structured EventData and 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.NewClient calls have been updated to pass a logger (testLog() or k8sEnv.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.Context as the first parameter for all logging methods, matching the new logger.Logger interface. The Fatal method correctly uses t.Fatalf instead of os.Exit for test compatibility.


91-94: The review comment is incorrect. The testLog() function is properly defined in setup_test.go (line 26) within the same package (executor_integration_test), and it correctly calls the exported testutil.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 PreconditionExecutor now takes ExecutorConfig and 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 ExecuteAll correctly uses pe.log with 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.log for all log statements
  • Sets ExecutionError with phase and step info on failures
  • Passes pe.log to ExecuteLogAction and criteria.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 ExecuteAPICall helper, enabling consistent logging during HTTP operations.

internal/executor/resource_executor.go (3)

20-33: Config-driven constructor pattern correctly implemented.

The ResourceExecutor now uses the same pattern as other executors, taking ExecutorConfig and extracting k8sClient and logger.


35-57: ExecuteAll correctly uses internal logger with context.

Resource processing logging properly uses re.log with 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 ctx and log parameters 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 return logger.Logger to support method chaining, and the Warn method captures warnings for test assertions.


41-42: Orphaned comment has been addressed.

The previous orphaned comment about testEventWithData has been removed. The current comment appropriately describes the TestNewExecutor function.


119-131: LGTM on TestExecutionContext.

The test correctly exercises the new NewExecutionContext API with context and map-based event data, and properly verifies the EventData field 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 the logger.WithEventID pattern and pass map-based event data to Execute.

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 NewLogger call is properly checked.


57-68: LGTM on invalid output validation test.

Good negative test case that verifies NewLogger properly 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, and WithTraceID correctly store values in the context that can be retrieved via GetLogFields.


386-423: LGTM on ConfigFromEnv tests.

Good coverage of environment variable configuration including defaults and case normalization (e.g., DEBUGdebug).


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.log logger with context propagation. The sequential execution pattern (stop on first failure) is preserved, and error context is properly captured in execCtx.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 apiClient and log dependencies. Error handling with NewExecutorError provides proper phase/step context, and response details are captured even when validation fails.

Copy link

@coderabbitai coderabbitai bot left a 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 (when WithLogger is not called), which causes a nil pointer panic when the validator tries to log via v.log.Debugf().

This issue remains unresolved. The validator must receive a valid logger instance. Consider one of these approaches:

  1. Pass a logger to newValidator(config, logger) - obtain it from a loader option or create a default no-op logger
  2. Ensure newValidator internally handles nil logger by providing a default no-op implementation
  3. 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: nullValue is no longer null.

The test case "access field on null returns error in result (safe)" at lines 182-188 expects nullValue to be null, but it's now set to testLog() (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 if NewExecutor centralizes validation.

Note: A past review flagged the missing nil check here. The comment now clarifies the design intent, but ensure NewExecutor validates config.APIClient and config.Logger are 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 resourceType is 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 jsonBytes twice: once into EventData struct (line 266) and once into rawData map (line 272). This is slightly inefficient but acceptable for correctness. The structured EventData provides type safety for known fields, while rawData allows 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 fields map and the context's LogFields contain 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.

Warn appends to m.warnings, but Warnf does 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 in TestParamExtractor (line 312) to create an event that's not actually used after setting data. The evt variable is assigned but the test uses eventData map 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

📥 Commits

Reviewing files that changed from the base of the PR and between c40b141 and 3b3c199.

⛔ Files ignored due to path filters (1)
  • go.sum is 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.go
  • internal/config_loader/loader.go
  • internal/hyperfleet_api/client.go
  • internal/config_loader/validator.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • internal/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 nolint annotation)
  • 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 in loader.go. However, once the nil logger issue is fixed (by passing a logger to newValidator), 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 ExecuteLogAction with context.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.Once for 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 include testLog() 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 ctx as the first parameter (e.g., log.Infof(ctx, ...) instead of log.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 context import and all NewEvaluator calls are properly updated to use the new three-parameter signature (context.Context, *EvaluationContext, Logger). Using context.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 context and testutil imports are properly added to support the new NewEvaluator signature.

Also applies to: 17-17


73-73: LGTM! Evaluator instantiation correctly updated.

All NewEvaluator calls throughout this integration test file are properly updated to use the new three-parameter signature with context.Background() and testutil.TestLogger().

internal/hyperfleet_api/client_test.go (2)

22-36: LGTM! Test logger helper correctly implemented.

The testLog() helper uses sync.Once for 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 NewClient calls throughout the test file are properly updated to pass testLog() as the first argument, aligning with the new signature NewClient(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.Context as the first parameter, and all log calls (Debugf, Infof, Warnf, Errorf) correctly pass the context. This aligns with the new Logger interface requirements.


87-87: LGTM! ExecuteAPICall logging correctly updated to use context.

All log statements in ExecuteAPICall now properly pass the ctx parameter 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 templateFuncs map entries with no functional impact.

internal/criteria/evaluator_test.go (2)

4-4: LGTM! Context import and evaluator instantiation correctly updated.

The context import is added and all NewEvaluator calls 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 NewEvaluator panics when any of its required parameters (ctx, evalCtx, or log) is nil. This provides good coverage for the constructor's defensive checks. The //nolint:staticcheck comment 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 TestNewCELEvaluator to Test_newCELEvaluator correctly reflects the unexported constructor, and the context/logger propagation is properly implemented.


438-488: LGTM!

The NewEvaluator calls are correctly updated to use the three-parameter signature with context.Background(), ctx, and testLog(). 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 DynType and actual types are only known at runtime. The comment clearly explains the rationale.


409-431: LGTM!

The validateBuildExpressions function correctly handles recursive validation of CEL expressions within nested build structures, checking for the expression key 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 createAPIClient function correctly propagates the logger to hyperfleet_api.NewClient, aligning with the new signature that requires a logger parameter.

internal/hyperfleet_api/client.go (2)

119-148: LGTM!

The NewClient signature correctly requires a logger as the first parameter, following the same pattern as k8s_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) from evalCtx (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 ResourceRef and EventData types are cleanly designed with appropriate JSON tags and omitempty for optional fields. The OwnedReference pointer allows for proper nil handling when no owned reference exists.


81-81: Logger field added to Executor struct.

Adding the log field to the Executor struct 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 EventData now 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 contextKey type 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.

GetLogFields returns a copy, but WithLogField calls GetLogFields and then mutates that copy before storing it back. While this works correctly, if GetLogFields is called between the get and the context.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 return l to 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 Logger interface in pkg/logger/logger.go does not define a Flush method. Since logCaptureLogger.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 PreconditionExecutor now receives its dependencies via ExecutorConfig, which is a cleaner pattern than passing individual dependencies. The lowercase newPreconditionExecutor indicates internal use, which is appropriate since it's constructed by NewExecutor.


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 ExecutionError with phase, step, and message provides valuable debugging information. The structured error is available for CEL expressions in post-actions, as tested in TestExecutor_ExecutionError_CELAccess.


141-144: Evaluator correctly receives context and logger.

The criteria.NewEvaluator is called with all required parameters (ctx, evalCtx, pe.log), matching the signature shown in the relevant code snippet from internal/criteria/evaluator.go.


203-212: executeAPICall properly delegates to shared utility.

The method delegates to ExecuteAPICall utility and validates the response. The error handling through ValidateAPIResponse provides 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. The log field is properly assigned from config.Logger.


39-54: Execute method signature change and initial error handling.

The signature change from accepting *event.Event to data 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 OwnedReference handling allows hierarchical resource tracking (e.g., NodePool owned by Cluster).


244-262: ParseEventData handles edge cases well.

The function correctly handles:

  • nil data (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 NewExecutionContext initializes EventData from the provided map and sets appropriate defaults for Params, Resources, and Adapter.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 NewLogger properly 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, and WithTraceID properly store values that can be retrieved via GetLogFields. 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 ctx and pae.log, aligning with the NewEvaluator signature that requires both parameters. Per the external snippet, NewEvaluator will 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.EvaluateExpressionDef is correctly placed before recursive processing.


224-249: executeAPICall properly captures response details even on error.

The implementation correctly populates result.APIResponse and result.HTTPStatus before checking for errors, ensuring response details are available for debugging failed calls.

Copy link

@coderabbitai coderabbitai bot left a 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 in NewExecutor leaves K8sClient unchecked.

The comment states the caller is responsible for config validation, but per the past review comment, NewExecutor only validates Logger and APIClient, not K8sClient. This could lead to nil pointer dereference in methods like createResource, updateResource, etc., that check re.k8sClient == nil but only after attempting operations.

internal/criteria/cel_evaluator_test.go (1)

156-156: Test semantics changed: nullValue is no longer null.

The test case "access field on null returns error in result (safe)" at lines 182-188 expects nullValue to be null, but it's now set to testLog() (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.NewClient is 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.NewClient is 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.NewClient is 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.NewClient is 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.NewClient is 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.NewClient is 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.NewClient is 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.NewClient is 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.NewClient is 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.NewClient is 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 from NewClient.

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), using require.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 adding Fatalf for consistency with other formatted methods.

The interface provides Debugf, Infof, Warnf, Errorf but lacks Fatalf. While Fatal is 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: Fatal calls os.Exit(1) which is not testable.

The Fatal method directly calls os.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: GetStackTrace is 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 CloudEvent and set data on it, but only eventData (the map) is used in the actual test at line 372. The evt variable 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 data is map[string]interface{}, it's marshaled to JSON and then unmarshaled twice (to EventData and back to map[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 directly
pkg/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

📥 Commits

Reviewing files that changed from the base of the PR and between 3b3c199 and 4ca8360.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (38)
  • cmd/adapter/main.go
  • go.mod
  • internal/config_loader/loader.go
  • internal/config_loader/validator.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/criteria/test_helpers_test.go
  • internal/executor/README.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/precondition_executor.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/k8s_client/client.go
  • internal/k8s_client/discovery.go
  • pkg/logger/context.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/integration/k8s_client/helper_envtest_prebuilt.go
  • test/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.go
  • internal/hyperfleet_api/client.go
  • internal/config_loader/validator.go
  • internal/executor/types.go
  • internal/executor/executor.go
  • internal/config_loader/loader.go
  • test/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 from loader.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 ExecuteAll method correctly uses the internal logger with context-aware logging. The structured logging with precondition index/count provides good observability.


73-200: LGTM!

The executePrecondition method properly:

  1. Uses context-aware logging throughout
  2. Sets ExecutionError on failures for downstream error reporting
  3. Correctly passes pe.log to ExecuteLogAction and criteria.NewEvaluator
  4. Maintains clear separation between execution errors and business outcomes (precondition not met)

21-28: Logger validation is properly implemented.

NewExecutor validates that config.Logger is non-nil via validateExecutorConfig() (lines 30-43), which checks "Logger" as a required field before newPreconditionExecutor is instantiated. The validation occurs at line 18 before line 24 where the constructor is called, ensuring no nil logger can reach criteria.NewEvaluator. No action required.

internal/executor/resource_executor.go (2)

35-55: LGTM!

The ExecuteAll method correctly uses context-aware logging with resource index/count for observability.


404-431: LGTM!

The deepCopyMap function 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 ExecuteAll method properly:

  1. Builds payloads with context-aware logging
  2. Sets ExecutionError on failures for error reporting
  3. Stops execution on first failure (fail-fast behavior)
  4. Uses structured logging with action index/count

81-116: LGTM!

Converting buildPostPayloads to a method and adding context propagation improves consistency. The evaluator is correctly initialized with pae.log.


156-197: LGTM!

The processValue method 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. NewExecutor calls validateExecutorConfig(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, complementing K8sTestEnv.Log for K8s-specific tests.

internal/criteria/test_helpers_test.go (1)

1-23: LGTM!

Well-structured test helper with:

  1. Thread-safe singleton initialization via sync.Once
  2. Appropriate test configuration (debug level for visibility, text format for readability)
  3. 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 NewClient call correctly passes testLog() 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 NewEvaluator calls correctly align with the new signature NewEvaluator(ctx context.Context, evalCtx *EvaluationContext, log logger.Logger). Using context.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 ExecuteLogAction call correctly includes context.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 ctx as 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.Once is idiomatic Go for test utilities. Using Level: "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 NewClient calls consistently pass testLog() as the first argument, correctly matching the updated signature NewClient(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_newCELEvaluator appropriately reflects testing the unexported newCELEvaluator function.

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 deepCopyMap calls are correctly updated to include context.Background() and testLog() 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. Using sync.Once for 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. The NewExecutionContext calls correctly include context.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 buildArgs merges l.fields and context LogFields, 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 mockLogger properly implements the updated Logger interface with context-aware methods. Capturing warnings at line 32 is useful for specific test assertions.


119-131: Test correctly validates new ExecutionContext API.

The test properly exercises the updated NewExecutionContext signature with map[string]interface{} and validates field access via EventData.


541-542: Good use of context-based event ID correlation.

Tests consistently use logger.WithEventID(context.Background(), ...) before calling Execute, 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 event package is only used at lines 312 and 319 to create a CloudEvent and set its data via evt.SetData(event.ApplicationJSON, eventData), but the evt variable is never referenced afterward. Since eventData is 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: ParseEventData is 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 EventData and 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 of WithError including 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 use t.Setenv.

Using t.Setenv ensures 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.

Copy link

@coderabbitai coderabbitai bot left a 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: nullValue is no longer null.

The test case "access field on null returns error in result (safe)" at lines 182-188 expects nullValue to be null, but it's set to testLog() (a logger instance). This changes the test semantics - the test still passes because accessing .field on 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: K8sClient is documented as optional in types.go (line 62: "optional, can be nil if not needed"), but validateExecutorConfig includes it in requiredFields and rejects nil values. Remove "K8sClient" from the requiredFields slice 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 finishWithError method has ctx as the last parameter (line 190), which violates Go conventions where context.Context should 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.NewClient are 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 from NewClient is 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 shared logger.NewTestLogger() instead of duplicating the pattern.

This testLog() helper duplicates the pattern from pkg/logger/test_support.go with 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 evt variable is created and SetData is called, but only eventData is 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

📥 Commits

Reviewing files that changed from the base of the PR and between 4ca8360 and 20ef0c6.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (38)
  • cmd/adapter/main.go
  • go.mod
  • internal/config_loader/loader.go
  • internal/config_loader/validator.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/criteria/test_helpers_test.go
  • internal/executor/README.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/precondition_executor.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/k8s_client/client.go
  • internal/k8s_client/discovery.go
  • pkg/logger/context.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/test_support.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/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.go
  • internal/config_loader/validator.go
  • cmd/adapter/main.go
  • internal/executor/executor.go
  • internal/executor/utils_test.go
  • internal/config_loader/loader.go
  • internal/executor/types.go
  • internal/hyperfleet_api/client.go
  • test/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 in NewTestLogger() 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 waitForAPIServerReady function uses a direct HTTP health check which is more reliable than Kubernetes client operations during API server initialization. Good security practice to set MinVersion: tls.VersionTLS12 alongside the necessary InsecureSkipVerify for 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 contextKey type prevents collisions
  • Defensive copy in GetLogFields prevents external mutation
  • Typed setters provide a clean API for common fields
  • WithDynamicResourceID offers flexible resource ID naming

The copy-on-write approach in WithLogField/WithLogFields ensures 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.Setenv for 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 ManifestItems are rejected with appropriate error messages.

pkg/logger/test_support.go (1)

1-29: LGTM! Well-implemented test logger singleton.

The implementation correctly uses sync.Once for 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 NewEvaluator signature with context.Background(), the evaluation context, and testLog(). 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. All NewEvaluator calls are properly updated to the new three-parameter signature.

internal/hyperfleet_api/client_test.go (1)

38-43: LGTM!

The NewClient calls are correctly updated to pass testLog() 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 ExecuteLogAction signature by passing context.Background() and using logger.NewTestLogger() for the logger parameter.

internal/criteria/cel_evaluator_test.go (2)

12-20: LGTM!

The test function is correctly renamed to Test_newCELEvaluator to reflect the now-private constructor, and the signature update to pass context.Background(), evaluation context, and testLog() is correct.


438-444: LGTM!

The NewEvaluator call in the integration test correctly uses the three-parameter signature.

internal/criteria/evaluator.go (3)

54-70: LGTM!

The updated NewEvaluator constructor 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 getCELEvaluator method 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 to evalCtx.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 deepCopyMap signature that accepts context.Context and logger.Logger parameters. The pattern deepCopyMap(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 ExecuteLogAction function now correctly accepts and propagates context.Context to 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 ExecuteAPICall now properly pass the context parameter. The log levels are appropriate:

  • Infof for operation start/completion
  • Warnf for timeout parsing issues and retryable failures
  • Errorf for 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:staticcheck for intentional nil context)
  • nil evalCtx
  • nil log

This 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 NewEvaluator calls now use the three-parameter signature NewEvaluator(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 newCELEvaluator is correctly made unexported since it's only created internally by Evaluator. The comment on lines 57-58 clearly documents that parameter validation is the caller's responsibility, which aligns with NewEvaluator's panic behavior for nil params.


18-23: LGTM! CELEvaluator struct updated for context-aware logging.

The struct now properly separates:

  • evalCtx for evaluation data context
  • ctx for Go context (used in logging)
  • log for the logger instance

164-176: LGTM! Safe evaluation with context-aware debug logging.

The evaluation correctly uses e.evalCtx.Data() for CEL evaluation data and e.ctx with e.log.Debugf for 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 ResourceRef and EventData types provide clear, typed representations of HyperFleet CloudEvent payloads. JSON tags are correctly defined with omitempty for optional fields.


75-76: LGTM! Logger field added to Executor.

The log field 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 createAPIClient function now accepts and propagates the logger to hyperfleet_api.NewClient, enabling context-aware logging throughout the API client lifecycle.

internal/config_loader/validator.go (3)

65-71: LGTM! Constructor appropriately unexported.

The newValidator function is now unexported since validation is invoked internally through runValidationPipeline in the loader (as shown in the relevant code snippet from internal/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 DynType since actual types are only known at runtime. Syntax validation via Parse() is sufficient to catch malformed expressions during config loading.


409-431: LGTM! Recursive build expression validation.

The validateBuildExpressions helper 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 NewClient function 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 NewClient handles the fallback logic internally.


202-221: LGTM! Retry logging with appropriate levels.

The retry loop correctly uses:

  • Warnf for failed attempts and retryable status codes
  • Infof for retry delay notifications
internal/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 ExecuteAll method properly uses the internal logger (pe.log) with context throughout. Error handling correctly populates ExecutionError and 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 stdout and stderr only 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 buildArgs method properly merges logger instance fields with context-derived fields, enabling flexible field attachment at both logger creation and call site. The flat structure extracted from LogFieldsKey aligns with the context helpers in pkg/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 NewClient was being ignored. This has been correctly fixed with require.NoError.


988-1008: LGTM - Test logger properly implements context-aware interface.

The logCaptureLogger correctly 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 NewExecutor and 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 ExecuteAll method 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 ctx and log parameters 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 NewExecutor and 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 ExecuteAll method correctly:

  • Builds payloads first with proper error handling
  • Executes actions sequentially with context-aware logging
  • Populates ExecutionError on 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 buildPostPayloads method 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.

@xueli181114 xueli181114 force-pushed the log-refactor branch 2 times, most recently from 6c0e49c to 0e0f0d0 Compare December 25, 2025 02:35
Copy link

@coderabbitai coderabbitai bot left a 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: nullValue is not null.

Setting nullValue to logger.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: ctx should be first.

The finishWithError method has ctx context.Context as the last parameter, which is unconventional in Go. This was flagged in a previous review. Consider moving ctx to 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), K8sClient is 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 from requiredFields.

🔎 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: copyFields comment 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.

WithDynamicResourceID derives 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 text or log after 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 with logger.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 evaluations
pkg/logger/logger.go (1)

238-242: Consider adding Fatalf for 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 using require.NoError instead of assert.NoError for 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 than assert.NoError (which continues execution) for critical setup steps.

This pattern is inconsistent across the file - some places use require.NoError (line 95) while others use assert.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.log calls should be indented consistently with the surrounding code block.

For example, lines 79-80, 85-86, 99-102 have re.log at 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

📥 Commits

Reviewing files that changed from the base of the PR and between 20ef0c6 and 6c0e49c.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (38)
  • REFACTORING_PLAN.md
  • cmd/adapter/main.go
  • go.mod
  • internal/config_loader/loader.go
  • internal/config_loader/validator.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/executor/README.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/precondition_executor.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/k8s_client/client.go
  • internal/k8s_client/discovery.go
  • pkg/logger/context.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/test_support.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/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.go
  • internal/executor/utils_test.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/config_loader/validator.go
  • internal/criteria/evaluator_test.go
  • internal/hyperfleet_api/client.go
  • internal/executor/executor.go
  • cmd/adapter/main.go
  • test/integration/executor/executor_integration_test.go
  • internal/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 ResourceRef and EventData types 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.

NewExecutionContext signature changed from accepting evt *event.Event to eventData 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 GetLogFields function 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 TestNewLoggerInvalidOutput to verify that invalid output configurations are properly rejected with errors.


70-175: LGTM! Fluent API tests are thorough.

The tests for With, WithFields, and WithError verify 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 via GetLogFields.

test/integration/k8s_client/helper_envtest_prebuilt.go (1)

100-100: LGTM! Updated to use test logger utility.

The change from logger.NewLogger(ctx) to logger.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:

  1. Uses logger.NewTestLogger() for test logging (line 775)
  2. Passes context.Background() as the first argument to ExecuteLogAction (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 changing NewValidator to newValidator does 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 including TestExecutor_CELExpressionEvaluation and TestCELEvaluatorEvaluate already 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 NewEvaluator signature with context.Background() and logger.NewTestLogger(), following the new API contract.


53-53: LGTM!

Consistent usage of the updated NewEvaluator API.


80-80: LGTM!

Consistent usage of the updated NewEvaluator API.


147-147: LGTM!

Consistent usage of the updated NewEvaluator API.

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 NewEvaluator signature.


121-121: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


134-138: LGTM!

Good practice to create isolated EvaluationContext and Evaluator per subtest to avoid shared state mutation issues.


171-171: LGTM!

Consistent usage of the updated NewEvaluator API.


211-211: LGTM!

Consistent usage of the updated NewEvaluator API.


262-262: LGTM!

Consistent usage of the updated NewEvaluator API.


342-342: LGTM!

Consistent usage of the updated NewEvaluator API.

internal/hyperfleet_api/client_test.go (1)

40-43: LGTM!

The NewClient call 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.VersionTLS12 ensures 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 uses sync.Once for thread-safe singleton initialization with "error" level to minimize test noise
  • LogCapture provides proper mutex protection for concurrent access
  • NewCaptureLogger() uses "debug" level to capture all log messages for assertions
  • The Contains() method correctly delegates to Messages() for thread-safe access
test/integration/executor/executor_k8s_integration_test.go (8)

318-322: LGTM!

The NewClient call correctly passes the logger as the first parameter and properly handles the error return with require.NoError(t, err).


471-472: LGTM!

Consistent usage of the updated NewClient API with proper error handling.


578-579: LGTM!

Consistent usage of the updated NewClient API with proper error handling.


649-650: LGTM!

Consistent usage of the updated NewClient API with proper error handling.


707-708: LGTM!

Consistent usage of the updated NewClient API with proper error handling.


755-756: LGTM!

Consistent usage of the updated NewClient API with proper error handling.


910-911: LGTM!

Consistent usage of the updated NewClient API with proper error handling.


974-975: LGTM!

Consistent usage of the updated NewClient API 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 NewEvaluator signature.


612-612: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


773-789: LGTM!

Comprehensive panic tests for all three nil parameter cases. The nolint:staticcheck comment is appropriate since passing nil context is intentional to verify the panic behavior.


802-802: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


827-827: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


848-848: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


884-884: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


935-935: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


961-961: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


986-986: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


1032-1032: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.


1086-1086: LGTM!

Correctly updated to use the three-parameter NewEvaluator signature.

internal/executor/utils.go (3)

36-70: LGTM! Context-aware logging properly threaded through ExecuteLogAction.

The addition of ctx context.Context as 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 to ExecuteAPICall.

All logging statements properly pass ctx as the first parameter, maintaining consistency with the new logger.Logger interface. 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, and contains are cosmetic only.

internal/executor/resource_executor_test.go (2)

10-33: LGTM! Tests correctly updated to new deepCopyMap signature.

All test functions consistently pass context.Background() and testLog() to match the updated function signature. Test assertions remain valid.


156-176: Test renamed appropriately to reflect verification purpose.

The renamed test TestDeepCopyMap_DeepCopyVerification with 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 *EvaluationContext for CEL evaluation data
  • ctx context.Context for logging context

This separation is appropriate - Go context for request lifecycle/logging, EvaluationContext for CEL variables.


56-73: Constructor correctly wires context and evaluation context.

The newCELEvaluator function properly initializes all fields. The function is now unexported (lowercase n), which is appropriate since it's called internally by NewEvaluator.


163-176: Context-aware logging in EvaluateSafe is correct.

Line 164 properly uses e.evalCtx.Data() for evaluation, and line 168 uses e.ctx for 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_newCELEvaluator follows 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.

NewEvaluator calls properly include context.Background() and logger.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, and log-output provide 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 fatalErrCh with a non-blocking send. This prevents the goroutine from blocking if an error was already sent.


305-334: LGTM! createAPIClient properly accepts and propagates logger.

The signature update and passing log to hyperfleet_api.NewClient completes 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 testEventWithData has been addressed.


101-113: LGTM! Test correctly uses map-based event data.

NewExecutionContext is properly called with eventData map, and assertions check execCtx.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 passing eventData map to Execute follows the new contract where the caller is responsible for context enrichment.


291-384: Test still creates CloudEvent but only uses its data.

TestParamExtractor creates a CloudEvent and calls evt.SetData() (line 301), but then only passes eventData map to NewExecutionContext (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.Logger field 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:

  1. Parses event data via ParseEventData
  2. Enriches context with resource IDs for logging
  3. Creates execution context with raw data
  4. Logs each phase appropriately

243-287: LGTM! ParseEventData handles multiple input types correctly.

The function properly handles:

  • nil input (returns empty data)
  • []byte (JSON bytes)
  • map[string]interface{} (already parsed)
  • Other types (attempts JSON marshaling)

Both structured EventData and raw map are returned for flexible access.


220-240: LGTM! CreateHandler correctly enriches context with event ID.

The handler:

  1. Attaches event ID to context via logger.WithEventID
  2. Logs event metadata
  3. Passes event data to Execute
  4. 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 NewLogger function 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 deepCopyMap function appropriately:

  1. Uses copystructure.Copy for proper deep copying
  2. Falls back to shallow copy on error with a warning log
  3. 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 NewExecutor is responsible for config validation. This is the same pattern used in precondition_executor.go and resource_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 ExecuteAll method correctly:

  1. Builds payloads first, failing fast on errors
  2. Executes actions sequentially, stopping on first failure
  3. Sets ExecutionError with phase/step context for debugging
  4. 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 processValue method 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.

Copy link

@coderabbitai coderabbitai bot left a 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: nullValue should be nil, not a logger instance.

Line 157 sets nullValue to logger.NewTestLogger(), but the test case at lines 183-189 named "access field on null returns error in result (safe)" expects nullValue to 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: ctx should be first.

Go convention places context.Context as the first parameter. Having it last in finishWithError is 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 K8sClient to be non-nil (line 39), but types.go (line 62-63) documents it as "optional, can be nil if not needed". Either:

  1. Remove K8sClient from requiredFields to match the documentation, or
  2. Update the documentation in types.go to 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), ctx is 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 using context.Background() for shutdown logging.

pkg/logger/context.go (1)

38-60: Consider performance for high-frequency logging paths.

WithLogField and WithLogFields create a copy of the existing fields map on every call via GetLogFields. While this provides immutability, chaining multiple WithLogField calls 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 like mapstructure for 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, nil

This 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 panic for 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 using require.NoError for critical setup failures.

Using assert.NoError here means the test will continue executing even if client creation fails, potentially causing nil pointer panics later. Consider using require.NoError for 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.NoError for hyperfleet_api.NewClient error checking (lines 232, 336, 449, 498, 551, 602, 635, 669, 734, 787, 918, 988, 1163, 1301), while others use require.NoError (line 95). For setup code that would cause nil pointer panics if it fails, require.NoError is preferred to fail fast with a clear error message.

Consider standardizing on require.NoError for all client creation error checks.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c0e49c and 0e0f0d0.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (37)
  • cmd/adapter/main.go
  • go.mod
  • internal/config_loader/loader.go
  • internal/config_loader/validator.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/executor/README.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/precondition_executor.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/k8s_client/client.go
  • internal/k8s_client/discovery.go
  • pkg/logger/context.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/test_support.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/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.go
  • cmd/adapter/main.go
  • internal/criteria/evaluator_test.go
  • internal/executor/utils_test.go
  • internal/config_loader/loader.go
  • internal/hyperfleet_api/client.go
  • internal/executor/executor.go
  • internal/config_loader/validator.go
  • internal/criteria/evaluator_version_test.go
  • internal/executor/types.go
  • internal/criteria/evaluator_scenarios_test.go
  • test/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/tls and net/http imports 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 NewLogger implementation properly validates configuration and handles output selection. By restricting outputs to stdout and stderr (or custom io.Writer), the previously flagged file handle leak concern is avoided by design.


177-196: LGTM!

The buildArgs method 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 NewLogger is comprehensive, including success cases with various configurations and error cases for invalid output.


148-175: LGTM!

The TestLoggerWithError function 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 passing context.Background() to ExecuteLogAction, 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 NewEvaluator signature with context.Background() and logger.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 NewEvaluator signature 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. The newValidator(config) approach removes the logger dependency entirely—the Validator struct contains no logger field, and the Validate() 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 context and logger imports aligns with the new API requirements.


47-47: LGTM! Evaluator initialization updated consistently.

All NewEvaluator calls 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 NewClient calls have been correctly updated to:

  1. Pass testLog() as the first parameter
  2. Capture the error return value
  3. 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.Once initialization 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 to NewClient, 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 centralizes PostActionExecutor creation 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 the pae instance (e.g., pae.buildPayload, pae.log), aligning with the updated API where these are receiver methods on PostActionExecutor.

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_newCELEvaluator correctly reflects that newCELEvaluator is 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()) or NewEvaluator(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 NewValidator to newValidator (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 DynType and 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 TestNewEvaluatorPanicsWithNilParams now covers all three nil-parameter cases:

  1. nil ctx
  2. nil evalCtx
  3. nil log

This provides better coverage of the constructor's parameter validation.


525-525: LGTM! All evaluator instantiations updated consistently.

All NewEvaluator calls 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:

  • evalCtx holds evaluation data
  • ctx provides context for propagation (cancellation, tracing, etc.)
  • log is the logger instance

This 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:

  1. Accepts ctx, evalCtx, and log parameters
  2. Uses evalCtx to build CEL options (line 60)
  3. 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.ctx for 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 ResourceRef and EventData types are cleanly defined with appropriate JSON tags and omitempty directives. 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 log field to the Executor struct enables context-aware logging throughout the executor lifecycle.


254-265: Simplified constructor aligns with data-driven approach.

The NewExecutionContext signature change from accepting *event.Event to just map[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 NewClient constructor properly:

  1. Accepts a logger as the first parameter for dependency injection
  2. Falls back to environment variable for base URL when not provided via options
  3. 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 of APIVersionFromEnv().

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 createAPIClient function properly accepts and forwards the logger to hyperfleet_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 NewExecutionContext signature accepting eventData as a map, and validates that EventData is properly accessible from the context.


270-289: Good test pattern for context-based event correlation.

Using logger.WithEventID(context.Background(), "test-event-123") before calling Execute demonstrates the expected pattern for callers to add event IDs to context for logging correlation.


291-384: Thorough param extraction test coverage.

The TestParamExtractor tests comprehensively cover various parameter sources (env, event, nested event) and edge cases (defaults, missing required). The NewExecutionContext call at line 354 correctly uses the new signature.

pkg/logger/context.go (3)

8-29: Well-designed context key structure.

Using a custom contextKey type 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.

WithDynamicResourceID nicely 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 LogFields map in GetLogFields is 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 Execute method now:

  1. Parses event data into both structured and raw forms
  2. Enriches context with resource IDs for logging correlation
  3. 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.

CreateHandler correctly adds the event ID to context using logger.WithEventID before calling Execute, ensuring all downstream logs are correlated with the event.

internal/criteria/evaluator.go (3)

40-51: Clear struct field organization.

The Evaluator struct now cleanly separates:

  • evalCtx: the data context for field lookups
  • ctx: the request context for logging correlation
  • log: the logger instance

This separation of concerns is well-designed.


72-93: Lazy CEL evaluator with version tracking.

The getCELEvaluator method properly:

  1. Uses mutex for thread safety
  2. Checks context version to detect modifications
  3. 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 to evalCtx.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 new deepCopyMap signature.

All test functions correctly updated to pass context.Background() and testLog() to match the new context-aware deepCopyMap signature. 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 NewExecutor as 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.NewClient is now properly captured and validated with require.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 NewClient error handling and NewCaptureLogger to 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 NewExecutor as 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 ExecutionError for API and parse failures
  • Integrates with criteria.NewEvaluator with proper context and logger

203-212: LGTM on executeAPICall delegation.

The method correctly delegates to the shared ExecuteAPICall utility 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 postConfig gracefully
  • Logs and propagates payload build failures
  • Sets ExecutionError with 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 ExecuteAPICall utility
  • Captures response details even on error for debugging
  • Creates appropriate ExecutorError with phase/step context

20-27: Constructor design is correct - validation is enforced at the entry point.

NewExecutor explicitly validates the config via validateExecutorConfig before calling any sub-executor constructors (line 18 of executor.go). This checks for nil config and required fields including APIClient and Logger. 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 with newResourceExecutor and newPreconditionExecutor.

Copy link

@coderabbitai coderabbitai bot left a 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: nullValue should be nil, not a logger.

The test case "access field on null returns error in result (safe)" (lines 183-189) expects nullValue to be null to verify null-safe error handling. Setting it to testLog() 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 gofmt or go fmt on 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: Fatal calls os.Exit(1) which is difficult to test.

This is a common pattern for fatal logging. Consider documenting that tests should not exercise Fatal directly, or optionally inject an exit function for testability.

internal/hyperfleet_api/client_test.go (1)

22-36: Consider using logger.NewTestLogger() for consistency.

The testLog() helper duplicates the singleton pattern already provided by logger.NewTestLogger() in pkg/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 sync import 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 OwnedReference exists:

  • 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 contextKey type prevents collisions
  • Consistent pattern across all With* functions
  • Defensive copy in GetLogFields prevents external mutation of the map

Minor observation: GetLogFields performs 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

📥 Commits

Reviewing files that changed from the base of the PR and between 0e0f0d0 and a546970.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (37)
  • cmd/adapter/main.go
  • go.mod
  • internal/config_loader/loader.go
  • internal/config_loader/validator.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/executor/README.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/precondition_executor.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/k8s_client/client.go
  • internal/k8s_client/discovery.go
  • pkg/logger/context.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/test_support.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/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.go
  • cmd/adapter/main.go
  • internal/config_loader/validator.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/executor/executor.go
  • internal/executor/utils_test.go
  • test/integration/executor/executor_integration_test.go
  • internal/criteria/evaluator_test.go
  • internal/executor/types.go
  • internal/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/tls and net/http imports 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 InsecureSkipVerify is correctly documented and necessary for envtest self-signed certificates. Setting MinVersion to 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 context and the logger package to support the new NewEvaluator signature.


47-47: LGTM!

The NewEvaluator call correctly uses the new 3-parameter signature with context.Background(), the evaluation context, and the test logger.


121-121: Consistent API usage across all test functions.

All NewEvaluator instantiations follow the same pattern, correctly passing context.Background(), the evaluation context, and logger.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 of Check(). This is the right approach since variables are declared as DynType and their actual types are only known at runtime. The documentation clearly explains this design decision.


409-431: LGTM!

The validateBuildExpressions helper 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 deepCopyMap call correctly includes context.Background() and testLog() as the new signature requires. The testLog() helper is defined in the executor package and is accessible to this test file.

pkg/logger/logger.go (5)

13-41: LGTM!

The Logger interface 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 Config struct provides good flexibility with the optional Writer field for testing scenarios while maintaining simple defaults for production use.


100-161: LGTM!

The NewLogger constructor correctly:

  • Validates output options and returns an error for invalid values
  • Supports custom io.Writer for testing
  • Builds hostname from multiple sources with sensible fallbacks
  • Creates the underlying slog.Logger with base fields

177-196: LGTM!

The buildArgs method correctly merges fields from both the logger instance and the context's LogFields. The capacity pre-allocation is a nice optimization.


244-254: LGTM!

The copyFields function 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 NewLogger with various configuration options including default config, JSON format, and text format with different outputs.


57-68: LGTM!

Correctly validates that NewLogger returns an error for invalid output values.


70-175: LGTM!

Comprehensive tests for With, WithFields, and WithError methods including the edge case of WithError(nil) returning the same logger instance.


386-423: LGTM!

Good test coverage for ConfigFromEnv using t.Setenv which properly restores environment variables after each test. Tests verify case-insensitive handling of environment variable values.


425-450: LGTM!

The parseLevel tests 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 context and logger packages to support the new NewEvaluator signature.


73-73: LGTM!

The NewEvaluator call correctly uses the new 3-parameter signature with context.Background(), the evaluation context, and the test logger.


158-158: Consistent API usage across all integration tests.

All NewEvaluator instantiations 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 NewEvaluator signature requirements.


18-18: Consistent API usage across version tracking tests.

All NewEvaluator instantiations correctly use context.Background(), the evaluation context, and logger.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 NewClient call 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 NewClient instantiations correctly pass testLog() as the first parameter, maintaining consistency with the updated NewClient(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 ExecuteLogAction signature that requires a context parameter. The use of logger.NewTestLogger() and context.Background() is appropriate for test scenarios.

test/integration/executor/executor_k8s_integration_test.go (1)

318-322: LGTM! NewClient API updated consistently.

All NewClient invocations throughout the test file have been correctly updated to:

  1. Pass testLog() as the first parameter (new logger requirement)
  2. 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.Context as the first parameter (breaking API change noted in PR objectives)
  • Consistently passes ctx to 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 newCELEvaluator have been correctly updated to pass:

  • context.Background() as the first parameter
  • The evaluation context as the second parameter
  • logger.NewTestLogger() as the third parameter

This 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 NewEvaluator panics 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 NewEvaluator throughout the test file have been correctly updated to pass the three required parameters:

  1. context.Background() for the context
  2. The evaluation context (ctx)
  3. logger.NewTestLogger() for the logger

This 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.Once initialization 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 create PostActionExecutor instances 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, and log 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.ctx for 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.Logger as 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 ResourceRef and EventData types provide a clean abstraction for CloudEvent payloads, replacing direct CloudEvent dependencies. The JSON tags are properly defined for serialization.


253-264: All call sites for NewExecutionContext have been properly updated to use the new signature. Verified 9 call sites across executor_test.go, executor.go, and post_action_executor_test.go, and all correctly pass only ctx and eventData parameters.

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. The hyperfleet_api.NewClient signature correctly accepts logger.Logger as the first parameter, and the implementation in cmd/adapter/main.go:334 uses 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 of execCtx.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 validateExecutorConfig function 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:

  • nil data → returns empty EventData and map
  • []byte → parses JSON
  • map[string]interface{} → marshals and unmarshals for consistency
  • Other types → attempts JSON marshaling

The dual return of structured EventData and raw map[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.NewClient is now captured and checked with require.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 using logCapture.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 getCELEvaluator method 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 newPreconditionExecutor constructor properly extracts the API client and logger from the ExecutorConfig. 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.ExecutionError with 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 requires context.Context as 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 newResourceExecutor constructor correctly extracts the K8s client and logger from the ExecutorConfig. The comment notes that NewExecutor handles 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.Copy for 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 ctx to all logging calls (lines 38, 40, 49, 56, 61, 73)
  • Passes ctx to 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.Context as a parameter
  • Propagate ctx through all recursive calls:
    • buildPostPayloadsbuildPayloadbuildMapPayload/processValue (lines 100, 123, 126, 144, 174, 178, 183)
    • executePostActionexecuteAPICall (lines 214, 225)
  • Pass ctx to evaluator creation (line 86)
  • Pass ctx to utility functions like ExecuteLogAction and ExecuteAPICall (lines 208, 225)
  • Use pae.log with ctx for all logging

The 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 NewExecutor function validates the ExecutorConfig parameter via validateExecutorConfig() before calling newPostActionExecutor(config) at line 26 of executor.go. The validation checks that config is 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.

Copy link

@coderabbitai coderabbitai bot left a 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: nullValue is no longer null.

The test case at lines 183-189 ("access field on null returns error in result (safe)") expects nullValue to be nil to test null value access behavior. Setting it to logger.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 resourceType to lowercase and appends "_id", but if resourceType is 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 using logger.NewTestLogger() instead of defining a local testLog().

This local testLog() duplicates the functionality of logger.NewTestLogger() from pkg/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

📥 Commits

Reviewing files that changed from the base of the PR and between a546970 and a9035f3.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (37)
  • cmd/adapter/main.go
  • go.mod
  • internal/config_loader/loader.go
  • internal/config_loader/validator.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/executor/README.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/precondition_executor.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/k8s_client/client.go
  • internal/k8s_client/discovery.go
  • pkg/logger/context.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/test_support.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/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.go
  • internal/criteria/evaluator_version_test.go
  • internal/criteria/evaluator_scenarios_test.go
  • cmd/adapter/main.go
  • internal/executor/utils_test.go
  • internal/executor/executor.go
  • internal/criteria/evaluator_test.go
  • test/integration/executor/executor_integration_test.go
  • internal/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
  • pkg/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 uses sync.Once for 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 NewClient invocations throughout the test file have been correctly updated to pass testLog() 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 NewEvaluator calls throughout the test file have been properly updated to:

  1. Pass context.Background() as the first parameter
  2. Pass the evaluation context
  3. Pass logger.NewTestLogger() for test logging
  4. Check for errors via require.NoError

This 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 passes context.Background() as the first parameter to ExecuteLogAction, 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. Using logger.NewTestLogger() aligns with the shared test logger pattern in pkg/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 NewEvaluator signature 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.NewClient calls are correctly updated to pass the logger as the first argument and handle the returned error. This aligns with the new client signature shown in internal/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 in pkg/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 deepCopyMap calls are correctly updated to include context.Background() and testLog(), 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_newCELEvaluator correctly reflects that it's testing the unexported newCELEvaluator function. 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 constructing PostActionExecutor instances 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 NewEvaluator error cases. Testing all three nil parameter scenarios (ctx, evalCtx, log) ensures the constructor's validation logic is properly verified. The nolint:staticcheck comment 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 using require.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 with sync.Once to avoid creating multiple instances
  • LogCapture is thread-safe with proper mutex usage
  • NewCaptureLogger() 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 ParseEventData function correctly handles multiple input types:

  • Empty/nil inputs return empty structures
  • []byte (JSON) is parsed directly
  • map[string]interface{} is marshaled then parsed
  • Other types are marshaled as JSON

The dual return of both structured EventData and raw map[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:

  1. Create a logger that writes to a buffer (line 842)
  2. Wire it into the executor (line 922)
  3. Inspect captured logs using logCapture.Contains() and logCapture.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:

  1. Payload build failures are logged as errors (lines 1346-1350)
  2. Post actions are blocked when payload building fails (line 1332)
  3. ExecutionError is populated correctly (lines 1335-1343)
  4. The error is logged with appropriate context

The log inspection correctly checks for both level=ERROR and failed to build patterns 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:

  1. Creates event data as a map (lines 271-273) instead of a CloudEvent
  2. Passes context with event ID via logger.WithEventID() (line 276)
  3. 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:

  1. Requires all parameters (ctx, evalCtx, log) and validates they're non-nil
  2. Returns an error instead of panicking, allowing graceful handling
  3. 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:

  1. Checks if the evaluation context version has changed (line 81)
  2. Recreates the CEL evaluator when the context is modified (lines 84-90)
  3. 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:

  1. Accepts ExecutorConfig instead of individual parameters
  2. Wires the logger from the centralized config (line 26)
  3. 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:

  1. Calls criteria.NewEvaluator(ctx, evalCtx, pe.log) with all required parameters
  2. Checks for errors from the constructor (lines 145-149)
  3. 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:

  1. Logger creation with default config
  2. Logger creation with JSON format
  3. Logger creation with text format
  4. 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:

  1. Context helper functions (WithEventID, WithClusterID, WithTraceID) properly add fields to context (lines 361-383)
  2. ConfigFromEnv() respects environment variables and provides sensible defaults (lines 386-423)
  3. 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 in executor.go where validateExecutorConfig() checks all required fields including Logger and APIClient.

This design centralizes validation logic and avoids duplication across executor constructors.


81-89: LGTM! Proper error handling for evaluator creation.

The code correctly:

  1. Calls criteria.NewEvaluator(ctx, evalCtx, pae.log) with the new signature
  2. Handles the error return (lines 87-89)
  3. 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 ExecutorConfig properly centralizes initialization and enables context-aware logging throughout the executor.


35-55: LGTM! Context-aware logging properly integrated.

The ExecuteAll method correctly threads context through to executeResource and uses the internal logger with context for all logging statements.


161-200: LGTM! Context and logger properly propagated.

The buildManifest method correctly passes context and the internal logger to deepCopyMap, enabling context-aware logging for copy failures.


308-332: LGTM! Recreate flow properly context-aware.

The recreateResource method 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 waitForDeletion method 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 deepCopyMap function correctly accepts context and logger parameters, enabling context-aware warning logs when deep copy falls back to shallow copy.

@xueli181114 xueli181114 force-pushed the log-refactor branch 2 times, most recently from b29668b to 1442108 Compare December 25, 2025 03:43
Copy link

@coderabbitai coderabbitai bot left a 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: nullValue should be nil, not a logger instance.

The test case at lines 183-189 ("access field on null returns error in result (safe)") expects nullValue to be null to verify null-access handling, but line 157 sets it to logger.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.

GetLogFields handles nil context (line 120-122), but WithLogField will panic if ctx is nil due to context.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: Replace testLog() with logger.NewTestLogger() to eliminate duplication.

The testLog() function duplicates the test logger pattern already provided by logger.NewTestLogger() in pkg/logger/test_support.go. The only difference is the output destination (stdout vs stderr), 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 ExecutorConfig without 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

📥 Commits

Reviewing files that changed from the base of the PR and between a9035f3 and 1442108.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (37)
  • cmd/adapter/main.go
  • go.mod
  • internal/config_loader/loader.go
  • internal/config_loader/validator.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/executor/README.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/precondition_executor.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/k8s_client/client.go
  • internal/k8s_client/discovery.go
  • pkg/logger/context.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/test_support.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/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.go
  • internal/executor/types.go
  • internal/criteria/evaluator_test.go
  • cmd/adapter/main.go
  • internal/hyperfleet_api/client.go
  • internal/executor/executor.go
  • internal/config_loader/validator.go
  • test/integration/executor/executor_integration_test.go
  • internal/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.go
  • pkg/logger/logger_test.go
  • internal/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 NewEvaluator signature with proper error handling. The pattern NewEvaluator(context.Background(), ctx, logger.NewTestLogger()) with require.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.

validateBuildExpressions correctly 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 NewValidator unexported is safe; no external packages depend on it. Callers use newValidator(config).Validate() internally.

pkg/logger/context.go (2)

119-131: LGTM on defensive copy.

GetLogFields correctly 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: WithDynamicResourceID field naming looks good.

The dynamic field naming pattern (strings.ToLower(resourceType) + "_id") produces consistent field names like cluster_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 NewEvaluator API. 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 waitForAPIServerReady using HTTP health checks against /healthz is more reliable during startup than the previous approach. The TLS configuration with InsecureSkipVerify is appropriate for envtest's self-signed certificates, and the nolint:gosec annotation properly documents this intentional choice.

internal/executor/resource_executor_test.go (2)

19-19: LGTM!

All deepCopyMap calls correctly updated to include context.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_DeepCopyVerification properly 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 ExecuteLogAction properly 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 ExecuteAPICall now 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 NewEvaluator now properly pass context.Background(), the evaluation context, and logger.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.Once ensures 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 LogCapture type 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.

NewCaptureLogger appropriately 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 ResourceRef and EventData structs 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 log field to the Executor struct 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 NewExecutionContext and 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 ctx field and renaming to evalCtx properly separates concerns: ctx for Go context propagation and evalCtx for 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 newCELEvaluator signature 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 and e.log.Debugf(e.ctx, ...) for context-aware logging on evaluation failure.

internal/executor/executor_test.go (3)

38-65: LGTM! Tests correctly use logger.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.NewClient API 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 NewClient signature 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.

ParseEventData handles multiple input types ([]byte, map, arbitrary types) gracefully, with clear error messages for each failure path. The dual return of structured EventData and 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 NewEvaluator signature with explicit error returns for nil parameters follows Go best practices. The separation of ctx (for logging correlation) and evalCtx (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, and Without methods 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 buildArgs method 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 err is 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 with result != log), validating the optimization behavior.


386-423: LGTM: Environment variable tests with proper isolation.

Using t.Setenv ensures 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 NewEvaluator call 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() and logCapture.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=ERROR format 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 log field eliminates parameter passing
  • All logging calls now include context for better observability
  • deepCopyMap signature enhanced with context and logger for diagnostic fallback warnings
  • Constructor properly wired via ExecutorConfig

The 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 log field eliminates redundant parameter threading
  • NewEvaluator now 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

Copy link

@coderabbitai coderabbitai bot left a 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 in Contains method.

The Contains method calls c.Messages() which acquires the lock, but strings.Contains operates on the returned string after the lock is released. If another goroutine writes to the buffer between Messages() returning and the Contains check 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 - ctx is placed after log instead 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 evt and calls evt.SetData(), but evt is never used - the test only uses eventData map. 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 TestParamExtractor to 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 NewClient function 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1442108 and 1ca3777.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (37)
  • cmd/adapter/main.go
  • go.mod
  • internal/config_loader/loader.go
  • internal/config_loader/validator.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/executor/README.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/precondition_executor.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/k8s_client/client.go
  • internal/k8s_client/discovery.go
  • pkg/logger/context.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/test_support.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/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.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • cmd/adapter/main.go
  • test/integration/executor/executor_integration_test.go
  • internal/config_loader/validator.go
  • internal/executor/executor.go
  • internal/executor/types.go
  • internal/hyperfleet_api/client.go
  • internal/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.go
  • internal/executor/resource_executor.go
  • pkg/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 via newValidator(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 newValidator unexported is consistent with the refactored validation flow where callers use Parse() for config loading with validation, rather than directly instantiating validators. The related test updates in validator_test.go confirm 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 validateBuildExpressions helper 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:

  • GetLogFields returns a copy of the fields map (lines 125-128)
  • WithLogField retrieves the copy, modifies it, and stores in a new context (lines 40-46)
  • All helper functions properly delegate through WithLogField

This 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 ctx as 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 ExecuteLogAction signature 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 NewEvaluator have been properly updated to pass:

  • context.Background() as the first parameter
  • logger.NewTestLogger() as the logger parameter

This 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 new NewClient signature.

The client creation now passes testLog() as the first argument and properly handles the returned error with require.NoError. This aligns with the API change where NewClient now requires a logger parameter.


471-472: LGTM!

Consistent update to the new API signature with proper error handling.


578-579: LGTM! All remaining NewClient call sites correctly updated.

All test functions consistently:

  1. Pass testLog() as the first argument
  2. Capture the error return value
  3. 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.Once pattern 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! All NewClient calls 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 context and logger imports are necessary for the updated NewEvaluator constructor signature.

Also applies to: 7-7


47-48: LGTM! All evaluator instantiations correctly updated.

Each NewEvaluator call now:

  1. Passes context.Background() as the first argument
  2. Uses logger.NewTestLogger() for the logger parameter
  3. 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 context and logger imports enable the updated NewEvaluator constructor calls.

Also applies to: 17-17


73-74: LGTM! Integration test evaluator calls correctly updated.

All NewEvaluator instantiations 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 waitForAPIServerReady function is well-implemented:

  • HTTP client with appropriate timeout (5s per request)
  • TLS 1.2 minimum version for security
  • InsecureSkipVerify is necessary for envtest self-signed certs (correctly annotated with nolint)
  • 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.Once pattern as other test files, ensuring consistent logger initialization.


36-42: LGTM! Clean test factory for PostActionExecutor.

The testPAE() helper encapsulates the executor construction with proper config, making tests cleaner and more maintainable. Using newMockAPIClient() as the default is appropriate for unit tests.


45-45: LGTM! Payload and value processing tests updated.

Tests now:

  1. Use testPAE() to get a configured executor
  2. Pass pae.log to NewEvaluator, ensuring consistent logging
  3. Call executor methods (buildPayload, buildMapPayload, processValue) via the pae instance

Also applies to: 117-120, 134-134, 223-225, 239-239, 349-351


438-441: LGTM! ExecuteAll and ExecuteAPICall tests updated.

The tests correctly:

  1. Create executors via newPostActionExecutor with proper config
  2. Use testLog() where standalone logger is needed
  3. Pass context to NewExecutionContext

Also applies to: 445-445, 655-655, 663-663

internal/criteria/evaluator_test.go (3)

4-4: LGTM! Required imports added.

The context and logger imports 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 argument
  • logger.NewTestLogger() for logger parameter
  • require.NoError(t, err) for error handling

Also 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:staticcheck comment appropriately suppresses the intentional nil context warning

This 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.Once ensures 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.

NewCaptureLogger properly 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 ExecuteLogAction function 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 newCELEvaluator function correctly:

  1. Builds CEL options from the evaluation context
  2. Creates the CEL environment with proper error handling
  3. 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:

  1. Uses e.evalCtx.Data() to get a thread-safe snapshot of the data
  2. Captures evaluation errors in the result rather than returning them (safe mode)
  3. Uses the stored context for debug logging
internal/executor/types.go (3)

40-54: LGTM - Well-defined event data types.

The new ResourceRef and EventData structs provide a clean internal representation of CloudEvent payloads, decoupling the executor from the CloudEvents SDK. JSON tags are properly configured with omitempty for optional fields.


68-75: LGTM - Logger integration in Executor.

Adding the log field to the Executor struct 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.Event parameter simplifies the API. Event data is now passed directly as a map, and event IDs are propagated via context (using logger.WithEventID as 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 on execCtx.EventData instead of the removed Event field.


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 to NewClient.


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:

  1. Bootstrap logger for early startup (before config is loaded)
  2. 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 TestNewCELEvaluator to Test_newCELEvaluator to follow Go conventions for testing unexported functions (using underscore prefix).


150-160: LGTM - nullValue test case is correct.

The past review flagged that nullValue was incorrectly set to testLog(). This has been properly fixed - line 157 now correctly sets ctx.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 to NewExecutor. 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) and evalCtx (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.NewClient is now properly captured and asserted with require.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. The logCapture.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.Context as 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) when err == nil avoids 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 NewExecutor is responsible for config validation. This is consistent with newPreconditionExecutor and newResourceExecutor, creating a uniform pattern across all sub-executors. The past review concern about nil config is addressed by centralized validation in validateExecutorConfig.


81-89: Good error handling for evaluator creation.

The evaluator creation now properly handles errors and propagates them with context, aligning with the updated NewEvaluator signature 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.

Copy link

@coderabbitai coderabbitai bot left a 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 nullValue was incorrectly set to testLog() instead of nil. The current code correctly sets nullValue to nil, 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: run gofmt -w on 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.go

Also 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 same gofmt fix 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.Do returns 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 calls Messages(), which acquires the lock, then strings.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 data is already a map[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, nil
pkg/logger/logger.go (1)

179-198: Potential field key collision between logger fields and context fields.

When both l.fields and context's LogFields contain 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1ca3777 and 1f522a1.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (37)
  • cmd/adapter/main.go
  • go.mod
  • internal/config_loader/loader.go
  • internal/config_loader/validator.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/executor/README.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/precondition_executor.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/k8s_client/client.go
  • internal/k8s_client/discovery.go
  • pkg/logger/context.go
  • pkg/logger/logger.go
  • pkg/logger/logger_test.go
  • pkg/logger/test_support.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/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.go
  • internal/criteria/evaluator_version_test.go
  • internal/criteria/evaluator_test.go
  • internal/config_loader/validator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/executor/executor.go
  • cmd/adapter/main.go
  • internal/executor/types.go
  • test/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
  • internal/executor/resource_executor.go
  • pkg/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 DynType at 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 NewEvaluator signature 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.Once ensures 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.NewClient calls 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 NewEvaluator API 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 NewEvaluator rejects nil parameters with appropriate error messages. The nolint:staticcheck comment 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 ExecuteLogAction consistently 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 ExecuteAPICall have 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 newCELEvaluator cleanly separates concerns by using ctx for control flow (logging) and evalCtx for 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.Once ensures 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 ResourceRef and EventData types 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 of NewExecutionContext have been correctly updated to use the new signature (ctx, eventData). The verification found 9 call sites across executor.go and 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 testEventWithData has 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 TestExecutionContext test correctly validates the new NewExecutionContext(ctx, eventData) signature and verifies that EventData map access works as expected.


270-289: LGTM!

The TestExecute_ParamExtraction test properly demonstrates the new pattern: using logger.WithEventID to attach event ID to context for logging correlation, then passing the map-based event data to Execute. This aligns well with the PR's objective of context-aware logging.

internal/executor/executor.go (2)

30-47: LGTM!

The validateExecutorConfig function 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 that K8sClient is 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:

  1. Create initial config from environment variables
  2. Override with command-line flags if provided
  3. Create bootstrap logger before config load
  4. 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 createAPIClient function signature correctly updated to accept the logger parameter, which is then passed to hyperfleet_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 Evaluator struct field renaming from context to evalCtx clarifies the purpose (evaluation data context vs. Go context). The new ctx field for Go context propagation enables context-aware logging in CEL evaluation.


53-71: LGTM!

The updated NewEvaluator constructor:

  1. Now requires all three parameters (ctx, evalCtx, log) with explicit validation
  2. Returns (*Evaluator, error) for proper error handling
  3. 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 both e.ctx and e.evalCtx to newCELEvaluator correctly threads both context types through.

internal/executor/precondition_executor.go (3)

21-28: LGTM!

The newPreconditionExecutor constructor 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 NewEvaluator signature returns an error, and this is properly handled here. The error case correctly sets the result status and returns an appropriate ExecutorError.


32-62: LGTM!

The ExecuteAll method 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 NewClient error is now properly handled with require.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() and logCapture.Contains() is clean and readable. The test properly checks for expected log messages with the [config] prefix.


1300-1350: LGTM!

The TestExecutor_PayloadBuildFailure test properly uses the capture logger to verify error logging behavior. The assertions checking for level=ERROR and failed to build ensure the logging subsystem correctly reports payload build failures.

pkg/logger/logger.go (4)

13-43: LGTM!

The Logger interface 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
  • WithError is a no-op for nil errors, avoiding unnecessary allocations

102-163: LGTM!

The NewLogger function:

  • 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 Fatal method logs then calls os.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 Fatal which would terminate the test process.


246-256: LGTM!

The copyFields function 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 contextKey type prevents collisions with other packages' context keys.


38-60: LGTM!

The WithLogField and WithLogFields functions properly:

  1. Retrieve existing fields (or initialize new map)
  2. Add/update the field(s)
  3. Return new context with updated fields

This pattern enables incremental field addition throughout the request lifecycle.


62-67: LGTM!

WithDynamicResourceID is 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.

Copy link

@coderabbitai coderabbitai bot left a 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 NewClient function now requires a logger.Logger as the first parameter, which is a good design aligned with the k8s_client pattern. However, unlike the validation done for BaseURL, there's no nil check for the logger. If a nil logger is passed, subsequent c.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 using require.NoError instead of assert.NoError.

This test uses assert.NoError which 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) use require.NoError for 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 NewClient and 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 with level=ERROR literal). 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: deepCopyMap fallback 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1f522a1 and 70b5cfd.

📒 Files selected for processing (47)
  • internal/config_loader/accessors.go
  • internal/config_loader/constants.go
  • internal/config_loader/loader_test.go
  • internal/config_loader/types.go
  • internal/config_loader/validator_test.go
  • internal/criteria/cel_evaluator.go
  • internal/criteria/cel_evaluator_test.go
  • internal/criteria/evaluator.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/criteria/evaluator_test.go
  • internal/criteria/evaluator_version_test.go
  • internal/criteria/types.go
  • internal/executor/executor_test.go
  • internal/executor/param_extractor.go
  • internal/executor/post_action_executor_test.go
  • internal/executor/resource_executor.go
  • internal/executor/resource_executor_test.go
  • internal/executor/types.go
  • internal/executor/utils_test.go
  • internal/hyperfleet_api/client.go
  • internal/hyperfleet_api/client_test.go
  • internal/hyperfleet_api/mock.go
  • internal/hyperfleet_api/types.go
  • internal/k8s_client/data_extractor.go
  • internal/k8s_client/discovery.go
  • internal/k8s_client/interface.go
  • internal/k8s_client/mock.go
  • internal/k8s_client/test_helpers_test.go
  • internal/k8s_client/types.go
  • internal/k8s_client/types_test.go
  • pkg/errors/cel_error.go
  • pkg/errors/error_test.go
  • pkg/errors/k8s_error.go
  • pkg/errors/k8s_error_test.go
  • pkg/errors/network_error.go
  • pkg/errors/network_error_test.go
  • pkg/logger/logger_test.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • test/integration/executor/executor_integration_test.go
  • test/integration/executor/executor_k8s_integration_test.go
  • test/integration/executor/main_test.go
  • test/integration/executor/setup_test.go
  • test/integration/k8s_client/helper_envtest_prebuilt.go
  • test/integration/k8s_client/helper_selector.go
  • test/integration/k8s_client/main_test.go
  • test/integration/testutil/container.go
  • test/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.go
  • test/integration/config-loader/config_criteria_integration_test.go
  • internal/criteria/evaluator_scenarios_test.go
  • internal/hyperfleet_api/client.go
  • internal/executor/types.go
  • test/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.go
  • pkg/logger/logger_test.go
  • internal/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 ctx as the first argument, aligning with the new Logger interface 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 context and logger imports are necessary to support the new NewEvaluator signature.

Also applies to: 17-17


73-74: LGTM! Consistent adaptation to new Evaluator API.

All NewEvaluator calls are correctly updated to the new signature (context.Context, *EvaluationContext, logger.Logger) (*Evaluator, error) with proper error handling via require.NoError. Using context.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 NewEvaluator calls 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_newCELEvaluator correctly reflects that newCELEvaluator is 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 NewEvaluator calls 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 centralizes PostActionExecutor construction 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.log for NewEvaluator ensures 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 newPostActionExecutor with ExecutorConfig containing the mock client and test logger, and NewExecutionContext is called with the updated signature.


636-644: LGTM! ExecuteAPICall tests updated.

The test correctly passes logger.NewTestLogger() as the logger parameter to ExecuteAPICall, aligning with the updated function signature.

internal/hyperfleet_api/client.go (3)

17-17: LGTM! Logger integration into httpClient.

The logger import and new log field 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.log with 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 NewLogger returns an error for unsupported output values.


70-175: LGTM! Fluent API tests are well-designed.

The With, WithFields, and WithError tests 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, WithTraceID helpers properly attach fields to context
  • GetLogFields retrieves 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.

  • parseLevel tests 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 with require.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.

  • TestVersionIncrements validates all scenarios (new key, same value, different value, merge)
  • TestNoVersionChangeNoRecreate verifies evaluator instance is reused when context unchanged and recreated when modified
test/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 via require.NoError.


471-479: LGTM! Consistent API client initialization across all integration tests.

All test functions properly use hyperfleet_api.NewClient(testLog()) with require.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 k8sTestAPIServer fields 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 deepCopyMap function now receives context.Background() and logger.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 waitForAPIServerReady function is well-implemented:

  • Uses HTTP client with 5s timeout per request
  • Properly configures TLS with InsecureSkipVerify for self-signed envtest certs (documented with nolint: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.

ResourceRef and EventData provide clean, typed structures for HyperFleet CloudEvent payloads:

  • JSON tags with omitempty allow flexible serialization
  • OwnedReference pointer enables optional nested ownership tracking
  • Fields align with HyperFleet API conventions

68-75: LGTM! Logger field added to Executor.

Adding log logger.Logger to the Executor struct 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.Event with EventData map[string]interface{}
  • Simplify NewExecutionContext(ctx, eventData) constructor
  • Initialize all required fields including the new Evaluations slice

This 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 configs
  • k8s_client.NewMockK8sClient() for valid config case
  • Proper error expectations for missing dependencies

82-113: LGTM! Builder and ExecutionContext tests updated.

  • Builder test uses NewTestLogger() and NewMockK8sClient()
  • TestExecutionContext correctly uses map-based event data and validates execCtx.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 CELEvaluator struct now properly distinguishes:

  • evalCtx *EvaluationContext: Holds CEL evaluation data (variables, version tracking)
  • ctx context.Context: Standard Go context for logging, cancellation, and tracing

This separation improves clarity and enables proper context-aware logging.


56-73: LGTM! Constructor properly wires both contexts.

The unexported newCELEvaluator function correctly:

  • Documents that caller (NewEvaluator) handles validation
  • Builds CEL options from evalCtx
  • Initializes all fields including both evalCtx and ctx

Making this unexported is appropriate since NewEvaluator is 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 using logCapture.Messages() and logCapture.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 NewEvaluator constructor 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 getCELEvaluator method 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 use evalCtx.

All field accessor methods (GetField, GetFieldOrDefault, GetFieldSafe, HasField) consistently use e.evalCtx.GetNestedField() for data access. This aligns with the architectural change to separate the Go context from the evaluation context.


141-143: Field accessor in EvaluateConditionWithResult also 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 for ExecuteAll.

The method now uses re.log instead 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 in executeResource.

All logging within executeResource uses the context-aware pattern (re.log.Debugf(ctx, ...), re.log.Infof(ctx, ...), etc.). This enables log correlation across the resource execution flow.


159-198: buildManifest now accepts context for logging.

The method signature correctly includes ctx context.Context which is passed to deepCopyMap. This maintains the context-aware logging pattern throughout the call chain.


306-330: recreateResource uses internal logger consistently.

The method no longer requires an explicit log parameter and uses re.log for all logging. The context-aware logging is properly applied throughout the delete-wait-create flow.


24-31: Constructor properly validates configuration including K8sClient.

The NewExecutor function correctly validates the config by calling validateExecutorConfig() before instantiating child executors, including newResourceExecutor(). The K8sClient field is explicitly included in the required fields validation (line 39), ensuring it cannot be nil when passed to newResourceExecutor().

Copy link

@coderabbitai coderabbitai bot left a 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 NewExecutor is responsible for config validation. This is consistent with the pattern in precondition_executor.go and resource_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 NewExecutor performs 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 K8sClient validation was marked as addressed in commit 4ca8360.

The validation concern was previously raised and addressed. The comment correctly documents that NewExecutor is 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 newCELEvaluator is unexported, the test should be named Test_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

📥 Commits

Reviewing files that changed from the base of the PR and between 2bd9cc6 and 88189ab.

📒 Files selected for processing (4)
  • internal/criteria/cel_evaluator_test.go
  • internal/executor/post_action_executor.go
  • internal/executor/precondition_executor.go
  • internal/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.Context and logger.Logger parameters. 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 ExecuteAll method 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.NewEvaluator properly 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 ExecuteAPICall utility, properly passing the internal logger and API client.

internal/executor/post_action_executor.go (4)

29-77: LGTM!

The ExecuteAll method 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 deepCopyMap for 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 NotFound as successful deletion
  • Informative logging at each step

Copy link

@coderabbitai coderabbitai bot left a 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 in NewExecutor. 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.Name as 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

📥 Commits

Reviewing files that changed from the base of the PR and between 88189ab and 05734f1.

📒 Files selected for processing (5)
  • cmd/adapter/main.go
  • internal/criteria/cel_evaluator_test.go
  • internal/executor/post_action_executor.go
  • internal/executor/precondition_executor.go
  • internal/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.go
  • internal/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.go
  • internal/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 context and logger imports 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 newCELEvaluator calls have been correctly updated to the new three-parameter signature with context.Background() and logger.NewTestLogger(). The use of context.Background() is appropriate for test scenarios, and logger.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 NewEvaluator calls have been properly updated to handle the new error return value. Using require.NoError is 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 nullValue is properly set to nil, 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 buildLoggerConfig function 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 ExecuteAll method 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 newPreconditionExecutor constructor safely assumes config.APIClient and config.Logger are non-nil because NewExecutor explicitly validates both fields via validateExecutorConfig() 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: buildPayloadbuildMapPayloadprocessValue, 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 that K8sClient validation was added to NewExecutor, 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 executeResource method 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()))

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?

@86254860
Copy link

/lgtm

@openshift-ci
Copy link

openshift-ci bot commented Dec 26, 2025

[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

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants