Skip to content

[generator] add recursive component discovery for GitHub repositories - #909

Open
ShigrafS wants to merge 11 commits into
meshery:masterfrom
ShigrafS:recursion
Open

[generator] add recursive component discovery for GitHub repositories#909
ShigrafS wants to merge 11 commits into
meshery:masterfrom
ShigrafS:recursion

Conversation

@ShigrafS

@ShigrafS ShigrafS commented Feb 1, 2026

Copy link
Copy Markdown

Closes #726

Description

This PR implements recursive component discovery for Meshery’s generator logic, addressing the limitation where only files directly under a specified directory were processed. With this enhancement:

  • Users can point to any root directory in a repository, and Meshery will automatically discover all component definition files in subdirectories.

  • Recursive search can be enabled via options (GeneratorOptions). By default, recursion is disabled for backward compatibility.

    • Maximum recursion depth (MaxDepth)
    • File pattern filtering (*.yaml, *.yml, *.json)
    • Recursive discovery toggle via Recursive option
  • Backward compatibility is maintained for existing workflows.

  • Relevant CLI commands and API endpoints have been updated to support these options.

Changes include updates to:

  • generators/generator.go & generator_test.go – Added GeneratorOptions for recursion and depth.
  • generators/github/git_repo.go & package_manager.go – GitRepo and GitHubPackageManager updated to handle recursive directory traversal.
  • generators/github/scheme_interface.go – Downloader updated to pass recursive options.
  • utils/walker/git.go – File walker now respects recursion and max depth.
  • Added new unit tests for recursive logic (recursive_test.go).

This fixes the configuration fragility for repositories with deeply nested component files and aligns with the desired behavior in #726 .

Notes for Reviewers

  • The recursive logic uses filepath.WalkDir with max depth checks in utils/walker/git.go.
  • Tests focus on option propagation and recursive field behavior; actual git clone testing may require integration testing.
  • By default, Recursive: false ensures backward compatibility; recursion is only enabled if explicitly set in GeneratorOptions.
  • Please verify the MaxDepth logic and that recursion is disabled when Recursive: false.

[Signed commits](../CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin)

  • Yes, I signed my commits.

Summary by CodeRabbit

  • New Features

    • Added optional recursive repository traversal.
    • Added maximum-depth controls for nested file discovery.
    • Added file-extension filters to include only selected file types.
    • Non-recursive behavior remains available for top-level files only.
  • Bug Fixes

    • Improved directory traversal and file filtering for more accurate package downloads.

@welcome

welcome Bot commented Feb 1, 2026

Copy link
Copy Markdown

Yay, your first pull request! 👍 A contributor will be by to give feedback soon. In the meantime, you can find updates in the #github-notifications channel in the community Slack.
Be sure to double-check that you have signed your commits. Here are instructions for making signing an implicit activity while performing a commit.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @ShigrafS, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves Meshery's ability to process component definitions from GitHub repositories by implementing recursive directory traversal. Users can now specify a root directory, and the system will automatically discover and process relevant files nested within subdirectories, overcoming previous limitations with deeply structured repositories. The new functionality is highly configurable, allowing fine-grained control over the depth of the recursive search, and has been integrated seamlessly while maintaining compatibility with existing operations.

Highlights

  • Recursive Component Discovery: Introduced the capability for Meshery's generator logic to recursively discover component definition files within GitHub repositories, addressing the limitation of only processing files directly under a specified directory.
  • Configurable Recursion Options: Added configurable options for recursive search, including a boolean flag to enable/disable recursion and an integer for maximum recursion depth (MaxDepth).
  • Option Propagation and Integration: Updated the generator and github packages to correctly propagate the new Recursive and MaxDepth options through the system, from the initial generator creation down to the GitRepo and the underlying git file walker.
  • Enhanced File Walker: The git file walker (utils/walker/git.go) has been enhanced to respect the MaxDepth setting during recursive directory traversal, using filepath.SkipDir to prune directories that exceed the specified depth.
  • Backward Compatibility and Testing: Ensured backward compatibility for existing non-recursive workflows and added new unit tests to validate the correct propagation and behavior of the new recursion options.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces recursive component discovery for GitHub repositories, a valuable enhancement. The implementation adds options for recursion and depth control, and updates relevant parts of the generator logic. My review has identified a couple of high-severity issues: one is a bug in the recursion handling logic that can cause incorrect behavior, and the other is an off-by-one error in the max depth calculation which leads to counter-intuitive results. Additionally, the new tests for the recursive functionality are currently quite minimal and should be expanded to ensure the feature is robust. Overall, the changes are in the right direction, but these key issues should be addressed before merging.

Comment thread generators/github/git_repo.go Outdated
Comment thread utils/walker/git.go Outdated
Comment thread generators/github/recursive_test.go Outdated
@ShigrafS
ShigrafS force-pushed the recursion branch 2 times, most recently from e177431 to 444c8fc Compare February 2, 2026 09:22
@ShigrafS
ShigrafS marked this pull request as ready for review February 2, 2026 09:24
@ShigrafS
ShigrafS marked this pull request as draft February 7, 2026 14:41
@ShigrafS
ShigrafS marked this pull request as ready for review February 16, 2026 08:09
Copilot AI review requested due to automatic review settings March 22, 2026 21:16

Copilot AI left a comment

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.

Pull request overview

Adds configurable recursive component discovery for GitHub-based generators by propagating recursion/depth/extension options down into the git walker, and introducing tests around recursive traversal behavior.

Changes:

  • Introduces GeneratorOptions and threads recursive options into GitHubPackageManager/downloaders.
  • Updates GitHub git downloader (GitRepo) and git walker to support max depth and extension filtering during recursive traversal.
  • Adds unit tests for recursive walk behavior and option propagation.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
utils/walker/git.go Adds MaxDepth and extension filtering, and applies max-depth logic during WalkDir traversal.
generators/github/scheme_interface.go Passes recursive options into the git downloader path via GitHubPackageManager.
generators/github/package_manager.go Stores recursion options on the package manager and passes them into downloader creation.
generators/github/git_repo.go Propagates recursion/maxDepth/extensions into the walker and adjusts root handling for recursive mode.
generators/generator.go Adds GeneratorOptions and a new constructor that forwards options to GitHub generator.
generators/generator_test.go Verifies option propagation through NewGeneratorWithOptions.
generators/github/recursive_test.go Adds functional tests for recursive walking, max depth, and extension filtering.
Comments suppressed due to low confidence (1)

utils/walker/git.go:242

  • After calling d.Info(), the code checks if err != nil but err is not the error returned by d.Info() (it’s an outer variable). This means errInfo can be non-nil and the code will still proceed to g.readFile(f, path) with a potentially nil FileInfo, which can panic. Check errInfo instead and return it when non-nil.
			f, errInfo := d.Info()
			if err != nil {
				return errInfo
			}
			return g.readFile(f, path)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread utils/walker/git.go
Comment thread utils/walker/git.go
Comment thread generators/generator.go
@leecalcote

Copy link
Copy Markdown
Member

Strong first PR, @ShigrafS — the recursive discovery feature with depth/extension control is well-architected. Several important issues to address:

  1. Double Root() call bug: In git_repo.go, you call gw.Root(root) during the builder chain, then conditionally call gw.Root(effectiveRoot) again. The Root() method sets an internal recurse flag to true when it sees /**, but doesn't reset it to false on subsequent calls without the suffix. This means if the original root contains /** but gr.Recursive is false, recursion will still be enabled. Fix: compute effectiveRoot first, then call Root() only once.

  2. Handle WalkDir callback error: The er parameter in the filepath.WalkDir callback is currently ignored. If WalkDir passes a non-nil error with a nil DirEntry, calling d.IsDir() will panic. Add if er != nil { return er } at the top of the callback.

  3. Normalize allowedExtensions: isAllowedFile lowercases the file extension but compares against raw allowedExtensions entries. If a caller passes ".YAML" or "yaml" (without the dot), filtering silently fails. Normalize extensions (lowercase, ensure leading .) when setting them.

  4. Bug in d.Info() error check: In the walker at line ~242, errInfo is captured from d.Info() but the code checks if err != nil (the outer variable) instead of if errInfo != nil. This can cause a nil-pointer panic on the FileInfo.

  5. PR description vs. behavior: The description says recursive discovery is enabled by default, but NewGenerator() passes GeneratorOptions{} which leaves Recursive: false. Clarify which is intended — if you want backward compatibility, update the description; if you want default-on, set Recursive: true in the zero-value options.

  6. Use ioutil alternatives: ioutil.TempDir and ioutil.WriteFile are deprecated since Go 1.16. Use os.MkdirTemp and os.WriteFile instead.

The functional test with a real git repo is excellent — well done on that.

@ShigrafS
ShigrafS force-pushed the recursion branch 2 times, most recently from a31d4f6 to 2e1dfaf Compare April 1, 2026 12:53
@ShigrafS

ShigrafS commented Apr 1, 2026

Copy link
Copy Markdown
Author

Thank you for the detailed review @leecalcote
All the points you raised have been addressed.

The PR now fully resolves the issues identified in the review while maintaining backward compatibility.
Please let me know if any more changes are required.

@ShigrafS
ShigrafS force-pushed the recursion branch 2 times, most recently from 3d97e47 to fb4177c Compare April 3, 2026 17:05
@ShigrafS
ShigrafS force-pushed the recursion branch 2 times, most recently from f0abf53 to a85d12d Compare April 27, 2026 20:09
@ShigrafS
ShigrafS force-pushed the recursion branch 2 times, most recently from e2e73bf to d951716 Compare May 10, 2026 16:13
@ShigrafS
ShigrafS force-pushed the recursion branch 2 times, most recently from 180b584 to ac285f0 Compare June 13, 2026 08:24
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds generator options for recursive Git traversal, maximum depth, and file extensions. GitHub downloaders pass these settings to GitRepo, while Git applies depth and extension filtering during traversal. Tests cover configuration and repository walking behavior.

Changes

Recursive generation configuration and traversal

Layer / File(s) Summary
Generator option contract
generators/generator.go, generators/generator_test.go
Adds GeneratorOptions and NewGeneratorWithOptions. The existing constructor delegates with default options. Tests verify option propagation.
GitHub downloader configuration
generators/github/package_manager.go, generators/github/scheme_interface.go, generators/github/git_repo.go
Passes recursive, depth, and extension settings from GitHubPackageManager to GitRepo. GetContent selects recursive or root-only traversal.
Configurable Git traversal
utils/walker/git.go
Adds maximum-depth and extension-filter configuration. Recursive walking skips .git, prunes deep directories, filters files, and handles file metadata errors.
Traversal behavior tests
generators/github/recursive_test.go
Tests root-only traversal, unlimited and bounded recursion, and YAML or JSON extension filtering in a temporary Git repository.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Generator
  participant GitHubPackageManager
  participant GitRepo
  participant Git
  Generator->>GitHubPackageManager: configure recursive, depth, and extensions
  GitHubPackageManager->>GitRepo: pass repository configuration
  GitRepo->>Git: apply traversal settings
  Git->>GitRepo: return matching repository files
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The implementation adds recursion, depth, and extension filtering [#726], but disables recursion by default and omits required CLI/API updates. Enable recursion by default or reconcile the compatibility decision, and update the relevant CLI commands and API endpoints to pass the new options.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 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 change: recursive component discovery for GitHub repositories.
Out of Scope Changes check ✅ Passed The code and tests remain focused on recursive GitHub repository discovery, traversal limits, extension filtering, and option propagation.
✨ 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.

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@generators/generator_test.go`:
- Around line 10-17: Extend the table-driven cases in the generator tests with
expected extension values through GeneratorOptions.Extensions, then assert the
resulting ghpm.Extensions matches tt.opts.Extensions after
NewGeneratorWithOptions. Ensure the test fails if Extensions is no longer
forwarded, while preserving existing assertions for the other generator fields.

In `@utils/walker/git.go`:
- Around line 92-104: The non-recursive file traversal must honor extension
filtering just like the recursive path. In the non-recursive loop, apply
Git.isAllowedFile to each filename before calling g.readFile, while preserving
the existing behavior when no extensions are configured; add a test covering
non-recursive traversal with an allowed extension that excludes other files.
🪄 Autofix

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 Plus

Run ID: 2c1472fe-6953-42c7-8a73-40d167904af4

📥 Commits

Reviewing files that changed from the base of the PR and between 762c011 and a78072c.

📒 Files selected for processing (7)
  • generators/generator.go
  • generators/generator_test.go
  • generators/github/git_repo.go
  • generators/github/package_manager.go
  • generators/github/recursive_test.go
  • generators/github/scheme_interface.go
  • utils/walker/git.go

Comment on lines +10 to +17
tests := []struct {
name string
registrant string
url string
packageName string
opts GeneratorOptions
wantRec bool
wantDepth int

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Test Extensions propagation.

Add expected extensions to each test case. Assert that ghpm.Extensions equals tt.opts.Extensions.

The current test can pass if NewGeneratorWithOptions stops forwarding Extensions.

As per coding guidelines, “Every behavioral change must include accompanying tests.”

Also applies to: 52-58

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@generators/generator_test.go` around lines 10 - 17, Extend the table-driven
cases in the generator tests with expected extension values through
GeneratorOptions.Extensions, then assert the resulting ghpm.Extensions matches
tt.opts.Extensions after NewGeneratorWithOptions. Ensure the test fails if
Extensions is no longer forwarded, while preserving existing assertions for the
other generator fields.

Source: Coding guidelines

Comment thread utils/walker/git.go
Comment on lines +92 to +104
func (g *Git) isAllowedFile(name string) bool {
if len(g.allowedExtensions) == 0 {
return true // no filtering
}

ext := strings.ToLower(filepath.Ext(name))
for _, allowed := range g.allowedExtensions {
if ext == allowed {
return true
}
}
return false
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Apply extension filtering in non-recursive mode.

The recursive branch calls g.isAllowedFile. The non-recursive loop reads every file without this check.

As a result, AllowedExtensions([]string{".yaml"}) still returns JSON and other files when recursion is disabled. Apply the same check before g.readFile in the non-recursive loop. Add a non-recursive filtered test case.

Proposed fix
 		if f.IsDir() {
 			continue
 		}
+		if !g.isAllowedFile(f.Name()) {
+			continue
+		}
 		err := g.readFile(f, fPath)

Also applies to: 249-250

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@utils/walker/git.go` around lines 92 - 104, The non-recursive file traversal
must honor extension filtering just like the recursive path. In the
non-recursive loop, apply Git.isAllowedFile to each filename before calling
g.readFile, while preserving the existing behavior when no extensions are
configured; add a test covering non-recursive traversal with an allowed
extension that excludes other files.

Signed-off-by: ShigrafS <shigrafsalik@proton.me>
Signed-off-by: ShigrafS <shigrafsalik@proton.me>
Signed-off-by: ShigrafS <shigrafsalik@proton.me>
Signed-off-by: ShigrafS <shigrafsalik@proton.me>
Signed-off-by: ShigrafS <shigrafsalik@proton.me>

# Conflicts:
#	generators/github/git_repo.go
Signed-off-by: ShigrafS <shigrafsalik@proton.me>
Signed-off-by: ShigrafS <shigrafsalik@proton.me>

# Conflicts:
#	generators/github/recursive_test.go
Signed-off-by: ShigrafS <shigrafsalik@proton.me>
Signed-off-by: ShigrafS <shigrafsalik@proton.me>
Signed-off-by: ShigrafS <shigrafsalik@proton.me>
…ions

- Computed effectiveRoot before calling Root() to prevent recursive mutation bugs
- Added er != nil check in WalkDir to prevent panic on nil DirEntry
- Normalized extension inputs in AllowedExtensions to guarantee accurate file filtering
- Corrected the error variable check from err to errInfo after d.Info()
- Replaced deprecated ioutil functions with os equivalents in tests

Signed-off-by: ShigrafS <shigrafsalik@proton.me>
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.

Recursive Directory Search for Model Generation

3 participants