diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..686c443cec --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# Drupal editor configuration normalization +# @see http://editorconfig.org/ + +# This is the top-most .editorconfig file; do not search in parent directories. +root = true + +# All files. +[*] +end_of_line = LF +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[composer.{json,lock}] +indent_size = 4 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6bf0c73b8..1cb83c189c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,12 @@ name: CI -on: [push] +on: + push: + pull_request: + types: + - opened + - synchronize + - reopened env: COMPOSER_MEMORY_LIMIT: -1 @@ -9,20 +15,15 @@ env: jobs: build: - runs-on: 'ubuntu-20.04' + runs-on: ubuntu-latest strategy: fail-fast: false + matrix: - php-versions: ['8.1'] - drupal-release: ['stable'] - composer-channel: ['stable'] - include: - - php-versions: '8.1' - drupal-release: dev - composer-channel: stable - - php-versions: '8.1' - drupal-release: stable - composer-channel: snapshot + php-versions: ['8.3'] + drupal-release: ['stable', 'beta', 'dev'] + composer-channel: ['stable', 'snapshot'] + steps: - name: Dump matrix context env: @@ -32,16 +33,25 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - name: Upgrade sqlite3 + run: | + wget https://www.sqlite.org/2024/sqlite-autoconf-3450300.tar.gz -O /tmp/sqlite.tar.gz + tar -xzf /tmp/sqlite.tar.gz -C /tmp + cd /tmp/sqlite-autoconf-3450300 + ./configure CFLAGS="-DSQLITE_ENABLE_COLUMN_METADATA=1" --prefix=/usr/local + make && sudo make install + sudo ldconfig + - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-versions }} - extensions: gd, pdo_sqlite + extensions: gd, sqlite, pdo_sqlite - - name: Update composer + - name: Update Composer run: composer --verbose self-update --${{ matrix.composer-channel }} - - name: Dump composer version + - name: Show Composer version run: composer --version - name: Validate composer.json @@ -50,24 +60,58 @@ jobs: - name: Install dependencies run: composer --verbose install - - if: matrix.drupal-release == 'dev' - run: composer --verbose require --no-update drupal/core-recommended:10.0.x-dev && composer --verbose require --no-update --dev drupal/core-dev:10.0.x-dev + - name: Validate composer.json structure + run: composer normalize --dry-run + + - name: Require bower-asset + run: | + test ! -d web/libraries/dropzone + composer require bower-asset/dropzone + test -d web/libraries/dropzone + + - name: Override Drupal version to dev for testing dev releases + if: matrix.drupal-release == 'dev' || matrix.drupal-release == 'beta' + run: | + composer config minimum-stability ${{ matrix.drupal-release }} + composer config prefer-stable false + composer --verbose require --no-update drupal/core-composer-scaffold:^11@${{ matrix.drupal-release }} + composer --verbose require --no-update drupal/core-recommended:^11@${{ matrix.drupal-release }} + composer --verbose require --no-update --dev drupal/core-dev:^11@${{ matrix.drupal-release }} + composer --verbose update + + - name: Install site + run: ./vendor/bin/drush site-install --verbose --yes --db-url=sqlite://tmp/site.sqlite + + - name: Show site information + run: ./vendor/bin/drush status + + - name: Start server + run: | + ./vendor/bin/drush runserver "$SIMPLETEST_BASE_URL" & + until curl -s "$SIMPLETEST_BASE_URL"; do true; done > /dev/null - - if: matrix.drupal-release == 'dev' - run: composer --verbose update + - name: Run a single unit test to verify the testing setup + run: ./vendor/bin/phpunit -c ./web/core "$(pwd)/web/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php" - - run: ./vendor/bin/drush site-install --verbose --yes --db-url=sqlite://tmp/site.sqlite + # Using outdated Composer version to test the Composer version constraint. + test-composer: + runs-on: ubuntu-latest - - run: ./vendor/bin/drush runserver $SIMPLETEST_BASE_URL & + steps: - - run: until curl -s $SIMPLETEST_BASE_URL; do true; done > /dev/null + - name: Checkout + uses: actions/checkout@v2 - # https://www.drupal.org/project/drupal/issues/3182653 - # https://www.drupal.org/node/3176567 - - if: ${{ matrix.php-versions == '8.1' }} - run: composer require phpspec/prophecy-phpunit:^2 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + extensions: gd, pdo_sqlite + tools: composer:v2.2 - - name: Run a single unit test to verify the testing setup. - run: ./vendor/bin/phpunit -c ./web/core ./web/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php + - name: Show Composer version + run: composer --version - - run: ./vendor/bin/drush + - name: Install dependencies + # This command should fail because of the Composer version constraint. + run: composer --verbose install && exit 1 || exit 0 diff --git a/.gitignore b/.gitignore index 12ad63d871..4669354007 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ -# Ignore directories generated by Composer +# To ignore OS temporary files use global .gitignore +# https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files#configuring-ignored-files-for-all-repositories-on-your-computer + +# Ignore directories generated by Composer. /drush/contrib/ /vendor/ /web/core/ @@ -7,19 +10,22 @@ /web/profiles/contrib/ /web/libraries/ -# Ignore sensitive information +# Ignore sensitive information. /web/sites/*/settings.php -/web/sites/*/settings.local.php -# Ignore Drupal's file directory +# Ignore Drupal's file directory. /web/sites/*/files/ -# Ignore SimpleTest multi-site environment +# Ignore SimpleTest multi-site environment. /web/sites/simpletest -# Ignore files generated by common IDEs -/.idea/ -/.vscode/ - -# Ignore .env files as they are personal +# Ignore .env files as they could contain sensitive information. /.env + +# Manage .gitattributes with Drupal scaffold for cross-platform compatibility. +# Remove the line below and commit the file for more granular control. +/.gitattributes + +# Manage all .gitignore files with Drupal scaffold. +# Remove the line below and commit the files for more granular control. +**/.gitignore diff --git a/README.md b/README.md index d87dba20b1..84427395b4 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,156 @@ # Composer template for Drupal projects -[![CI](https://github.com/drupal-composer/drupal-project/actions/workflows/ci.yml/badge.svg?branch=10.x)](https://github.com/drupal-composer/drupal-project/actions/workflows/ci.yml) +[![CI](https://github.com/drupal-composer/drupal-project/actions/workflows/ci.yml/badge.svg?branch=11.x)](https://github.com/drupal-composer/drupal-project/actions/workflows/ci.yml) +![LICENSE](https://img.shields.io/github/license/drupal-composer/drupal-project) This project template provides a starter kit for managing your site dependencies with [Composer](https://getcomposer.org/). -## Usage +## What does the template do? + +* Drupal will be installed in the `web` directory. +* Generated composer autoloader `vendor/autoload.php` is used instead of + `web/vendor/autoload.php` provided by Drupal core. +* Modules (packages of type `drupal-module`) will be placed in `web/modules/contrib` directory. +* Themes (packages of type `drupal-theme`) will be placed in `web/themes/contrib` directory. +* Profiles (packages of type `drupal-profile`) will be placed in `web/profiles/contrib` directory. +* Creates default writable versions of `settings.php` and `services.yml`. +* Creates `web/sites/default/files` directory. +* Drush is installed for use as `vendor/bin/drush`. +* Provides an [example](.env.example) of the `.env` file. -First you need to [install Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx). +## Installing -> Note: The instructions below refer to the [global Composer installation](https://getcomposer.org/doc/00-intro.md#globally). +> [!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) for your setup. -After that you can create the project: +Create your project: -``` -composer create-project drupal-composer/drupal-project:10.x-dev some-dir --no-interaction +```bash +composer create-project drupal-composer/drupal-project:11.x-dev some-dir --no-interaction ``` -With `composer require ...` you can download new dependencies to your -installation. +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. -``` +## Usage + +### Adding new dependencies + +Use `composer require` to include and download dependencies for your project. + +```bash cd some-dir composer require drupal/devel ``` -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. +By default, this project is set to install only stable releases of dependencies, +as specified by `"minimum-stability": "stable"` in `composer.json`. If you need +to use non-stable releases (e.g., `alpha`, `beta`, `RC`), you can modify the +version constraint to allow for such versions. For instance, to require a beta +version of a module: -## What does the template do? +```bash +composer require drupal/devel:1.0.0-beta1 +``` -When installing the given `composer.json` some tasks are taken care of: +Alternatively, you can globally adjust the stability settings by modifying +`composer.json` to include the desired stability level and explicitly allow it: -* Drupal will be installed in the `web`-directory. -* Autoloader is implemented to use the generated composer autoloader in `vendor/autoload.php`, - instead of the one provided by Drupal (`web/vendor/autoload.php`). -* Modules (packages of type `drupal-module`) will be placed in `web/modules/contrib/` -* 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 `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). +```json +{ + "minimum-stability": "beta", + "prefer-stable": true +} +``` + +This configuration ensures that stable releases are preferred, but allows the +installation of non-stable packages when necessary. + +### Adding libraries + +You can manage front-end asset libraries with Composer thanks to the +[asset-packagist repository](https://asset-packagist.org/). Composer will detect +and install new versions of a library that meet the stated constraints. + +```bash +composer require bower-asset/dropzone +``` + +### Custom installation paths for libraries + +The installation path of a specific library can be controlled by adding it to +the `extra.installer-paths` configuration preceding `web/libraries/{$name}`. +For example, the `chosen` Drupal module expects the `chosen` library to be +located on `web/libraries/chosen`, but `composer require npm-asset/chosen-js` +installs the library into `web/libraries/chosen-js`. The following configuration +overrides installation it into the expected directory: + +```json +{ + "extra": { + "installer-paths": { + "web/libraries/chosen": [ + "npm-asset/chosen-js" + ], + "web/libraries/{$name}": [ + "type:drupal-library", + "type:npm-asset", + "type:bower-asset" + ] + } + } +} +``` + +For more details, see https://asset-packagist.org/site/about -## Updating Drupal Core +### Updating Drupal Core 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`), +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. +Follow the steps below to update your Drupal core files. 1. Run `composer update "drupal/core-*" --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 + `.htaccess` or `robots.txt`. +3. 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 +4. 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. -## FAQ +## FAQs ### Should I commit the contrib modules I download? 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). +workarounds 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: +plugin can download the scaffold files (like `index.php`, `update.php` etc.) 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": { @@ -102,14 +165,14 @@ post-update command in your composer.json: }, ``` -### How can I apply patches to downloaded modules? +### How can I apply patches to included dependencies? -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. +If you need to apply patches, you can do so with the +[composer-patches](https://github.com/cweagans/composer-patches) plugin included +in this project. -To add a patch to drupal module foobar insert the patches section in the extra -section of composer.json: +To add a patch to Drupal module `foobar`, insert the `patches` section in the +`extra` section of `composer.json`: ```json "extra": { @@ -123,15 +186,36 @@ section of composer.json: ### How do I specify a PHP version? -This project supports PHP 8.1 as minimum version (see [Environment requirements of Drupal 10](https://www.drupal.org/docs/system-requirements/php-requirements)), however it's possible that a `composer update` will upgrade some package that will then require PHP 8.1+. +There are 2 places where Composer will be looking for PHP version requirements +when resolving dependencies: +1. The `require.php` version value in `composer.json`. +2. The `config.platform` version value in `composer.json`. + +The purpose of `require.php` is to set the minimum PHP language requirements +for a package. For example, the minimum version required for Drupal 11.0 is +`8.3` or above, which can be specified as `>=8.3`. + +The purpose of `config.platform` is to set the PHP language requirements for the +specific instance of the package running in the current environment. For +example, while the minimum version required for Drupal 11 is `8.3` or above, +the actual PHP version on the hosting provider could be `8.3.1`. The value of +this field should provide your exact version of PHP with all 3 parts of the +version. + +#### Which versions to specify in my Drupal site? + +This project includes `drupal/core` which already has `require.php` added. Your +would inherit that constraint. There is no need to add `require.php` to your +`composer.json`. -To prevent this you can add this code to specify the PHP version you want to use in the `config` section of `composer.json`: +`config.platform` is a platform-specific. It is recommended to specify +`config.platform` as a _specific version_ (e.g.`8.3.1`) constraint to ensure +that only the package versions supported by your current environment are used. ```json "config": { - "sort-packages": true, "platform": { - "php": "8.1.13" + "php": "8.3.1" } }, ``` diff --git a/composer.json b/composer.json index d1f2250cd3..ad45f372d8 100644 --- a/composer.json +++ b/composer.json @@ -1,89 +1,130 @@ { "name": "drupal-composer/drupal-project", - "description": "Project template for Drupal 10 projects with Composer", - "type": "project", + "description": "Project template for Drupal 11 projects with Composer", "license": "GPL-2.0-or-later", + "type": "project", "authors": [ { "name": "", "role": "" } ], - "repositories": [ - { - "type": "composer", - "url": "https://packages.drupal.org/8" - } - ], "require": { - "php": ">=8.1", "composer/installers": "^2.1", "cweagans/composer-patches": "^1.7", - "drupal/core-composer-scaffold": "^10.2.0", - "drupal/core-recommended": "^10.2.0", - "drush/drush": "^12.4.3", + "drupal/core-composer-scaffold": "^11", + "drupal/core-recommended": "^11", + "drush/drush": "^13", + "oomphinc/composer-installers-extender": "^2.0", "vlucas/phpdotenv": "^5.1", - "webflo/drupal-finder": "^1.2" + "webflo/drupal-finder": "^1.3" }, "require-dev": { - "drupal/core-dev": "^10.2.0" + "drupal/core-dev": "^11", + "ergebnis/composer-normalize": "^2.42" }, "conflict": { "drupal/drupal": "*" }, - "minimum-stability": "dev", + "repositories": [ + { + "type": "composer", + "url": "https://packages.drupal.org/8" + }, + { + "type": "composer", + "url": "https://asset-packagist.org/" + } + ], + "minimum-stability": "stable", "prefer-stable": true, + "autoload": { + "classmap": [ + "scripts/composer/ScriptHandler.php" + ], + "files": [ + "load.environment.php" + ] + }, "config": { - "discard-changes": true, - "sort-packages": true, "allow-plugins": { "composer/installers": true, "cweagans/composer-patches": true, - "drupal/core-composer-scaffold": true, "dealerdirect/phpcodesniffer-composer-installer": true, + "drupal/core-composer-scaffold": true, + "ergebnis/composer-normalize": true, + "oomphinc/composer-installers-extender": true, "php-http/discovery": true, - "phpstan/extension-installer": true - } + "phpstan/extension-installer": true, + "tbachert/spi": true + }, + "discard-changes": true, + "sort-packages": true }, - "autoload": { - "classmap": [ - "scripts/composer/ScriptHandler.php" + "extra": { + "composer-exit-on-patch-failure": true, + "drupal-scaffold": { + "file-mapping": { + "[project-root]/.gitignore": false, + "[web-root]/INSTALL.txt": false, + "[web-root]/README.txt": false + }, + "locations": { + "web-root": "web/" + } + }, + "installer-paths": { + "web/core": [ + "type:drupal-core" + ], + "web/libraries/{$name}": [ + "type:drupal-library", + "type:bower-asset", + "type:npm-asset" + ], + "web/modules/contrib/{$name}": [ + "type:drupal-module" + ], + "web/profiles/contrib/{$name}": [ + "type:drupal-profile" + ], + "web/themes/contrib/{$name}": [ + "type:drupal-theme" + ], + "drush/Commands/contrib/{$name}": [ + "type:drupal-drush" + ], + "web/modules/custom/{$name}": [ + "type:drupal-custom-module" + ], + "web/profiles/custom/{$name}": [ + "type:drupal-custom-profile" + ], + "web/themes/custom/{$name}": [ + "type:drupal-custom-theme" + ] + }, + "installer-types": [ + "bower-asset", + "npm-asset" ], - "files": ["load.environment.php"] + "patchLevel": { + "drupal/core": "-p2" + }, + "patches": {} }, "scripts": { "pre-install-cmd": [ "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" ], - "pre-update-cmd": [ - "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" - ], "post-install-cmd": [ "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" ], + "pre-update-cmd": [ + "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" + ], "post-update-cmd": [ "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" ] - }, - "extra": { - "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/Commands/contrib/{$name}": ["type:drupal-drush"] - }, - "composer-exit-on-patch-failure": true, - "patchLevel": { - "drupal/core": "-p2" - }, - "patches": { - } } } diff --git a/scripts/composer/ScriptHandler.php b/scripts/composer/ScriptHandler.php index 1531a8793b..0ccdb85642 100644 --- a/scripts/composer/ScriptHandler.php +++ b/scripts/composer/ScriptHandler.php @@ -11,7 +11,7 @@ use Composer\Semver\Comparator; use Drupal\Core\Site\Settings; use Drupal\Core\Site\SettingsEditor; -use DrupalFinder\DrupalFinder; +use DrupalFinder\DrupalFinderComposerRuntime; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Path; @@ -19,10 +19,14 @@ class ScriptHandler { public static function createRequiredFiles(Event $event) { $fs = new Filesystem(); - $drupalFinder = new DrupalFinder(); - $drupalFinder->locateRoot(getcwd()); + $drupalFinder = new DrupalFinderComposerRuntime(); $drupalRoot = $drupalFinder->getDrupalRoot(); + if (is_null($drupalRoot)) { + $event->getIO()->writeError('Drupal root could not be detected.'); + exit(1); + } + $dirs = [ 'modules', 'profiles', @@ -53,7 +57,7 @@ public static function createRequiredFiles(Event $event) { } // Create the files directory with chmod 0777 - if (!$fs->exists($drupalRoot . '/sites/default/files')) { + if (!$fs->exists($drupalRoot . '/sites/default/files') && !is_link($drupalRoot . '/sites/default/files')) { $oldmask = umask(0); $fs->mkdir($drupalRoot . '/sites/default/files', 0777); umask($oldmask); @@ -92,8 +96,8 @@ public static function checkComposerVersion(Event $event) { 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.'); + elseif (Comparator::lessThan($version, '2.3.6')) { + $io->writeError('Drupal-project requires Composer version 2.3.6 or higher. Please update your Composer before continuing.'); exit(1); } }