diff --git a/.github/workflows/TestTugboat.yml b/.github/workflows/TestTugboat.yml new file mode 100644 index 000000000..ed504b74c --- /dev/null +++ b/.github/workflows/TestTugboat.yml @@ -0,0 +1,75 @@ +name: "Test Tugboat" + +on: + pull_request: + types: [opened, synchronize, reopened] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + Test-Tugboat: + runs-on: ubuntu-latest + steps: + - name: Create a Drupal project + run: composer create-project drupal/recommended-project . --ignore-platform-req=ext-gd + + - 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 }} + + - name: Setup Project + run: | + ddev config --auto + ddev config --php-version "8.1" + ddev config --nodejs-version "18" + ddev config --database=mariadb:10.4 + ddev start + ddev composer config extra.drupal-scaffold.gitignore true + ddev composer config --json extra.drupal-scaffold.allowed-packages \[\"lullabot/drainpipe\"] + ddev composer config --no-plugins allow-plugins.composer/installers true + ddev composer config --no-plugins allow-plugins.drupal/core-composer-scaffold true + 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 + ddev composer config extra.drainpipe --json '{"tugboat": {}}' + ddev composer require lullabot/drainpipe --with-all-dependencies + + # Compare the generated files to the ones used to build this repository + # preview - they should be the same. + - name: Test Generated Files + run: | + cmp -b drainpipe/.tugboat/config.yml .tugboat/config.yml + sed -i '/#drainpipe-start/,/#drainpipe-end/d' drainpipe/.tugboat/steps/1-init.sh + sed -i '/#drainpipe-start/,/#drainpipe-end/d' drainpipe/.tugboat/steps/2-update.sh + sed -i '/#drainpipe-start/,/#drainpipe-end/d' drainpipe/.tugboat/steps/3-build.sh + cmp -b drainpipe/.tugboat/steps/1-init.sh .tugboat/steps/1-init.sh + cmp -b drainpipe/.tugboat/steps/2-update.sh .tugboat/steps/2-update.sh + cmp -b drainpipe/.tugboat/steps/3-build.sh .tugboat/steps/3-build.sh + + - name: Add a build:tugboat step + run: | + echo " build:tugboat:" >> Taskfile.yml + echo " cmds:" >> Taskfile.yml + echo " - echo \"Tugboat build\"" >> Taskfile.yml + ddev composer install + if ! grep -q './vendor/bin/task build:tugboat' .tugboat/steps/3-build.sh; then + exit 1 + fi + + - name: Upload test artifacts + if: ${{ always() }} + uses: actions/upload-artifact@v3 + with: + name: .tugboat + path: .tugboat diff --git a/.tugboat/config.yml b/.tugboat/config.yml new file mode 100644 index 000000000..add32b415 --- /dev/null +++ b/.tugboat/config.yml @@ -0,0 +1,16 @@ +services: + php: + http: false + image: tugboatqa/php-nginx:8.1-fpm + default: true + + depends: + - mariadb + + commands: + init: ./.tugboat/steps/1-init.sh + update: ./.tugboat/steps/2-update.sh + build: ./.tugboat/steps/3-build.sh + + mariadb: + image: tugboatqa/mariadb:10.4 diff --git a/.tugboat/steps/1-init.sh b/.tugboat/steps/1-init.sh new file mode 100755 index 000000000..2424972f7 --- /dev/null +++ b/.tugboat/steps/1-init.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +set -eux +echo "Initializing..." + +# Install task +sh -c "$(curl --location https://raw.githubusercontent.com/go-task/task/v3.24.0/install-task.sh)" -- -d -b /usr/local/bin + +# Install mysql or mariadb client. +apt-get update +apt-get install -y mariadb-client + +# Link the document root to the expected path. Tugboat uses /docroot +# by default. So, if Drupal is located at any other path in your git +# repository, change that here. This example links /web to the docroot +ln -snf "${TUGBOAT_ROOT}/web" "${DOCROOT}" + +# Create the Drupal private and public files directories if they aren't +# already present. +mkdir -p "${TUGBOAT_ROOT}/web/sites/default/files" +chmod 777 "${TUGBOAT_ROOT}/web/sites/default/files" + +# Install the PHP opcache as it's not included by default and needed for +# decent performance. +docker-php-ext-install opcache + +# GD dependencies. +apt-get install -y libpng-dev libjpeg-dev libfreetype6-dev + +# WebP dependencies. +apt-get install -y libwebp-dev libwebp7 webp libmagickwand-dev + +# Build and install gd. +docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp +docker-php-ext-install gd + +# Install ImageMagick. This is recommended by both Acquia and Pantheon instead +# of GD. Lullabot will likely be publishing an ADR recommending it too. +apt-get install -y imagemagick + +# Install node +curl -fsSL https://deb.nodesource.com/setup_current.x | bash - +apt-get install -y nodejs +npm install -g n +n 18 +# This only works for node > 16, but that version is unsupported now anyway. +corepack enable +#drainpipe-start +# This is necessary for testing as this repository doesn't hold a Drupal site. +shopt -s dotglob +mkdir ../drainpipe-tmp +mv * ../drainpipe-tmp/ +composer create-project drupal/recommended-project . +mv ../drainpipe-tmp drainpipe +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 +composer config --no-plugins allow-plugins.drupal/core-composer-scaffold true +composer config --no-plugins allow-plugins.lullabot/drainpipe true +composer config repositories.drainpipe --json '{"type": "path", "url": "drainpipe", "options": {"symlink": true}}' +composer config extra.drainpipe --json '{"tugboat": {}}' +composer config minimum-stability dev +composer require lullabot/drainpipe --with-all-dependencies +cp web/sites/default/default.settings.php web/sites/default/settings.php +#drainpipe-end + +composer install +#drainpipe-start +rm -rf .tugboat +mv drainpipe/.tugboat .tugboat +#drainpipe-end diff --git a/.tugboat/steps/2-update.sh b/.tugboat/steps/2-update.sh new file mode 100755 index 000000000..6ef6567de --- /dev/null +++ b/.tugboat/steps/2-update.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -eux +echo "Updating..." + +#drainpipe-start +mv .tugboat .tugboat-tmp +#drainpipe-end +composer install +./vendor/bin/task sync +#drainpipe-start +./vendor/bin/drush config:export --yes +rm -rf .tugboat +mv .tugboat-tmp .tugboat +#drainpipe-end diff --git a/.tugboat/steps/3-build.sh b/.tugboat/steps/3-build.sh new file mode 100755 index 000000000..0c089ec96 --- /dev/null +++ b/.tugboat/steps/3-build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -eux +echo "Building..." + +./vendor/bin/task build +./vendor/bin/task drupal:update diff --git a/README.md b/README.md index 0662776d9..e4b32ac01 100644 --- a/README.md +++ b/README.md @@ -419,8 +419,101 @@ Requires `GITLAB_ACCESS_TOKEN` variable to be set, which is an access token with } ``` +- Add the following the composer.json to enable deployment of Pantheon Review Apps + ```json + "extra": { + "drainpipe": { + "github": ["PantheonReviewApps"] + } + } + ``` +- Run `composer install` +- Add your Pantheon `site-name` to the last job in the new + workflow file at `.github/workflows/PantheonReviewApps.yml` +- Add the following secrets to your repository: + - `PANTHEON_TERMINUS_TOKEN` See https://pantheon.io/docs/terminus/install#machine-token + - `SSH_PRIVATE_KEY` A private key of a user which can push to Pantheon + - `SSH_KNOWN_HOSTS` The result of running `ssh-keyscan -H codeserver.dev.$PANTHEON_SITE_ID.drush.in` + - `TERMINUS_PLUGINS` Comma-separated list of Terminus plugins to be available (optional) + This will setup Merge Request deployment to Pantheon Multidev environments. See [scaffold/gitlab/gitlab-ci.example.yml] for an example. You can also just include which will give you helpers that you can include and reference for tasks such as setting up [Terminus](https://pantheon.io/docs/terminus). See [scaffold/gitlab/Pantheon.gitlab-ci.yml](scaffold/gitlab/Pantheon.gitlab-ci.yml). + +## Tugboat + +Add the following to `composer.json` to add Tugboat configuration: + +```json +{ + "extra": { + "drainpipe": { + "tugboat": {} + } + } +} +``` + +The following will be autodetected based on your `.ddev/config.yml`: +- Web server (nginx or apache) +- PHP version +- Database type and version +- nodejs version +- Redis (Obtained with `ddev get ddev/ddev-redis`) + +Additionally, Pantheon Terminus can be added: +```json +{ + "extra": { + "drainpipe": { + "tugboat": { + "terminus": true + } + } + } +} +``` + +It is assumed the following tasks exist: +- `build` +- `sync` + +The `build` and `sync` tasks can be overridden with a `build:tugboat` and +`sync:tugboat` task if required (you will need to re-run `composer install` to +regenerate the Tugboat scripts if you are adding this task to your +`Taskfile.yml` for the first time). + +``` + sync: + desc: "Fetches a database from Pantheon and imports it" + cmds: + - task: pantheon:fetch-db + - task: drupal:import-db + sync:tugboat: + desc: "Fetches a database from Pantheon and imports it in Tugboat" + cmds: + - task: pantheon:fetch-db + vars: + DB_DIR: /var/lib/tugboat/files/db + - task: drupal:import-db + vars: + DB_DIR: /var/lib/tugboat/files/db +``` + +>>> +💡 +`composer install` should be re-run if any changes are made to the DDEV +configuration. +>>> + +You can hook into the `init` step of images by adding them to your +`Taskfile.yml`, e.g. + +``` +tugboat:php:init: + cmds: + - apt-get install -y libldap2-dev + - docker-php-ext-install ldap +``` diff --git a/composer.json b/composer.json index b7f2e8c04..6624c9d57 100644 --- a/composer.json +++ b/composer.json @@ -11,9 +11,11 @@ }, "require": { "php": "^7.3||^8.0", + "ext-json": "*", "composer-plugin-api": "^2.0", "drush/drush": "^10|^11", "symfony/yaml": "^3|^4|^5|^6", + "twig/twig": "^2|^3", "vlucas/phpdotenv": "^4|^5", "ext-json": "*" }, diff --git a/scaffold/Taskfile.yml b/scaffold/Taskfile.yml index 0c0c5299f..a37a3929d 100644 --- a/scaffold/Taskfile.yml +++ b/scaffold/Taskfile.yml @@ -35,3 +35,11 @@ tasks: # assets:watch: # desc: "Builds assets such as CSS & JS, and watches them for changes" # deps: [sass:watch, javascript:watch] + sync: + desc: "Sync a database from production and import it" + cmds: + # Replace this with a command to fetch your database. + - ./vendor/bin/drush site:install -y + - echo "🧹 Sanitising database" + - ./vendor/bin/drush sql:sanitize --yes + diff --git a/scaffold/tugboat/config.yml.twig b/scaffold/tugboat/config.yml.twig new file mode 100644 index 000000000..76f19d049 --- /dev/null +++ b/scaffold/tugboat/config.yml.twig @@ -0,0 +1,42 @@ +services: + php: + http: false + image: {{ webserver_image }} + default: true + + depends: + - {{ database_type }} +{% if memory_cache_type %} + - {{ memory_cache_type }} +{% endif %} + + commands: + init: ./.tugboat/steps/1-init.sh + update: ./.tugboat/steps/2-update.sh + build: ./.tugboat/steps/3-build.sh + + {{ database_type }}: + image: tugboatqa/{{ database_type }}:{{ database_version }} +{% if init.mysql %} + checkout: true + commands: + init: + - sh -c "$(curl --location https://raw.githubusercontent.com/go-task/task/v{{ task_version }}/install-task.sh)" -- -d -b /usr/local/bin + - wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq && chmod +x /usr/bin/yq + - yq -i 'del(."includes")' Taskfile.yml + - task tugboat:mysql:init +{% endif %} +{% if memory_cache_type %} + + {{ memory_cache_type }}: + image: tugboatqa/{{ memory_cache_type }}:{{ memory_cache_version }} +{% if init.redis %} + checkout: true + commands: + init: + - sh -c "$(curl --location https://raw.githubusercontent.com/go-task/task/v{{ task_version }}/install-task.sh)" -- -d -b /usr/local/bin + - wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq && chmod +x /usr/bin/yq + - yq -i 'del(."includes")' Taskfile.yml + - task tugboat:redis:init +{% endif %} +{% endif %} diff --git a/scaffold/tugboat/settings.tugboat.php.twig b/scaffold/tugboat/settings.tugboat.php.twig new file mode 100644 index 000000000..ca5c4e04c --- /dev/null +++ b/scaffold/tugboat/settings.tugboat.php.twig @@ -0,0 +1,32 @@ + 'tugboat', + 'username' => 'tugboat', + 'password' => 'tugboat', + 'prefix' => '', + 'host' => '{{ database_type }}', + 'port' => '3306', + 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', + 'driver' => 'mysql', + ]; + + $settings['hash_salt'] = hash('sha256', getenv('TUGBOAT_REPO_ID')); + + $settings['trusted_host_patterns'] = [ + '\.tugboatqa\.com$', + ]; + + $config['environment_indicator.indicator']['name'] = '☑️ Tugboat'; + $config['environment_indicator.indicator']['bg_color'] = '#07688c'; + $config['environment_indicator.indicator']['fg_color'] = '#ffffff'; +} diff --git a/scaffold/tugboat/steps/1-init.sh.twig b/scaffold/tugboat/steps/1-init.sh.twig new file mode 100644 index 000000000..4eec6d22a --- /dev/null +++ b/scaffold/tugboat/steps/1-init.sh.twig @@ -0,0 +1,80 @@ +#!/bin/bash + +set -eux +echo "Initializing..." + +# Install task +sh -c "$(curl --location https://raw.githubusercontent.com/go-task/task/v3.24.0/install-task.sh)" -- -d -b /usr/local/bin + +# Install mysql or mariadb client. +apt-get update +{% if database_type == "mysql" %} +# mysql was replaced by mariadb in Debian, so we have to install it manually. +# https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/#repo-qg-apt-repo-manual-setup +# apt-key is also deprecated, so here we install the key manually. +./.tugboat/steps/install-mysql-client.sh +{% else %} +apt-get install -y {{ database_type }}-client +{% endif %} + +# Link the document root to the expected path. Tugboat uses /docroot +# by default. So, if Drupal is located at any other path in your git +# repository, change that here. This example links /web to the docroot +ln -snf "${TUGBOAT_ROOT}/web" "${DOCROOT}" + +# Create the Drupal private and public files directories if they aren't +# already present. +mkdir -p "${TUGBOAT_ROOT}/web/sites/default/files" +chmod 777 "${TUGBOAT_ROOT}/web/sites/default/files" + +# Install the PHP opcache as it's not included by default and needed for +# decent performance. +docker-php-ext-install opcache + +# GD dependencies. +apt-get install -y libpng-dev libjpeg-dev libfreetype6-dev + +# WebP dependencies. +apt-get install -y libwebp-dev libwebp7 webp libmagickwand-dev + +# Build and install gd. +docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp +docker-php-ext-install gd + +# Install ImageMagick. This is recommended by both Acquia and Pantheon instead +# of GD. Lullabot will likely be publishing an ADR recommending it too. +apt-get install -y imagemagick +{% if memory_cache_type == "memcached" %} +# Install the PHP memcache extension. The Drupal Redis module recommends +# phpredis so no PHP extension is required. + +apt-get install -y zlib1g-dev +pecl install memcache +echo 'extension=memcache.so' > /usr/local/etc/php/conf.d/memcache.ini +{% endif %} + +# Install node +curl -fsSL https://deb.nodesource.com/setup_current.x | bash - +apt-get install -y nodejs +npm install -g n +n {{ nodejs_version }} +# This only works for node > 16, but that version is unsupported now anyway. +corepack enable +{% if 'apache' in webserver_image %} +# Apache +a2enmod headers rewrite +{% endif %} +{% if pantheon %} + +# Pantheon +curl --fail -sSL https://github.com/pantheon-systems/terminus/releases/download/$(curl -L --fail --silent "https://api.github.com/repos/pantheon-systems/terminus/releases/latest" | perl -nle'print $& while m{"tag_name": "\K.*?(?=")}g')/terminus.phar --output /usr/local/bin/terminus +chmod 777 /usr/local/bin/terminus +{% endif %} +{% if init.php %} + +# Bring in tasks. +composer install --ignore-platform-reqs +task tugboat:php:init +{% endif %} + +composer install diff --git a/scaffold/tugboat/steps/2-update.sh.twig b/scaffold/tugboat/steps/2-update.sh.twig new file mode 100644 index 000000000..b1e19f946 --- /dev/null +++ b/scaffold/tugboat/steps/2-update.sh.twig @@ -0,0 +1,7 @@ +#!/bin/bash + +set -eux +echo "Updating..." + +composer install +./vendor/bin/task {{ sync_command }} diff --git a/scaffold/tugboat/steps/3-build.sh.twig b/scaffold/tugboat/steps/3-build.sh.twig new file mode 100644 index 000000000..d99a38ae3 --- /dev/null +++ b/scaffold/tugboat/steps/3-build.sh.twig @@ -0,0 +1,7 @@ +#!/bin/bash + +set -eux +echo "Building..." + +./vendor/bin/task {{ build_command }} +./vendor/bin/task drupal:update diff --git a/scaffold/tugboat/steps/install-mysql-client.sh b/scaffold/tugboat/steps/install-mysql-client.sh new file mode 100755 index 000000000..839ecc072 --- /dev/null +++ b/scaffold/tugboat/steps/install-mysql-client.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# apt-key is deprecated! We follow the guide at https://askubuntu.com/a/1307181 +mkdir -p /etc/apt/keyrings +cd /etc/apt/keyrings + +cat > mysql.txt << EOD +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: SKS 1.1.6 +Comment: Hostname: pgp.mit.edu + +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 +sTSKHe+QnnnoFmu4gnmDU31i +=Xqbo +-----END PGP PUBLIC KEY BLOCK----- +EOD + +apt-get update +apt-get -y install gnupg + +gpg --no-default-keyring --keyring ./temp-keyring.gpg --import mysql.txt +gpg --no-default-keyring --keyring ./temp-keyring.gpg --export --output mysql.gpg +rm temp-keyring.gpg + +# Oracle / MySQL still doesn't support Debian 11, even on newer versions of +# MySQL. However, buster packages still work. +echo 'deb [signed-by=/etc/apt/keyrings/mysql.gpg] http://repo.mysql.com/apt/debian/ buster mysql-5.7' > /etc/apt/sources.list.d/mysql.list +apt-get update + +# Purge mariadb if installed +apt-get -y --autoremove purge 'mariadb*' +apt-get -y install mysql-client diff --git a/src/BinaryInstallerPlugin.php b/src/BinaryInstallerPlugin.php index 20ce65331..ef71289c7 100644 --- a/src/BinaryInstallerPlugin.php +++ b/src/BinaryInstallerPlugin.php @@ -34,4 +34,14 @@ class BinaryInstallerPlugin extends BinaryInstaller 'version' => '3.24.0', ], ]; + + /** + * Gets the version for a binary. + * + * @param $binary + * @return mixed|string + */ + public function getBinaryVersion($binary) { + return $this->binaries[$binary]['version']; + } } diff --git a/src/ScaffoldInstallerPlugin.php b/src/ScaffoldInstallerPlugin.php index 2099478c9..78ec8b32f 100644 --- a/src/ScaffoldInstallerPlugin.php +++ b/src/ScaffoldInstallerPlugin.php @@ -13,6 +13,8 @@ use Composer\Script\ScriptEvents; use Composer\Util\Filesystem; use Symfony\Component\Yaml\Yaml; +use Twig\Environment; +use Twig\Loader\FilesystemLoader; class ScaffoldInstallerPlugin implements PluginInterface, EventSubscriberInterface { @@ -154,7 +156,7 @@ private function installGitignore(): void if (strpos($contents, '.task') === false) { $this->io->warning( sprintf( - '.gitignore does not contain drainpipe ignores. Compare .gitignore in the root of your repository with %s and update as needed.', + '.gitignore does not contain drainpipe ignores. Compare .gitignore in the root of your repository with %s and update as needed.', $gitignorePath ) ); @@ -184,7 +186,7 @@ private function installEnvSupport(): void } /** - * Install DDEV Commands. + * */ private function installDdevCommand(): void { @@ -274,5 +276,89 @@ private function installCICommands(): void } } } + + // Tugboat + if (isset($this->extra['drainpipe']['tugboat'])) { + $fs->removeDirectory('./.tugboat'); + $binaryInstallerPlugin = new BinaryInstallerPlugin(); + $tugboatConfig = [ + 'nodejs_version' => '18', + 'webserver_image' => 'tugboatqa/php-nginx:8.1-fpm', + 'database_type' => 'mariadb', + 'database_version' => '10.6', + 'php_version' => '8.1', + 'build_command' => 'build', + 'sync_command' => 'sync', + 'init' => [], + 'task_version' => $binaryInstallerPlugin->getBinaryVersion('task'), + 'pantheon' => isset($this->extra['drainpipe']['tugboat']['pantheon']), + ]; + + if (file_exists('./.ddev/config.yaml')) { + $ddevConfig = Yaml::parseFile('./.ddev/config.yaml'); + $tugboatConfig['database_type'] = $ddevConfig['database']['type']; + $tugboatConfig['database_version'] = $ddevConfig['database']['version']; + $tugboatConfig['webserver_image'] = 'tugboatqa/php-nginx:' . $ddevConfig['php_version'] . '-fpm'; + + if (!empty($ddevConfig['nodejs_version'])) { + $tugboatConfig['nodejs_version'] = $ddevConfig['nodejs_version']; + } + if (!empty($ddevConfig['webserver_type']) && $ddevConfig['webserver_type'] === 'apache-fpm') { + $tugboatConfig['webserver_image'] = 'tugboatqa/php:' . $ddevConfig['php_version'] . '-apache'; + } + } + + if (file_exists('./.ddev/docker-compose.redis.yaml')) { + $redisConfig = Yaml::parseFile('.ddev/docker-compose.redis.yaml'); + $redisImage = explode(':', $redisConfig['services']['redis']['image']); + $tugboatConfig['memory_cache_type'] = 'redis'; + $tugboatConfig['memory_cache_version'] = array_pop($redisImage); + } + + if (file_exists('Taskfile.yml')) { + // Get steps out of the Taskfile. + $taskfile = Yaml::parseFile('./Taskfile.yml'); + if (isset($taskfile['tasks']['build:tugboat'])) { + $tugboatConfig['build_command'] = 'build:tugboat'; + } + if (isset($taskfile['tasks']['sync:tugboat'])) { + $tugboatConfig['sync_command'] = 'sync:tugboat'; + } + if (isset($taskfile['tasks']['tugboat:php:init'])) { + $tugboatConfig['init']['php'] = true; + } + if (isset($taskfile['tasks']['tugboat:mysql:init'])) { + $tugboatConfig['init']['mysql'] = true; + } + if (isset($taskfile['tasks']['tugboat:redis:init'])) { + $tugboatConfig['init']['redis'] = true; + } + } + + if (count($tugboatConfig) > 0) { + $fs->ensureDirectoryExists('./.tugboat'); + $fs->ensureDirectoryExists('./.tugboat/steps'); + $loader = new FilesystemLoader(__DIR__ . '/../scaffold/tugboat'); + $twig = new Environment($loader); + file_put_contents('./.tugboat/config.yml', $twig->render('config.yml.twig', $tugboatConfig)); + file_put_contents('./.tugboat/steps/1-init.sh', $twig->render('steps/1-init.sh.twig', $tugboatConfig)); + file_put_contents('./.tugboat/steps/2-update.sh', $twig->render('steps/2-update.sh.twig', $tugboatConfig)); + file_put_contents('./.tugboat/steps/3-build.sh', $twig->render('steps/3-build.sh.twig', $tugboatConfig)); + chmod('./.tugboat/steps/1-init.sh', 0755); + chmod('./.tugboat/steps/2-update.sh', 0755); + chmod('./.tugboat/steps/3-build.sh', 0755); + + file_put_contents('./web/sites/default/settings.tugboat.php', $twig->render('settings.tugboat.php.twig', $tugboatConfig)); + if (file_exists('./web/sites/default/settings.php')) { + $settings = file_get_contents('./web/sites/default/settings.php'); + if (strpos($settings, 'settings.tugboat.php') === false) { + $include = <<<'EOT' +include __DIR__ . "/settings.tugboat.php"; +EOT; + file_put_contents('./web/sites/default/settings.php', $include . PHP_EOL, FILE_APPEND); + } + } + } + } } }