diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000..60581237b1 --- /dev/null +++ b/.env.example @@ -0,0 +1,27 @@ +# +# Copy and rename this file to .env at root of this project. +# + +# A common use case is to supply database creds via the environment. Edit settings.php +# like so: +# +# $databases['default']['default'] = [ +# 'database' => getenv('MYSQL_DATABASE'), +# 'driver' => 'mysql', +# 'host' => getenv('MYSQL_HOSTNAME'), +# 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', +# 'password' => getenv('MYSQL_PASSWORD'), +# 'port' => getenv('MYSQL_PORT'), +# 'prefix' => '', +# 'username' => getenv('MYSQL_USER'), +# ]; +# +# Uncomment and populate as needed. +# MYSQL_DATABASE= +# MYSQL_HOSTNAME= +# MYSQL_PASSWORD= +# MYSQL_PORT= +# MYSQL_USER= + +# Another common use case is to set Drush's --uri via environment. +# DRUSH_OPTIONS_URI=http://example.com diff --git a/.gitignore b/.gitignore index 181eef61dc..50d278d8f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,24 @@ # Ignore directories generated by Composer -drush/contrib -vendor -web/core -web/modules/contrib -web/themes/contrib -web/profiles/contrib +/drush/contrib/ +/vendor/ +/web/core/ +/web/modules/contrib/ +/web/themes/contrib/ +/web/profiles/contrib/ +/web/libraries/ + +# Ignore sensitive information +/web/sites/*/settings.php +/web/sites/*/settings.local.php # Ignore Drupal's file directory -web/sites/default/files +/web/sites/*/files/ + +# Ignore SimpleTest multi-site environment. +/web/sites/simpletest # Ignore files generated by PhpStorm -.idea +/.idea/ + +# Ignore .env files as they are personal +/.env diff --git a/.travis.yml b/.travis.yml index fda43a5403..ac51e49242 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,36 +1,40 @@ language: php +dist: trusty +sudo: false + php: - - 5.5 - - 5.6 - 7.0 - -sudo: false + - 7.1 + - 7.2 + - 7.3 env: global: - SIMPLETEST_DB=sqlite://tmp/site.sqlite - SIMPLETEST_BASE_URL="http://127.0.0.1:8080" matrix: - - RELEASE=stable - - RELEASE=dev + - RELEASE=stable COMPOSER_CHANNEL=stable + - RELEASE=dev COMPOSER_CHANNEL=stable + - RELEASE=stable COMPOSER_CHANNEL=snapshot before_install: - echo 'sendmail_path = /bin/true' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - phpenv config-rm xdebug.ini - - composer --verbose self-update + - composer --verbose self-update --$COMPOSER_CHANNEL - composer --version install: + - composer --verbose validate - composer --verbose install script: - - if [[ $RELEASE = dev ]]; then composer --verbose require --no-update drupal/core:8.0.x-dev; fi; + - if [[ $RELEASE = dev ]]; then composer --verbose remove --no-update drupal/console; fi; + - if [[ $RELEASE = dev ]]; then composer --verbose require --no-update drupal/core:8.8.x-dev; composer --verbose require --no-update --dev drupal/core-dev:8.8.x-dev; fi; - if [[ $RELEASE = dev ]]; then composer --verbose update; fi; - - cd $TRAVIS_BUILD_DIR/web - - ./../vendor/bin/drush site-install --verbose --yes --db-url=sqlite://tmp/site.sqlite - - ./../vendor/bin/drush runserver http://127.0.0.1:8080 & - - sleep 3 - # Skip core/tests/Drupal/Tests/ComposerIntegrationTest.php because web/ has no composer.json - - ./../vendor/bin/phpunit -c core --exclude-group Composer - - ./../vendor/bin/drush - - ./../vendor/bin/drupal + - ./vendor/bin/drush site-install --verbose --yes --db-url=sqlite://tmp/site.sqlite + - ./vendor/bin/drush runserver $SIMPLETEST_BASE_URL & + - until curl -s $SIMPLETEST_BASE_URL; do true; done > /dev/null + # Run a single unit test to verfiy the testing setup. + - ./vendor/bin/phpunit -c ./web/core ./web/core/modules/system/tests/src/Unit/SystemRequirementsTest.php + - ./vendor/bin/drush + - if [[ $RELEASE = stable ]]; then ./vendor/bin/drupal; fi; diff --git a/README.md b/README.md index 09c369b6bd..2c40e4384f 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ [![Build Status](https://travis-ci.org/drupal-composer/drupal-project.svg?branch=8.x)](https://travis-ci.org/drupal-composer/drupal-project) -This project template should provide a kickstart for managing your site +This project template provides a starter kit for managing your site dependencies with [Composer](https://getcomposer.org/). If you want to know how to use it as replacement for -[Drush Make](https://github.com/drush-ops/drush/blob/master/docs/make.md) visit +[Drush Make](https://github.com/drush-ops/drush/blob/8.x/docs/make.md) visit the [Documentation on drupal.org](https://www.drupal.org/node/2471553). ## Usage @@ -14,25 +14,25 @@ the [Documentation on drupal.org](https://www.drupal.org/node/2471553). First you need to [install composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx). > Note: The instructions below refer to the [global composer installation](https://getcomposer.org/doc/00-intro.md#globally). -You might need to replace `composer` with `php composer.phar` (or similar) +You might need to replace `composer` with `php composer.phar` (or similar) for your setup. After that you can create the project: ``` -composer create-project drupal-composer/drupal-project:8.x-dev some-dir --stability dev --no-interaction +composer create-project drupal-composer/drupal-project:8.x-dev some-dir --no-interaction ``` -With `composer require ...` you can download new dependencies to your +With `composer require ...` you can download new dependencies to your installation. ``` cd some-dir -composer require drupal/devel:8.* +composer require drupal/devel:~1.0 ``` -The `composer create-project` command passes ownership of all files to the -project that is created. You should create a new git repository, and commit +The `composer create-project` command passes ownership of all files to the +project that is created. You should create a new git repository, and commit all files not excluded by the .gitignore file. ## What does the template do? @@ -46,32 +46,33 @@ When installing the given `composer.json` some tasks are taken care of: * Theme (packages of type `drupal-theme`) will be placed in `web/themes/contrib/` * Profiles (packages of type `drupal-profile`) will be placed in `web/profiles/contrib/` * Creates default writable versions of `settings.php` and `services.yml`. -* Creates `sites/default/files`-directory. +* Creates `web/sites/default/files`-directory. * Latest version of drush is installed locally for use at `vendor/bin/drush`. * Latest version of DrupalConsole is installed locally for use at `vendor/bin/drupal`. +* Creates environment variables based on your .env file. See [.env.example](.env.example). ## Updating Drupal Core -This project will attempt to keep all of your Drupal Core files up-to-date; the -project [drupal-composer/drupal-scaffold](https://github.com/drupal-composer/drupal-scaffold) -is used to ensure that your scaffold files are updated every time drupal/core is -updated. If you customize any of the "scaffolding" files (commonly .htaccess), -you may need to merge conflicts if any of your modfied files are updated in a +This project will attempt to keep all of your Drupal Core files up-to-date; the +project [drupal/core-composer-scaffold](https://github.com/drupal/core-composer-scaffold) +is used to ensure that your scaffold files are updated every time drupal/core is +updated. If you customize any of the "scaffolding" files (commonly .htaccess), +you may need to merge conflicts if any of your modified files are updated in a new release of Drupal core. Follow the steps below to update your core files. -1. Run `composer update drupal/core`. -1. Run `git diff` to determine if any of the scaffolding files have changed. - Review the files for any changes and restore any customizations to +1. Run `composer update drupal/core drupal/core-dev --with-dependencies` to update Drupal Core and its dependencies. +2. Run `git diff` to determine if any of the scaffolding files have changed. + Review the files for any changes and restore any customizations to `.htaccess` or `robots.txt`. 1. Commit everything all together in a single commit, so `web` will remain in sync with the `core` when checking out branches or running `git bisect`. -1. In the event that there are non-trivial conflicts in step 2, you may wish - to perform these steps on a branch, and use `git merge` to combine the - updated core files with your customized files. This facilitates the use - of a [three-way merge tool such as kdiff3](http://www.gitshah.com/2010/12/how-to-setup-kdiff-as-diff-tool-for-git.html). This setup is not necessary if your changes are simple; - keeping all of your modifications at the beginning or end of the file is a +1. In the event that there are non-trivial conflicts in step 2, you may wish + to perform these steps on a branch, and use `git merge` to combine the + updated core files with your customized files. This facilitates the use + of a [three-way merge tool such as kdiff3](http://www.gitshah.com/2010/12/how-to-setup-kdiff-as-diff-tool-for-git.html). This setup is not necessary if your changes are simple; + keeping all of your modifications at the beginning or end of the file is a good strategy to keep merges easy. ## Generate composer.json from existing project @@ -83,25 +84,62 @@ that the generated `composer.json` might differ from this project's file. ## FAQ -### Should I commit the contrib modules I download +### Should I commit the contrib modules I download? -Composer recommends **no**. They provide [argumentation against but also +Composer recommends **no**. They provide [argumentation against but also workrounds if a project decides to do it anyway](https://getcomposer.org/doc/faqs/should-i-commit-the-dependencies-in-my-vendor-directory.md). +### Should I commit the scaffolding files? + +The [Drupal Composer Scaffold](https://github.com/drupal/core-composer-scaffold) plugin can download the scaffold files (like +index.php, update.php, …) to the web/ directory of your project. If you have not customized those files you could choose +to not check them into your version control system (e.g. git). If that is the case for your project it might be +convenient to automatically run the drupal-scaffold plugin after every install or update of your project. You can +achieve that by registering `@composer drupal:scaffold` as post-install and post-update command in your composer.json: + +```json +"scripts": { + "post-install-cmd": [ + "@composer drupal:scaffold", + "..." + ], + "post-update-cmd": [ + "@composer drupal:scaffold", + "..." + ] +}, +``` ### How can I apply patches to downloaded modules? -If you need to apply patches (depending on the project being modified, a pull -request is often a better solution), you can do so with the +If you need to apply patches (depending on the project being modified, a pull +request is often a better solution), you can do so with the [composer-patches](https://github.com/cweagans/composer-patches) plugin. -To add a patch to drupal module foobar insert the patches section in the extra +To add a patch to drupal module foobar insert the patches section in the extra section of composer.json: ```json "extra": { "patches": { "drupal/foobar": { - "Patch description": "URL to patch" + "Patch description": "URL or local path to patch" } } } ``` +### How do I switch from packagist.drupal-composer.org to packages.drupal.org? + +Follow the instructions in the [documentation on drupal.org](https://www.drupal.org/docs/develop/using-composer/using-packagesdrupalorg). + +### How do I specify a PHP version ? + +This project supports PHP 7.0 as minimum version (see [Drupal 8 PHP requirements](https://www.drupal.org/docs/8/system-requirements/drupal-8-php-requirements)), however it's possible that a `composer update` will upgrade some package that will then require PHP 7+. + +To prevent this you can add this code to specify the PHP version you want to use in the `config` section of `composer.json`: +```json +"config": { + "sort-packages": true, + "platform": { + "php": "7.0.33" + } +}, +``` diff --git a/composer.json b/composer.json index c877abd3a9..b29500cc0c 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "drupal-composer/drupal-project", "description": "Project template for Drupal 8 projects with composer", "type": "project", - "license": "GPL-2.0+", + "license": "GPL-2.0-or-later", "authors": [ { "name": "", @@ -12,54 +12,69 @@ "repositories": [ { "type": "composer", - "url": "https://packagist.drupal-composer.org" + "url": "https://packages.drupal.org/8" } ], "require": { - "composer/installers": "^1.0.20", - "drupal-composer/drupal-scaffold": "^1.3.1", - "cweagans/composer-patches": "~1.0", - "drupal/core": "~8.0", - "drush/drush": "~8.0", - "drupal/console": "~0.10" + "php": ">=7.0.8", + "composer/installers": "^1.2", + "cweagans/composer-patches": "^1.6.5", + "drupal/console": "^1.0.2", + "drupal/core": "^8.8.0", + "drupal/core-composer-scaffold": "^8.8.0", + "drush/drush": "^9.7.1 | ^10.0.0", + "vlucas/phpdotenv": "^4.0", + "webflo/drupal-finder": "^1.0.0", + "zaporylie/composer-drupal-optimizations": "^1.0" }, "require-dev": { - "behat/mink": "~1.6", - "behat/mink-goutte-driver": "~1.2", - "jcalderonzumba/gastonjs": "^1.1@dev", - "jcalderonzumba/mink-phantomjs-driver": "~0.3.1", - "mikey179/vfsStream": "~1.2", - "phpunit/phpunit": "~4.8", - "symfony/css-selector": "2.7.*" + "drupal/core-dev": "^8.8.0" }, "conflict": { "drupal/drupal": "*" }, "minimum-stability": "dev", "prefer-stable": true, + "config": { + "sort-packages": true + }, "autoload": { "classmap": [ "scripts/composer/ScriptHandler.php" - ] + ], + "files": ["load.environment.php"] }, "scripts": { - "drupal-scaffold": "DrupalComposer\\DrupalScaffold\\Plugin::scaffold", + "pre-install-cmd": [ + "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" + ], + "pre-update-cmd": [ + "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" + ], "post-install-cmd": [ - "DrupalProject\\composer\\ScriptHandler::buildScaffold", "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" ], "post-update-cmd": [ - "DrupalProject\\composer\\ScriptHandler::buildScaffold", "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" ] }, "extra": { + "composer-exit-on-patch-failure": true, + "patchLevel": { + "drupal/core": "-p2" + }, + "drupal-scaffold": { + "locations": { + "web-root": "web/" + } + }, "installer-paths": { "web/core": ["type:drupal-core"], + "web/libraries/{$name}": ["type:drupal-library"], "web/modules/contrib/{$name}": ["type:drupal-module"], "web/profiles/contrib/{$name}": ["type:drupal-profile"], "web/themes/contrib/{$name}": ["type:drupal-theme"], - "drush/contrib/{$name}": ["type:drupal-drush"] + "drush/Commands/contrib/{$name}": ["type:drupal-drush"] } } } diff --git a/drush/Commands/PolicyCommands.php b/drush/Commands/PolicyCommands.php new file mode 100644 index 0000000000..290b4e0331 --- /dev/null +++ b/drush/Commands/PolicyCommands.php @@ -0,0 +1,38 @@ +input()->getArgument('target') == '@prod') { + throw new \Exception(dt('Per !file, you may never overwrite the production database.', ['!file' => __FILE__])); + } + } + + /** + * Limit rsync operations to production site. + * + * @hook validate core:rsync + * + * @throws \Exception + */ + public function rsyncValidate(CommandData $commandData) { + if (preg_match("/^@prod/", $commandData->input()->getArgument('target'))) { + throw new \Exception(dt('Per !file, you may never rsync to the production site.', ['!file' => __FILE__])); + } + } +} diff --git a/drush/README.md b/drush/README.md index 8c85c145d6..9d7bd397ad 100644 --- a/drush/README.md +++ b/drush/README.md @@ -1 +1 @@ -This directory contains commands, configuration and site aliases for Drush. See http://packages.drush.org/ for a directory of Drush commands installable via Composer. +This directory contains commands, configuration and site aliases for Drush. See https://packagist.org/search/?type=drupal-drush for a directory of Drush commands installable via Composer. diff --git a/drush/drush.yml b/drush/drush.yml new file mode 100644 index 0000000000..a8cbd00730 --- /dev/null +++ b/drush/drush.yml @@ -0,0 +1,6 @@ +# +# A Drush configuration file +# +# Docs at https://github.com/drush-ops/drush/blob/master/examples/example.drush.yml +# +# Edit or remove this file as needed. diff --git a/drush/policy.drush.inc b/drush/policy.drush.inc deleted file mode 100644 index 6a1242e5de..0000000000 --- a/drush/policy.drush.inc +++ /dev/null @@ -1,39 +0,0 @@ -safeLoad(); diff --git a/scripts/composer/ScriptHandler.php b/scripts/composer/ScriptHandler.php index ab1dcda627..51026d38a1 100644 --- a/scripts/composer/ScriptHandler.php +++ b/scripts/composer/ScriptHandler.php @@ -8,24 +8,19 @@ namespace DrupalProject\composer; use Composer\Script\Event; +use Composer\Semver\Comparator; +use Drupal\Core\Site\Settings; +use DrupalFinder\DrupalFinder; use Symfony\Component\Filesystem\Filesystem; +use Webmozart\PathUtil\Path; class ScriptHandler { - protected static function getDrupalRoot($project_root) { - return $project_root . '/web'; - } - - public static function buildScaffold(Event $event) { - $fs = new Filesystem(); - if (!$fs->exists(static::getDrupalRoot(getcwd()) . '/autoload.php')) { - \DrupalComposer\DrupalScaffold\Plugin::scaffold($event); - } - } - public static function createRequiredFiles(Event $event) { $fs = new Filesystem(); - $root = static::getDrupalRoot(getcwd()); + $drupalFinder = new DrupalFinder(); + $drupalFinder->locateRoot(getcwd()); + $drupalRoot = $drupalFinder->getDrupalRoot(); $dirs = [ 'modules', @@ -35,32 +30,70 @@ public static function createRequiredFiles(Event $event) { // Required for unit testing foreach ($dirs as $dir) { - if (!$fs->exists($root . '/'. $dir)) { - $fs->mkdir($root . '/'. $dir); - $fs->touch($root . '/'. $dir . '/.gitkeep'); + if (!$fs->exists($drupalRoot . '/'. $dir)) { + $fs->mkdir($drupalRoot . '/'. $dir); + $fs->touch($drupalRoot . '/'. $dir . '/.gitkeep'); } } // Prepare the settings file for installation - if (!$fs->exists($root . '/sites/default/settings.php')) { - $fs->copy($root . '/sites/default/default.settings.php', $root . '/sites/default/settings.php'); - $fs->chmod($root . '/sites/default/settings.php', 0666); - $event->getIO()->write("Create a sites/default/settings.php file with chmod 0666"); - } - - // Prepare the services file for installation - if (!$fs->exists($root . '/sites/default/services.yml')) { - $fs->copy($root . '/sites/default/default.services.yml', $root . '/sites/default/services.yml'); - $fs->chmod($root . '/sites/default/services.yml', 0666); - $event->getIO()->write("Create a sites/default/services.yml file with chmod 0666"); + if (!$fs->exists($drupalRoot . '/sites/default/settings.php') && $fs->exists($drupalRoot . '/sites/default/default.settings.php')) { + $fs->copy($drupalRoot . '/sites/default/default.settings.php', $drupalRoot . '/sites/default/settings.php'); + require_once $drupalRoot . '/core/includes/bootstrap.inc'; + require_once $drupalRoot . '/core/includes/install.inc'; + new Settings([]); + $settings['settings']['config_sync_directory'] = (object) [ + 'value' => Path::makeRelative($drupalFinder->getComposerRoot() . '/config/sync', $drupalRoot), + 'required' => TRUE, + ]; + drupal_rewrite_settings($settings, $drupalRoot . '/sites/default/settings.php'); + $fs->chmod($drupalRoot . '/sites/default/settings.php', 0666); + $event->getIO()->write("Created a sites/default/settings.php file with chmod 0666"); } // Create the files directory with chmod 0777 - if (!$fs->exists($root . '/sites/default/files')) { + if (!$fs->exists($drupalRoot . '/sites/default/files')) { $oldmask = umask(0); - $fs->mkdir($root . '/sites/default/files', 0777); + $fs->mkdir($drupalRoot . '/sites/default/files', 0777); umask($oldmask); - $event->getIO()->write("Create a sites/default/files directory with chmod 0777"); + $event->getIO()->write("Created a sites/default/files directory with chmod 0777"); + } + } + + /** + * Checks if the installed version of Composer is compatible. + * + * Composer 1.0.0 and higher consider a `composer install` without having a + * lock file present as equal to `composer update`. We do not ship with a lock + * file to avoid merge conflicts downstream, meaning that if a project is + * installed with an older version of Composer the scaffolding of Drupal will + * not be triggered. We check this here instead of in drupal-scaffold to be + * able to give immediate feedback to the end user, rather than failing the + * installation after going through the lengthy process of compiling and + * downloading the Composer dependencies. + * + * @see https://github.com/composer/composer/pull/5035 + */ + public static function checkComposerVersion(Event $event) { + $composer = $event->getComposer(); + $io = $event->getIO(); + + $version = $composer::VERSION; + + // The dev-channel of composer uses the git revision as version number, + // try to the branch alias instead. + if (preg_match('/^[0-9a-f]{40}$/i', $version)) { + $version = $composer::BRANCH_ALIAS_VERSION; + } + + // If Composer is installed through git we have no easy way to determine if + // it is new enough, just display a warning. + if ($version === '@package_version@' || $version === '@package_branch_alias_version@') { + $io->writeError('You are running a development version of Composer. If you experience problems, please update Composer to the latest stable version.'); + } + elseif (Comparator::lessThan($version, '1.0.0')) { + $io->writeError('Drupal-project requires Composer version 1.0.0 or higher. Please update your Composer before continuing.'); + exit(1); } }