Skip to content

Ractored. #24

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

Merged
merged 8 commits into from
May 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,33 @@
}
],
"require": {
"php": "^8.2",
"spatie/laravel-package-tools": "^1.16",
"illuminate/contracts": "^10.0||^11.0||^12.0"
"php": "^8.3 || ^8.2",
"illuminate/contracts": "^10.0||^11.0||^12.0",
"spatie/laravel-package-tools": "^1.16"
},
"require-dev": {
"tightenco/duster": "^3.2",
"driftingly/rector-laravel": "^1.2",
"larastan/larastan": "^2.9",
"laravel/pint": "^1.14",
"nunomaduro/collision": "^8.1.1||^7.10.0",
"larastan/larastan": "^2.9",
"orchestra/testbench": "^9.0.0||^8.22.0",
"pestphp/pest": "^2.34",
"pestphp/pest-plugin-arch": "^2.7",
"pestphp/pest-plugin-laravel": "^2.3",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-phpunit": "^1.3"
"phpstan/phpstan-phpunit": "^1.3",
"rector/rector": "^1.2"
},
"autoload": {
"psr-4": {
"Msamgan\\LaravelEnvKeysChecker\\": "src/",
"Msamgan\\LaravelEnvKeysChecker\\Database\\Factories\\": "database/factories/"
"Msamgan\\LaravelEnvKeysChecker\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Msamgan\\LaravelEnvKeysChecker\\Tests\\": "tests/",
"Workbench\\App\\": "workbench/app/"
"Msamgan\\LaravelEnvKeysChecker\\Tests\\": "tests/"
}
},
"scripts": {
Expand All @@ -69,7 +70,7 @@
"analyse": "vendor/bin/phpstan analyse",
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage",
"format": "vendor/bin/pint"
"format": "./vendor/bin/rector process && vendor/bin/pint && ./vendor/bin/duster fix"
},
"config": {
"sort-packages": true,
Expand Down
8 changes: 5 additions & 3 deletions config/env-keys-checker.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<?php

declare(strict_types=1);

return [
// List of all the .env files to ignore while checking the env keys
'ignore_files' => explode(',', env('KEYS_CHECKER_IGNORE_FILES', '')),
'ignore_files' => explode(',', (string) env('KEYS_CHECKER_IGNORE_FILES', '')),

// List of all the env keys to ignore while checking the env keys
'ignore_keys' => explode(',', env('KEYS_CHECKER_IGNORE_KEYS', '')),
'ignore_keys' => explode(',', (string) env('KEYS_CHECKER_IGNORE_KEYS', '')),

// strategy to add the missing keys to the .env file
// ask: will ask the user to add the missing keys
Expand All @@ -15,7 +17,7 @@

// List of all the .env.* files to be checked if they
// are present in the .gitignore file
'gitignore_files' => explode(',', env('KEYS_CHECKER_GITIGNORE_FILES', '.env')),
'gitignore_files' => explode(',', (string) env('KEYS_CHECKER_GITIGNORE_FILES', '.env')),

// Master .env file to be used for syncing the keys
'master_env' => env('MASTER_ENV', '.env'),
Expand Down
59 changes: 56 additions & 3 deletions pint.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,64 @@
{
"preset": "laravel",
"notPath": [
"tests/TestCase.php"
],
"rules": {
"array_push": true,
"backtick_to_shell_exec": true,
"date_time_immutable": true,
"declare_strict_types": true,
"lowercase_keywords": true,
"lowercase_static_reference": true,
"final_class": true,
"final_internal_class": true,
"final_public_method_for_abstract_class": true,
"fully_qualified_strict_types": true,
"global_namespace_import": {
"import_classes": true,
"import_constants": true,
"import_functions": true
},
"mb_str_functions": true,
"modernize_types_casting": true,
"new_with_parentheses": false,
"no_superfluous_elseif": true,
"no_useless_else": true,
"no_multiple_statements_per_line": true,
"ordered_class_elements": {
"order": [
"use_trait",
"case",
"constant",
"constant_public",
"constant_protected",
"constant_private",
"property_public",
"property_protected",
"property_private",
"construct",
"destruct",
"magic",
"phpunit",
"method_abstract",
"method_public_static",
"method_public",
"method_protected_static",
"method_protected",
"method_private_static",
"method_private"
],
"sort_algorithm": "none"
},
"ordered_interfaces": true,
"ordered_traits": true,
"protected_to_private": true,
"self_accessor": true,
"self_static_accessor": true,
"strict_comparison": true,
"visibility_required": true,
"concat_space": {
"spacing": "one"
},
"ordered_imports": {
"sort_algorithm": "alpha"
}
}
}
34 changes: 34 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\ValueObject\PhpVersion;
use RectorLaravel\Set\LaravelSetList;

return RectorConfig::configure()
->withPaths([
__DIR__ . '/src',
__DIR__ . '/config',
__DIR__ . '/tests',
])->withPhpSets(php83: true)
->withPhpVersion(PhpVersion::PHP_83)
->withPreparedSets(
deadCode: true,
codeQuality: true,
typeDeclarations: true,
privatization: true,
instanceOf: true,
earlyReturn: true,
carbon: true,
)->withSets([
LaravelSetList::LARAVEL_110,
LaravelSetList::LARAVEL_CODE_QUALITY,
LaravelSetList::LARAVEL_IF_HELPERS,
LaravelSetList::LARAVEL_ARRAY_STR_FUNCTION_TO_STATIC_CALL,
LaravelSetList::LARAVEL_FACADE_ALIASES_TO_FULL_NAMES,
LaravelSetList::LARAVEL_ELOQUENT_MAGIC_METHOD_TO_QUERY_BUILDER,
LaravelSetList::LARAVEL_CONTAINER_STRING_TO_FULLY_QUALIFIED_NAME,
LaravelSetList::LARAVEL_ARRAYACCESS_TO_METHOD_CALL,
LaravelSetList::LARAVEL_COLLECTION,
])->withImportNames(importDocBlockNames: false);
6 changes: 4 additions & 2 deletions src/Actions/AddKeys.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
<?php

declare(strict_types=1);

namespace Msamgan\LaravelEnvKeysChecker\Actions;

use Illuminate\Support\Collection;

class AddKeys
final class AddKeys
{
public function handle(Collection $missingKeys): void
{
$missingKeys->each(function ($missingKey) {
$missingKeys->each(function (array $missingKey): void {
$filePath = base_path($missingKey['envFile']);
$envContent = file($filePath);

Expand Down
8 changes: 5 additions & 3 deletions src/Actions/CheckKeys.php
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<?php

declare(strict_types=1);

namespace Msamgan\LaravelEnvKeysChecker\Actions;

use Illuminate\Support\Collection;

class CheckKeys
final class CheckKeys
{
public function handle(array $keyData, array $envFiles, Collection $missingKeys): void
{
collect($envFiles)->each(function ($envFile) use ($keyData, $missingKeys) {
collect($envFiles)->each(function ($envFile) use ($keyData, $missingKeys): void {
$envContent = file($envFile);
$keyExists = false;

foreach ($envContent as $line) {
if (str_starts_with($line, $keyData['key'])) {
if (str_starts_with($line, (string) $keyData['key'])) {
$keyExists = true;
break;
}
Expand Down
16 changes: 16 additions & 0 deletions src/Actions/FilterFiles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Msamgan\LaravelEnvKeysChecker\Actions;

final class FilterFiles
{
public function handle(array $envFiles, array $ignoredFiles): array
{
return collect(value: $envFiles)
->reject(callback: fn ($file): bool => in_array(needle: basename((string) $file), haystack: $ignoredFiles))
->reject(callback: fn ($file): bool => str_ends_with(haystack: basename((string) $file), needle: '.encrypted'))
->toArray();
}
}
14 changes: 6 additions & 8 deletions src/Actions/GetKeys.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<?php

declare(strict_types=1);

namespace Msamgan\LaravelEnvKeysChecker\Actions;

use Illuminate\Support\Collection;

class GetKeys
final class GetKeys
{
public function handle(array|string $files, ?bool $withComments = false): Collection
{
Expand All @@ -16,7 +18,7 @@ public function handle(array|string $files, ?bool $withComments = false): Collec

return $files
->map(function ($file) use ($ignoredKeys, $withComments) {
$collection = collect(file($file))->map(function ($line, $index) use ($file) {
$collection = collect(file($file))->map(function ($line, $index) use ($file): array {
[$key] = explode('=', $line);

return [
Expand All @@ -27,14 +29,10 @@ public function handle(array|string $files, ?bool $withComments = false): Collec
});

if (! $withComments) {
$collection = $collection->filter(function ($item) {
return $item['key'] !== "\n" && ! str_starts_with($item['key'], '#');
});
$collection = $collection->filter(fn ($item): bool => $item['key'] !== "\n" && ! str_starts_with($item['key'], '#'));
}

return $collection->filter(function ($keyData) use ($ignoredKeys) {
return ! in_array($keyData['key'], $ignoredKeys);
});
return $collection->reject(fn ($keyData): bool => in_array($keyData['key'], $ignoredKeys));
})
->flatten(1)
->unique('key');
Expand Down
6 changes: 4 additions & 2 deletions src/Commands/EnvInGitIgnoreCommand.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<?php

declare(strict_types=1);

namespace Msamgan\LaravelEnvKeysChecker\Commands;

use Illuminate\Console\Command;
use Msamgan\LaravelEnvKeysChecker\Concerns\HelperFunctions;

class EnvInGitIgnoreCommand extends Command
final class EnvInGitIgnoreCommand extends Command
{
use HelperFunctions;

Expand All @@ -28,7 +30,7 @@ public function handle(): int
$filesToCheck = config(key: 'env-keys-checker.gitignore_files', default: ['.env']);

$missingFiles = collect();
collect(value: $filesToCheck)->each(callback: function ($file) use ($gitIgnoreContent, $missingFiles) {
collect(value: $filesToCheck)->each(callback: function ($file) use ($gitIgnoreContent, $missingFiles): void {
if (! in_array(needle: $file, haystack: $gitIgnoreContent)) {
$missingFiles->push(values: $file);
}
Expand Down
35 changes: 16 additions & 19 deletions src/Commands/EnvKeysSyncCommand.php
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
<?php

declare(strict_types=1);

namespace Msamgan\LaravelEnvKeysChecker\Commands;

use Illuminate\Console\Command;
use Msamgan\LaravelEnvKeysChecker\Actions\FilterFiles;
use Msamgan\LaravelEnvKeysChecker\Concerns\HelperFunctions;

class EnvKeysSyncCommand extends Command
final class EnvKeysSyncCommand extends Command
{
use HelperFunctions;

public $signature = 'env:sync-keys';

public $description = 'Sync keys from master .env file to other .env files.';

public function handle(): int
public function handle(FilterFiles $filterFiles): int
{
$allKeysCheck = $this->call('env:keys-check', [
'--auto-add' => 'none',
Expand All @@ -28,30 +31,26 @@ public function handle(): int
return self::FAILURE;
}

$envFiles = glob(pattern: base_path(path: '.env*'));
$ignoredFiles = config(key: 'env-keys-checker.ignore_files', default: []);
$envFiles = $this->getEnvs();
$ignoredFiles = $this->getFilesToIgnore();

if (empty($envFiles)) {
if ($envFiles === []) {
$this->showFailureInfo(message: 'No .env files found.');

return self::FAILURE;
}

$envFiles = collect(value: $envFiles)->filter(callback: function ($file) use ($ignoredFiles) {
return ! in_array(needle: basename(path: $file), haystack: $ignoredFiles);
})->toArray();
$envFiles = $filterFiles->handle(envFiles: $envFiles, ignoredFiles: $ignoredFiles);

if (empty($envFiles)) {
if ($envFiles === []) {
$this->showFailureInfo(message: 'No .env files found.');

return self::FAILURE;
}

$envFiles = collect(value: $envFiles)->filter(callback: function ($file) {
return basename(path: $file) !== $this->getMasterEnv();
});
$envFiles = collect(value: $envFiles)->filter(callback: fn ($file): bool => basename(path: (string) $file) !== $this->getMasterEnv());

$envFiles->each(callback: function ($envFile) {
$envFiles->each(callback: function ($envFile): void {
$totalKeysFromMaster = count(value: file(filename: $this->getMasterEnv()));
for ($line = 1; $line <= $totalKeysFromMaster; $line++) {
$keyMaster = $this->getKeyFromFileOnLine(file: $this->getMasterEnv(), line: $line);
Expand Down Expand Up @@ -93,12 +92,12 @@ public function handle(): int

private function getMasterEnv(): string
{
return config(key: 'env-keys-checker.master_env', default: '.env');
return (string) config(key: 'env-keys-checker.master_env', default: '.env');
}

private function getKeyFromFileOnLine(string $file, int $line): string
{
return file(filename: $file)[$line - 1];
return file(filename: $file)[$line - 1] ?? '';
}

private function checkIfComment(string $line): bool
Expand All @@ -122,11 +121,9 @@ private function checkIfEmptyLine(string $line): bool
private function moveKeyToLine(string $file, string $key, int $toLine): void
{
$lines = file(filename: $file);
$keyLine = array_filter(array: $lines, callback: function ($line) use ($key) {
return str_starts_with($line, $key);
});
$keyLine = array_filter(array: $lines, callback: fn ($line): bool => str_starts_with($line, $key));

if (empty($keyLine)) {
if ($keyLine === []) {
return;
}

Expand Down
Loading