├── .editorconfig ├── .gitattributes ├── .gitignore ├── README.md ├── app ├── Application │ ├── .gitkeep │ ├── Load │ │ ├── LoadHandler.php │ │ ├── LoadOutputInterface.php │ │ └── LoadRequestInterface.php │ └── Report │ │ ├── ReportHandler.php │ │ ├── ReportOutputInterface.php │ │ └── ReportRequestInterface.php ├── Domain │ ├── .gitkeep │ ├── Aggregators │ │ ├── ReportAggregator.php │ │ └── TrackedFileAggregator.php │ ├── Contracts │ │ ├── Gateways │ │ │ └── FileVersionControlGateway.php │ │ └── Repositories │ │ │ └── TrackedFileRepository.php │ ├── Entities │ │ ├── Analysis.php │ │ ├── Metric.php │ │ ├── Path.php │ │ ├── ReportLine.php │ │ └── TrackedFile.php │ └── Services │ │ ├── ReportGenerator.php │ │ ├── TrackedFileAnalyzer.php │ │ └── TrackedFileService.php ├── Infrastructure │ ├── .gitkeep │ ├── Gateways │ │ └── CliGitGateway.php │ └── Repositories │ │ └── TrackedFileStorageRepository.php ├── Presenter │ └── Commands │ │ ├── .gitkeep │ │ ├── Load │ │ ├── LoadCliOutput.php │ │ ├── LoadCliRequest.php │ │ └── LoadCommand.php │ │ └── Report │ │ ├── Cli │ │ ├── Concerns │ │ │ ├── Sorts.php │ │ │ └── Thresholds.php │ │ ├── ReportCliOutput.php │ │ ├── ReportCliRequest.php │ │ └── ReportClipOutputOptions.php │ │ └── ReportCommand.php └── Providers │ └── AppServiceProvider.php ├── bootstrap └── app.php ├── box.json ├── builds └── php-git-insights-analyzer ├── composer.json ├── composer.lock ├── config ├── app.php ├── commands.php └── filesystems.php ├── php-git-insights-analyzer ├── phpunit.xml.dist └── tests ├── CreatesApplication.php ├── Feature └── InspireCommandTest.php ├── Pest.php ├── TestCase.php └── Unit └── ExampleTest.php /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.yml] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | /.github export-ignore 3 | .scrutinizer.yml export-ignore 4 | BACKERS.md export-ignore 5 | CONTRIBUTING.md export-ignore 6 | CHANGELOG.md export-ignore 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | /.vscode 4 | /.vagrant 5 | .phpunit.result.cache 6 | 7 | storage/app/analyse.json 8 | 9 | analyse.json 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # php-git-insights-analyzer 6 | 7 | ## Phar 8 | This tool is distributed as a [PHP Archive (PHAR)](https://www.php.net/phar): 9 | 10 | ``` 11 | wget https://github.com/DeGraciaMathieu/php-git-insights-analyzer/raw/master/builds/php-git-insights-analyzer 12 | ``` 13 | 14 | ``` 15 | php php-git-insights-analyzer --version 16 | ``` 17 | 18 | ## Usage 19 | 20 | First, you need to load the data required for the analysis : 21 | 22 | ``` 23 | php php-git-insights-analyzer app:load 24 | ``` 25 | 26 | Package uses git commands to retrieve files history, which is relatively time-consuming, so it was more efficient to create a database before carrying out the analyses. 27 | 28 | > For information, database is stored in the analyse.json 29 | 30 | Then analyse the data using the following command : 31 | 32 | ``` 33 | php php-git-insights-analyzer app:report 34 | ``` 35 | 36 | ``` 37 | $ php php-git-insights-analyzer app:report 38 | 39 | ❀ PHP Git Insights Analyzer ❀ 40 | 41 | ┌─────────────────────────────────────────────┬───────┬───────┬───────┬─────┬──────┬─────┬──────┐ 42 | │ name │ lines │ comm. │ cont. │ acs │ acsr │ wpc │ wpcr │ 43 | ├─────────────────────────────────────────────┼───────┼───────┼───────┼─────┼──────┼─────┼──────┤ 44 | │ Actions/GameAndRandomClipsSample.php │ 55 │ 2 │ 1 │ 27 │ 49 │ 55 │ 100 │ 45 | │ Console/Kernel.php │ 27 │ 1 │ 1 │ 27 │ 100 │ 27 │ 100 │ 46 | │ Dtos/Uuid.php │ 37 │ 3 │ 1 │ 12 │ 32 │ 37 │ 100 │ 47 | │ Enums/AutoplayEnum.php │ 9 │ 1 │ 1 │ 9 │ 100 │ 9 │ 100 │ 48 | │ Enums/ClipStateEnum.php │ 15 │ 2 │ 1 │ 7 │ 46 │ 15 │ 100 │ 49 | │ Exceptions/AssertException.php │ 10 │ 1 │ 1 │ 10 │ 100 │ 10 │ 100 │ 50 | │ Exceptions/Handler.php │ 35 │ 4 │ 1 │ 8 │ 22 │ 35 │ 100 │ 51 | │ Http/Controllers/Controller.php │ 12 │ 1 │ 1 │ 12 │ 100 │ 12 │ 100 │ 52 | │ Http/Controllers/HomeController.php │ 37 │ 9 │ 2 │ 4 │ 10 │ 18 │ 48 │ 53 | │ Http/Controllers/PaginateClipController.php │ 48 │ 8 │ 2 │ 6 │ 12 │ 24 │ 50 │ 54 | └─────────────────────────────────────────────┴───────┴───────┴───────┴─────┴──────┴─────┴──────┘ 55 | ``` 56 | 57 | Understanding analysis : 58 | 59 | | Abbreviation | Metric | Description | 60 | | ------------ | ------------------------------ | ------------------------------------------------------------------------------ | 61 | | comm. | Commits | Number of file commits. | 62 | | cont. | Contributors | Number of distinct contributors. | 63 | | acs | Average Commit Size | Average size of file commits. | 64 | | acsr | Average Commit Size Ratio | Proportion of average commit size compared to the total file size. | 65 | | wpc | Workload Per Contributor | Average size of a contributor's commits. | 66 | | wpcr | Workload Per Contributor Ratio | Proportion of average contributor commit size compared to the total file size. | 67 | 68 | ## Options 69 | 70 | | Options | Description | 71 | |-----------------------|-------------| 72 | | --folder= | Filter results by folder (e.g., --folder=Http/Controllers).| 73 | | --limit= | Specify the maximum number of results to display (default is 10).| 74 | | --sorts= | Sets the sorting order for results. The first value (lines, commits, contributors, acs, acsr, wpc, wpcr) corresponds to the affected field, and the second value (desc,asc; default desc) determines the sorting order.| 75 | | --thresholds= | Sets a threshold for the specified metric to filter results. The first value (lines, commits, contributors, acs, acsr, wpc, wpcr) corresponds to the affected metric, and the second value (e.g., 60) represents the minimum value required to apply the threshold.| 76 | 77 | ## Examples 78 | 79 | Files with more than 300 lines and low contributor diversity : 80 | 81 | ``` 82 | php php-git-insights-analyzer app:report --limit=10 --thresholds=wpcr,60 --thresholds=lines,300 83 | ``` 84 | 85 | Files with more than 10 commits and low contributor diversity : 86 | 87 | ``` 88 | php php-git-insights-analyzer app:report --limit=10 --thresholds=wpcr,60 --thresholds=commits,10 89 | ``` 90 | 91 | File with more than 10 commits and a renewal ratio of 10% with each commit. 92 | 93 | ``` 94 | php php-git-insights-analyzer app:report --limit=10 --thresholds=acsr,10 --thresholds=commits,10 95 | ``` 96 | 97 | > [!TIP] 98 | > Other analysis [tools](https://github.com/DeGraciaMathieu) are available. 99 | -------------------------------------------------------------------------------- /app/Application/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeGraciaMathieu/php-git-insights-analyzer/9b94a4f4aa6a615a31d38e4c0ba92ec04fe578e6/app/Application/.gitkeep -------------------------------------------------------------------------------- /app/Application/Load/LoadHandler.php: -------------------------------------------------------------------------------- 1 | hello(); 30 | 31 | $output->inProgress(); 32 | 33 | $aggregator = $this->trackedFileService->all( 34 | new Path($request->path()), 35 | ); 36 | 37 | $this->trackedFileAnalyzer->analyze($aggregator); 38 | 39 | $this->trackedFileRepository->store($aggregator); 40 | 41 | $output->present(); 42 | 43 | } catch (Throwable $th) { 44 | $output->error($th); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /app/Application/Load/LoadOutputInterface.php: -------------------------------------------------------------------------------- 1 | hello(); 25 | 26 | $reportAggregator = $this->reportGenerator->make(); 27 | 28 | $output->present($reportAggregator); 29 | 30 | } catch (Throwable $th) { 31 | $output->error($th); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /app/Application/Report/ReportOutputInterface.php: -------------------------------------------------------------------------------- 1 | reportLines[] = $reportLine; 17 | } 18 | 19 | public function toArray(): array 20 | { 21 | return array_map(function (ReportLine $reportLine) { 22 | return $reportLine->toArray(); 23 | }, $this->reportLines); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/Domain/Aggregators/TrackedFileAggregator.php: -------------------------------------------------------------------------------- 1 | path = $path; 19 | } 20 | 21 | public function add(TrackedFile $trackedFile): void 22 | { 23 | $this->trackedFiles[] = $trackedFile; 24 | } 25 | 26 | public function path(): Path|null 27 | { 28 | return $this->path; 29 | } 30 | 31 | public function trackedFiles(): array 32 | { 33 | return $this->trackedFiles; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Domain/Contracts/Gateways/FileVersionControlGateway.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | public function get(): array; 14 | 15 | public function store(TrackedFileAggregator $aggregator): void; 16 | } 17 | -------------------------------------------------------------------------------- /app/Domain/Entities/Analysis.php: -------------------------------------------------------------------------------- 1 | value = $value ?: 1; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Domain/Entities/Path.php: -------------------------------------------------------------------------------- 1 | name = $name; 21 | 22 | $this->load($analysis); 23 | 24 | $this->computeAverageSize(); 25 | 26 | $this->computeWorkloadPerContributor(); 27 | } 28 | 29 | private function load(Analysis $analysis): void 30 | { 31 | $this->totalLines = $analysis->totalLine->value; 32 | $this->totalCommits = $analysis->commitsCount->value; 33 | $this->totalContributors = $analysis->contributorsCount->value; 34 | } 35 | 36 | private function computeAverageSize(): void 37 | { 38 | $this->averageCommitSize = $this->totalLines / $this->totalCommits; 39 | $this->averageCommitSizeRatio = $this->averageCommitSize * 100 / $this->totalLines; 40 | } 41 | 42 | private function computeWorkloadPerContributor(): void 43 | { 44 | $this->workloadPerContributor = $this->totalLines / $this->totalContributors; 45 | $this->workloadPerContributorRatio = $this->workloadPerContributor * 100 / $this->totalLines; 46 | } 47 | 48 | public function toArray(): array 49 | { 50 | return get_object_vars($this); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/Domain/Entities/TrackedFile.php: -------------------------------------------------------------------------------- 1 | trackedFileRepository->get(); 20 | 21 | foreach ($trackedFiles as $trackedFile) { 22 | 23 | $reportLine = new ReportLine( 24 | name: $trackedFile->name, 25 | analysis: $trackedFile->analysis, 26 | ); 27 | 28 | $this->aggregator->add($reportLine); 29 | } 30 | 31 | return $this->aggregator; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Domain/Services/TrackedFileAnalyzer.php: -------------------------------------------------------------------------------- 1 | trackedFiles(); 18 | 19 | foreach ($trackedFiles as $trackedFile) { 20 | 21 | $analysis = $this->fileVersionControl->analyze($trackedFile); 22 | 23 | $trackedFile->analysis = $analysis; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Domain/Services/TrackedFileService.php: -------------------------------------------------------------------------------- 1 | aggregator->setPath($path); 21 | 22 | $names = $this->fileVersionControl->allTrackedFilesName($path); 23 | 24 | foreach ($names as $name) { 25 | 26 | $trackedFile = new TrackedFile($name); 27 | 28 | $this->aggregator->add($trackedFile); 29 | } 30 | 31 | return $this->aggregator; 32 | } 33 | } -------------------------------------------------------------------------------- /app/Infrastructure/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeGraciaMathieu/php-git-insights-analyzer/9b94a4f4aa6a615a31d38e4c0ba92ec04fe578e6/app/Infrastructure/.gitkeep -------------------------------------------------------------------------------- /app/Infrastructure/Gateways/CliGitGateway.php: -------------------------------------------------------------------------------- 1 | value); 17 | 18 | $cmdFiles = "git ls-files '*.php'"; 19 | 20 | $names = explode("\n", trim(shell_exec($cmdFiles))); 21 | 22 | return $names; 23 | } 24 | 25 | public function analyze(TrackedFile $trackedFile): Analysis 26 | { 27 | $name = $trackedFile->name; 28 | 29 | $cdm = "git log --pretty=format:'%an' -- " . $name . "| awk '!seen[$0]++ { contributors++ } END { print contributors }' && git log --oneline -- $name | wc -l"; 30 | 31 | $output = trim(shell_exec($cdm)); 32 | 33 | [$contributorsCount, $commitsCount] = explode("\n", trim($output)); 34 | 35 | $lines = file($name); 36 | 37 | $totalLine = count($lines) ?: 0; 38 | 39 | return new Analysis( 40 | totalLine: new Metric($totalLine), 41 | commitsCount: new Metric($commitsCount), 42 | contributorsCount: new Metric($contributorsCount), 43 | ); 44 | } 45 | } -------------------------------------------------------------------------------- /app/Infrastructure/Repositories/TrackedFileStorageRepository.php: -------------------------------------------------------------------------------- 1 | makeStorageFileName(); 20 | 21 | $trackedFiles = $aggregator->trackedFiles(); 22 | 23 | $this->filesystem->put($storageFileName, serialize($trackedFiles)); 24 | } 25 | 26 | /** 27 | * @return array 28 | */ 29 | public function get(): array 30 | { 31 | $storageFileName = $this->makeStorageFileName(); 32 | 33 | $trackedFiles = $this->filesystem->get($storageFileName); 34 | 35 | if ($trackedFiles === null) { 36 | throw new Exception('Please, run app:load command before.'); 37 | } 38 | 39 | return unserialize($trackedFiles); 40 | } 41 | 42 | private function makeStorageFileName(): string 43 | { 44 | return 'analyse.json'; 45 | } 46 | } -------------------------------------------------------------------------------- /app/Presenter/Commands/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeGraciaMathieu/php-git-insights-analyzer/9b94a4f4aa6a615a31d38e4c0ba92ec04fe578e6/app/Presenter/Commands/.gitkeep -------------------------------------------------------------------------------- /app/Presenter/Commands/Load/LoadCliOutput.php: -------------------------------------------------------------------------------- 1 | getMessage()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Presenter/Commands/Load/LoadCliRequest.php: -------------------------------------------------------------------------------- 1 | path; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Presenter/Commands/Load/LoadCommand.php: -------------------------------------------------------------------------------- 1 | handle( 34 | new LoadCliRequest( 35 | path: $this->argument('path'), 36 | ), 37 | new LoadCliOutput(), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Presenter/Commands/Report/Cli/Concerns/Sorts.php: -------------------------------------------------------------------------------- 1 | sorts === [] 10 | ? $this->getDefaultSorting() 11 | : $this->sanitizeSortingPairing(); 12 | } 13 | 14 | private function getDefaultSorting(): array 15 | { 16 | return [ 17 | 'totalCommits', 18 | 'desc', 19 | ]; 20 | } 21 | 22 | private function sanitizeSortingPairing(): array 23 | { 24 | return array_map(function ($sort) { 25 | 26 | [$sortKey, $sortValue] = explode(',', $sort); 27 | 28 | $sortValue ??= 'desc'; 29 | 30 | return [ 31 | $this->mapIdentifier($sortKey), 32 | $sortValue, 33 | ]; 34 | 35 | }, $this->sorts); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/Presenter/Commands/Report/Cli/Concerns/Thresholds.php: -------------------------------------------------------------------------------- 1 | thresholds === []) { 10 | return []; 11 | } 12 | 13 | return $this->sanitizeThresholdsPairing(); 14 | } 15 | 16 | private function sanitizeThresholdsPairing(): ?array 17 | { 18 | return array_map(function ($threshold) { 19 | 20 | [$minKey, $minValue] = explode(',', $threshold); 21 | 22 | return [ 23 | $this->mapIdentifier($minKey), 24 | $minValue, 25 | ]; 26 | 27 | }, $this->thresholds); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Presenter/Commands/Report/Cli/ReportCliOutput.php: -------------------------------------------------------------------------------- 1 | toArray()); 28 | 29 | $rows = $this->sort($rows); 30 | 31 | $rows = $this->cut($rows); 32 | 33 | $this->display($rows); 34 | } 35 | 36 | public function error(Throwable $throwable): void 37 | { 38 | error($throwable->getMessage()); 39 | 40 | error('Maybe run app:load again ?'); 41 | } 42 | 43 | private function sort(Collection $rows): Collection 44 | { 45 | $sorts = $this->options->getSorts(); 46 | 47 | $rows = $rows->sortBy($sorts); 48 | 49 | return $rows; 50 | } 51 | 52 | private function cut(Collection $rows): Collection 53 | { 54 | $rows = $this->cuttingFolder($rows); 55 | 56 | $rows = $this->cuttingThresholds($rows); 57 | 58 | return $rows->take($this->options->getLimit()); 59 | } 60 | 61 | private function cuttingFolder(Collection $rows): Collection 62 | { 63 | $rows = $rows->filter(function ($row) { 64 | 65 | if ($folder = $this->options->getFolder()) { 66 | return str_starts_with($row['name'], $folder); 67 | } 68 | 69 | return true; 70 | }); 71 | 72 | return $rows; 73 | } 74 | 75 | private function cuttingThresholds(Collection $rows): Collection 76 | { 77 | $rows = $rows->filter(function ($row) { 78 | 79 | $thresholds = $this->options->getThresholds(); 80 | 81 | foreach ($thresholds as $threshold) { 82 | 83 | [$key, $value] = $threshold; 84 | 85 | if ($row[$key] < $value) { 86 | return false; 87 | } 88 | } 89 | 90 | return true; 91 | }); 92 | 93 | return $rows; 94 | } 95 | 96 | private function display(Collection $rows): void 97 | { 98 | table( 99 | [ 100 | 'name', 101 | 'lines', 102 | 'comm.', 103 | 'cont.', 104 | 'acs', 105 | 'acsr%', 106 | 'wpc', 107 | 'wpcr%', 108 | ], 109 | $rows, 110 | ); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/Presenter/Commands/Report/Cli/ReportCliRequest.php: -------------------------------------------------------------------------------- 1 | folder; 20 | } 21 | 22 | public function getLimit(): int|null 23 | { 24 | return $this->limit; 25 | } 26 | 27 | protected function mapIdentifier(string $key): string 28 | { 29 | return match ($key) { 30 | 'lines' => 'totalLines', 31 | 'commits' => 'totalCommits', 32 | 'contributors' => 'totalContributors', 33 | 'acs' => 'averageCommitSize', 34 | 'acsr' => 'averageCommitSizeRatio', 35 | 'wpc' => 'workloadPerContributor', 36 | 'wpcr' => 'workloadPerContributorRatio', 37 | default => 'totalCommits', 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Presenter/Commands/Report/ReportCommand.php: -------------------------------------------------------------------------------- 1 | option('folder'), 39 | limit: $this->option('limit'), 40 | sorts: $this->option('sorts'), 41 | thresholds: $this->option('thresholds'), 42 | ); 43 | 44 | $reportHandler->handle( 45 | new ReportCliRequest(), 46 | new ReportCliOutput($options), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->singleton(FileVersionControlGateway::class, function ($app) { 29 | 30 | $aggregator = $app[TrackedFileAggregator::class]; 31 | 32 | return new CliGitGateway($aggregator); 33 | }); 34 | 35 | $this->app->singleton(TrackedFileRepository::class, function ($app) { 36 | 37 | $filesystem = $app[FilesystemManager::class]; 38 | 39 | return new TrackedFileStorageRepository($filesystem); 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | Illuminate\Contracts\Console\Kernel::class, 31 | LaravelZero\Framework\Kernel::class 32 | ); 33 | 34 | $app->singleton( 35 | Illuminate\Contracts\Debug\ExceptionHandler::class, 36 | Illuminate\Foundation\Exceptions\Handler::class 37 | ); 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | Return The Application 42 | |-------------------------------------------------------------------------- 43 | | 44 | | This script returns the application instance. The instance is given to 45 | | the calling script so we can separate the building of the instances 46 | | from the actual running of the application and sending responses. 47 | | 48 | */ 49 | 50 | return $app; 51 | -------------------------------------------------------------------------------- /box.json: -------------------------------------------------------------------------------- 1 | { 2 | "chmod": "0755", 3 | "directories": [ 4 | "app", 5 | "bootstrap", 6 | "config", 7 | "vendor" 8 | ], 9 | "files": [ 10 | "composer.json" 11 | ], 12 | "exclude-composer-files": false, 13 | "compression": "GZ", 14 | "compactors": [ 15 | "KevinGH\\Box\\Compactor\\Php", 16 | "KevinGH\\Box\\Compactor\\Json" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /builds/php-git-insights-analyzer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeGraciaMathieu/php-git-insights-analyzer/9b94a4f4aa6a615a31d38e4c0ba92ec04fe578e6/builds/php-git-insights-analyzer -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-zero/laravel-zero", 3 | "description": "The Laravel Zero Framework.", 4 | "keywords": ["framework", "laravel", "laravel zero", "console", "cli"], 5 | "homepage": "https://laravel-zero.com", 6 | "type": "project", 7 | "license": "MIT", 8 | "support": { 9 | "issues": "https://github.com/laravel-zero/laravel-zero/issues", 10 | "source": "https://github.com/laravel-zero/laravel-zero" 11 | }, 12 | "authors": [ 13 | { 14 | "name": "Nuno Maduro", 15 | "email": "enunomaduro@gmail.com" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.1", 20 | "laravel-zero/framework": "^10.2", 21 | "nunomaduro/termwind": "^1.15.1" 22 | }, 23 | "require-dev": { 24 | "laravel/pint": "^1.13", 25 | "mockery/mockery": "^1.6", 26 | "pestphp/pest": "^2.22" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "App\\": "app/", 31 | "Database\\Factories\\": "database/factories/", 32 | "Database\\Seeders\\": "database/seeders/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "Tests\\": "tests/" 38 | } 39 | }, 40 | "config": { 41 | "preferred-install": "dist", 42 | "sort-packages": true, 43 | "optimize-autoloader": true, 44 | "allow-plugins": { 45 | "pestphp/pest-plugin": true 46 | } 47 | }, 48 | "minimum-stability": "stable", 49 | "prefer-stable": true, 50 | "bin": ["php-git-insights-analyzer"] 51 | } 52 | -------------------------------------------------------------------------------- /config/app.php: -------------------------------------------------------------------------------- 1 | 'Php-git-insights-analyzer', 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Application Version 21 | |-------------------------------------------------------------------------- 22 | | 23 | | This value determines the "version" your application is currently running 24 | | in. You may want to follow the "Semantic Versioning" - Given a version 25 | | number MAJOR.MINOR.PATCH when an update happens: https://semver.org. 26 | | 27 | */ 28 | 29 | 'version' => app('git.version'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Application Environment 34 | |-------------------------------------------------------------------------- 35 | | 36 | | This value determines the "environment" your application is currently 37 | | running in. This may determine how you prefer to configure various 38 | | services the application utilizes. This can be overridden using 39 | | the global command line "--env" option when calling commands. 40 | | 41 | */ 42 | 43 | 'env' => 'development', 44 | 45 | /* 46 | |-------------------------------------------------------------------------- 47 | | Application Timezone 48 | |-------------------------------------------------------------------------- 49 | | 50 | | Here you may specify the default timezone for your application, which 51 | | will be used by the PHP date and date-time functions. We have gone 52 | | ahead and set this to a sensible default for you out of the box. 53 | | 54 | */ 55 | 56 | 'timezone' => 'UTC', 57 | 58 | /* 59 | |-------------------------------------------------------------------------- 60 | | Autoloaded Service Providers 61 | |-------------------------------------------------------------------------- 62 | | 63 | | The service providers listed here will be automatically loaded on the 64 | | request to your application. Feel free to add your own services to 65 | | this array to grant expanded functionality to your applications. 66 | | 67 | */ 68 | 69 | 'providers' => [ 70 | App\Providers\AppServiceProvider::class, 71 | ], 72 | 73 | ]; 74 | -------------------------------------------------------------------------------- /config/commands.php: -------------------------------------------------------------------------------- 1 | NunoMaduro\LaravelConsoleSummary\SummaryCommand::class, 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Commands Paths 21 | |-------------------------------------------------------------------------- 22 | | 23 | | This value determines the "paths" that should be loaded by the console's 24 | | kernel. Foreach "path" present on the array provided below the kernel 25 | | will extract all "Illuminate\Console\Command" based class commands. 26 | | 27 | */ 28 | 29 | 'paths' => [app_path('Presenter/Commands')], 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Added Commands 34 | |-------------------------------------------------------------------------- 35 | | 36 | | You may want to include a single command class without having to load an 37 | | entire folder. Here you can specify which commands should be added to 38 | | your list of commands. The console's kernel will try to load them. 39 | | 40 | */ 41 | 42 | 'add' => [ 43 | // .. 44 | ], 45 | 46 | /* 47 | |-------------------------------------------------------------------------- 48 | | Hidden Commands 49 | |-------------------------------------------------------------------------- 50 | | 51 | | Your application commands will always be visible on the application list 52 | | of commands. But you can still make them "hidden" specifying an array 53 | | of commands below. All "hidden" commands can still be run/executed. 54 | | 55 | */ 56 | 57 | 'hidden' => [ 58 | NunoMaduro\LaravelConsoleSummary\SummaryCommand::class, 59 | Symfony\Component\Console\Command\DumpCompletionCommand::class, 60 | Symfony\Component\Console\Command\HelpCommand::class, 61 | Illuminate\Console\Scheduling\ScheduleRunCommand::class, 62 | Illuminate\Console\Scheduling\ScheduleListCommand::class, 63 | Illuminate\Console\Scheduling\ScheduleFinishCommand::class, 64 | Illuminate\Foundation\Console\VendorPublishCommand::class, 65 | LaravelZero\Framework\Commands\StubPublishCommand::class, 66 | ], 67 | 68 | /* 69 | |-------------------------------------------------------------------------- 70 | | Removed Commands 71 | |-------------------------------------------------------------------------- 72 | | 73 | | Do you have a service provider that loads a list of commands that 74 | | you don't need? No problem. Laravel Zero allows you to specify 75 | | below a list of commands that you don't to see in your app. 76 | | 77 | */ 78 | 79 | 'remove' => [ 80 | // .. 81 | ], 82 | 83 | ]; 84 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | 'local', 5 | 'disks' => [ 6 | 'local' => [ 7 | 'driver' => 'local', 8 | 'root' => getcwd(), 9 | ], 10 | ], 11 | ]; 12 | -------------------------------------------------------------------------------- /php-git-insights-analyzer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | ./tests/Feature 10 | 11 | 12 | ./tests/Unit 13 | 14 | 15 | 16 | 17 | ./app 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 18 | 19 | return $app; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/Feature/InspireCommandTest.php: -------------------------------------------------------------------------------- 1 | artisan('inspire')->assertExitCode(0); 5 | }); 6 | -------------------------------------------------------------------------------- /tests/Pest.php: -------------------------------------------------------------------------------- 1 | in('Feature'); 15 | 16 | /* 17 | |-------------------------------------------------------------------------- 18 | | Expectations 19 | |-------------------------------------------------------------------------- 20 | | 21 | | When you're writing tests, you often need to check that values meet certain conditions. The 22 | | "expect()" function gives you access to a set of "expectations" methods that you can use 23 | | to assert different things. Of course, you may extend the Expectation API at any time. 24 | | 25 | */ 26 | 27 | expect()->extend('toBeOne', function () { 28 | return $this->toBe(1); 29 | }); 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Functions 34 | |-------------------------------------------------------------------------- 35 | | 36 | | While Pest is very powerful out-of-the-box, you may have some testing code specific to your 37 | | project that you don't want to repeat in every file. Here you can also expose helpers as 38 | | global functions to help you to reduce the number of lines of code in your test files. 39 | | 40 | */ 41 | 42 | function something(): void 43 | { 44 | // .. 45 | } 46 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | toBeTrue(); 5 | }); 6 | --------------------------------------------------------------------------------