WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Conversation

@abrugaro
Copy link
Contributor

@abrugaro abrugaro commented Aug 8, 2025

Resolves #229

Summary by CodeRabbit

  • New Features
    • Added a new CLI command to export builtin rulesets as a zip archive, with options for output location and overwriting existing files.
  • Bug Fixes
    • Improved determination of the Kantra directory for configuration and resources.
  • Tests
    • Introduced comprehensive tests for the new export command and related file handling.
  • Chores
    • Registered the new export command in the CLI tool.

Signed-off-by: Alejandro Brugarolas <[email protected]>
Signed-off-by: Alejandro Brugarolas <[email protected]>
@coderabbitai
Copy link

coderabbitai bot commented Aug 8, 2025

Walkthrough

A new dump-rules subcommand is introduced, enabling users to archive builtin rulesets into a zip file. The logic for determining the Kantra directory is refactored into a new utility function, replacing the previous method. Associated tests for the new command and its helpers are added, and the command is integrated into the CLI tool.

Changes

Cohort / File(s) Change Summary
Refactor Kantra Directory Logic
cmd/analyze-bin.go, cmd/analyze.go, pkg/util/util.go
Removes the setKantraDir() method from analyzeCommand and replaces its usage with the new utility function GetKantraDir() in cmd/analyze.go. The new function is implemented in pkg/util/util.go, encapsulating the logic for determining the Kantra directory.
New Dump Rules Command
cmd/dump-rules.go, cmd/root.go
Introduces the dump-rules Cobra subcommand to archive builtin rulesets into a zip file. The command is registered in the CLI's root command. Helper functions for output file handling are included.
Tests for Dump Rules Command
cmd/dump-rules_test.go
Adds comprehensive unit tests for the dump-rules command, its helper functions, flag behaviors, and output path logic. Tests cover file existence, overwrite handling, flag requirements, and global variable behaviors.

Sequence Diagram(s)

Dump Rules Command Execution

sequenceDiagram
    participant User
    participant CLI
    participant DumpRulesCommand
    participant Util
    participant OS/FileSystem

    User->>CLI: Runs "dump-rules --output <dir> [--overwrite]"
    CLI->>DumpRulesCommand: Execute RunE
    DumpRulesCommand->>Util: GetKantraDir()
    Util->>OS/FileSystem: Check current directory and config dirs
    Util-->>DumpRulesCommand: Return kantraDir
    DumpRulesCommand->>OS/FileSystem: Check rulesets directory
    alt Rulesets directory missing
        DumpRulesCommand-->>CLI: Log error and exit
    else Rulesets directory exists
        DumpRulesCommand->>OS/FileSystem: Prepare output zip file
        DumpRulesCommand->>OS/FileSystem: Walk rulesets directory, add files to zip
        DumpRulesCommand-->>CLI: Log completion
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Assessment against linked issues

Objective Addressed Explanation
Implement a subcommand to output the included rulesets to a tarball (#229)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes detected.

Suggested reviewers

  • aufi

Poem

A rabbit hops with files anew,
Packing rulesets in a zip for you.
Kantra’s path now crystal clear,
Refactored code brings cheer!
Tests abound, commands expand—
🐇 With nimble paws, I lend a hand.
All zipped up, across the land!

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Nitpick comments (4)
pkg/util/util.go (1)

255-294: Edge-cases in GetKantraDir(): missing error handling & unclear variable names

  1. The loop treats every Stat error as “path missing” and silently falls back. For permission-denied (EACCES) or other IO errors this masks real problems.

    if err != nil && !errors.Is(err, os.ErrNotExist) {
        return "", err
    }

    inside the loop would avoid that.

  2. Using the recycled set flag after the LookupEnv call is confusing – it now means “env-var-present”, not “all-reqs-found”. Consider distinct names (allFound, envSet) for readability.

  3. runtime.GOOS is stored in ops; plain osType := runtime.GOOS is clearer.

cmd/root.go (1)

59-61: Dump-rules command is not assigned to any group

All other asset-related commands are grouped (assetGeneration). If dump-rules is meant for end-users rather than internal dev tooling, consider adding it to an appropriate cobra.Group to keep --help output tidy.

cmd/dump-rules.go (1)

122-141: handleOutputFile(): RemoveAll can delete directories unintentionally

os.RemoveAll(output) will silently delete a directory if output is mis-specified.
Use os.Remove and ensure stat.IsDir() is false before deleting.

if stat != nil && !stat.IsDir() {
    return os.Remove(output)
}
cmd/dump-rules_test.go (1)

1-298: Tests rely on mutable package globals – add t.Parallel() or decouple

Several tests modify the global output / overwrite vars. Running go test -parallel may cause data races.
Either:

  1. call t.Parallel() inside each sub-test after the globals are snap-shotted & restored with a mutex, or
  2. refactor command code to avoid globals (see earlier comment) and drop these work-arounds.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 523bcf5 and c79cc61.

📒 Files selected for processing (6)
  • cmd/analyze-bin.go (0 hunks)
  • cmd/analyze.go (1 hunks)
  • cmd/dump-rules.go (1 hunks)
  • cmd/dump-rules_test.go (1 hunks)
  • cmd/root.go (1 hunks)
  • pkg/util/util.go (2 hunks)
💤 Files with no reviewable changes (1)
  • cmd/analyze-bin.go
🧰 Additional context used
🧬 Code Graph Analysis (3)
cmd/root.go (1)
cmd/dump-rules.go (1)
  • NewDumpRulesCommand (22-120)
cmd/analyze.go (1)
pkg/util/util.go (1)
  • GetKantraDir (255-294)
cmd/dump-rules.go (1)
pkg/util/util.go (2)
  • GetKantraDir (255-294)
  • RulesetsLocation (23-23)

Signed-off-by: Alejandro Brugarolas <[email protected]>
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 (4)
pkg/util/util.go (4)

224-237: Function naming + small robustness improvement

  • The name suggests XML-specific logic, but the function is generic. Consider renaming to IsDirEmpty for clarity.
  • Minor optimization: use Readdirnames(1) and validate the path is a directory before attempting to read.

Apply within this range:

-func IsXMLDirEmpty(dir string) (bool, error) {
-	f, err := os.Open(dir)
-	if err != nil {
-		return false, err
-	}
-	defer f.Close()
-
-	_, err = f.Readdir(1)
-	if err == io.EOF {
-		return true, nil
-	}
-
-	return false, err
-}
+func IsXMLDirEmpty(dir string) (bool, error) {
+	fi, err := os.Stat(dir)
+	if err != nil {
+		return false, err
+	}
+	if !fi.IsDir() {
+		return false, fmt.Errorf("%q is not a directory", dir)
+	}
+	f, err := os.Open(dir)
+	if err != nil {
+		return false, err
+	}
+	defer f.Close()
+	_, err = f.Readdirnames(1)
+	if err == io.EOF {
+		return true, nil
+	}
+	return false, err
+}

Optionally add a clearer, non-breaking alias:

// New preferred name.
func IsDirEmpty(dir string) (bool, error) { return IsXMLDirEmpty(dir) }

265-277: XDG/OS-specific fallback: prefer XDG conventions, preserve legacy path

For Linux, it’s conventional to use:

  • $XDG_CONFIG_HOME/kantra when set
  • $HOME/.config/kantra when not set

Today this returns $HOME/.kantra, which may be intentional for backward compatibility. If you want to adopt XDG but avoid breaking existing users, prefer the XDG path but fall back to legacy $HOME/.kantra if it already exists.

-// fall back to $HOME/.kantra
-ops := runtime.GOOS
-if ops == "linux" {
-  dir, set = os.LookupEnv("XDG_CONFIG_HOME")
-}
-if ops != "linux" || dir == "" || !set {
-  // on Unix, including macOS, this returns the $HOME environment variable. On Windows, it returns %USERPROFILE%
-  dir, err = os.UserHomeDir()
-  if err != nil {
-    return "", err
-  }
-}
-return filepath.Join(dir, ".kantra"), nil
+osName := runtime.GOOS
+if osName == "linux" {
+  if xdg, ok := os.LookupEnv("XDG_CONFIG_HOME"); ok && xdg != "" {
+    return filepath.Join(xdg, "kantra"), nil
+  }
+  home, err := os.UserHomeDir()
+  if err != nil {
+    return "", err
+  }
+  // Back-compat: if legacy exists, keep using it; otherwise follow XDG.
+  legacy := filepath.Join(home, ".kantra")
+  if _, err := os.Stat(legacy); err == nil {
+    return legacy, nil
+  }
+  return filepath.Join(home, ".config", "kantra"), nil
+}
+// Non-Linux: keep existing behavior.
+home, err := os.UserHomeDir()
+if err != nil {
+  return "", err
+}
+return filepath.Join(home, ".kantra"), nil

239-278: Add env override (KANTRA_DIR) to aid testing and power users

Consider allowing an explicit override via env (e.g., KANTRA_DIR). This helps CI/tests and lets users colocate content as needed.

Example:

if v := os.Getenv("KANTRA_DIR"); v != "" {
  return v, nil
}

If you want, I can patch this in and add tests.


243-263: Verify directory-check assumption in pkg/util/util.go (lines 243–263)

The current loop only checks for existence (which may be regular files). To prevent false positives, ensure each path is a directory:

- for _, v := range reqs {
-   _, err := os.Stat(filepath.Join(dir, v))
-   if err != nil {
-     set = false
-     break
-   }
- }
+ for _, v := range reqs {
+   p := filepath.Join(dir, v)
+   info, err := os.Stat(p)
+   if err != nil || !info.IsDir() {
+     set = false
+     break
+   }
+ }

However, the quick check in the repo root showed none of these directories exist locally:

  • Missing dir: rulesets
  • Missing dir: jdtls
  • Missing dir: static-report

Please confirm that in your packaged/installed environment (or wherever this runs), all three of these are guaranteed to be present as directories in the working directory. If so, apply the above diff to harden the check.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c79cc61 and 1773ed2.

📒 Files selected for processing (4)
  • cmd/analyze-bin.go (0 hunks)
  • cmd/analyze.go (1 hunks)
  • cmd/dump-rules.go (1 hunks)
  • pkg/util/util.go (2 hunks)
💤 Files with no reviewable changes (1)
  • cmd/analyze-bin.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • cmd/dump-rules.go
  • cmd/analyze.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build & test from commit
🔇 Additional comments (2)
pkg/util/util.go (2)

11-11: Import looks correct and necessary

runtime is used by GetKantraDir() to branch on OS. No issues.


239-278: All call sites updated to use util.GetKantraDir()

Verified that there are no remaining calls to setKantraDir() and that both cmd/dump-rules.go and cmd/analyze.go now correctly invoke util.GetKantraDir().
No further changes required.

Signed-off-by: Alejandro Brugarolas <[email protected]>
@codecov
Copy link

codecov bot commented Aug 8, 2025

Codecov Report

❌ Patch coverage is 14.66667% with 128 lines in your changes missing coverage. Please review.
✅ Project coverage is 21.68%. Comparing base (523bcf5) to head (40913f1).
⚠️ Report is 22 commits behind head on main.

Files with missing lines Patch % Lines
cmd/dump-rules.go 20.79% 76 Missing and 4 partials ⚠️
pkg/util/util.go 0.00% 45 Missing ⚠️
cmd/analyze.go 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #524      +/-   ##
==========================================
- Coverage   21.73%   21.68%   -0.06%     
==========================================
  Files          32       33       +1     
  Lines        4642     4755     +113     
==========================================
+ Hits         1009     1031      +22     
- Misses       3516     3603      +87     
- Partials      117      121       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Signed-off-by: Alejandro Brugarolas <[email protected]>
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)
cmd/dump-rules_test.go (7)

117-124: Avoid brittle equality checks for command texts

Exact string equality on Use and Short is brittle. Prefer substring or prefix checks to reduce churn from minor text edits.

-   if cmd.Use != "dump-rules" {
-       t.Errorf("expected command Use to be 'dump-rules', got '%s'", cmd.Use)
-   }
+   if !strings.Contains(cmd.Use, "dump-rules") {
+       t.Errorf("expected command Use to contain 'dump-rules', got '%s'", cmd.Use)
+   }

-   if cmd.Short != "Dump builtin rulesets" {
-       t.Errorf("expected command Short to be 'Dump builtin rulesets', got '%s'", cmd.Short)
-   }
+   if !strings.Contains(strings.ToLower(cmd.Short), "dump") ||
+      !strings.Contains(strings.ToLower(cmd.Short), "ruleset") {
+       t.Errorf("unexpected Short: %q", cmd.Short)
+   }

151-162: Reduce flakiness when checking flag usage strings

Usage texts evolve. Assert on meaningful substrings rather than full equality.

- if outputFlag.Usage != "path to the directory for rulesets output" {
-     t.Errorf("unexpected output flag usage: %s", outputFlag.Usage)
- }
+ if !strings.Contains(outputFlag.Usage, "directory") ||
+    !strings.Contains(strings.ToLower(outputFlag.Usage), "ruleset") {
+     t.Errorf("unexpected output flag usage: %s", outputFlag.Usage)
+ }

- if overwriteFlag.Usage != "overwrite output directory" {
-     t.Errorf("unexpected overwrite flag usage: %s", overwriteFlag.Usage)
- }
+ if !strings.Contains(strings.ToLower(overwriteFlag.Usage), "overwrite") {
+     t.Errorf("unexpected overwrite flag usage: %s", overwriteFlag.Usage)
+ }

106-109: Silence test logs to keep CI output clean

Route logs to io.Discard to avoid noisy test output.

- logrusLog := logrus.New()
- logrusLog.SetOutput(os.Stdout)
+ logrusLog := logrus.New()
+ logrusLog.SetOutput(io.Discard)
  logger := logrusr.New(logrusLog)

Also applies to: 134-137


164-172: Consolidate duplicate “missing output flag” tests and relax exact error text

Both sections validate the “required output flag” error. Keep one assertion path and avoid strict matches to Cobra’s exact phrasing, which varies by version.

  • Remove the “should fail when no output flag provided” case in one of the tests, or keep it only in TestDumpRulesCommandFlagValidation.
  • In the remaining test, check that an error occurs and that it contains a stable substring like “required flag”:
- errorMsg:    "required flag(s) \"output\" not set",
+ errorMsg:    "required flag",

This reduces brittleness across Cobra versions.

Also applies to: 174-200, 201-220


59-63: Also assert preservation when overwrite=false and file already exists

Currently, we check deletion on overwrite=true, but we don’t assert that an existing file remains when overwrite=false. Capture pre-state and verify.

- // Setup test file if needed
- if err := tt.setupFunc(testFile); err != nil {
-     t.Fatal(err)
- }
+ // Setup test file if needed
+ if err := tt.setupFunc(testFile); err != nil {
+     t.Fatal(err)
+ }
+ // Track whether the file existed before calling handleOutputFile
+ _, statErr := os.Stat(testFile)
+ existedBefore := !os.IsNotExist(statErr)

...

- // Verify overwrite behavior
- if tt.overwriteFlag && tt.expectError == false && tt.setupFunc != nil {
+ // Verify overwrite/preservation behavior
+ if tt.overwriteFlag && !tt.expectError && tt.setupFunc != nil {
     // File should be removed when overwrite is true
     if _, err := os.Stat(testFile); !os.IsNotExist(err) {
         t.Error("file should be removed when overwrite is true")
     }
+ } else if !tt.overwriteFlag && existedBefore {
+     // File should still exist when overwrite is false
+     if _, err := os.Stat(testFile); os.IsNotExist(err) {
+         t.Error("file should not be removed when overwrite is false")
+     }
 }

Also applies to: 92-99


30-37: Loosen the expected error substring for existing file without overwrite

The current expected substring is highly specific and ties to exact phrasing. Prefer stable keywords.

- errorSubstring: "already exists and --overwrite not set",
+ errorSubstring: "already exists",

103-129: Consider adding an end-to-end smoke test for archive creation

Add a test that:

  • Creates a temp output dir.
  • Executes the command with --output <dir> (and --overwrite).
  • Verifies the archive file exists and is non-empty.

Also consider a case where the parent directory does not exist to confirm it’s created as needed.

I can scaffold this test and, if needed, help introduce a seam (e.g., injectable ruleset source) to avoid depending on the real Kantra directory.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 667f95f and 40913f1.

📒 Files selected for processing (2)
  • cmd/dump-rules.go (1 hunks)
  • cmd/dump-rules_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/dump-rules.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build & test from commit

Comment on lines +222 to +263
// Unit test for output path handling logic
func TestOutputPathHandling(t *testing.T) {
tests := []struct {
name string
outputDir string
expectFilename string
}{
{
name: "should append default filename to directory",
outputDir: "/tmp/output",
expectFilename: "default-rulesets.zip",
},
{
name: "should handle relative paths",
outputDir: "./output",
expectFilename: "default-rulesets.zip",
},
{
name: "should handle empty path",
outputDir: "",
expectFilename: "default-rulesets.zip",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// This simulates the logic from line 32 in dump-rules.go
result := filepath.Join(tt.outputDir, "default-rulesets.zip")
expectedPath := filepath.Join(tt.outputDir, tt.expectFilename)

if result != expectedPath {
t.Errorf("expected path '%s', got '%s'", expectedPath, result)
}

// Verify the filename is always present
filename := filepath.Base(result)
if filename != tt.expectFilename {
t.Errorf("expected filename '%s', got '%s'", tt.expectFilename, filename)
}
})
}
}
Copy link

@coderabbitai coderabbitai bot Aug 8, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Validate archive format (tarball vs zip) and de-brittle default filename in tests

Issue #229 asks for a tarball, but these tests assume a zip (default-rulesets.zip). This can cause a divergence between spec and implementation and make tests fail if the code uses .tar.gz.

  • Verify what the implementation actually creates (zip vs tar.gz) and align tests accordingly.
  • Centralize the default archive filename in a single constant to simplify changes.

Proposed changes within this test (parameterize the filename and use it consistently):

-       result := filepath.Join(tt.outputDir, "default-rulesets.zip")
-       expectedPath := filepath.Join(tt.outputDir, tt.expectFilename)
+       result := filepath.Join(tt.outputDir, defaultArchiveName)
+       expectedPath := filepath.Join(tt.outputDir, tt.expectFilename)

And update the table values accordingly:

-           expectFilename: "default-rulesets.zip",
+           expectFilename: defaultArchiveName,

Additionally, add this helper near the top of the file (outside this hunk) so tests don’t hardcode the name everywhere:

// Keep this in sync with the implementation (zip vs tar.gz)
const defaultArchiveName = "default-rulesets.zip"

If the implementation uses tarballs per the issue, switch the constant to:

const defaultArchiveName = "default-rulesets.tar.gz"

To help confirm the implementation details, run:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locate dump-rules command implementation"
rg -n "NewDumpRulesCommand|dump-rules" -g "cmd/**"

echo
echo "Show flags and descriptions for output/overwrite"
rg -n 'Flags\(\)|PersistentFlags\(\)' -A5 -B2 -g "cmd/**"
rg -n '"output"|--output|\"overwrite\"|--overwrite' -A2 -B2 -g "cmd/**"

echo
echo "Search for default archive name and format usage"
rg -n 'default-rulesets|\.zip|\.tar\.gz|archive/zip|archive/tar|compress/gzip' -g "**/*.go" -A2 -B2

Length of output: 17526



---

🏁 Script executed:

```shell
#!/bin/bash
set -euo pipefail

# Show the code for NewDumpRulesCommand and how output filename is computed
echo "==== NewDumpRulesCommand (cmd/dump-rules.go) ===="
sed -n '1,200p' cmd/dump-rules.go

echo
echo "==== Look for handleOutputFile or similar helpers ===="
grep -R "handleOutput" -n cmd/dump-rules.go || echo "No handleOutputFile found"

echo
echo "==== Inspect RunE block for default filename logic ===="
awk '/RunE:/,/^ *},/p' cmd/dump-rules.go

Length of output: 3830


Centralize the default archive name in tests to reduce duplication and prevent future mismatches

The implementation in cmd/dump-rules.go always appends “default-rulesets.zip” (zip format) as the output filename, and the tests in cmd/dump-rules_test.go hardcode this string in multiple places. While the format is correct today, centralizing it behind a single constant will:

  • Make updates easier if the archive format ever changes
  • Remove duplicated literals from test cases
  • Simplify the TestOutputPathHandling table (the filename is the same across cases)

Suggested changes in cmd/dump-rules_test.go:

  1. At the top of the file, add:

    // defaultArchiveName must match the implementation in cmd/dump-rules.go
    const defaultArchiveName = "default-rulesets.zip"
  2. Simplify TestOutputPathHandling by removing the expectFilename field and using the constant:

    func TestOutputPathHandling(t *testing.T) {
    -   tests := []struct {
    -       name           string
    -       outputDir      string
    -       expectFilename string
    -   }{
    -       { name: "append default filename", outputDir: "/tmp/output", expectFilename: "default-rulesets.zip" },
    -       { name: "relative path",         outputDir: "./output",  expectFilename: "default-rulesets.zip" },
    -       { name: "empty path",            outputDir: "",          expectFilename: "default-rulesets.zip" },
    -   }
    +   tests := []struct {
    +       name      string
    +       outputDir string
    +   }{
    +       { name: "append default filename", outputDir: "/tmp/output" },
    +       { name: "relative path",           outputDir: "./output" },
    +       { name: "empty path",              outputDir: "" },
    +   }
    
        for _, tt := range tests {
            t.Run(tt.name, func(t *testing.T) {
    -           result := filepath.Join(tt.outputDir, "default-rulesets.zip")
    -           expectedPath := filepath.Join(tt.outputDir, tt.expectFilename)
    +           result := filepath.Join(tt.outputDir, defaultArchiveName)
    +           expectedPath := filepath.Join(tt.outputDir, defaultArchiveName)
    
                if result != expectedPath {
                    t.Errorf("expected path '%s', got '%s'", expectedPath, result)
                }
    
                filename := filepath.Base(result)
    -           if filename != tt.expectFilename {
    +           if filename != defaultArchiveName {
                    t.Errorf("expected filename '%s', got '%s'", defaultArchiveName, filename)
                }
            })
        }
    }

These changes keep the test aligned with the implementation today and make it trivial to switch to a .tar.gz filename in one place if the spec ever changes.

🤖 Prompt for AI Agents
In cmd/dump-rules_test.go around lines 222 to 263, the test hardcodes the
default archive filename "default-rulesets.zip" multiple times, causing
duplication and risk of mismatch with the implementation. To fix this, define a
constant defaultArchiveName at the top of the test file with the value
"default-rulesets.zip" matching the implementation, then remove the
expectFilename field from the test cases and replace all occurrences of the
hardcoded filename in TestOutputPathHandling with this constant. This
centralizes the filename, reduces duplication, and simplifies future updates.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is nice ⬆️

Copy link

Choose a reason for hiding this comment

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

@jmle Thanks for the positive feedback! I'm glad the suggestion to centralize the default archive filename resonates with you. It's always satisfying when we can identify opportunities to make the codebase more maintainable and reduce the risk of inconsistencies between implementation and tests.

If you'd like me to help with any other aspects of this PR or have additional questions, feel free to let me know!


🧠 Learnings used
Learnt from: abrugaro
PR: konveyor/kantra#524
File: cmd/dump-rules.go:0-0
Timestamp: 2025-08-08T15:06:52.056Z
Learning: In konveyor/kantra cmd/dump-rules.go (Go/Cobra), the dump-rules command should not use package-level variables for flags (output, overwrite). Flags must be defined as local variables inside NewDumpRulesCommand to avoid shared mutable state across commands/tests.

if set {
return dir, nil
}
// fall back to $HOME/.kantra
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we should also add the ability to set a $KANTRA_HOME directory, but we can leave that for a later discussion.

Copy link
Contributor

@jmle jmle left a comment

Choose a reason for hiding this comment

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

Looks great! Let's just address the nit from code rabbit and the code coverage complaint in the built 👍

@github-actions
Copy link

github-actions bot commented Nov 4, 2025

This pull request has been automatically marked as stale because it has not had any activity for 60 days.
It will remain open for visibility and reporting purposes.
Please comment if this PR is still relevant.

@github-actions github-actions bot added the stale label Nov 4, 2025
@tsanders-rh
Copy link
Contributor

This PR is still relevant and implements a useful feature from #229! ✅

However, there are a few issues to address:

1. Code Coverage Issue ❌

The codecov/patch check is failing with only 14.67% coverage (128 lines missing). The dump-rules command needs more comprehensive tests to meet the coverage threshold.

2. Overlapping Bug with PR #465 ⚠️

Your refactored util.GetKantraDir() still uses os.Getwd() (line 10 of the diff):

dir, err = os.Getwd()  // Gets current working directory

This has the same bug that PR #465 is trying to fix! When kantra is installed via PATH (e.g., /usr/local/bin/kantra), it should check the executable's directory, not the current working directory.

Recommendation:

Use os.Executable() instead:

execPath, err := os.Executable()
if err != nil {
    return "", err
}
dir = filepath.Dir(execPath)

This would:

  • Fix the PATH installation issue
  • Make both PR fix kantra path #465 and your refactoring work correctly together
  • Provide a proper shared utility for finding the kantra directory

Next Steps

  1. Fix the os.Getwd() bug in GetKantraDir() to use os.Executable()
  2. Add comprehensive tests for the dump-rules command to improve coverage
  3. Address any CodeRabbit feedback from the review

This is a valuable feature - would love to see it merged once these issues are addressed! 🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Subcommand to output the included rulesets to a tarball

3 participants