Skip to content

Commit

Permalink
Initial configuration feature implementation. Closes jonathantorres#86.
Browse files Browse the repository at this point in the history
  • Loading branch information
raphaelstolt committed Apr 2, 2016
1 parent bbf434f commit def1203
Show file tree
Hide file tree
Showing 15 changed files with 411 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
* text=auto

/example export-ignore
/tests export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

#### v1.9.0 `2016-mm-dd`
- `Added`
- User can load common option settings from a configuration file. Done by [@raphaelstolt](https://github.com/raphaelstolt). See [#86](https://github.com/jonathantorres/construct/issues/86).

#### v1.8.0 `2016-03-12`
- `Added`
- User can optionally generate [GitHub templates](https://github.com/blog/2111-issue-and-pull-request-templates). Done by [@raphaelstolt](https://github.com/raphaelstolt).
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,21 @@ The `--github-templates` option will generate [GitHub template](https://github.c
construct generate jonathantorres/logger --github-templates
```

## Use a configuration for recurring settings
The `--config` option allows the usage of a configuration file in the `YAML` format. There are two ways to provide such a configuration file: One is to provide a specific file as an option argument, the other is to put a `.construct` configuration file in the home directory of your system. For the structure of a configuration file have a look at the [.construct](example/.construct) example file. When no configuration keys are provided for settings having a default value (i.e. `test-framework`, `license`, `php`) their default value is used.

```bash
construct generate jonathantorres/logger --config /path/to/config.yml
```

You can also use the short option `-c`.

```bash
construct generate jonathantorres/logger -c /path/to/config.yml
```

When there's a `.construct` configuration file in your home directory it will be used per default. If required it's possible to disable the usage via the `--ignore-default-config` option or the equivalent short option `-i`.

## Interactive Mode
This mode will ask you all the required (and optional) information to generate your project.

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
],
"require": {
"php": "^5.4 || ^7.0",
"symfony/console": "^2.6 || ^3.0"
"symfony/console": "^2.6 || ^3.0",
"symfony/yaml": "^2.6 || ^3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8 || ^5.0",
Expand Down
5 changes: 3 additions & 2 deletions construct
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ use JonathanTorres\Construct\Helpers\Str;
use Symfony\Component\Console\Application;

$str = new Str();
$construct = new Construct(new Filesystem(), $str);
$filesystem = new Filesystem();
$construct = new Construct($filesystem, $str);
$app = new Application('Construct', '1.8.0');
$app->add(new ConstructCommand($construct, $str));
$app->add(new ConstructCommand($construct, $str, $filesystem));
$app->add(new InteractiveCommand($construct, $str));
$app->run();
13 changes: 13 additions & 0 deletions example/.construct
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace: Vendor\Project
test-framework: phpspec
license: MIT
php: 5.6

construct-with:
- git
- phpcs
- vagrant
- editor-config
- env
- lgtm
- github-templates
84 changes: 66 additions & 18 deletions src/Commands/ConstructCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace JonathanTorres\Construct\Commands;

use JonathanTorres\Construct\Configuration;
use JonathanTorres\Construct\Construct;
use JonathanTorres\Construct\Defaults;
use JonathanTorres\Construct\Helpers\Filesystem;
use JonathanTorres\Construct\Helpers\Git;
use JonathanTorres\Construct\Helpers\Script;
use JonathanTorres\Construct\Helpers\Str;
Expand All @@ -30,6 +32,13 @@ class ConstructCommand extends Command
*/
protected $str;

/**
* Filesystem helper.
*
* @var \JonathanTorres\Construct\Filesystem
*/
protected $filesystem;

/**
* Construct settings.
*
Expand All @@ -54,15 +63,17 @@ class ConstructCommand extends Command
/**
* Initialize.
*
* @param \JonathanTorres\Construct\Construct $construct
* @param \JonathanTorres\Construct\Str $str
* @param \JonathanTorres\Construct\Construct $construct
* @param \JonathanTorres\Construct\Str $str
* @param \JonathanTorres\Construct\Filesystem $filesystem
*
* @return void
*/
public function __construct(Construct $construct, Str $str)
public function __construct(Construct $construct, Str $str, Filesystem $filesystem)
{
$this->construct = $construct;
$this->str = $str;
$this->filesystem = $filesystem;
$this->defaults = new Defaults();
$this->systemPhpVersion = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;

Expand All @@ -89,6 +100,9 @@ protected function configure()
$environmentDescription = 'Generate .env environment files';
$lgtmDescription = 'Generate LGTM configuration files';
$githubTemplatesDescription = 'Generate GitHub templates';
$configurationDescription = 'Generate from configuration file';
$ignoreDefaultConfigurationDescription = 'Ignore present default configuration file';
$configurationDefault = $this->filesystem->getDefaultConfigurationFile();

$this->setName('generate');
$this->setDescription('Generates a basic PHP project');
Expand All @@ -105,6 +119,8 @@ protected function configure()
$this->addOption('env', null, InputOption::VALUE_NONE, $environmentDescription);
$this->addOption('lgtm', null, InputOption::VALUE_NONE, $lgtmDescription);
$this->addOption('github-templates', null, InputOption::VALUE_NONE, $githubTemplatesDescription);
$this->addOption('config', 'c', InputOption::VALUE_OPTIONAL, $configurationDescription, $configurationDefault);
$this->addOption('ignore-default-config', 'i', InputOption::VALUE_NONE, $ignoreDefaultConfigurationDescription);
}

/**
Expand All @@ -130,6 +146,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
$environment = $input->getOption('env');
$lgtm = $input->getOption('lgtm');
$githubTemplates = $input->getOption('github-templates');
$ignoreDefaultConfiguration = $input->getOption('ignore-default-config');
$configuration = $input->getOption('config');

if (!$this->str->isValid($projectName)) {
$output->writeln('<error>Warning: "' . $projectName . '" is not a valid project name, please use "vendor/project"</error>');
Expand All @@ -142,21 +160,31 @@ protected function execute(InputInterface $input, OutputInterface $output)
$testFramework = $this->testFrameworkWarning($testFramework, $output);
$phpVersion = $this->phpVersionWarning($phpVersion, $output);

$this->settings = new Settings(
$projectName,
$testFramework,
$license,
$namespace,
$git,
$phpcs,
$keywords,
$vagrant,
$editorConfig,
$phpVersion,
$environment,
$lgtm,
$githubTemplates
);
if ($this->isConfigurationApplicable($configuration)
&& $ignoreDefaultConfiguration === false) {
$this->settings = Configuration::getSettings(
$configuration,
$projectName,
$keywords,
$this->filesystem
);
} else {
$this->settings = new Settings(
$projectName,
$testFramework,
$license,
$namespace,
$git,
$phpcs,
$keywords,
$vagrant,
$editorConfig,
$phpVersion,
$environment,
$lgtm,
$githubTemplates
);
}

$this->construct->generate($this->settings, new Git, new Script);

Expand All @@ -167,6 +195,26 @@ protected function execute(InputInterface $input, OutputInterface $output)
$output->writeln('<info>Project "' . $projectName . '" constructed.</info>');
}

/**
* Determine if a configuration is applicable.
*
* @param string The default or a command line provided configuration file.
* @return boolean
*/
private function isConfigurationApplicable($configuration)
{
if ($configuration === $this->filesystem->getDefaultConfigurationFile()
&& $this->filesystem->hasDefaultConfigurationFile()) {
return true;
}

if ($configuration !== $this->filesystem->getDefaultConfigurationFile()) {
return true;
}

return false;
}

/**
* Show warning if the project name contains the string "php"
*
Expand Down
53 changes: 53 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace JonathanTorres\Construct;

use Symfony\Component\Yaml\Yaml;

class Configuration
{
/**
* Get settings derived from the configuration file.
*
* @param string $configurationFile Path to the configuration file.
* @param string $projectName Name of the project.
* @param string $keywords Composer keywords.
* @param \JonathanTorres\Construct\Helpers\Filesystem $filesystemHelper
*
* @return \JonathanTorres\Construct\Settings
*/
public static function getSettings($configurationFile, $projectName, $keywords, $filesystemHelper)
{
if (!$filesystemHelper->isFile($configurationFile)) {
$exceptionMessage = "Configuration file '$configurationFile' is not existent.";
throw new \RuntimeException($exceptionMessage);
}

if (!$filesystemHelper->isReadable($configurationFile)) {
$exceptionMessage = "Configuration file '$configurationFile' is not readable.";
throw new \RuntimeException($exceptionMessage);
}

$configuration = Yaml::parse($filesystemHelper->get($configurationFile));

if (isset($configuration['construct-with'])) {
$configuration['construct-with'] = array_flip($configuration['construct-with']);
}

return new Settings(
$projectName,
isset($configuration['test-framework']) ? $configuration['test-framework'] : (new Defaults())->testingFrameworks[0],
isset($configuration['license']) ? $configuration['license'] : (new Defaults())->licenses[0],
isset($configuration['namespace']) ? $configuration['namespace'] : null,
isset($configuration['construct-with']['git']) ? true : false,
isset($configuration['construct-with']['phpcs']) ? true : false,
$keywords,
isset($configuration['construct-with']['vagrant']) ? true : false,
isset($configuration['construct-with']['editor-config']) ? true : false,
isset($configuration['php']) ? (string) $configuration['php'] : PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION,
isset($configuration['construct-with']['env']) ? true : false,
isset($configuration['construct-with']['lgtm']) ? true : false,
isset($configuration['construct-with']['github-templates']) ? true : false
);
}
}
2 changes: 2 additions & 0 deletions src/Defaults.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ class Defaults
* @var array
*/
public $phpVersions = ['5.4', '5.5', '5.6', '7.0'];

const CONFIGURATION_FILE = '.construct';
}
61 changes: 61 additions & 0 deletions src/Helpers/Filesystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace JonathanTorres\Construct\Helpers;

use JonathanTorres\Construct\Defaults;

class Filesystem
{
/**
Expand Down Expand Up @@ -29,6 +31,65 @@ public function isDirectory($path)
return is_dir($path);
}

/**
* Check if the path is a file.
*
* @param string $path
*
* @return boolean
*/
public function isFile($path)
{
return is_file($path);
}

/**
* Check if the path is readable.
*
* @param string $path
*
* @return boolean
*/
public function isReadable($path)
{
return is_readable($path);
}

/**
* Get the home directory.
*
* @return string
*/
public function getHomeDirectory($os = PHP_OS)
{
if (strtoupper(substr($os, 0, 3)) !== 'WIN') {
return getenv('HOME');
}

return getenv('userprofile');
}

/**
* Get the default construct configuration file.
*
* @return string
*/
public function getDefaultConfigurationFile()
{
return $this->getHomeDirectory()
. DIRECTORY_SEPARATOR . Defaults::CONFIGURATION_FILE;
}

/**
* Determine if system has a default configuration file.
*
* @return boolean boolean
*/
public function hasDefaultConfigurationFile()
{
return $this->isFile($this->getDefaultConfigurationFile());
}

/**
* Copy the given file a new location.
*
Expand Down

0 comments on commit def1203

Please sign in to comment.