Skip to content

Add test to verify dep output#62

Open
eemcmullan wants to merge 2 commits into
konveyor:mainfrom
eemcmullan:dep-output
Open

Add test to verify dep output#62
eemcmullan wants to merge 2 commits into
konveyor:mainfrom
eemcmullan:dep-output

Conversation

@eemcmullan

@eemcmullan eemcmullan commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Tests can now validate dependency outputs generated by analysis tools.
    • Added support for defining target-specific expected dependencies (Kantra and Tackle Hub).
  • Tests

    • Added test coverage for dependency file normalization and validation.
    • Added expected dependency fixtures for the book-server test scenario.

Signed-off-by: Emily McMullan <emcmulla@redhat.com>
@eemcmullan
eemcmullan requested a review from shawn-hurley March 31, 2026 17:58
@coderabbitai

coderabbitai Bot commented Mar 31, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The changes introduce a comprehensive dependency handling system for the test framework, adding configuration fields, parsing/normalization utilities, validation logic, and enhanced Hub integration to support dependency manifest generation and validation for both Kantra and Hub targets.

Changes

Cohort / File(s) Summary
Configuration & Type System
pkg/config/types.go, pkg/config/loader.go
Added DepFileKantra, DepFileHub, DepItemsKantra, DepItemsHub fields to ExpectedOutput; new ExpectedDepItemsForTarget() method; new LoadExpectedDependencies() helper to load and parse dependency YAML files.
Dependency Parsing & Normalization
pkg/parser/deps.go, pkg/parser/deps_test.go
Introduced ParseDependencies() and NormalizeDepsFlat() functions for reading YAML dependency files and deterministically normalizing dependency items (URI paths, sorting by FileURI/Provider/dependency fields); includes test coverage for URI and path normalization.
Dependency Validation
pkg/validator/deps.go
Added ValidateDependenciesFlat() to validate actual dependencies against expected ones, reporting missing/mismatched dependencies and unexpected extra entries via structured error paths.
CLI Command Enhancements
pkg/cli/generate.go, pkg/cli/run.go
Extended generate command to conditionally parse and save normalized dependency files (expected-deps-*.yaml); extended run command to validate parsed dependencies against expected items when available, failing test or appending validation errors accordingly.
Hub Target Integration
pkg/targets/tackle_hub.go, pkg/targets/tackle_hub_attachments.go
Added hubTechDependenciesToDepsFlat() converter for Hub dependencies; new writeHubDependenciesOutput() routine to retrieve, extract, and write Hub dependency manifests from task attachments or API, with fallback sequence; modified task mode configuration based on DepFileHub presence; eliminated redundant API calls.
Test Infrastructure & Fixtures
Makefile, tests/book-server-deps/test.yaml, tests/book-server-deps/expected-deps-*.yaml
Updated test archive target to include new dependency YAML files; extended test expectations with dep-file-kantra and dep-file-hub references; added comprehensive expected dependency fixtures for Hub and Kantra targets (Maven project with ~70 dependencies each).

Sequence Diagram(s)

sequenceDiagram
    participant Test Framework
    participant Config Loader
    participant Kantra/Hub Target
    participant Parser
    participant Validator
    participant CLI Output

    Test Framework->>Config Loader: Load test definition + expected deps
    Config Loader->>Config Loader: LoadExpectedDependencies() for kantra/hub
    Config Loader-->>Test Framework: Return test config with DepItems

    alt Generate Command
        Test Framework->>Kantra/Hub Target: Execute analysis
        Kantra/Hub Target->>Kantra/Hub Target: Emit dependencies.yaml
        Test Framework->>Parser: ParseDependencies(dependencies.yaml)
        Parser-->>Test Framework: Parsed DepsFlatItem list
        Test Framework->>Parser: NormalizeDepsFlat(parsed, testDir)
        Parser-->>Test Framework: Normalized & sorted items
        Test Framework->>CLI Output: Save expected-deps-*.yaml
    end

    alt Run Test Command
        Test Framework->>Kantra/Hub Target: Execute analysis
        Kantra/Hub Target->>Kantra/Hub Target: Emit dependencies.yaml
        Test Framework->>Parser: ParseDependencies(dependencies.yaml)
        Parser-->>Test Framework: Parsed actual deps
        Test Framework->>Parser: NormalizeDepsFlat(actual, testDir)
        Parser-->>Test Framework: Normalized actual deps
        Test Framework->>Validator: ValidateDependenciesFlat(actual, expected)
        Validator-->>Test Framework: ValidationResult with errors
        Test Framework->>Test Framework: Update test result (pass/fail)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Hops excitedly

Dependencies now aligned with care,
Hub and Kantra both prepared to share,
Normalized paths and sorted with precision,
Validation flows make every decision clear,
Archive extraction hops without a fear! 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is generic and vague, referring only to adding 'a test to verify dep output' without clarifying the substantial scope of changes that extend beyond test additions to include dependency parsing, validation, and output handling infrastructure. Consider a more descriptive title such as 'Add dependency output parsing and validation' or 'Implement dependency manifest generation for test verification' to better reflect the extensive code changes in addition to test files.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
pkg/parser/deps.go (2)

74-82: Consider strings.TrimPrefix instead of ReplaceAll.

strings.ReplaceAll replaces all occurrences of testDir in the path. If testDir appears elsewhere in the path (e.g., in a directory name), it could cause unintended modifications.

Suggested fix using TrimPrefix
 func normalizeDepsPathLike(s, testDir string) string {
 	if s == "" || testDir == "" {
 		return NormalizePath(s)
 	}
 	normalizedTestDir := filepath.ToSlash(testDir)
 	s = filepath.ToSlash(s)
-	s = strings.ReplaceAll(s, normalizedTestDir, "")
+	s = strings.TrimPrefix(s, normalizedTestDir)
 	return NormalizePath(s)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/parser/deps.go` around lines 74 - 82, The function normalizeDepsPathLike
currently uses strings.ReplaceAll to strip normalizedTestDir from s which can
remove occurrences beyond the path prefix; update normalizeDepsPathLike to use
strings.TrimPrefix on the filepath.ToSlash(s) with normalizedTestDir so only a
leading testDir is removed, then pass the result to NormalizePath; keep the
existing empty-string guard and use filepath.ToSlash for both inputs as before.

31-60: Unused error return value.

The function signature returns an error, but the function always returns nil. Either propagate errors from internal operations (e.g., line 70 ignores error from normalizeIncident), or simplify the signature to return only []konveyor.DepsFlatItem.

Option 1: Simplify signature if errors aren't expected
-func NormalizeDepsFlat(items []konveyor.DepsFlatItem, testDir string) ([]konveyor.DepsFlatItem, error) {
+func NormalizeDepsFlat(items []konveyor.DepsFlatItem, testDir string) []konveyor.DepsFlatItem {

(Would require updating callers accordingly)

Option 2: Propagate errors from normalizeIncident
 func normalizeDepsFileURI(s, testDir string) string {
+func normalizeDepsFileURI(s, testDir string) (string, error) {
 	if s == "" {
-		return s
+		return s, nil
 	}
 	if !strings.Contains(s, "file://") {
-		return NormalizePath(normalizeDepsPathLike(s, testDir))
+		return NormalizePath(normalizeDepsPathLike(s, testDir)), nil
 	}
 	inc := konveyor.Incident{URI: uri.URI(s)}
-	out, _ := normalizeIncident(inc, testDir)
-	return string(out.URI)
+	out, err := normalizeIncident(inc, testDir)
+	if err != nil {
+		return "", err
+	}
+	return string(out.URI), nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/parser/deps.go` around lines 31 - 60, The NormalizeDepsFlat function
currently returns ([]konveyor.DepsFlatItem, error) but never returns a non-nil
error; either remove the error from the signature or actually propagate errors
from the internal normalization helpers. Pick one: (A) simplify the signature of
NormalizeDepsFlat to return only []konveyor.DepsFlatItem and update all callers,
or (B) change calls to normalizeDepsFileURI, normalizeDepExtrasMap and any
normalizeIncident usage inside NormalizeDepsFlat to capture and check returned
errors and return them (e.g., if normalizeDepsFileURI or normalizeDepExtrasMap
can fail, handle the error and return nil, err). Update the signature and
callers consistently so the unused error return is eliminated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/cli/generate.go`:
- Around line 233-248: The code currently only sets test.Expect.Output.DepFile
when dependencies.yaml exists and leaves any prior value in place when it does
not, and it silently ignores os.Stat errors other than "not found"; update the
block around depsOutPath and os.Stat so that: if os.Stat returns nil, parse and
save as before (using parser.ParseDependencies and saveNormalizedDepsFlat) and
set test.Expect.Output.DepFile = "expected-deps-output.yaml"; if os.Stat signals
"not found" (os.IsNotExist), explicitly clear test.Expect.Output.DepFile (set to
empty string) to avoid stale values; if os.Stat returns any other error, treat
it as a failure (log via color.Red or increment failCount and continue) rather
than ignoring it. Ensure references to depsOutPath, parser.ParseDependencies,
saveNormalizedDepsFlat, and test.Expect.Output.DepFile are used to locate and
modify the logic.

In `@tests/book-server-deps/expected-deps-output.yaml`:
- Around line 1-759: The baseline fixture is polluted with environment-specific
absolute URIs (notably the fileURI field "file:///opt/input/source/pom.xml" and
many prefix values like "file:///addon/.m2/repository/..."); update the YAML
fixture (tests/book-server-deps/expected-deps-output.yaml) to use normalized,
non-machine-specific values by removing or replacing absolute paths in the
fileURI and prefix fields (e.g., use relative paths or a stable placeholder such
as "<REPO_ROOT>/pom.xml" and "<M2_REPO>/..."), and ensure the generator that
created this fixture emits those normalized forms for the fileURI and prefix
fields so the baseline no longer churns on environment changes.

---

Nitpick comments:
In `@pkg/parser/deps.go`:
- Around line 74-82: The function normalizeDepsPathLike currently uses
strings.ReplaceAll to strip normalizedTestDir from s which can remove
occurrences beyond the path prefix; update normalizeDepsPathLike to use
strings.TrimPrefix on the filepath.ToSlash(s) with normalizedTestDir so only a
leading testDir is removed, then pass the result to NormalizePath; keep the
existing empty-string guard and use filepath.ToSlash for both inputs as before.
- Around line 31-60: The NormalizeDepsFlat function currently returns
([]konveyor.DepsFlatItem, error) but never returns a non-nil error; either
remove the error from the signature or actually propagate errors from the
internal normalization helpers. Pick one: (A) simplify the signature of
NormalizeDepsFlat to return only []konveyor.DepsFlatItem and update all callers,
or (B) change calls to normalizeDepsFileURI, normalizeDepExtrasMap and any
normalizeIncident usage inside NormalizeDepsFlat to capture and check returned
errors and return them (e.g., if normalizeDepsFileURI or normalizeDepExtrasMap
can fail, handle the error and return nil, err). Update the signature and
callers consistently so the unused error return is eliminated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5ce36ced-2294-431d-bb14-0566fcb81cfa

📥 Commits

Reviewing files that changed from the base of the PR and between c7a407f and b83792e.

📒 Files selected for processing (10)
  • Makefile
  • pkg/cli/generate.go
  • pkg/cli/run.go
  • pkg/config/loader.go
  • pkg/config/types.go
  • pkg/parser/deps.go
  • pkg/parser/deps_test.go
  • pkg/validator/deps.go
  • tests/book-server-deps/expected-deps-output.yaml
  • tests/book-server-deps/test.yaml

Comment thread pkg/cli/generate.go
Comment on lines +233 to +248
depsOutPath := filepath.Join(filepath.Dir(result.OutputFile), "dependencies.yaml")
if _, statErr := os.Stat(depsOutPath); statErr == nil {
depsList, err := parser.ParseDependencies(depsOutPath)
if err != nil {
color.Red(" ✗ Failed to parse dependencies.yaml: %v", err)
failCount++
continue
}
expectedDepsFile := filepath.Join(testDirPath, "expected-deps-output.yaml")
if err := saveNormalizedDepsFlat(depsList, expectedDepsFile, testDirPath); err != nil {
color.Red(" ✗ Failed to save expected dependencies: %v", err)
failCount++
continue
}
test.Expect.Output.DepFile = "expected-deps-output.yaml"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Clear stale dep-file and handle non-ENOENT Stat failures.

At Line 247, DepFile is only assigned when dependencies.yaml exists, but it is never reset when it does not. Regeneration can therefore preserve a stale dep-file from prior runs and trigger false validation failures later. Also, non-not found stat errors are currently ignored.

🔧 Proposed fix
 import (
 	"context"
+	"errors"
 	"fmt"
 	"os"
 	"path/filepath"
 	"strings"
@@
-				depsOutPath := filepath.Join(filepath.Dir(result.OutputFile), "dependencies.yaml")
-				if _, statErr := os.Stat(depsOutPath); statErr == nil {
+				depsOutPath := filepath.Join(filepath.Dir(result.OutputFile), "dependencies.yaml")
+				test.Expect.Output.DepFile = ""
+				if _, statErr := os.Stat(depsOutPath); statErr == nil {
 					depsList, err := parser.ParseDependencies(depsOutPath)
 					if err != nil {
 						color.Red("  ✗ Failed to parse dependencies.yaml: %v", err)
@@
 					}
 					test.Expect.Output.DepFile = "expected-deps-output.yaml"
+				} else if !errors.Is(statErr, os.ErrNotExist) {
+					color.Red("  ✗ Failed to stat dependencies.yaml: %v", statErr)
+					failCount++
+					continue
 				}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
depsOutPath := filepath.Join(filepath.Dir(result.OutputFile), "dependencies.yaml")
if _, statErr := os.Stat(depsOutPath); statErr == nil {
depsList, err := parser.ParseDependencies(depsOutPath)
if err != nil {
color.Red(" ✗ Failed to parse dependencies.yaml: %v", err)
failCount++
continue
}
expectedDepsFile := filepath.Join(testDirPath, "expected-deps-output.yaml")
if err := saveNormalizedDepsFlat(depsList, expectedDepsFile, testDirPath); err != nil {
color.Red(" ✗ Failed to save expected dependencies: %v", err)
failCount++
continue
}
test.Expect.Output.DepFile = "expected-deps-output.yaml"
}
depsOutPath := filepath.Join(filepath.Dir(result.OutputFile), "dependencies.yaml")
test.Expect.Output.DepFile = ""
if _, statErr := os.Stat(depsOutPath); statErr == nil {
depsList, err := parser.ParseDependencies(depsOutPath)
if err != nil {
color.Red(" ✗ Failed to parse dependencies.yaml: %v", err)
failCount++
continue
}
expectedDepsFile := filepath.Join(testDirPath, "expected-deps-output.yaml")
if err := saveNormalizedDepsFlat(depsList, expectedDepsFile, testDirPath); err != nil {
color.Red(" ✗ Failed to save expected dependencies: %v", err)
failCount++
continue
}
test.Expect.Output.DepFile = "expected-deps-output.yaml"
} else if !errors.Is(statErr, os.ErrNotExist) {
color.Red(" ✗ Failed to stat dependencies.yaml: %v", statErr)
failCount++
continue
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/cli/generate.go` around lines 233 - 248, The code currently only sets
test.Expect.Output.DepFile when dependencies.yaml exists and leaves any prior
value in place when it does not, and it silently ignores os.Stat errors other
than "not found"; update the block around depsOutPath and os.Stat so that: if
os.Stat returns nil, parse and save as before (using parser.ParseDependencies
and saveNormalizedDepsFlat) and set test.Expect.Output.DepFile =
"expected-deps-output.yaml"; if os.Stat signals "not found" (os.IsNotExist),
explicitly clear test.Expect.Output.DepFile (set to empty string) to avoid stale
values; if os.Stat returns any other error, treat it as a failure (log via
color.Red or increment failCount and continue) rather than ignoring it. Ensure
references to depsOutPath, parser.ParseDependencies, saveNormalizedDepsFlat, and
test.Expect.Output.DepFile are used to locate and modify the logic.

Comment on lines +1 to +759
- name: org.springframework.spring-expression
version: 5.1.2.RELEASE
type: compile
indirect: true
resolvedIdentifier: 7f45b616d59579e07c44ae01b5fc5821db19b322
extras:
artifactId: spring-expression
baseDep:
extras:
artifactId: spring-boot-starter-web
groupId: org.springframework.boot
pomPath: /opt/input/source/pom.xml
name: org.springframework.boot.spring-boot-starter-web
version: 2.1.0.RELEASE
groupId: org.springframework
pomPath: /opt/input/source/pom.xml
labels:
- konveyor.io/dep-source=open-source
- konveyor.io/language=java
prefix: file:///addon/.m2/repository/org/springframework/spring-expression/5.1.2.RELEASE
- name: org.springframework.spring-jcl
version: 5.1.2.RELEASE
type: compile
indirect: true
resolvedIdentifier: b35f3aeb0afcc782ec7a1c1f1ab8325fb7a9e223
extras:
artifactId: spring-jcl
baseDep:
extras:
artifactId: spring-boot-starter-web
groupId: org.springframework.boot
pomPath: /opt/input/source/pom.xml
name: org.springframework.boot.spring-boot-starter-web
version: 2.1.0.RELEASE
groupId: org.springframework
pomPath: /opt/input/source/pom.xml
labels:
- konveyor.io/dep-source=open-source
- konveyor.io/language=java
prefix: file:///addon/.m2/repository/org/springframework/spring-jcl/5.1.2.RELEASE
- name: org.springframework.spring-web
version: 5.1.2.RELEASE
type: compile
indirect: true
resolvedIdentifier: ed47f5756ab15e223ac5cb4993beb8bfa5adc130
extras:
artifactId: spring-web
baseDep:
extras:
artifactId: spring-boot-starter-web
groupId: org.springframework.boot
pomPath: /opt/input/source/pom.xml
name: org.springframework.boot.spring-boot-starter-web
version: 2.1.0.RELEASE
groupId: org.springframework
pomPath: /opt/input/source/pom.xml
labels:
- konveyor.io/dep-source=open-source
- konveyor.io/language=java
prefix: file:///addon/.m2/repository/org/springframework/spring-web/5.1.2.RELEASE
- name: org.springframework.spring-webmvc
version: 5.1.2.RELEASE
type: compile
indirect: true
resolvedIdentifier: ee1900a33a5376cb0b9514cc29db80aa6bf7c291
extras:
artifactId: spring-webmvc
baseDep:
extras:
artifactId: spring-boot-starter-web
groupId: org.springframework.boot
pomPath: /opt/input/source/pom.xml
name: org.springframework.boot.spring-boot-starter-web
version: 2.1.0.RELEASE
groupId: org.springframework
pomPath: /opt/input/source/pom.xml
labels:
- konveyor.io/dep-source=open-source
- konveyor.io/language=java
prefix: file:///addon/.m2/repository/org/springframework/spring-webmvc/5.1.2.RELEASE
- name: org.yaml.snakeyaml
version: "1.23"
type: runtime
indirect: true
resolvedIdentifier: 0542a3f938aebd15b1ae655c89344835e502a87d
extras:
artifactId: snakeyaml
baseDep:
extras:
artifactId: spring-boot-starter-web
groupId: org.springframework.boot
pomPath: /opt/input/source/pom.xml
name: org.springframework.boot.spring-boot-starter-web
version: 2.1.0.RELEASE
groupId: org.yaml
pomPath: /opt/input/source/pom.xml
labels:
- konveyor.io/dep-source=open-source
- konveyor.io/language=java
prefix: file:///addon/.m2/repository/org/yaml/snakeyaml/1.23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fixture appears non-canonical for a “normalized deps output” baseline.

Line 1 (file:///opt/input/source/...) and many prefix entries (e.g., Line 23 with file:///addon/.m2/...) are environment-specific. This makes the committed baseline noisier than necessary and likely to churn when regenerated via the new normalized generation flow.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/book-server-deps/expected-deps-output.yaml` around lines 1 - 759, The
baseline fixture is polluted with environment-specific absolute URIs (notably
the fileURI field "file:///opt/input/source/pom.xml" and many prefix values like
"file:///addon/.m2/repository/..."); update the YAML fixture
(tests/book-server-deps/expected-deps-output.yaml) to use normalized,
non-machine-specific values by removing or replacing absolute paths in the
fileURI and prefix fields (e.g., use relative paths or a stable placeholder such
as "<REPO_ROOT>/pom.xml" and "<M2_REPO>/..."), and ensure the generator that
created this fixture emits those normalized forms for the fileURI and prefix
fields so the baseline no longer churns on environment changes.

Signed-off-by: Emily McMullan <emcmulla@redhat.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
pkg/targets/tackle_hub_attachments.go (1)

125-135: Deferred cleanup inside loop accumulates until function returns.

The defer os.RemoveAll(sub) at line 129 is inside the loop, so all temp directories accumulate until findDepsYAMLInTree returns. With many tar archives, this could temporarily consume more disk space than necessary.

♻️ Optional: extract to helper for immediate cleanup
+func (t *TackleHubTarget) tryExtractDepsFromTar(tarPath string) (string, error) {
+	sub, err := os.MkdirTemp("", "koncur-hub-tar-*")
+	if err != nil {
+		return "", err
+	}
+	defer os.RemoveAll(sub)
+	if err := extractTarArchive(tarPath, sub); err != nil {
+		return "", fmt.Errorf("extract %s: %w", filepath.Base(tarPath), err)
+	}
+	if p, err := walkForDepsYAML(sub); err == nil {
+		// Copy file out before cleanup
+		dst, _ := os.CreateTemp("", "deps-*.yaml")
+		dst.Close()
+		if err := copyFile(p, dst.Name()); err != nil {
+			return "", err
+		}
+		return dst.Name(), nil
+	}
+	return "", os.ErrNotExist
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/targets/tackle_hub_attachments.go` around lines 125 - 135, The defer
os.RemoveAll(sub) inside the loop in findDepsYAMLInTree causes all temp dirs
created by os.MkdirTemp to remain until the function returns; change the logic
so each temporary directory is removed immediately after it's no longer needed:
create the temp dir (os.MkdirTemp), call extractTarArchive and then call
walkForDepsYAML on it, and if walkForDepsYAML returns a path return it after
removing the temp dir, otherwise remove the temp dir immediately (or encapsulate
the extract+inspect+cleanup into a helper that ensures os.RemoveAll(sub) runs
before continuing); reference extractTarArchive, walkForDepsYAML and
os.RemoveAll to locate and implement the change.
pkg/config/types.go (1)

143-159: Consider documenting behavior for unsupported target types.

The method handles "tackle-hub" and "kantra" explicitly, with a default case falling back to DepItemsKantra. For other target types ("tackle-ui", "kai-rpc", "vscode"), if only DepFileHub is configured (without DepFileKantra), the method returns nil, false, silently skipping dependency validation.

This asymmetry may be intentional (those targets might not support dependency validation), but a brief doc comment would clarify the expected behavior.

📝 Suggested documentation
+// ExpectedDepItemsForTarget returns the expected dependency items for the given target type.
+// For "tackle-hub", it returns DepItemsHub; for "kantra", it returns DepItemsKantra.
+// For other target types (tackle-ui, kai-rpc, vscode), it falls back to DepItemsKantra
+// if configured, otherwise returns nil (no dependency validation).
 func (e *ExpectedOutput) ExpectedDepItemsForTarget(targetType string) ([]konveyor.DepsFlatItem, bool) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/config/types.go` around lines 143 - 159, Add a doc comment to the
ExpectedDepItemsForTarget method explaining its behavior for unsupported/other
target types: state that it explicitly handles "tackle-hub" (returns DepItemsHub
when DepFileHub is set) and "kantra" (returns DepItemsKantra when DepFileKantra
is set), and that the default case falls back to kantra semantics (i.e., will
only return items if DepFileKantra is set), so targets like "tackle-ui",
"kai-rpc", "vscode" will not perform dependency validation unless DepFileKantra
is present; reference the method ExpectedDepItemsForTarget and the fields
DepFileHub, DepItemsHub, DepFileKantra, DepItemsKantra in the comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/targets/tackle_hub_attachments.go`:
- Around line 258-271: copyFile currently defers in.Close() and out.Close()
which can swallow Close() errors (e.g., disk full after io.Copy); change
copyFile to capture and return any Close() errors by replacing the deferred
out.Close() and in.Close() with explicit close calls after io.Copy (or defer but
store their error values), e.g., call n, err := io.Copy(out, in); then closeErr
:= out.Close(); if err == nil { err = closeErr }; finally closeErr2 :=
in.Close(); if err == nil { err = closeErr2 }; return err so any failure from
out.Close() or in.Close() is propagated from copyFile.

---

Nitpick comments:
In `@pkg/config/types.go`:
- Around line 143-159: Add a doc comment to the ExpectedDepItemsForTarget method
explaining its behavior for unsupported/other target types: state that it
explicitly handles "tackle-hub" (returns DepItemsHub when DepFileHub is set) and
"kantra" (returns DepItemsKantra when DepFileKantra is set), and that the
default case falls back to kantra semantics (i.e., will only return items if
DepFileKantra is set), so targets like "tackle-ui", "kai-rpc", "vscode" will not
perform dependency validation unless DepFileKantra is present; reference the
method ExpectedDepItemsForTarget and the fields DepFileHub, DepItemsHub,
DepFileKantra, DepItemsKantra in the comment.

In `@pkg/targets/tackle_hub_attachments.go`:
- Around line 125-135: The defer os.RemoveAll(sub) inside the loop in
findDepsYAMLInTree causes all temp dirs created by os.MkdirTemp to remain until
the function returns; change the logic so each temporary directory is removed
immediately after it's no longer needed: create the temp dir (os.MkdirTemp),
call extractTarArchive and then call walkForDepsYAML on it, and if
walkForDepsYAML returns a path return it after removing the temp dir, otherwise
remove the temp dir immediately (or encapsulate the extract+inspect+cleanup into
a helper that ensures os.RemoveAll(sub) runs before continuing); reference
extractTarArchive, walkForDepsYAML and os.RemoveAll to locate and implement the
change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 98fa4293-d5d0-4606-9c8e-16385c335164

📥 Commits

Reviewing files that changed from the base of the PR and between b83792e and 1437fc7.

📒 Files selected for processing (10)
  • Makefile
  • pkg/cli/generate.go
  • pkg/cli/run.go
  • pkg/config/loader.go
  • pkg/config/types.go
  • pkg/targets/tackle_hub.go
  • pkg/targets/tackle_hub_attachments.go
  • tests/book-server-deps/expected-deps-hub.yaml
  • tests/book-server-deps/expected-deps-kantra.yaml
  • tests/book-server-deps/test.yaml
✅ Files skipped from review due to trivial changes (2)
  • tests/book-server-deps/expected-deps-kantra.yaml
  • tests/book-server-deps/expected-deps-hub.yaml
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/book-server-deps/test.yaml
  • Makefile
  • pkg/cli/run.go
  • pkg/config/loader.go

Comment on lines +258 to +271
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
return err
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

copyFile may lose errors on Close().

If io.Copy succeeds but out.Close() fails (e.g., disk full during flush), the error is silently lost because defer out.Close() discards its return value.

🔧 Proposed fix
 func copyFile(src, dst string) error {
 	in, err := os.Open(src)
 	if err != nil {
 		return err
 	}
 	defer in.Close()
 	out, err := os.Create(dst)
 	if err != nil {
 		return err
 	}
-	defer out.Close()
-	_, err = io.Copy(out, in)
-	return err
+	_, copyErr := io.Copy(out, in)
+	closeErr := out.Close()
+	if copyErr != nil {
+		return copyErr
+	}
+	return closeErr
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
return err
}
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
_, copyErr := io.Copy(out, in)
closeErr := out.Close()
if copyErr != nil {
return copyErr
}
return closeErr
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/targets/tackle_hub_attachments.go` around lines 258 - 271, copyFile
currently defers in.Close() and out.Close() which can swallow Close() errors
(e.g., disk full after io.Copy); change copyFile to capture and return any
Close() errors by replacing the deferred out.Close() and in.Close() with
explicit close calls after io.Copy (or defer but store their error values),
e.g., call n, err := io.Copy(out, in); then closeErr := out.Close(); if err ==
nil { err = closeErr }; finally closeErr2 := in.Close(); if err == nil { err =
closeErr2 }; return err so any failure from out.Close() or in.Close() is
propagated from copyFile.

@eemcmullan
eemcmullan requested review from ibragins and mguetta1 April 23, 2026 13:32
output:
file: expected-output.yaml
dep-file-kantra: expected-deps-kantra.yaml
dep-file-hub: expected-deps-hub.yaml

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a single source of truth to check dependencies?
I’m not aware of the differences, but if it’s only file paths, koncur generate should update the expected file to contain only the suffix.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants