diff --git a/.github/workflows/TestEnv.yml b/.github/workflows/TestEnv.yml index baf1a82eb..a0b2a8161 100644 --- a/.github/workflows/TestEnv.yml +++ b/.github/workflows/TestEnv.yml @@ -30,6 +30,7 @@ jobs: - name: Setup Project run: | + set -x ddev config --auto ddev start ddev composer config extra.drupal-scaffold.gitignore true @@ -39,7 +40,10 @@ jobs: ddev composer config --no-plugins allow-plugins.lullabot/drainpipe true ddev composer config repositories.drainpipe --json "{\"type\": \"path\", \"url\": \"drainpipe\", \"options\": {\"symlink\": false}}" ddev composer config minimum-stability dev - cat composer.json | jq --indent 4 '."autoload-dev" = {"files": ["vendor/lullabot/drainpipe/scaffold/env/dotenv.php"]}' | tee composer.json > /dev/null + # cat + tee still has a race condition causing random failures. + # https://stackoverflow.com/a/68676400 + cat composer.json | jq --indent 4 '."autoload-dev" = {"files": ["vendor/lullabot/drainpipe/scaffold/env/dotenv.php"]}' | tee composer.new.json + mv composer.new.json composer.json ddev composer update --lock ddev composer validate ddev composer require lullabot/drainpipe --with-all-dependencies diff --git a/.github/workflows/test-production-build.yml b/.github/workflows/test-production-build.yml index cd37bdb32..c5af1b4a4 100644 --- a/.github/workflows/test-production-build.yml +++ b/.github/workflows/test-production-build.yml @@ -39,7 +39,7 @@ jobs: cd ../ composer create-project drupal/recommended-project drupal --ignore-platform-req=ext-gd cd drupal - cp ${GITHUB_WORKSPACE}/tests/fixtures.drainpipe-test-build/Taskfile.yml . + cp ${GITHUB_WORKSPACE}/tests/fixtures/drainpipe-test-production-build/Taskfile.yml . composer config extra.drupal-scaffold.gitignore true composer config --json extra.drupal-scaffold.allowed-packages '["lullabot/drainpipe"]' composer config --no-plugins allow-plugins.composer/installers true @@ -49,7 +49,44 @@ jobs: composer config minimum-stability dev composer require "lullabot/drainpipe @dev" --with-all-dependencies - - name: Run static tests + - name: Run production build run: | cd ../drupal ./vendor/bin/task build + + Test-Production-Build-DDEV-Global-Binary: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + path: drainpipe + + - uses: ./drainpipe/scaffold/github/actions/common/set-env + + - name: Install DDEV + uses: ./drainpipe/scaffold/github/actions/common/ddev + with: + git-name: Drainpipe Bot + git-email: no-reply@example.com + ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + ssh-known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }} + + - name: Setup Project + run: | + cp drainpipe/tests/fixtures/drainpipe-test-production-build/composer-ddev-global-binary.json composer.json + cp drainpipe/tests/fixtures/drainpipe-test-production-build/Taskfile.yml . + ddev config --project-type=drupal9 + ddev start + ddev composer install + # ddev won't create settings.ddev.php until settings.php exists. + ddev config --project-type=drupal9 + ddev restart + + - name: Install Drupal + run: | + ddev drush site:install minimal -y + echo "\$settings['config_sync_directory'] = '../config';" >> web/sites/default/settings.php + ddev drush config:export -y + + - name: Run production build + run: ddev task build diff --git a/README.md b/README.md index 15f7f4f21..4a73d9feb 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,17 @@ for a Drupal site, including: ```sh composer config extra.drupal-scaffold.gitignore true composer config --json extra.drupal-scaffold.allowed-packages "[\"lullabot/drainpipe\", \"lullabot/drainpipe-dev\"]" +composer config --json extra.drainpipe.global-binaries.task "true" +composer config --json extra.drainpipe.global-binaries.local-php-security-checker "true" +``` + +If using DDEV (highly recommended!), additionally set `task` to be a global binary: +```sh +ddev composer config extra.drainpipe.global-binaries.task true +``` + +Finally, require `drainpipe` and `drainpipe-dev` +```sh composer require lullabot/drainpipe composer require lullabot/drainpipe-dev --dev ``` @@ -72,7 +83,7 @@ Task is just a single binary and has no other dependencies. It's also cross-platform with everything running through the same [shell interpreter](https://github.com/mvdan/sh). You can see what tasks are available after installation by running -`./vendor/bin/task --list` or `ddev task --list` if you're running DDEV. To get +`task --list` or `ddev task --list` if you're running DDEV. To get more information on a specific task e.g. what parameters it takes, you can run `task [task name] --summary`. diff --git a/scaffold/ddev/task-command.sh b/scaffold/ddev/task-command.sh index 42fa537fb..3226e39bc 100644 --- a/scaffold/ddev/task-command.sh +++ b/scaffold/ddev/task-command.sh @@ -4,4 +4,4 @@ ## Usage: task ## Example: "ddev task build" -./vendor/bin/task "$@" +task "$@" diff --git a/scaffold/ddev/web-build/Dockerfile.drainpipe b/scaffold/ddev/web-build/Dockerfile.drainpipe new file mode 100644 index 000000000..4cd441600 --- /dev/null +++ b/scaffold/ddev/web-build/Dockerfile.drainpipe @@ -0,0 +1,8 @@ +COPY install-task.sh /usr/local/bin +RUN chmod +x /usr/local/bin/install-task.sh +# Also update .github/workflows/ValidateTaskfile.yml if changing version. +RUN install-task.sh -b /usr/local/bin -d v3.28.0 + +COPY install-local-php-security-checker.sh /usr/local/bin +RUN chmod +x /usr/local/bin/install-local-php-security-checker.sh +RUN install-local-php-security-checker.sh -b /usr/local/bin -d v2.0.6 diff --git a/scaffold/ddev/web-build/install-local-php-security-checker.sh b/scaffold/ddev/web-build/install-local-php-security-checker.sh new file mode 100755 index 000000000..863524d16 --- /dev/null +++ b/scaffold/ddev/web-build/install-local-php-security-checker.sh @@ -0,0 +1,381 @@ +#!/bin/sh +set -e +# Code generated by godownloader on 2021-01-12T13:40:40Z. +# +# godownloader is no longer maintained. This file has been copied from task's +# install script and edited to support local-php-security-checker. +# + +usage() { + this=$1 + cat </dev/null +} +echoerr() { + echo "$@" 1>&2 +} +log_prefix() { + echo "$0" +} +_logp=6 +log_set_priority() { + _logp="$1" +} +log_priority() { + if test -z "$1"; then + echo "$_logp" + return + fi + [ "$1" -le "$_logp" ] +} +log_tag() { + case $1 in + 0) echo "emerg" ;; + 1) echo "alert" ;; + 2) echo "crit" ;; + 3) echo "err" ;; + 4) echo "warning" ;; + 5) echo "notice" ;; + 6) echo "info" ;; + 7) echo "debug" ;; + *) echo "$1" ;; + esac +} +log_debug() { + log_priority 7 || return 0 + echoerr "$(log_prefix)" "$(log_tag 7)" "$@" +} +log_info() { + log_priority 6 || return 0 + echoerr "$(log_prefix)" "$(log_tag 6)" "$@" +} +log_err() { + log_priority 3 || return 0 + echoerr "$(log_prefix)" "$(log_tag 3)" "$@" +} +log_crit() { + log_priority 2 || return 0 + echoerr "$(log_prefix)" "$(log_tag 2)" "$@" +} +uname_os() { + os=$(uname -s | tr '[:upper:]' '[:lower:]') + case "$os" in + cygwin_nt*) os="windows" ;; + mingw*) os="windows" ;; + msys_nt*) os="windows" ;; + esac + echo "$os" +} +uname_arch() { + arch=$(uname -m) + case $arch in + x86_64) arch="amd64" ;; + x86) arch="386" ;; + i686) arch="386" ;; + i386) arch="386" ;; + aarch64) arch="arm64" ;; + armv5*) arch="arm" ;; + armv6*) arch="arm" ;; + armv7*) arch="arm" ;; + esac + echo ${arch} +} +uname_os_check() { + os=$(uname_os) + case "$os" in + darwin) return 0 ;; + dragonfly) return 0 ;; + freebsd) return 0 ;; + linux) return 0 ;; + android) return 0 ;; + nacl) return 0 ;; + netbsd) return 0 ;; + openbsd) return 0 ;; + plan9) return 0 ;; + solaris) return 0 ;; + windows) return 0 ;; + esac + log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" + return 1 +} +uname_arch_check() { + arch=$(uname_arch) + case "$arch" in + 386) return 0 ;; + amd64) return 0 ;; + arm64) return 0 ;; + arm) return 0 ;; + ppc64) return 0 ;; + ppc64le) return 0 ;; + mips) return 0 ;; + mipsle) return 0 ;; + mips64) return 0 ;; + mips64le) return 0 ;; + s390x) return 0 ;; + amd64p32) return 0 ;; + esac + log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" + return 1 +} +untar() { + tarball=$1 + case "${tarball}" in + *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;; + *.tar) tar --no-same-owner -xf "${tarball}" ;; + *.zip) unzip "${tarball}" ;; + *) + log_err "untar unknown archive format for ${tarball}" + return 1 + ;; + esac +} +http_download_curl() { + local_file=$1 + source_url=$2 + header=$3 + if [ -z "$header" ]; then + code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") + else + code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url") + fi + if [ "$code" != "200" ]; then + log_debug "http_download_curl received HTTP status $code" + return 1 + fi + return 0 +} +http_download_wget() { + local_file=$1 + source_url=$2 + header=$3 + if [ -z "$header" ]; then + wget -q -O "$local_file" "$source_url" + else + wget -q --header "$header" -O "$local_file" "$source_url" + fi +} +http_download() { + log_debug "http_download $2" + if is_command curl; then + http_download_curl "$@" + return + elif is_command wget; then + http_download_wget "$@" + return + fi + log_crit "http_download unable to find wget or curl" + return 1 +} +http_copy() { + tmp=$(mktemp) + http_download "${tmp}" "$1" "$2" || return 1 + body=$(cat "$tmp") + rm -f "${tmp}" + echo "$body" +} +github_release() { + owner_repo=$1 + version=$2 + test -z "$version" && version="latest" + giturl="https://github.com/${owner_repo}/releases/${version}" + json=$(http_copy "$giturl" "Accept:application/json") + test -z "$json" && return 1 + version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//') + test -z "$version" && return 1 + echo "$version" +} +hash_sha256() { + TARGET=${1:-/dev/stdin} + if is_command gsha256sum; then + hash=$(gsha256sum "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command sha256sum; then + hash=$(sha256sum "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command shasum; then + hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command openssl; then + hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f a + else + log_crit "hash_sha256 unable to find command to compute sha-256 hash" + return 1 + fi +} +hash_sha256_verify() { + TARGET=$1 + checksums=$2 + if [ -z "$checksums" ]; then + log_err "hash_sha256_verify checksum file not specified in arg2" + return 1 + fi + BASENAME=${TARGET##*/} + want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1) + if [ -z "$want" ]; then + log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'" + return 1 + fi + got=$(hash_sha256 "$TARGET") + if [ "$want" != "$got" ]; then + log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got" + return 1 + fi +} +cat /dev/null </dev/null +} +echoerr() { + echo "$@" 1>&2 +} +log_prefix() { + echo "$0" +} +_logp=6 +log_set_priority() { + _logp="$1" +} +log_priority() { + if test -z "$1"; then + echo "$_logp" + return + fi + [ "$1" -le "$_logp" ] +} +log_tag() { + case $1 in + 0) echo "emerg" ;; + 1) echo "alert" ;; + 2) echo "crit" ;; + 3) echo "err" ;; + 4) echo "warning" ;; + 5) echo "notice" ;; + 6) echo "info" ;; + 7) echo "debug" ;; + *) echo "$1" ;; + esac +} +log_debug() { + log_priority 7 || return 0 + echoerr "$(log_prefix)" "$(log_tag 7)" "$@" +} +log_info() { + log_priority 6 || return 0 + echoerr "$(log_prefix)" "$(log_tag 6)" "$@" +} +log_err() { + log_priority 3 || return 0 + echoerr "$(log_prefix)" "$(log_tag 3)" "$@" +} +log_crit() { + log_priority 2 || return 0 + echoerr "$(log_prefix)" "$(log_tag 2)" "$@" +} +uname_os() { + os=$(uname -s | tr '[:upper:]' '[:lower:]') + case "$os" in + cygwin_nt*) os="windows" ;; + mingw*) os="windows" ;; + msys_nt*) os="windows" ;; + esac + echo "$os" +} +uname_arch() { + arch=$(uname -m) + case $arch in + x86_64) arch="amd64" ;; + x86) arch="386" ;; + i686) arch="386" ;; + i386) arch="386" ;; + aarch64) arch="arm64" ;; + armv5*) arch="arm" ;; + armv6*) arch="arm" ;; + armv7*) arch="arm" ;; + esac + echo ${arch} +} +uname_os_check() { + os=$(uname_os) + case "$os" in + darwin) return 0 ;; + dragonfly) return 0 ;; + freebsd) return 0 ;; + linux) return 0 ;; + android) return 0 ;; + nacl) return 0 ;; + netbsd) return 0 ;; + openbsd) return 0 ;; + plan9) return 0 ;; + solaris) return 0 ;; + windows) return 0 ;; + esac + log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" + return 1 +} +uname_arch_check() { + arch=$(uname_arch) + case "$arch" in + 386) return 0 ;; + amd64) return 0 ;; + arm64) return 0 ;; + arm) return 0 ;; + ppc64) return 0 ;; + ppc64le) return 0 ;; + mips) return 0 ;; + mipsle) return 0 ;; + mips64) return 0 ;; + mips64le) return 0 ;; + s390x) return 0 ;; + amd64p32) return 0 ;; + esac + log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" + return 1 +} +untar() { + tarball=$1 + case "${tarball}" in + *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;; + *.tar) tar --no-same-owner -xf "${tarball}" ;; + *.zip) unzip "${tarball}" ;; + *) + log_err "untar unknown archive format for ${tarball}" + return 1 + ;; + esac +} +http_download_curl() { + local_file=$1 + source_url=$2 + header=$3 + if [ -z "$header" ]; then + code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") + else + code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url") + fi + if [ "$code" != "200" ]; then + log_debug "http_download_curl received HTTP status $code" + return 1 + fi + return 0 +} +http_download_wget() { + local_file=$1 + source_url=$2 + header=$3 + if [ -z "$header" ]; then + wget -q -O "$local_file" "$source_url" + else + wget -q --header "$header" -O "$local_file" "$source_url" + fi +} +http_download() { + log_debug "http_download $2" + if is_command curl; then + http_download_curl "$@" + return + elif is_command wget; then + http_download_wget "$@" + return + fi + log_crit "http_download unable to find wget or curl" + return 1 +} +http_copy() { + tmp=$(mktemp) + http_download "${tmp}" "$1" "$2" || return 1 + body=$(cat "$tmp") + rm -f "${tmp}" + echo "$body" +} +github_release() { + owner_repo=$1 + version=$2 + test -z "$version" && version="latest" + giturl="https://github.com/${owner_repo}/releases/${version}" + json=$(http_copy "$giturl" "Accept:application/json") + test -z "$json" && return 1 + version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//') + test -z "$version" && return 1 + echo "$version" +} +hash_sha256() { + TARGET=${1:-/dev/stdin} + if is_command gsha256sum; then + hash=$(gsha256sum "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command sha256sum; then + hash=$(sha256sum "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command shasum; then + hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command openssl; then + hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f a + else + log_crit "hash_sha256 unable to find command to compute sha-256 hash" + return 1 + fi +} +hash_sha256_verify() { + TARGET=$1 + checksums=$2 + if [ -z "$checksums" ]; then + log_err "hash_sha256_verify checksum file not specified in arg2" + return 1 + fi + BASENAME=${TARGET##*/} + want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1) + if [ -z "$want" ]; then + log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'" + return 1 + fi + got=$(hash_sha256 "$TARGET") + if [ "$want" != "$got" ]; then + log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got" + return 1 + fi +} +cat /dev/null < environment_url.txt drainpipe_pantheon_drupal_review_app: diff --git a/scaffold/tugboat/steps/2-update.sh.twig b/scaffold/tugboat/steps/2-update.sh.twig index b4a7e14d4..f9de3ea27 100644 --- a/scaffold/tugboat/steps/2-update.sh.twig +++ b/scaffold/tugboat/steps/2-update.sh.twig @@ -7,7 +7,7 @@ set -eux echo "Updating..." composer install -./vendor/bin/task {{ sync_command }} +{{ task_path }} {{ sync_command }} # Set file permissions such that Drupal will not complain. chgrp -R www-data "${DOCROOT}/sites/default/files" diff --git a/scaffold/tugboat/steps/3-build.sh.twig b/scaffold/tugboat/steps/3-build.sh.twig index ad88cb452..0adbb4446 100644 --- a/scaffold/tugboat/steps/3-build.sh.twig +++ b/scaffold/tugboat/steps/3-build.sh.twig @@ -6,5 +6,5 @@ set -eux echo "Building..." -./vendor/bin/task {{ build_command }} -./vendor/bin/task {{ update_command }} +{{ task_path }} {{ build_command }} +{{ task_path }} {{ update_command }} diff --git a/src/BinaryInstaller.php b/src/BinaryInstaller.php index b5db8482e..a412f2d03 100644 --- a/src/BinaryInstaller.php +++ b/src/BinaryInstaller.php @@ -54,6 +54,11 @@ class BinaryInstaller implements PluginInterface, EventSubscriberInterface */ protected $processor; + /** + * @var array + */ + private $extra; + /** * {@inheritdoc} */ @@ -61,6 +66,7 @@ public function activate(Composer $composer, IOInterface $io) { $this->io = $io; $this->config = $composer->getConfig(); + $this->extra = $composer->getPackage()->getExtra(); $this->platform = strtolower(\PHP_OS_FAMILY); $uname = strtolower(php_uname('m')); if ($uname === 'arm64' || $uname === 'aarch64') { @@ -146,6 +152,20 @@ public function onPostUpdateCmd(Event $event) public function installBinaries(Event $event) { foreach ($this->binaries as $binary => $info) { + $migrated_to_global = isset($this->extra['drainpipe']['global-binaries']); + if ($migrated_to_global) { + $global_binaries = $this->extra['drainpipe']['global-binaries']; + if (isset($global_binaries[$binary]) && $global_binaries[$binary]) { + continue; + } + $migrated_to_global = FALSE; + } + if (!$migrated_to_global) { + $this->io->warning('Downloading binaries to vendor/bin is deprecated and will be removed in Drainpipe 4.0.'); + $this->io->warning('Run the following composer command and update any CI scripts to use the commands installed in /usr/local/bin to migrate.'); + $this->io->warning('composer config --json --merge extra.drainpipe \'{"global-binaries": { "local-php-security-checker": true, "task": true } }\''); + } + $platform = $this->platform; $processor = $this->processor; diff --git a/src/ScaffoldInstallerPlugin.php b/src/ScaffoldInstallerPlugin.php index 2994fa27f..e0e45d52b 100644 --- a/src/ScaffoldInstallerPlugin.php +++ b/src/ScaffoldInstallerPlugin.php @@ -82,6 +82,7 @@ public function onPostInstallCmd(Event $event) $this->installTaskfile(); $this->installGitignore(); $this->installDdevCommand(); + $this->installDdevTask(); $this->installCICommands(); $this->installEnvSupport(); } @@ -96,6 +97,7 @@ public function onPostUpdateCmd(Event $event) $this->installTaskfile(); $this->installGitignore(); $this->installDdevCommand(); + $this->installDdevTask(); $this->installCICommands(); $this->installEnvSupport(); } @@ -200,6 +202,16 @@ private function installEnvSupport(): void } } + private function installDdevTask(): void + { + if (file_exists('./.ddev/config.yaml')) { + $vendor = $this->config->get('vendor-dir'); + $webBuildPath = $vendor . '/lullabot/drainpipe/scaffold/ddev/web-build/'; + $fs = new Filesystem(); + $fs->copy($webBuildPath, './.ddev/web-build'); + } + } + /** * */ @@ -335,6 +347,7 @@ private function installCICommands(): void 'build_command' => 'build', 'update_command' => 'drupal:update', 'init' => [], + 'task_path' => isset($this->extra['drainpipe']['global-binaries']['task']) && $this->extra['drainpipe']['global-binaries']['task'] ? 'task' : './vendor/bin/task', 'task_version' => $binaryInstallerPlugin->getBinaryVersion('task'), 'pantheon' => isset($this->extra['drainpipe']['tugboat']['pantheon']), 'overrides' => ['php' => ''], diff --git a/tasks/test.yml b/tasks/test.yml index 5608db95a..030b509d9 100644 --- a/tasks/test.yml +++ b/tasks/test.yml @@ -27,7 +27,7 @@ tasks: - cmd: | if [ "{{.format}}" == "junit" ]; then mkdir -p test_result - ./vendor/bin/local-php-security-checker --format=json > test_result/local-php-security-checker.json + local-php-security-checker --format=json > test_result/local-php-security-checker.json fi ignore_error: true - | @@ -38,7 +38,7 @@ tasks: exit 1 fi else - ./vendor/bin/local-php-security-checker + local-php-security-checker fi - composer audit lint: diff --git a/tests/fixtures.drainpipe-test-build/Taskfile.yml b/tests/fixtures/drainpipe-test-production-build/Taskfile.yml similarity index 100% rename from tests/fixtures.drainpipe-test-build/Taskfile.yml rename to tests/fixtures/drainpipe-test-production-build/Taskfile.yml diff --git a/tests/fixtures/drainpipe-test-production-build/composer-ddev-global-binary.json b/tests/fixtures/drainpipe-test-production-build/composer-ddev-global-binary.json new file mode 100644 index 000000000..bfeb36481 --- /dev/null +++ b/tests/fixtures/drainpipe-test-production-build/composer-ddev-global-binary.json @@ -0,0 +1,109 @@ +{ + "name": "drupal/recommended-project", + "description": "Project template for Drupal 9 projects with a relocated document root", + "type": "project", + "license": "GPL-2.0-or-later", + "homepage": "https://www.drupal.org/project/drupal", + "support": { + "docs": "https://www.drupal.org/docs/user_guide/en/index.html", + "chat": "https://www.drupal.org/node/314178" + }, + "repositories": [ + { + "type": "path", + "url": "drainpipe", + "options": { + "symlink": false + } + }, + { + "type": "composer", + "url": "https://packages.drupal.org/8" + } + ], + "require": { + "composer/installers": "^1.9", + "drupal/core": "^8.9|^9.2", + "drupal/core-composer-scaffold": "^8.9|^9.2", + "drupal/core-project-message": "^8.9|^9.2", + "drupal/core-recommended": "^8.9|^9.2", + "lullabot/drainpipe": "*" + }, + "conflict": { + "drupal/drupal": "*" + }, + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "sort-packages": true, + "allow-plugins": { + "composer/installers": true, + "drupal/core-composer-scaffold": true, + "drupal/core-project-message": true, + "lullabot/drainpipe": true + } + }, + "extra": { + "drainpipe": { + "global-binaries": { + "task": true, + "local-php-security-checker": true + } + }, + "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" + ], + "web/modules/custom/{$name}": [ + "type:drupal-custom-module" + ], + "web/profiles/custom/{$name}": [ + "type:drupal-custom-profile" + ], + "web/themes/custom/{$name}": [ + "type:drupal-custom-theme" + ] + }, + "drupal-core-project-message": { + "include-keys": [ + "homepage", + "support" + ], + "post-create-project-cmd-message": [ + " ", + " Congratulations, you’ve installed the Drupal codebase ", + " from the drupal/recommended-project template! ", + " ", + "", + "Next steps:", + " * Install the site: https://www.drupal.org/docs/8/install", + " * Read the user guide: https://www.drupal.org/docs/user_guide/en/index.html", + " * Get support: https://www.drupal.org/support", + " * Get involved with the Drupal community:", + " https://www.drupal.org/getting-involved", + " * Remove the plugin that prints this message:", + " composer remove drupal/core-project-message" + ] + } + } +} diff --git a/tests/fixtures/drainpipe-test-production-build/composer.json b/tests/fixtures/drainpipe-test-production-build/composer.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/fixtures/drainpipe-test-project-global-binaries/composer.json b/tests/fixtures/drainpipe-test-project-global-binaries/composer.json new file mode 100644 index 000000000..fec759714 --- /dev/null +++ b/tests/fixtures/drainpipe-test-project-global-binaries/composer.json @@ -0,0 +1,28 @@ +{ + "name": "lullabot/drainpipe-test-project", + "type": "project", + "repositories": [ + { + "type": "path", + "url": "../../../" + } + ], + "minimum-stability": "dev", + "prefer-stable": true, + "require": { + "lullabot/drainpipe": "*" + }, + "config": { + "allow-plugins": { + "lullabot/drainpipe": true + } + }, + "extra": { + "drainpipe": { + "global-binaries": { + "task": true, + "local-php-security-checker": true + } + } + } +} diff --git a/tests/src/Functional/InstallerScaffoldGlobalBinariesTest.php b/tests/src/Functional/InstallerScaffoldGlobalBinariesTest.php new file mode 100644 index 000000000..ea3524f70 --- /dev/null +++ b/tests/src/Functional/InstallerScaffoldGlobalBinariesTest.php @@ -0,0 +1,48 @@ +run(); + } + + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + + if (file_exists(self::PROJECT_PATH.'/.gitignore')) { + unlink(self::PROJECT_PATH.'/.gitignore'); + } + $clean = new Process(['git', 'clean', '-fdX'], self::PROJECT_PATH); + $clean->run(); + } + + public function testTaskfile(): void + { + $this->assertEquals(sha1_file(self::PROJECT_PATH.'/vendor/lullabot/drainpipe/scaffold/Taskfile.yml'), sha1_file(self::PROJECT_PATH.'/Taskfile.yml')); + } + + public function testGitIgnore(): void + { + $gitignore = file_get_contents(self::PROJECT_PATH.'/.gitignore'); + $this->assertStringContainsString('.task', $gitignore); + } + + public function testBinaries(): void + { + $this->assertFileDoesNotExist(self::PROJECT_PATH.'/vendor/bin/task'); + $this->assertFileDoesNotExist(self::PROJECT_PATH.'/vendor/bin/local-php-security-checker'); + } +}