diff --git a/.circleci/.gitignore b/.circleci/.gitignore
new file mode 100644
index 00000000000..b0e880b7738
--- /dev/null
+++ b/.circleci/.gitignore
@@ -0,0 +1,4 @@
+.DS_Store
+local.test
+local.env
+local.ssh
diff --git a/.circleci/behat.yml b/.circleci/behat.yml
new file mode 100644
index 00000000000..fde56526c74
--- /dev/null
+++ b/.circleci/behat.yml
@@ -0,0 +1,17 @@
+# behat.yml
+default:
+ suites:
+ default:
+ paths:
+ - features
+ contexts:
+ - Drupal\DrupalExtension\Context\DrupalContext
+ - Drupal\DrupalExtension\Context\MinkContext
+ - FeatureContext
+ extensions:
+ Behat\MinkExtension:
+ # base_url set by ENV
+ goutte: ~
+ Drupal\DrupalExtension:
+ blackbox: ~
+ api_driver: 'drush'
diff --git a/.circleci/cleanup.sh b/.circleci/cleanup.sh
new file mode 100755
index 00000000000..43f85c472ab
--- /dev/null
+++ b/.circleci/cleanup.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# Echo commands as they are executed, but don't allow errors to stop the script.
+set -x
+
+if [ -z "$TERMINUS_SITE" ] || [ -z "$TERMINUS_ENV" ]; then
+ echo "TERMINUS_SITE and TERMINUS_ENV environment variables must be set"
+ exit 1
+fi
+
+# Only delete old environments if there is a pattern defined to
+# match environments eligible for deletion. Otherwise, delete the
+# current multidev environment immediately.
+#
+# To use this feature, set MULTIDEV_DELETE_PATTERN to '^ci-' or similar
+# in the CI server environment variables.
+if [ -z "$MULTIDEV_DELETE_PATTERN" ] ; then
+ terminus env:delete $TERMINUS_SITE.$TERMINUS_ENV --delete-branch --yes
+ exit 0
+fi
+
+# List all but the newest two environments.
+OLDEST_ENVIRONMENTS=$(terminus env:list "$TERMINUS_SITE" --format=list | grep -v dev | grep -v test | grep -v live | sort -k2 | grep "$MULTIDEV_DELETE_PATTERN" | sed -e '$d' | sed -e '$d')
+
+# Exit if there are no environments to delete
+if [ -z "$OLDEST_ENVIRONMENTS" ] ; then
+ exit 0
+fi
+
+# Go ahead and delete the oldest environments.
+for ENV_TO_DELETE in $OLDEST_ENVIRONMENTS ; do
+ terminus env:delete $TERMINUS_SITE.$ENV_TO_DELETE --delete-branch --yes
+done
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 00000000000..c35571db9ce
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,58 @@
+test-defaults: &test-defaults
+ docker:
+ - image: quay.io/pantheon-public/build-tools-ci:2.x
+ working_directory: ~/work/d7
+ environment:
+ TZ: "/usr/share/zoneinfo/America/Los_Angeles"
+ TERM: dumb
+
+merge-defaults: &merge-defaults
+ docker:
+ - image: quay.io/getpantheon/upstream-update-build:1.x
+ working_directory: ~/work/d7
+ environment:
+ TZ: "/usr/share/zoneinfo/America/Los_Angeles"
+ TERM: dumb
+
+version: 2
+jobs:
+ test:
+ <<: *test-defaults
+ steps:
+ - checkout
+ - run:
+ name: Set up environment
+ command: ./.circleci/set-up-globals.sh
+ - run:
+ name: Prepare
+ command: ./.circleci/prepare.sh
+ - run:
+ name: Test
+ command: ./.circleci/test.sh --strict
+ - run:
+ name: Cleanup
+ command: ./.circleci/cleanup.sh
+ - run:
+ name: Confirm that it is safe to merge
+ command: ./.circleci/confirm-safety.sh
+ merge:
+ <<: *merge-defaults
+ steps:
+ - checkout
+ - run:
+ # https://github.com/pantheon-systems/upstream-update-build/blob/1.x/bin/automerge.sh
+ name: Merge the default branch back to the master branch
+ command: automerge.sh
+
+workflows:
+ version: 2
+ drops7:
+ jobs:
+ - test
+ - merge:
+ requires:
+ - test
+ filters:
+ branches:
+ only:
+ - default
diff --git a/.circleci/confirm-safety.sh b/.circleci/confirm-safety.sh
new file mode 100755
index 00000000000..1a6f7171019
--- /dev/null
+++ b/.circleci/confirm-safety.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+#
+# The purpose of this script is to examine the base branch that this PR is
+# set to merge into by usig the GitHub API. We are only querying a public
+# repo here, so we do not need to use the GITHUB_TOKEN.
+#
+
+# Exit if we are not running on Circle CI.
+if [ -z "$CIRCLECI" ] ; then
+ exit 0
+fi
+
+# We only need to make this check for branches forked from default (right) / master (wrong).
+# Skip the test for the default branch. (The .circleci directory will never be added to the master branch).
+if [ "$CIRCLE_BRANCH" == "default" ] ; then
+ exit 0
+fi
+
+# We cannot continue unless we have a pull request.
+if [ -z "$CIRCLE_PULL_REQUEST" ] ; then
+ echo "No CIRCLE_PULL_REQUEST defined; please create a pull request."
+ exit 1
+fi
+
+# CIRCLE_PULL_REQUEST=https://github.com/ORG/PROJECT/pull/NUMBER
+PR_NUMBER=$(echo $CIRCLE_PULL_REQUEST | sed -e 's#.*/pull/##')
+
+# Display the API call we are using
+echo curl https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER
+
+base=$(curl https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pulls/$PR_NUMBER 2>/dev/null | jq .base.ref)
+
+echo "The base branch is $base"
+
+# If the PR merges into 'default', then it is safe to merge.
+if [ "$base" == '"default"' ] ; then
+ echo "It is safe to merge this PR into the $base branch"
+ exit 0
+fi
+
+# Force a test failure if the PR's base is the master branch.
+if [ "$base" == '"master"' ] ; then
+ echo "ERROR: merging this PR into the $base branch is not allowed. Change the base branch for the PR to merge into the \"default\" branch instead."
+ exit 1
+fi
+
+echo "Merging probably okay, if you are merging one PR into another. Use caution; do not merge to the \"master\" branch."
diff --git a/.circleci/features/0-install.feature b/.circleci/features/0-install.feature
new file mode 100644
index 00000000000..625ae06d19a
--- /dev/null
+++ b/.circleci/features/0-install.feature
@@ -0,0 +1,10 @@
+Feature: Installer
+ In order to know that we can install the site via drush
+ As a website user
+ I need to be able to install a Drupal site
+
+ Scenario: Installer is ready
+ Given I have wiped the site
+ And I have reinstalled "CI Drops-7 [{site-name}.{env}]"
+ And I visit "/"
+ Then I should see "Welcome to CI Drops-7"
diff --git a/.circleci/features/bootstrap/FeatureContext.php b/.circleci/features/bootstrap/FeatureContext.php
new file mode 100644
index 00000000000..9dd9e81c2f7
--- /dev/null
+++ b/.circleci/features/bootstrap/FeatureContext.php
@@ -0,0 +1,232 @@
+getEnvironment();
+ $this->minkContext = $environment->getContext('Drupal\DrupalExtension\Context\MinkContext');
+ }
+
+//
+// Place your definition and hook methods here:
+//
+// /**
+// * @Given I have done something with :stuff
+// */
+// public function iHaveDoneSomethingWith($stuff) {
+// doSomethingWith($stuff);
+// }
+//
+
+ /**
+ * Fills in form field with specified id|name|label|value
+ * Example: And I enter the value of the env var "TEST_PASSWORD" for "edit-account-pass-pass1"
+ *
+ * @Given I enter the value of the env var :arg1 for :arg2
+ */
+ public function fillFieldWithEnv($value, $field)
+ {
+ $this->minkContext->fillField($field, getenv($value));
+ }
+
+ /**
+ * Checks, that option from select with specified id|name|label|value is selected.
+ *
+ * @Then the :arg1 option from :arg2 should be selected
+ */
+ public function theOptionFromShouldBeSelected($option, $select)
+ {
+ $selectField = $this->getSession()->getPage()->findField($select);
+ if (null === $selectField) {
+ throw new ElementNotFoundException($this->getSession(), 'select field', 'id|name|label|value', $select);
+ }
+
+ $optionField = $selectField->find('named', array(
+ 'option',
+ $option,
+ ));
+
+ if (null === $optionField) {
+ throw new ElementNotFoundException($this->getSession(), 'select option field', 'id|name|label|value', $option);
+ }
+
+ if (!$optionField->isSelected()) {
+ throw new ExpectationException('Select option field with value|text "'.$option.'" is not selected in the select "'.$select.'"', $this->getSession());
+ }
+ }
+
+ /**
+ * @Given I have wiped the site
+ */
+ public function iHaveWipedTheSite()
+ {
+ $site = getenv('TERMINUS_SITE');
+ $env = getenv('TERMINUS_ENV');
+
+ passthru("terminus --yes env:wipe {$site}.{$env}");
+ }
+
+ /**
+ * @Given I have reinstalled :arg1
+ */
+ public function iHaveReinstalled($arg1)
+ {
+ $site = getenv('TERMINUS_SITE');
+ $env = getenv('TERMINUS_ENV');
+ $password = getenv('ADMIN_PASSWORD');
+
+ $replacements = [
+ '{site-name}' => $site,
+ '{env}' => $env,
+ ];
+
+ $arg1 = str_replace(array_keys($replacements), array_values($replacements), $arg1);
+
+ $cmd = "terminus --yes drush {$site}.{$env} -- site-install pantheon --yes --site-name=\"$arg1\" --account-name=admin";
+ if (!empty($password)) {
+ $cmd .= " --account-pass='$password'";
+ }
+
+ passthru($cmd);
+ }
+
+ /**
+ * @Given I have run the drush command :arg1
+ */
+ public function iHaveRunTheDrushCommand($arg1)
+ {
+ $site = getenv('TERMINUS_SITE');
+ $env = getenv('TERMINUS_ENV');
+
+ $return = '';
+ $output = array();
+ exec("terminus --yes drush {$site}.{$env} -- --yes $arg1", $output, $return);
+ $output = implode("\n", $output);
+
+ if ($return) {
+ throw new Exception("Error running Drush command:\n$output");
+ }
+
+ print "$output";
+ }
+
+ /**
+ * @Given I have committed my changes with comment :arg1
+ */
+ public function iHaveCommittedMyChangesWithComment($arg1)
+ {
+ $site = getenv('TERMINUS_SITE');
+ $env = getenv('TERMINUS_ENV');
+
+ passthru("terminus --yes env:commit {$site}.{$env} --message='$arg1'");
+ }
+
+ /**
+ * @Given I wait :seconds seconds
+ */
+ public function iWaitSeconds($seconds)
+ {
+ sleep($seconds);
+ }
+
+ /**
+ * @When I print the page contents
+ */
+ public function iPrintThePageContents()
+ {
+ $content = $this->getSession()->getPage()->getContent();
+ print $content;
+ }
+
+ /**
+ * @Given I wait :seconds seconds or until I see :text
+ */
+ public function iWaitSecondsOrUntilISee($seconds, $text)
+ {
+ $errorNode = $this->spin( function($context) use($text) {
+ $node = $context->getSession()->getPage()->find('named', array('content', $text));
+ if (!$node) {
+ return false;
+ }
+ return $node->isVisible();
+ }, $seconds);
+
+ // Throw to signal a problem if we were passed back an error message.
+ if (is_object($errorNode)) {
+ throw new Exception("Error detected when waiting for '$text': " . $errorNode->getText());
+ }
+ }
+
+ // http://docs.behat.org/en/v2.5/cookbook/using_spin_functions.html
+ // http://mink.behat.org/en/latest/guides/traversing-pages.html#selectors
+ public function spin ($lambda, $wait = 60)
+ {
+ for ($i = 0; $i <= $wait; $i++)
+ {
+ if ($i > 0) {
+ sleep(1);
+ }
+
+ $debugContent = $this->getSession()->getPage()->getContent();
+ file_put_contents("/tmp/mink/debug-" . $i, "\n\n\n=================================\n$debugContent\n=================================\n\n\n");
+
+ try {
+ if ($lambda($this)) {
+ return true;
+ }
+ } catch (Exception $e) {
+ // do nothing
+ }
+
+ // If we do not see the text we are waiting for, fail fast if
+ // we see a Drupal 8 error message pane on the page.
+ $node = $this->getSession()->getPage()->find('named', array('content', 'Error'));
+ if ($node) {
+ $errorNode = $this->getSession()->getPage()->find('css', '.messages--error');
+ if ($errorNode) {
+ return $errorNode;
+ }
+ $errorNode = $this->getSession()->getPage()->find('css', 'main');
+ if ($errorNode) {
+ return $errorNode;
+ }
+ return $node;
+ }
+ }
+
+ $backtrace = debug_backtrace();
+
+ throw new Exception(
+ "Timeout thrown by " . $backtrace[1]['class'] . "::" . $backtrace[1]['function'] . "()\n" .
+ $backtrace[1]['file'] . ", line " . $backtrace[1]['line']
+ );
+
+ return false;
+ }
+}
diff --git a/.circleci/features/content.feature b/.circleci/features/content.feature
new file mode 100644
index 00000000000..08e4ec9fe2d
--- /dev/null
+++ b/.circleci/features/content.feature
@@ -0,0 +1,12 @@
+Feature: Create Content through Drupal Content UI
+ In order to know that the Drupal content UI is working
+ As a website user
+ I need to be able to add a basic page
+
+ @api
+ Scenario: Add a basic page
+ Given I am logged in as a user with the "administrator" role
+ And I am on "/node/add/page"
+ And I enter "Test Page" for "Title"
+ And I press "Save"
+ Then I should see "Basic page Test Page has been created."
diff --git a/.circleci/features/pagecache.feature b/.circleci/features/pagecache.feature
new file mode 100644
index 00000000000..3b49193de44
--- /dev/null
+++ b/.circleci/features/pagecache.feature
@@ -0,0 +1,10 @@
+Feature: Check for settings on the cache configuration page
+ In order to know that the site was installed from the pantheon profile
+ As a website administrator
+ I need to know that Pantheon's initial settings were applied by the installer
+
+ @api
+ Scenario: Check to see if the page cache setting is set
+ Given I am logged in as a user with the "administrator" role
+ And I am on "/admin/config/development/performance"
+ Then the "900" option from "page_cache_maximum_age" should be selected
diff --git a/.circleci/features/pantheonsolr.feature b/.circleci/features/pantheonsolr.feature
new file mode 100644
index 00000000000..1d8b4d4cd8f
--- /dev/null
+++ b/.circleci/features/pantheonsolr.feature
@@ -0,0 +1,10 @@
+Feature: Check for existance of Pantheon Solr module
+ In order to know that the site was installed from Pantheon's upstream
+ As a website user
+ I need to know that Pantheon's Solr module is available
+
+ @api
+ Scenario: Check to see if Pantheon Solr is available
+ Given I am logged in as a user with the "administrator" role
+ And I am on "/admin/modules"
+ Then I should see "Pantheon Apache Solr"
diff --git a/.circleci/features/phpversion.feature b/.circleci/features/phpversion.feature
new file mode 100644
index 00000000000..2e7670e88e4
--- /dev/null
+++ b/.circleci/features/phpversion.feature
@@ -0,0 +1,10 @@
+Feature: Check php version
+ In order to know that pantheon.upstream.yml is working
+ As a website user
+ I need to know that I am running the correct version of php
+
+ @api
+ Scenario: Check the php version in the phpinfo output
+ Given I am logged in as a user with the "administrator" role
+ And I am on "/admin/reports/status/php"
+ Then I should see "PHP Version 5.6."
diff --git a/.circleci/local.test.dist b/.circleci/local.test.dist
new file mode 100755
index 00000000000..1a152540720
--- /dev/null
+++ b/.circleci/local.test.dist
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Copy to local.test and customize
+circleci \
+ -e CIRCLE_BUILD_NUM=0 \
+ -e TERMINUS_TOKEN=$TERMINUS_TOKEN \
+ -e TERMINUS_SITE=$TERMINUS_SITE \
+ -e TERMINUS_ENV=ci-$CIRCLE_BUILD_NUM \
+ -e TERMINUS_HIDE_UPDATE_MESSAGE=1 \
+ -e WORDPRESS_ADMIN_USERNAME=admin \
+ -e WORDPRESS_ADMIN_PASSWORD=$ADMIN_PASSWORD \
+ build --job test
diff --git a/.circleci/prepare.sh b/.circleci/prepare.sh
new file mode 100755
index 00000000000..994fa021bc3
--- /dev/null
+++ b/.circleci/prepare.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+###
+# Prepare a Pantheon site environment for the Behat test suite, by pushing the
+# requested upstream branch to the environment.
+###
+
+set -ex
+
+if [ -z "$TERMINUS_SITE" ] || [ -z "$TERMINUS_ENV" ]; then
+ echo "TERMINUS_SITE and TERMINUS_ENV environment variables must be set"
+ exit 1
+fi
+
+###
+# Clean up old unused environments, and make sure the dev site is spun up.
+###
+terminus build:env:delete:ci -n "$TERMINUS_SITE" --keep=2 --yes
+terminus env:wake -n "$TERMINUS_SITE.dev"
+
+###
+# Create a new environment for this particular test run.
+###
+terminus build:env:create -n "$TERMINUS_SITE.dev" "$TERMINUS_ENV" --yes
+terminus drush -n "$TERMINUS_SITE.$TERMINUS_ENV" -- updatedb -y
diff --git a/.circleci/set-up-globals.sh b/.circleci/set-up-globals.sh
new file mode 100755
index 00000000000..4e689efe8cd
--- /dev/null
+++ b/.circleci/set-up-globals.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# Create a local .ssh directory if needed & available
+SELF_DIRNAME="`dirname -- "$0"`"
+[ -d "$HOME/.ssh" ] || [ ! -d "$SELF_DIRNAME/local.ssh" ] || cp -R "$SELF_DIRNAME/local.ssh" "$HOME/.ssh"
+
+# If an admin password has not been defined, write one to ~/WORDPRESS_ADMIN_PASSWORD
+if [ ! -f ~/WORDPRESS_ADMIN_PASSWORD ] && [ -z "$WORDPRESS_ADMIN_PASSWORD" ] ; then
+ echo $(openssl rand -hex 8) > ~/WORDPRESS_ADMIN_PASSWORD
+fi
+
+# If an admin password has not been defined, read it from ~/WORDPRESS_ADMIN_PASSWORD
+if [ ! -f ~/WORDPRESS_ADMIN_PASSWORD ] && [ -z "$WORDPRESS_ADMIN_PASSWORD" ] ; then
+ WORDPRESS_ADMIN_PASSWORD="$(cat ~/WORDPRESS_ADMIN_PASSWORD)"
+fi
+
+#=====================================================================================================================
+# EXPORT needed environment variables
+#
+# Circle CI 2.0 does not yet expand environment variables so they have to be manually EXPORTed
+# Once environment variables can be expanded this section can be removed
+# See: https://discuss.circleci.com/t/unclear-how-to-work-with-user-variables-circleci-provided-env-variables/12810/11
+# See: https://discuss.circleci.com/t/environment-variable-expansion-in-working-directory/11322
+# See: https://discuss.circleci.com/t/circle-2-0-global-environment-variables/8681
+#=====================================================================================================================
+mkdir -p $(dirname $BASH_ENV)
+touch $BASH_ENV
+(
+ echo 'export PATH=$PATH:$HOME/bin'
+ echo 'export TERMINUS_HIDE_UPDATE_MESSAGE=1'
+ echo 'export TERMINUS_ENV=ci-$CIRCLE_BUILD_NUM'
+ echo 'export WORDPRESS_ADMIN_USERNAME=pantheon'
+ echo "export WORDPRESS_ADMIN_PASSWORD=$WORDPRESS_ADMIN_PASSWORD"
+) >> $BASH_ENV
+source $BASH_ENV
+
+echo "Test site is $TERMINUS_SITE.$TERMINUS_ENV"
+echo "Logging in with a machine token:"
+terminus auth:login -n --machine-token="$TERMINUS_TOKEN"
+terminus whoami
+touch $HOME/.ssh/config
+echo "StrictHostKeyChecking no" >> "$HOME/.ssh/config"
+git config --global user.email "$GIT_EMAIL"
+git config --global user.name "Circle CI"
+# Ignore file permissions.
+git config --global core.fileMode false
diff --git a/.circleci/test.sh b/.circleci/test.sh
new file mode 100755
index 00000000000..640e668300c
--- /dev/null
+++ b/.circleci/test.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+###
+# Execute the Behat test suite against a prepared Pantheon site environment.
+###
+
+set -ex
+
+SELF_DIRNAME="`dirname -- "$0"`"
+
+# Require a target site
+if [ -z "$TERMINUS_SITE" ] || [ -z "$TERMINUS_ENV" ]; then
+ echo "TERMINUS_SITE and TERMINUS_ENV environment variables must be set"
+ exit 1
+fi
+
+PATH=$PATH:~/.composer/vendor/bin
+
+# Create a drush alias file so that Behat tests can be executed against Pantheon.
+terminus aliases
+# Drush Behat driver fails without this option.
+echo "\$options['strict'] = 0;" >> ~/.drush/pantheon.aliases.drushrc.php
+
+export BEHAT_PARAMS='{"extensions" : {"Behat\\MinkExtension" : {"base_url" : "http://'$TERMINUS_ENV'-'$TERMINUS_SITE'.pantheonsite.io/"}, "Drupal\\DrupalExtension" : {"drush" : { "alias": "@pantheon.'$TERMINUS_SITE'.'$TERMINUS_ENV'" }}}}'
+
+# We expect 'behat' to be in our PATH. Our container symlinks it at /usr/local/bin
+cd $SELF_DIRNAME && behat --config=behat.yml $*
diff --git a/modules/pantheon/pantheon_apachesolr/pantheon_apachesolr.module b/modules/pantheon/pantheon_apachesolr/pantheon_apachesolr.module
index 76e355d3d1e..b0d658ce6e3 100644
--- a/modules/pantheon/pantheon_apachesolr/pantheon_apachesolr.module
+++ b/modules/pantheon/pantheon_apachesolr/pantheon_apachesolr.module
@@ -463,7 +463,7 @@ function pantheon_apachesolr_post_schema_form($form, &$form_state) {
$form['schemas'] = array(
'#type' => 'fieldset',
'#title' => t('Solr Schema File'),
- '#description' => t('The following schema.xml files exist in your Drupal site code. Pantheon uses Apache Solr v3.5.0, so you should use 3.x/schema.xml as the base configuration.') . '
',
+ '#description' => t('The following schema.xml files exist in your Drupal site code. Pantheon uses Apache Solr v3.6, so you should use 3.x/schema.xml as the base configuration.') . '
',
'#weight' => -10,
);
if (count($schemas) > 0) {