-
Notifications
You must be signed in to change notification settings - Fork 0
feat: optimize repository listing performance and add search support #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…tionality - Reduce default repository fetch limit from 100 to 10 for faster TUI experience - Add support for GitHub's native search API via updated github-client - Implement graceful fallback when search unavailable in standalone mode - Update composer dependency to github-client ^2.2.0 - Maintain backward compatibility for all existing features Performance improvement: Commands now complete in ~1s instead of 3-5s
|
Warning Rate limit exceeded@jordanpartridge has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 5 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
WalkthroughThis update introduces advanced filtering and search capabilities for GitHub repositories and issues, adds a new data filtering utility, expands the CLI with new commands and improved command registration, and provides comprehensive tests. Several new configuration and example files are included, along with stylistic improvements and enhanced error handling throughout the codebase. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI
participant Application
participant Command
participant GithubClient
participant FilterableGitHubData
User->>CLI: Run a command (e.g., repo:list, issue:list)
CLI->>Application: Bootstrap and parse command
Application->>GithubClient: (If needed) Create or use injected client
Application->>Command: Instantiate command (inject client if required)
Command->>GithubClient: Fetch repositories/issues data
Command->>FilterableGitHubData: Initialize with data
Command->>FilterableGitHubData: Apply filters/sorting/queries
FilterableGitHubData-->>Command: Return filtered data
Command->>CLI: Output results (list, stats, details)
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
🔭 Outside diff range comments (1)
src/Commands/ReposCommand.php (1)
345-355: Critical: Command injection vulnerability in git clone.Using
exec()with user-controlled input is dangerous and can lead to command injection attacks.Use Symfony Process component like in CloneCommand:
if (confirm( label: "🚀 Clone {$selected}?", default: true )) { $output->writeln("<info>🔄 Cloning {$selected}...</info>"); $repoName = basename($selected, '.git'); - exec("git clone {$selected} {$repoName}", $gitOutput, $exitCode); + $process = new \Symfony\Component\Process\Process(['git', 'clone', $selected, $repoName]); + $process->run(); + $exitCode = $process->getExitCode(); if ($exitCode === 0) { $output->writeln("<info>✅ Successfully cloned to ./{$repoName}</info>"); } else { $output->writeln('<error>❌ Failed to clone repository</error>'); } }
🧹 Nitpick comments (5)
tests/TestCase.php (1)
11-14: Consider removing empty setUp() override.The
setUp()method only callsparent::setUp()without adding any custom setup logic. Consider removing this method until custom setup is needed.abstract class TestCase extends BaseTestCase { - protected function setUp(): void - { - parent::setUp(); - } }src/Support/FilterableGitHubData.php (1)
222-233: Consider making the language list more extensible.The hardcoded regex pattern for languages might miss some languages. Consider extracting this to a constant or configuration for easier maintenance.
+private const SUPPORTED_LANGUAGES = [ + 'php', 'python', 'javascript', 'js', 'typescript', 'ts', 'go', 'rust', + 'java', 'ruby', 'c++', 'cpp', 'c#', 'csharp', 'swift', 'kotlin', 'scala' +]; + public function query(string $query): self { $query = strtolower(trim($query)); $result = $this; // Language patterns - if (preg_match('/\b(php|python|javascript|js|typescript|ts|go|rust|java|ruby|c\+\+|cpp|c#|csharp)\b/', $query, $matches)) { + $languagePattern = '/\b(' . implode('|', array_map('preg_quote', self::SUPPORTED_LANGUAGES)) . ')\b/'; + if (preg_match($languagePattern, $query, $matches)) { $lang = $matches[1];tests/ApplicationTest.php (1)
14-27: Consider using environment isolation for better test reliability.The test correctly verifies command registration, but setting environment variables globally could cause issues in parallel test execution.
Consider using a more isolated approach for environment variable testing:
it('has required commands registered', function () { - $_ENV['GITHUB_TOKEN'] = 'fake-token-for-testing'; - - $app = new Application; + $app = new Application; + + // Mock or inject the GitHub client if needed for command registration + // This avoids global environment modification expect($app->has('list'))->toBeTrue() ->and($app->has('repo'))->toBeTrue() ->and($app->has('issue'))->toBeTrue() ->and($app->has('repo:list'))->toBeTrue() ->and($app->has('repo:clone'))->toBeTrue() ->and($app->has('issue:list'))->toBeTrue(); - - unset($_ENV['GITHUB_TOKEN']); });examples/filtering-demo.php (1)
64-128: Comprehensive demonstration of filtering capabilities.The demo effectively showcases the full range of FilterableGitHubData functionality including basic filtering, natural language queries, complex chaining, and statistics. The progressive examples help users understand the capabilities step-by-step.
Consider adding basic error handling for production-ready examples:
+try { $repos = FilterableGitHubData::repositories($sampleRepos); // ... demo code ... +} catch (\Exception $e) { + echo "Error: " . $e->getMessage() . "\n"; + exit(1); +}src/Application.php (1)
52-63: Consider simplifying command instantiation logic.The differentiation between "discovery" and "functional" commands seems arbitrary. Consider either:
- Passing the GitHub client to all commands for consistency, or
- Making the distinction clearer with interfaces or base classes
private function setupCommands(Github $github): void { foreach ($this->commandClasses as $commandClass) { - // Discovery commands don't need GitHub client - if (in_array($commandClass, [ - Commands\ListCommand::class, - Commands\RepoCommand::class, - Commands\IssueCommand::class, - ])) { - $this->add(new $commandClass); - } else { - $this->add(new $commandClass($github)); - } + // Check if command requires GitHub client via reflection or interface + $reflection = new \ReflectionClass($commandClass); + $constructor = $reflection->getConstructor(); + + if ($constructor && $constructor->getNumberOfRequiredParameters() > 0) { + $this->add(new $commandClass($github)); + } else { + $this->add(new $commandClass); + } } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
composer.lockis excluded by!**/*.lock
📒 Files selected for processing (20)
.claude/settings.local.json(1 hunks).phpactor.json(1 hunks)composer.json(1 hunks)config/github-zero.php(1 hunks)examples/filtering-demo.php(1 hunks)src/Application.php(1 hunks)src/Commands/CloneCommand.php(6 hunks)src/Commands/IssueCommand.php(1 hunks)src/Commands/IssuesCommand.php(1 hunks)src/Commands/ListCommand.php(1 hunks)src/Commands/RepoCommand.php(1 hunks)src/Commands/ReposCommand.php(10 hunks)src/ConduitExtension.php(3 hunks)src/GitHubZeroServiceProvider.php(1 hunks)src/Support/FilterableGitHubData.php(1 hunks)test-package.php(5 hunks)tests/ApplicationTest.php(1 hunks)tests/Pest.php(1 hunks)tests/Support/FilterableGitHubDataTest.php(1 hunks)tests/TestCase.php(1 hunks)
🧰 Additional context used
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: The package uses the jordanpartridge/github-client package for all GitHub API operations, ensuring a consistent integration layer.
composer.json (2)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: The package uses the jordanpartridge/github-client package for all GitHub API operations, ensuring a consistent integration layer.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Interactive prompts in CLI commands should utilize Laravel\Prompts for a rich terminal UI experience.
tests/Pest.php (2)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Testing should be performed using the Pest framework, as indicated by the use of ./vendor/bin/pest.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Dependency injection should be used to provide the GitHub client to command classes, promoting testability and modularity.
src/ConduitExtension.php (5)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: In this repository, command classes should extend Illuminate\Console\Command to ensure consistency across standalone CLI, Laravel, and Conduit environments.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Dependency injection should be used to provide the GitHub client to command classes, promoting testability and modularity.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: The package uses the jordanpartridge/github-client package for all GitHub API operations, ensuring a consistent integration layer.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: All commands that interact with the GitHub API must require the GITHUB_TOKEN environment variable for authentication.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Command classes should validate the presence and correctness of the GitHub token in their handle() method before proceeding with API operations.
test-package.php (2)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.746Z
Learning: Testing should be performed using the Pest framework, as indicated by the use of ./vendor/bin/pest.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: All commands that interact with the GitHub API must require the GITHUB_TOKEN environment variable for authentication.
src/Commands/ListCommand.php (1)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: In this repository, command classes should extend Illuminate\Console\Command to ensure consistency across standalone CLI, Laravel, and Conduit environments.
tests/ApplicationTest.php (1)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Testing should be performed using the Pest framework, as indicated by the use of ./vendor/bin/pest.
src/GitHubZeroServiceProvider.php (3)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Dependency injection should be used to provide the GitHub client to command classes, promoting testability and modularity.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: In this repository, command classes should extend Illuminate\Console\Command to ensure consistency across standalone CLI, Laravel, and Conduit environments.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: The package uses the jordanpartridge/github-client package for all GitHub API operations, ensuring a consistent integration layer.
src/Commands/CloneCommand.php (5)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: In this repository, command classes should extend Illuminate\Console\Command to ensure consistency across standalone CLI, Laravel, and Conduit environments.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Dependency injection should be used to provide the GitHub client to command classes, promoting testability and modularity.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Interactive prompts in CLI commands should utilize Laravel\Prompts for a rich terminal UI experience.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: The package uses the jordanpartridge/github-client package for all GitHub API operations, ensuring a consistent integration layer.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: All commands that interact with the GitHub API must require the GITHUB_TOKEN environment variable for authentication.
src/Commands/IssueCommand.php (1)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: In this repository, command classes should extend Illuminate\Console\Command to ensure consistency across standalone CLI, Laravel, and Conduit environments.
src/Commands/RepoCommand.php (2)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: In this repository, command classes should extend Illuminate\Console\Command to ensure consistency across standalone CLI, Laravel, and Conduit environments.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Dependency injection should be used to provide the GitHub client to command classes, promoting testability and modularity.
src/Application.php (1)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Dependency injection should be used to provide the GitHub client to command classes, promoting testability and modularity.
src/Commands/IssuesCommand.php (2)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: In this repository, command classes should extend Illuminate\Console\Command to ensure consistency across standalone CLI, Laravel, and Conduit environments.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Dependency injection should be used to provide the GitHub client to command classes, promoting testability and modularity.
src/Commands/ReposCommand.php (3)
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: In this repository, command classes should extend Illuminate\Console\Command to ensure consistency across standalone CLI, Laravel, and Conduit environments.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: All commands that interact with the GitHub API must require the GITHUB_TOKEN environment variable for authentication.
Learnt from: CR
PR: jordanpartridge/github-zero#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-27T07:38:04.768Z
Learning: Command classes should validate the presence and correctness of the GitHub token in their handle() method before proceeding with API operations.
🧬 Code Graph Analysis (3)
tests/Pest.php (1)
tests/TestCase.php (1)
TestCase(9-15)
src/Commands/ListCommand.php (6)
src/Commands/IssueCommand.php (2)
configure(13-18)execute(20-51)src/Commands/CloneCommand.php (2)
configure(27-35)execute(37-61)src/Commands/RepoCommand.php (2)
configure(13-18)execute(20-51)src/Commands/IssuesCommand.php (2)
configure(29-43)execute(45-70)src/Commands/ReposCommand.php (2)
configure(29-44)execute(46-81)src/ConduitExtension.php (2)
commands(40-47)description(32-35)
examples/filtering-demo.php (1)
src/Support/FilterableGitHubData.php (11)
FilterableGitHubData(10-364)repositories(25-28)count(296-299)language(41-47)get(280-283)minStars(84-87)query(216-275)visibility(92-99)sortBy(192-200)limit(205-211)stats(331-340)
🔇 Additional comments (24)
config/github-zero.php (1)
55-55: Good practice: File ends with newline.Adding a newline at the end of the file follows POSIX standards and prevents potential issues with certain tools.
.phpactor.json (1)
2-2: Verify the schema path is correct.The schema path
/phpactor.schema.jsonappears to be an absolute path from the root directory, which may not exist on all systems. Consider using a relative path or a URL to the official schema.#!/bin/bash # Check if phpactor.schema.json exists in common locations fd -t f "phpactor.schema.json" -d 3 # Check for .phpactor.json files in the repo to see common schema patterns fd -t f ".phpactor.json" -x head -n 5 {} \;composer.json (1)
16-16: Dependency update aligns with PR objectives.The update to
github-client ^2.2.0is necessary for the new search functionality mentioned in the PR summary.src/Support/FilterableGitHubData.php (1)
10-364: Well-designed filtering utility with fluent interface.The class demonstrates good design patterns:
- Immutable filtering with method chaining
- Clear separation of repository vs issue concerns
- Comprehensive natural language query support
- Good documentation
The implementation aligns well with the PR objectives for enhanced filtering capabilities.
tests/Pest.php (1)
1-5: LGTM! Standard Pest framework bootstrap configuration.The setup correctly configures all tests in the directory to use the custom
TestCaseclass, following Pest framework conventions..claude/settings.local.json (1)
1-15: Well-configured security boundaries for development environment.The allowed bash commands are appropriate for the project's toolchain and development needs, including Pest testing, Composer operations, and GitHub CLI interactions.
src/ConduitExtension.php (2)
8-8: Proper import addition for new command.The import follows the established pattern and namespace convention.
45-45: Consistent command registration.The IssuesCommand is properly registered following the same pattern as existing commands, maintaining consistency in the extension's command mapping.
tests/ApplicationTest.php (1)
7-12: Clean test for application metadata.The test correctly verifies the application name and version using Pest's fluent expectation syntax.
test-package.php (5)
10-11: Improved string concatenation formatting.Consistent spacing around concatenation operators enhances readability.
24-24: Cleaner conditional spacing.The spacing improvement makes the conditional check more readable.
78-84: Consistent object instantiation and string formatting.Removing unnecessary parentheses in object instantiation and consistent concatenation spacing improves code style.
94-99: Consistent formatting improvements.The stylistic changes maintain consistency with the rest of the file's formatting improvements.
131-131: Final formatting consistency.The concatenation spacing aligns with the formatting improvements throughout the file.
src/Commands/IssueCommand.php (1)
20-51: The command logic is well-implemented.The output formatting, command categorization, and examples are clear and helpful. When switching to
Illuminate\Console\Command, this method will need to be renamed tohandle()and the parameters will change to use Laravel's console output methods.src/Commands/ListCommand.php (1)
27-67: Excellent command organization and user guidance.The categorization of commands is logical and comprehensive, and the tips section provides valuable guidance for users. The output formatting is clean and consistent.
src/Commands/RepoCommand.php (1)
20-51: Well-structured repository command discovery.The command provides clear organization of repository-related functionality with helpful examples. The implementation follows good patterns established in the other discovery commands.
src/GitHubZeroServiceProvider.php (1)
27-34: Command registration is properly implemented.The service provider correctly registers all new commands using the appropriate Laravel patterns. The console-only registration is appropriate.
Note: Once the command classes are updated to extend
Illuminate\Console\Commandas suggested in the other reviews, ensure the registration continues to work properly.examples/filtering-demo.php (2)
8-11: Clean demo setup with proper imports.The autoloader inclusion and import statement are correctly implemented for the demo script.
13-59: Realistic sample data enhances demo value.The sample repository data closely matches GitHub API response structure and includes realistic examples (Laravel, Vue, etc.) that users can easily relate to. This makes the demo more effective for understanding real-world usage.
tests/Support/FilterableGitHubDataTest.php (1)
7-67: Well-structured test data setup.The sample data provides good coverage for testing various filtering scenarios with diverse attributes including different languages, star counts, visibility states, and issue properties.
src/Commands/CloneCommand.php (2)
30-31: Good command naming consistency.The rename from
ghz:clonetorepo:clonealigns well with the new command organization where repository-related commands are grouped under thereponamespace.
131-137: Good security practice using Symfony Process.Using Symfony's Process component instead of
exec()prevents shell injection vulnerabilities when executing the git clone command. This is the correct approach.src/Commands/ReposCommand.php (1)
250-276: Well-implemented natural language query parsing.The regex-based parsing handles common query patterns effectively, extracting language and star filters from natural language input. Good user experience enhancement.
| public function assignedTo(string $username): self | ||
| { | ||
| return $this->filter(function ($item) use ($username) { | ||
| $assignee = $item['assignee']['login'] ?? null; | ||
|
|
||
| return $assignee === $username; | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use safe array access for nested assignee data.
Direct access to $item['assignee']['login'] could cause warnings if 'assignee' key doesn't exist.
public function assignedTo(string $username): self
{
return $this->filter(function ($item) use ($username) {
- $assignee = $item['assignee']['login'] ?? null;
+ $assignee = isset($item['assignee']['login']) ? $item['assignee']['login'] : null;
return $assignee === $username;
});
}📝 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.
| public function assignedTo(string $username): self | |
| { | |
| return $this->filter(function ($item) use ($username) { | |
| $assignee = $item['assignee']['login'] ?? null; | |
| return $assignee === $username; | |
| }); | |
| } | |
| public function assignedTo(string $username): self | |
| { | |
| return $this->filter(function ($item) use ($username) { | |
| $assignee = isset($item['assignee']['login']) | |
| ? $item['assignee']['login'] | |
| : null; | |
| return $assignee === $username; | |
| }); | |
| } |
🤖 Prompt for AI Agents
In src/Support/FilterableGitHubData.php around lines 156 to 163, the code
directly accesses $item['assignee']['login'], which can cause warnings if the
'assignee' key is missing. Modify the code to safely check if 'assignee' exists
and is an array before accessing 'login', using conditional checks or null
coalescing to avoid warnings.
| class FilterableGitHubData | ||
| { | ||
| private Collection $data; | ||
|
|
||
| private string $type; | ||
|
|
||
| public function __construct(array $data, string $type) | ||
| { | ||
| $this->data = collect($data); | ||
| $this->type = $type; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add type validation and use constants for valid types.
The constructor accepts any string for $type but only 'repository' and 'issue' are valid. Consider adding validation and using constants.
class FilterableGitHubData
{
+ private const TYPE_REPOSITORY = 'repository';
+ private const TYPE_ISSUE = 'issue';
+ private const VALID_TYPES = [self::TYPE_REPOSITORY, self::TYPE_ISSUE];
+
private Collection $data;
private string $type;
public function __construct(array $data, string $type)
{
+ if (!in_array($type, self::VALID_TYPES)) {
+ throw new \InvalidArgumentException("Invalid type: {$type}. Valid types are: " . implode(', ', self::VALID_TYPES));
+ }
$this->data = collect($data);
$this->type = $type;
}Then update the static constructors:
public static function repositories(array $repos): self
{
- return new self($repos, 'repository');
+ return new self($repos, self::TYPE_REPOSITORY);
}
public static function issues(array $issues): self
{
- return new self($issues, 'issue');
+ return new self($issues, self::TYPE_ISSUE);
}📝 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.
| class FilterableGitHubData | |
| { | |
| private Collection $data; | |
| private string $type; | |
| public function __construct(array $data, string $type) | |
| { | |
| $this->data = collect($data); | |
| $this->type = $type; | |
| } | |
| class FilterableGitHubData | |
| { | |
| private const TYPE_REPOSITORY = 'repository'; | |
| private const TYPE_ISSUE = 'issue'; | |
| private const VALID_TYPES = [self::TYPE_REPOSITORY, self::TYPE_ISSUE]; | |
| private Collection $data; | |
| private string $type; | |
| public function __construct(array $data, string $type) | |
| { | |
| if (! in_array($type, self::VALID_TYPES, true)) { | |
| throw new \InvalidArgumentException( | |
| "Invalid type: {$type}. Valid types are: " . implode(', ', self::VALID_TYPES) | |
| ); | |
| } | |
| $this->data = collect($data); | |
| $this->type = $type; | |
| } | |
| public static function repositories(array $repos): self | |
| { | |
| return new self($repos, self::TYPE_REPOSITORY); | |
| } | |
| public static function issues(array $issues): self | |
| { | |
| return new self($issues, self::TYPE_ISSUE); | |
| } | |
| // ... other methods ... | |
| } |
🤖 Prompt for AI Agents
In src/Support/FilterableGitHubData.php around lines 10 to 20, the constructor
accepts any string for the $type parameter without validation, but only
'repository' and 'issue' are valid types. Define class constants for these valid
types and add validation in the constructor to check if the provided $type
matches one of these constants. If the $type is invalid, throw an appropriate
exception. Also, update any static constructors to use these constants instead
of hardcoded strings.
| public function sortBy(string $field, string $direction = 'desc'): self | ||
| { | ||
| $ascending = strtolower($direction) === 'asc'; | ||
|
|
||
| return new self( | ||
| $this->data->sortBy($field, SORT_REGULAR, ! $ascending)->values()->toArray(), | ||
| $this->type | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider using appropriate sort flags for different data types.
Using SORT_REGULAR for all fields might not sort numeric fields like 'stargazers_count' correctly. Consider detecting the field type or allowing sort flag customization.
public function sortBy(string $field, string $direction = 'desc'): self
{
$ascending = strtolower($direction) === 'asc';
+
+ // Determine sort flag based on common numeric fields
+ $numericFields = ['stargazers_count', 'forks_count', 'open_issues_count', 'size'];
+ $sortFlag = in_array($field, $numericFields) ? SORT_NUMERIC : SORT_REGULAR;
return new self(
- $this->data->sortBy($field, SORT_REGULAR, ! $ascending)->values()->toArray(),
+ $this->data->sortBy($field, $sortFlag, ! $ascending)->values()->toArray(),
$this->type
);
}📝 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.
| public function sortBy(string $field, string $direction = 'desc'): self | |
| { | |
| $ascending = strtolower($direction) === 'asc'; | |
| return new self( | |
| $this->data->sortBy($field, SORT_REGULAR, ! $ascending)->values()->toArray(), | |
| $this->type | |
| ); | |
| } | |
| public function sortBy(string $field, string $direction = 'desc'): self | |
| { | |
| $ascending = strtolower($direction) === 'asc'; | |
| // Determine sort flag based on common numeric fields | |
| $numericFields = ['stargazers_count', 'forks_count', 'open_issues_count', 'size']; | |
| $sortFlag = in_array($field, $numericFields) ? SORT_NUMERIC : SORT_REGULAR; | |
| return new self( | |
| $this->data->sortBy($field, $sortFlag, ! $ascending)->values()->toArray(), | |
| $this->type | |
| ); | |
| } |
🤖 Prompt for AI Agents
In src/Support/FilterableGitHubData.php around lines 192 to 200, the sortBy
method uses SORT_REGULAR for all fields, which may not correctly sort numeric
fields like 'stargazers_count'. Modify the method to detect the data type of the
field being sorted or add an optional parameter to specify the sort flag (e.g.,
SORT_NUMERIC for numbers). Use the appropriate sort flag when calling
$this->data->sortBy to ensure correct sorting behavior based on the field type.
| public function updatedSince(string $date): self | ||
| { | ||
| $since = Carbon::parse($date); | ||
|
|
||
| return $this->filter(function ($item) use ($since) { | ||
| $updated = Carbon::parse($item['updated_at'] ?? null); | ||
|
|
||
| return $updated->gte($since); | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for date parsing.
Carbon::parse() can throw exceptions for invalid date strings. Consider adding try-catch blocks or validation to handle invalid dates gracefully.
public function updatedSince(string $date): self
{
- $since = Carbon::parse($date);
+ try {
+ $since = Carbon::parse($date);
+ } catch (\Exception $e) {
+ // Return unfiltered data or handle error appropriately
+ return $this;
+ }
return $this->filter(function ($item) use ($since) {
- $updated = Carbon::parse($item['updated_at'] ?? null);
+ if (!isset($item['updated_at'])) {
+ return false;
+ }
+ try {
+ $updated = Carbon::parse($item['updated_at']);
+ } catch (\Exception $e) {
+ return false;
+ }
return $updated->gte($since);
});
}📝 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.
| public function updatedSince(string $date): self | |
| { | |
| $since = Carbon::parse($date); | |
| return $this->filter(function ($item) use ($since) { | |
| $updated = Carbon::parse($item['updated_at'] ?? null); | |
| return $updated->gte($since); | |
| }); | |
| } | |
| public function updatedSince(string $date): self | |
| { | |
| try { | |
| $since = Carbon::parse($date); | |
| } catch (\Exception $e) { | |
| // Return unfiltered data or handle error appropriately | |
| return $this; | |
| } | |
| return $this->filter(function ($item) use ($since) { | |
| if (!isset($item['updated_at'])) { | |
| return false; | |
| } | |
| try { | |
| $updated = Carbon::parse($item['updated_at']); | |
| } catch (\Exception $e) { | |
| return false; | |
| } | |
| return $updated->gte($since); | |
| }); | |
| } |
🤖 Prompt for AI Agents
In src/Support/FilterableGitHubData.php around lines 104 to 113, the method
updatedSince uses Carbon::parse without handling exceptions, which can cause
errors if the date string is invalid. Add try-catch blocks around the
Carbon::parse calls for both the input $date and the item's 'updated_at' field
to catch parsing exceptions. In the catch block, handle the error gracefully,
such as by returning false in the filter callback or throwing a custom exception
with a clear message for the input date.
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class IssueCommand extends Command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use Illuminate\Console\Command for consistency across environments.
Based on the retrieved learnings, command classes should extend Illuminate\Console\Command to ensure consistency across standalone CLI, Laravel, and Conduit environments, rather than the Symfony base class.
Apply this diff to fix the base class:
-use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Output\OutputInterface;
+use Illuminate\Console\Command;
-class IssueCommand extends Command
+class IssueCommand extends Command
-{
- protected function configure(): void
- {
- $this
- ->setName('issue')
- ->setDescription('Show available issue commands');
- }
-
- protected function execute(InputInterface $input, OutputInterface $output): int
+{
+ protected $signature = 'issue';
+ protected $description = 'Show available issue commands';
+
+ public function handle(): intCommittable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/Commands/IssueCommand.php around lines 7 to 11, the class currently
extends Symfony's Command class, but it should extend Illuminate\Console\Command
for consistency across environments. Replace the import of
Symfony\Component\Console\Command\Command with Illuminate\Console\Command and
update the class to extend this Illuminate base class instead.
| use Symfony\Component\Console\Command\Command; | ||
| use Symfony\Component\Console\Input\InputInterface; | ||
| use Symfony\Component\Console\Output\OutputInterface; | ||
|
|
||
| class RepoCommand extends Command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use Illuminate\Console\Command for consistency across environments.
This command also extends the wrong base class. Apply the same fix as the other command classes to use Illuminate\Console\Command.
🤖 Prompt for AI Agents
In src/Commands/RepoCommand.php around lines 7 to 11, the class extends
Symfony's Command instead of Illuminate's. Change the import statement to use
Illuminate\Console\Command and update the class to extend
Illuminate\Console\Command for consistency with other command classes.
| if ($directory && confirm("📂 Open {$directory} in your editor?", false)) { | ||
| exec("code \"{$directory}\""); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security: Potential command injection vulnerability.
The exec() function is used with a potentially user-controlled $directory variable without proper escaping. This could allow command injection attacks.
Use escapeshellarg() to properly escape the directory parameter:
- if ($directory && confirm("📂 Open {$directory} in your editor?", false)) {
- exec("code \"{$directory}\"");
- }
+ if ($directory && confirm("📂 Open {$directory} in your editor?", false)) {
+ $escapedDirectory = escapeshellarg($directory);
+ exec("code {$escapedDirectory}");
+ }📝 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.
| if ($directory && confirm("📂 Open {$directory} in your editor?", false)) { | |
| exec("code \"{$directory}\""); | |
| } | |
| if ($directory && confirm("📂 Open {$directory} in your editor?", false)) { | |
| $escapedDirectory = escapeshellarg($directory); | |
| exec("code {$escapedDirectory}"); | |
| } |
🤖 Prompt for AI Agents
In src/Commands/CloneCommand.php around lines 143 to 145, the exec() call uses
the $directory variable directly, which can lead to command injection
vulnerabilities. To fix this, wrap the $directory variable with escapeshellarg()
before passing it to exec(), ensuring the directory path is safely escaped and
preventing injection attacks.
| $selectedIssue = collect($issues)->firstWhere('number', $selectedNumber); | ||
|
|
||
| if ($selectedIssue) { | ||
| $this->showIssueDetails($selectedIssue, $repository, $output); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid Laravel-specific helpers for better compatibility.
Using collect() creates a dependency on Laravel's support package which might not be available in standalone mode.
Replace with standard PHP array functions:
- $selectedIssue = collect($issues)->firstWhere('number', $selectedNumber);
+ $selectedIssue = null;
+ foreach ($issues as $issue) {
+ if ($issue['number'] === $selectedNumber) {
+ $selectedIssue = $issue;
+ break;
+ }
+ }🤖 Prompt for AI Agents
In src/Commands/IssuesCommand.php around lines 322 to 327, the use of Laravel's
collect() helper creates an unnecessary dependency on Laravel's support package.
Replace collect($issues)->firstWhere('number', $selectedNumber) with a standard
PHP array function such as a foreach loop to iterate over $issues and find the
first element where 'number' equals $selectedNumber, then assign it to
$selectedIssue. This removes the Laravel-specific helper and improves
compatibility.
| [$owner, $repo] = explode('/', $repository, 2); | ||
|
|
||
| $rawIssues = spin( | ||
| fn () => $this->github->issues()->list($owner, $repo, [ | ||
| 'state' => $options['state'], | ||
| 'per_page' => min($fetchLimit, 100), | ||
| ])->json(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add validation for repository format.
The explode() function assumes the repository is in "owner/repo" format, but there's no validation. This will cause an error if the format is incorrect.
Add validation before parsing:
// Fetch more issues for better filtering
$fetchLimit = max(100, (int)$options['limit'] * 2);
+ if (!str_contains($repository, '/')) {
+ $output->writeln('<error>❌ Invalid repository format. Use: owner/repo</error>');
+ return 1;
+ }
+
[$owner, $repo] = explode('/', $repository, 2);📝 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.
| [$owner, $repo] = explode('/', $repository, 2); | |
| $rawIssues = spin( | |
| fn () => $this->github->issues()->list($owner, $repo, [ | |
| 'state' => $options['state'], | |
| 'per_page' => min($fetchLimit, 100), | |
| ])->json(), | |
| // Fetch more issues for better filtering | |
| $fetchLimit = max(100, (int)$options['limit'] * 2); | |
| if (!str_contains($repository, '/')) { | |
| $output->writeln('<error>❌ Invalid repository format. Use: owner/repo</error>'); | |
| return 1; | |
| } | |
| [$owner, $repo] = explode('/', $repository, 2); | |
| $rawIssues = spin( | |
| fn () => $this->github->issues()->list($owner, $repo, [ | |
| 'state' => $options['state'], | |
| 'per_page' => min($fetchLimit, 100), | |
| ])->json(), |
🤖 Prompt for AI Agents
In src/Commands/IssuesCommand.php around lines 137 to 143, the code uses
explode() on the repository string assuming it is in "owner/repo" format without
validation, which can cause errors if the format is incorrect. Add a validation
step before parsing to check if the repository string contains exactly one '/'
character and both owner and repo parts are non-empty. If the validation fails,
handle the error gracefully, for example by showing an error message and
stopping execution.
src/Commands/ReposCommand.php
Outdated
| if (!function_exists('config')) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve standalone mode detection.
Checking for the config() function existence is a fragile way to detect standalone mode. Consider using a more explicit approach.
Add a property or method to detect the environment:
+ private function isStandaloneMode(): bool
+ {
+ // Check for Laravel/Conduit environment more reliably
+ return !class_exists(\Illuminate\Support\Facades\App::class);
+ }
+
private function buildSearchQuery(array $options): ?string
{
// Disable search in standalone mode due to Laravel dependency issues
- if (!function_exists('config')) {
+ if ($this->isStandaloneMode()) {
return null;
}📝 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.
| if (!function_exists('config')) { | |
| return null; | |
| } | |
| // Add this helper to detect standalone mode more explicitly | |
| private function isStandaloneMode(): bool | |
| { | |
| // Check for Laravel/Conduit environment more reliably | |
| return !class_exists(\Illuminate\Support\Facades\App::class); | |
| } | |
| private function buildSearchQuery(array $options): ?string | |
| { | |
| // Disable search in standalone mode due to Laravel dependency issues | |
| if ($this->isStandaloneMode()) { | |
| return null; | |
| } | |
| // ... rest of existing search query logic ... | |
| } |
🤖 Prompt for AI Agents
In src/Commands/ReposCommand.php around lines 221 to 223, the current check for
standalone mode by verifying if the function 'config' exists is fragile. Replace
this with a more explicit environment detection by adding a dedicated property
or method in the class that clearly determines if the application is running in
standalone mode. Use this property or method instead of the function_exists
check to improve reliability and clarity.
- Update to github-client v2.3.0 with simple DTOs (no Laravel dependencies) - Enable GitHub's native search API in standalone mode - Update connector import to use conduit-ui/github-connector - Remove Laravel Data dependency restrictions - Support dev-master stability for cutting-edge features Search functionality now works perfectly: - Fast GitHub API search with proper query building - Natural language query parsing (e.g., 'laravel', 'php projects') - Graceful fallback to repository listing when needed - Framework agnostic - works in any PHP environment
Summary
Significantly improves repository listing performance and prepares for GitHub's native search functionality.
Performance Improvements
Search Functionality
Technical Changes
github-client ^2.2.0Benefits
Test Commands
🤖 Generated with Claude Code
Co-Authored-By: Claude [email protected]
Summary by CodeRabbit
New Features
Bug Fixes
Style
Chores
Tests