Skip to content

Commit

Permalink
Merge pull request #54 from koriym/refactor
Browse files Browse the repository at this point in the history
Validate package name input
  • Loading branch information
koriym authored Nov 4, 2020
2 parents 2cc61ab + f168348 commit 85f983a
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 59 deletions.
12 changes: 6 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ jobs:
php: 7.4
install: composer global require --dev phpstan/phpstan ^0.12 vimeo/psalm ^3.11 phpmetrics/phpmetrics ^2.6 maglnet/composer-require-checker ^2.0
script:
- ~/.composer/vendor/bin/phpstan analyse -c phpstan.neon --no-progress --no-interaction
- ~/.composer/vendor/bin/psalm --show-info=false --shepherd
- ~/.composer/vendor/bin/psalm -c psalm.compiler.xml --show-info=true
- ~/.composer/vendor/bin/phpmetrics --exclude=Exception src
- ~/.composer/vendor/bin/composer-require-checker check ./composer.json
- ~composer global exec -v -- phpstan analyse -c phpstan.neon --no-progress --no-interaction
- ~composer global exec -v -- psalm --show-info=false --shepherd
- ~composer global exec -v -- psalm -c psalm.compiler.xml --show-info=true
- ~composer global exec -v -- phpmetrics --exclude=Exception src
- ~composer global exec -v -- composer-require-checker check ./composer.json

- stage: Code Quality
name: Coding standards
php: 7.4
install: composer global require --dev doctrine/coding-standard ^8.1
script:
- ~/.composer/vendor/bin/phpcs --standard=./phpcs.xml src tests
- ~composer global exec -v -- phpcs --standard=./phpcs.xml src tests
14 changes: 14 additions & 0 deletions README.proj.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# _package_name_

## Installation

composer install

## Available Commands

composer test // Run unit test
composer tests // Test and quality checks
composer cs-fix // Fix the coding style
composer sa // Run static analysys tools
composer run-script --list // List all commands

21 changes: 14 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"squizlabs/php_codesniffer": "^3.5",
"phpmd/phpmd": "^2.9",
"phpstan/phpstan" : "^0.12",
"vimeo/psalm": "^3.17",
"vimeo/psalm": "^4.1",
"phpmetrics/phpmetrics": "^2.7",
"doctrine/coding-standard": "^8.1",
"composer/composer": "^2.0"
Expand All @@ -44,17 +44,13 @@
"Koriym\\PhpSkeleton\\Installer::preInstall"
],
"post-install-cmd": [
"Koriym\\PhpSkeleton\\Installer::postInstall",
"composer update",
"./vendor/bin/psalm --init"
"Koriym\\PhpSkeleton\\Installer::postInstall"
],
"pre-update-cmd": [
"Koriym\\PhpSkeleton\\Installer::preInstall"
],
"post-create-project-cmd": [
"Koriym\\PhpSkeleton\\Installer::postInstall",
"composer update",
"./vendor/bin/psalm --init"
"Koriym\\PhpSkeleton\\Installer::postInstall"
],
"test": ["vendor/bin/phpunit"],
"tests": ["@cs", "@sa", "@test"],
Expand All @@ -65,5 +61,16 @@
"sa": ["phpstan analyse -c phpstan.neon", "psalm --show-info=true"],
"metrics": ["phpmetrics --report-html=build/metrics --excluded-dirs=src/Exception src"],
"build": ["@cs", "@sa", "@pcov","@metrics"]
},
"scripts-descriptions": {
"test": "Run unit tests",
"tests": "Run tests and quality checks",
"coverage": "Generate test coverage report",
"pcov": "Generate test coverage report (pcov)",
"cs": "Check the coding style",
"cs-fix": "Fix the coding style",
"sa": "Run static analysis",
"metrics": "Build metrics report",
"build": "Build project"
}
}
126 changes: 80 additions & 46 deletions src/Installer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,81 @@

namespace Koriym\PhpSkeleton;

use Closure;
use Composer\Factory;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Script\Event;
use function is_string;
use Exception;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;

use function copy;
use function date;
use function dirname;
use function file_get_contents;
use function file_put_contents;
use function is_callable;
use function is_writable;
use function lcfirst;
use function preg_match;
use function preg_replace;
use function shell_exec;
use function sprintf;
use function str_replace;
use function strpos;
use function strtolower;
use function trim;
use function ucfirst;
use function unlink;
use function var_dump;

final class Installer
{
/**
* @var list<string>
*/
/** @var list<string> */
private static $appName;

/** @var string */
private static $packageName;

/**
* @var string
*/
private static $name;
/** @var string */
private static $userName;

/**
* @var string
*/
private static $email;
/** @var string */
private static $userEmail;

public static function preInstall(Event $event) : void
public static function preInstall(Event $event): void
{
$pacakageNameValidator = self::getValidator();
$io = $event->getIO();
$vendorClass = self::ask($io, 'What is the vendor name?', 'MyVendor');
$packageClass = self::ask($io, 'What is the package name?', 'MyPackage');
self::$name = self::ask($io, 'What is your name?', self::getUserName());
self::$email = self::ask($io, 'What is your email address ?', self::getUserEmail());
$packageName = sprintf('%s/%s', self::camel2dashed($vendorClass), self::camel2dashed($packageClass));
$vendorClass = self::ask($io, 'What is the vendor name?', 'MyVendor', $pacakageNameValidator);
$packageClass = self::ask($io, 'What is the package name?', 'MyPackage', $pacakageNameValidator);
self::$userName = self::ask($io, 'What is your name?', self::getUserName());
self::$userEmail = self::ask($io, 'What is your email address ?', self::getUserEmail());
self::$packageName = sprintf('%s/%s', self::camel2dashed($vendorClass), self::camel2dashed($packageClass));
$json = new JsonFile(Factory::getComposerFile());
$composerDefinition = self::getDefinition($vendorClass, $packageClass, $packageName, $json);
self::$packageName = [$vendorClass, $packageClass];
$composerDefinition = self::getDefinition($vendorClass, $packageClass, self::$packageName, $json);
self::$appName = [$vendorClass, $packageClass];
// Update composer definition
$json->write($composerDefinition);
assert(is_string($composerDefinition['name']));
$name = $composerDefinition['name'];
$io->write("<info>composer.json for {$name} is created.\n</info>");
}

public static function postInstall(Event $event) : void
private static function getValidator(): callable
{
return static function (string $input): string {
if (! preg_match('/^[A-Za-z][A-Za-z0-9]+$/', $input)) {
throw new Exception();
}

return ucfirst($input);
};
}

public static function postInstall(Event $event): void
{
$io = $event->getIO();
[$vendorName, $packageName] = self::$packageName;
[$vendorName, $packageName] = self::$appName;
$skeletonRoot = dirname(__DIR__);
self::recursiveJob("{$skeletonRoot}", self::rename($vendorName, $packageName));
//mv
Expand All @@ -62,20 +91,28 @@ public static function postInstall(Event $event) : void
unlink($skeletonPhp);
unlink($skeletoTest);
unlink(__FILE__);
$io->write("<info>{$vendorName}/{$packageName} class files created.\n</info>");
// run tools
shell_exec(dirname(__DIR__) . '/vendor/bin/phpcbf');
shell_exec(dirname(__DIR__) . '/vendor/bin/composer dump-autoload --quiet');
shell_exec(dirname(__DIR__) . '/vendor/bin/psalm --init > /dev/null');
// README
rename($skeletonRoot . '/README.proj.md', $skeletonRoot . '/README.md');
$io->write(sprintf('<info>%s package created.</info>', self::$packageName));
$io->write('<info>Happy quality coding!</info>');
}

private static function ask(IOInterface $io, string $question, string $default) : string
private static function ask(IOInterface $io, string $question, string $default, ?callable $validation = null): string
{
$ask = sprintf("\n<question>%s</question>\n(<comment>%s</comment>): ", $question, $default);
$answer = (string) $io->ask($ask, $default);
$answer = is_callable($validation) ? (string) $io->askAndValidate($ask, $validation, null, $default) : (string) $io->ask($ask, $default);
$io->write(sprintf('<info>%s</info>', $answer));

return $answer;
}

private static function recursiveJob(string $path, callable $job) : void
private static function recursiveJob(string $path, callable $job): void
{
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::SELF_FIRST);
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $file) {
$job($file);
}
Expand All @@ -84,7 +121,7 @@ private static function recursiveJob(string $path, callable $job) : void
/**
* @return array<string, string|array<string, string>>
*/
private static function getDefinition(string $vendor, string $package, string $packageName, JsonFile $json) : array
private static function getDefinition(string $vendor, string $package, string $packageName, JsonFile $json): array
{
$composerDefinition = $json->read();
unset(
Expand All @@ -100,49 +137,46 @@ private static function getDefinition(string $vendor, string $package, string $p
$composerDefinition['name'] = $packageName;
$composerDefinition['authors'] = [
[
'name' => self::$name,
'email' => self::$email
]
'name' => self::$userName,
'email' => self::$userEmail,
],
];
$composerDefinition['description'] = '';
$composerDefinition['autoload']['psr-4'] = ["{$vendor}\\{$package}\\" => 'src/'];

return $composerDefinition;
}

private static function rename(string $vendor, string $package) : \Closure
private static function rename(string $vendor, string $package): Closure
{
$jobRename = function (\SplFileInfo $file) use ($vendor, $package) : void {
return static function (SplFileInfo $file) use ($vendor, $package): void {
$fileName = $file->getFilename();
$filePath = (string) $file;
if ($file->isDir() || strpos($fileName, '.') === 0 || ! is_writable($filePath)) {
return;
}

$contents = (string) file_get_contents($filePath);
$contents = str_replace('__Vendor__', "{$vendor}", $contents);
$contents = str_replace('__Package__', "{$package}", $contents);
$contents = str_replace('__year__', date('Y'), $contents);
$contents = str_replace('__name__', self::$name, $contents);
$contents = str_replace('__PackageVarName__', lcfirst($package), $contents);
$search = ['__Vendor__', '__Package__', '__year__', '__name__', '__PackageVarName__', '_package_name_'];
$replace = [$vendor, $package, date('Y'), self::$userName, lcfirst($package), self::$packageName];
$contents = str_replace($search, $replace, $contents);
file_put_contents($filePath, $contents);
};

return $jobRename;
}

private static function camel2dashed(string $name) : string
private static function camel2dashed(string $name): string
{
return strtolower((string) preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $name));
}

private static function getUserName() : string
private static function getUserName(): string
{
$author = shell_exec('git config --global user.name || git config user.name');

return $author ? trim($author) : '';
}

private static function getUserEmail() : string
private static function getUserEmail(): string
{
$email = shell_exec('git config --global user.email || git config user.email');

Expand Down

0 comments on commit 85f983a

Please sign in to comment.