├── .drush-use ├── template ├── docroot │ ├── modules │ │ ├── .gitkeep │ │ └── custom │ │ │ └── README.md │ ├── themes │ │ ├── .gitkeep │ │ └── custom │ │ │ └── README.md │ ├── profiles │ │ ├── .gitkeep │ │ └── custom │ │ │ ├── minimal │ │ │ ├── config │ │ │ │ └── install │ │ │ │ │ ├── system.theme.yml │ │ │ │ │ ├── block.block.seven_help.yml │ │ │ │ │ ├── block.block.bartik_help.yml │ │ │ │ │ ├── block.block.bartik_page_title.yml │ │ │ │ │ ├── block.block.seven_local_actions.yml │ │ │ │ │ ├── block.block.seven_login.yml │ │ │ │ │ ├── block.block.bartik_local_actions.yml │ │ │ │ │ ├── block.block.seven_content.yml │ │ │ │ │ ├── block.block.bartik_content.yml │ │ │ │ │ ├── block.block.bartik_local_tasks.yml │ │ │ │ │ ├── block.block.seven_breadcrumbs.yml │ │ │ │ │ ├── block.block.seven_messages.yml │ │ │ │ │ ├── block.block.bartik_breadcrumbs.yml │ │ │ │ │ ├── block.block.bartik_messages.yml │ │ │ │ │ ├── block.block.bartik_powered.yml │ │ │ │ │ ├── block.block.seven_primary_local_tasks.yml │ │ │ │ │ ├── block.block.seven_secondary_local_tasks.yml │ │ │ │ │ ├── block.block.bartik_branding.yml │ │ │ │ │ ├── block.block.bartik_footer.yml │ │ │ │ │ ├── block.block.bartik_main_menu.yml │ │ │ │ │ └── block.block.bartik_account_menu.yml │ │ │ ├── minimal.info.yml │ │ │ └── minimal.install │ │ │ └── README.md │ ├── .eslintrc │ ├── sites │ │ ├── default │ │ │ ├── default.local.drushrc.php │ │ │ └── settings │ │ │ │ ├── cache.settings.php │ │ │ │ ├── readme.md │ │ │ │ ├── logging.settings.php │ │ │ │ ├── sample-secrets.settings.php │ │ │ │ ├── base.settings.php │ │ │ │ └── default.local.settings.php │ │ ├── development.services.yml │ │ └── example.sites.php │ ├── .eslintignore │ ├── .editorconfig │ ├── autoload.php │ ├── index.php │ ├── update.php │ ├── .csslintrc │ ├── robots.txt │ ├── .gitattributes │ └── web.config ├── .drush-use ├── build │ ├── custom │ │ ├── phing │ │ │ ├── tasks │ │ │ │ └── README.md │ │ │ ├── build.yml │ │ │ └── build.xml │ │ ├── files │ │ │ └── README.md │ │ └── README.md │ ├── core │ │ ├── files │ │ │ ├── README.md │ │ │ └── .gitignore │ │ ├── README.md │ │ └── phing │ │ │ ├── tasks │ │ │ ├── properties.xml │ │ │ ├── local-sync.xml │ │ │ ├── filesets.xml │ │ │ ├── frontend.xml │ │ │ └── validate.xml │ │ │ ├── build.yml │ │ │ ├── example.multisite.yml │ │ │ ├── build.xml │ │ │ └── phingcludes │ │ │ ├── PhpVariableTask.php │ │ │ ├── FilterFileListByFileSetTask.php │ │ │ └── FileInFilesetCondition.php │ └── README.md ├── hooks │ ├── dev │ │ ├── post-db-copy │ │ │ └── .gitignore │ │ ├── post-code-deploy │ │ │ └── .gitignore │ │ └── post-files-copy │ │ │ └── .gitignore │ ├── prod │ │ ├── post-db-copy │ │ │ └── .gitignore │ │ ├── post-code-deploy │ │ │ └── .gitignore │ │ └── post-files-copy │ │ │ └── .gitignore │ ├── test │ │ ├── post-db-copy │ │ │ └── .gitignore │ │ ├── post-code-deploy │ │ │ └── .gitignore │ │ └── post-files-copy │ │ │ └── .gitignore │ ├── common │ │ ├── post-db-copy │ │ │ └── .gitignore │ │ ├── post-files-copy │ │ │ └── .gitignore │ │ └── post-code-deploy │ │ │ └── .gitignore │ ├── samples │ │ ├── tests │ │ │ ├── readme.md │ │ │ └── drupal-tests.sh │ │ ├── rollback │ │ │ ├── rollback_settings │ │ │ ├── README.md │ │ │ └── rollback.sh │ │ ├── slack │ │ │ ├── slack_settings │ │ │ ├── README.md │ │ │ └── slack.sh │ │ ├── hipchat │ │ │ ├── hipchat_settings │ │ │ ├── README.md │ │ │ └── hipchat.sh │ │ ├── newrelic │ │ │ ├── newrelic_settings │ │ │ ├── newrelic.sh │ │ │ └── README.md │ │ ├── domain_access │ │ │ ├── readme.md │ │ │ └── domain-fix.sh │ │ └── scrub │ │ │ ├── readme.md │ │ │ ├── db-scrub-s3.sh │ │ │ └── db-scrub.sh │ ├── templates │ │ ├── post-files-copy.tmpl │ │ ├── post-db-copy.tmpl │ │ ├── post-code-deploy.tmpl │ │ └── post-code-update.tmpl │ └── README.md ├── scripts │ ├── README.md │ ├── release-notes │ │ ├── release.example.md │ │ ├── pull-request.example.md │ │ ├── README.md │ │ ├── generate-release-notes.md │ │ └── generate-release-notes.php │ ├── bolt │ │ ├── alias │ │ ├── install-alias.sh │ │ └── update-scaffold │ ├── git-hooks │ │ ├── pre-commit │ │ ├── README.md │ │ └── commit-msg │ └── drupal │ │ └── update-scaffold ├── tests │ ├── behat │ │ ├── .gitignore │ │ ├── media │ │ │ └── readme.md │ │ ├── features │ │ │ ├── Examples.feature │ │ │ └── bootstrap │ │ │ │ └── Drupal │ │ │ │ └── FeatureContext.php │ │ ├── integration.yml │ │ ├── behat.yml │ │ └── example.local.yml │ └── phpunit │ │ ├── phpunit.xml │ │ ├── BuildTest.php │ │ ├── BehatTest.php │ │ ├── src │ │ └── TestBase.php │ │ ├── DrushTest.php │ │ ├── SettingsTest.php │ │ └── GitTest.php ├── config │ └── default │ │ ├── README.md │ │ └── .htaccess ├── .editorconfig ├── drush │ ├── site-aliases │ │ ├── example.local.aliases.drushrc.php │ │ └── example.acsf.aliases.drushrc.php │ └── README.md ├── bolt.sh ├── factory-hooks │ ├── post-settings-php │ │ └── protect_env.php.example │ └── pre-settings-php │ │ └── includes.php.example ├── readme │ ├── acsf-setup.md │ ├── examples │ │ └── readme.md │ ├── views.md │ ├── os-contribution.md │ ├── repo-architecture.md │ ├── deploy.md │ ├── release-process.md │ ├── code-review.md │ ├── onboarding.md │ ├── project-tasks.md │ └── dev-workflow.md ├── README.md ├── project.yml ├── patches │ └── README.md ├── drush.wrapper ├── .gitignore ├── .travis.yml ├── composer.json └── .gitattributes ├── .gitattributes ├── composer.json ├── bolt.sh ├── .gitignore ├── .travis.yml ├── tests └── phpunit │ ├── BoltTest.php │ └── DeployTest.php ├── README.md └── INSTALL.md /.drush-use: -------------------------------------------------------------------------------- 1 | ./drush.wrapper -------------------------------------------------------------------------------- /template/docroot/modules/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/docroot/themes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | template/.gitattributes -------------------------------------------------------------------------------- /template/.drush-use: -------------------------------------------------------------------------------- 1 | ./drush.wrapper -------------------------------------------------------------------------------- /template/docroot/profiles/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/build/custom/phing/tasks/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/dev/post-db-copy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/prod/post-db-copy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/test/post-db-copy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/common/post-db-copy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/common/post-files-copy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/dev/post-code-deploy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/dev/post-files-copy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/prod/post-code-deploy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/prod/post-files-copy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/test/post-code-deploy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/test/post-files-copy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/hooks/common/post-code-deploy/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/docroot/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./core/.eslintrc" 3 | } 4 | -------------------------------------------------------------------------------- /template/docroot/themes/custom/README.md: -------------------------------------------------------------------------------- 1 | This directory should contain all custom themes. 2 | -------------------------------------------------------------------------------- /template/docroot/modules/custom/README.md: -------------------------------------------------------------------------------- 1 | This directory should contain all custom modules and features. 2 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/config/install/system.theme.yml: -------------------------------------------------------------------------------- 1 | admin: seven 2 | default: bartik -------------------------------------------------------------------------------- /template/build/core/files/README.md: -------------------------------------------------------------------------------- 1 | This directory contains static files that are used during the build process. -------------------------------------------------------------------------------- /template/build/custom/files/README.md: -------------------------------------------------------------------------------- 1 | This directory contains static files that are used during the build process. 2 | -------------------------------------------------------------------------------- /template/hooks/samples/tests/readme.md: -------------------------------------------------------------------------------- 1 | ### Purpose 2 | 3 | ### Example Scenario 4 | 5 | ### Installation Steps 6 | -------------------------------------------------------------------------------- /template/hooks/samples/rollback/rollback_settings: -------------------------------------------------------------------------------- 1 | ORIGSOURCE="master" 2 | TESTS="UserRegistrationTestCase" 3 | ATTEMPTS=3 4 | -------------------------------------------------------------------------------- /template/scripts/README.md: -------------------------------------------------------------------------------- 1 | # Custom Scripts 2 | 3 | This directory contains scripts that may be used to general project maintenance. 4 | -------------------------------------------------------------------------------- /template/tests/behat/.gitignore: -------------------------------------------------------------------------------- 1 | composer.phar 2 | composer.lock 3 | bin 4 | vendor 5 | behat.local.yml 6 | *.rej 7 | test_releases 8 | 9 | -------------------------------------------------------------------------------- /template/hooks/samples/slack/slack_settings: -------------------------------------------------------------------------------- 1 | TOKEN=yourtoken 2 | SLACK_WEBHOOK_URL=https://yoursite.slack.com/services/hooks/incoming-webhook?token=$TOKEN -------------------------------------------------------------------------------- /template/hooks/samples/hipchat/hipchat_settings: -------------------------------------------------------------------------------- 1 | ROOM_ID=AAABBBAAA 2 | AUTH_TOKEN=XXXYYYXXX 3 | 4 | HIPCHAT_WEBHOOK_URL=https://api.hipchat.com/v2/room/$ROOM_ID/notification -------------------------------------------------------------------------------- /template/hooks/samples/newrelic/newrelic_settings: -------------------------------------------------------------------------------- 1 | APIKEY='123456abcdefgh1234567890abcdefgh1234567890abc1234567890' 2 | APPID='123456' 3 | username='myname@mydomain.com' 4 | -------------------------------------------------------------------------------- /template/build/custom/phing/build.yml: -------------------------------------------------------------------------------- 1 | # Define custom property values here. You can override values defined in 2 | # ../../core/phing/build.yml. 3 | example.property: 'example value' 4 | -------------------------------------------------------------------------------- /template/docroot/sites/default/default.local.drushrc.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /template/build/custom/README.md: -------------------------------------------------------------------------------- 1 | This directory should contain custom build tasks and properties that extend or override those defined in `build/core/phing`. 2 | 3 | To see instructions for pulling in upstream updates to core tasks, see `build/core/README.md`. 4 | -------------------------------------------------------------------------------- /template/config/default/README.md: -------------------------------------------------------------------------------- 1 | This directory contains configuration to be imported into your Drupal site. To make this configuration active, visit admin/config/development/configuration/sync. For information about deploying configuration between servers, see https://www.drupal.org/documentation/administer/config 2 | -------------------------------------------------------------------------------- /template/docroot/sites/default/settings/cache.settings.php: -------------------------------------------------------------------------------- 1 | '[PROJECT-NAME].dev', 7 | // 'root' => '/Users/[YOUR USERNAME]/Sites/[PROJECT-NAME]/docroot', 8 | // 'path-aliases' => array( 9 | // '%dump-dir' => '/tmp', 10 | // ), 11 | // ); 12 | -------------------------------------------------------------------------------- /template/scripts/bolt/alias: -------------------------------------------------------------------------------- 1 | 2 | function bolt() { 3 | if [ "`git rev-parse --show-cdup 2> /dev/null`" != "" ]; then 4 | GIT_ROOT=$(git rev-parse --show-cdup) 5 | else 6 | GIT_ROOT="." 7 | fi 8 | 9 | if [ -f "$GIT_ROOT/bolt.sh" ]; then 10 | $GIT_ROOT/bolt.sh "$@" 11 | else 12 | echo "You must run this command from within a Bolt-generated project repository." 13 | fi 14 | } 15 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/config/install/block.block.seven_help.yml: -------------------------------------------------------------------------------- 1 | langcode: en 2 | status: true 3 | dependencies: 4 | module: 5 | - help 6 | theme: 7 | - seven 8 | id: seven_help 9 | theme: seven 10 | region: help 11 | weight: 0 12 | provider: null 13 | plugin: help_block 14 | settings: 15 | id: help_block 16 | label: Help 17 | provider: help 18 | label_display: '0' 19 | visibility: { } 20 | -------------------------------------------------------------------------------- /template/build/core/README.md: -------------------------------------------------------------------------------- 1 | This directory contains the core tasks that ship with Bolt. No files in this 2 | directory should be customized. You may pull in upstream changes with: 3 | 4 | ./bolt.sh setup:bolt:update 5 | 6 | Please note that pulling in upstream changes in this way may break your project. 7 | In some cases, you will need to change aspects of your project configuration or 8 | modify your project's directory structure. 9 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/config/install/block.block.bartik_help.yml: -------------------------------------------------------------------------------- 1 | langcode: en 2 | status: true 3 | dependencies: 4 | module: 5 | - help 6 | theme: 7 | - bartik 8 | id: bartik_help 9 | theme: bartik 10 | region: content 11 | weight: -30 12 | provider: null 13 | plugin: help_block 14 | settings: 15 | id: help_block 16 | label: Help 17 | provider: help 18 | label_display: '0' 19 | visibility: { } 20 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/config/install/block.block.bartik_page_title.yml: -------------------------------------------------------------------------------- 1 | langcode: en 2 | status: true 3 | dependencies: 4 | theme: 5 | - bartik 6 | id: bartik_page_title 7 | theme: bartik 8 | region: content 9 | weight: -50 10 | provider: null 11 | plugin: page_title_block 12 | settings: 13 | id: page_title_block 14 | label: 'Page title' 15 | provider: core 16 | label_display: '0' 17 | visibility: { } 18 | -------------------------------------------------------------------------------- /template/docroot/.editorconfig: -------------------------------------------------------------------------------- 1 | # Drupal editor configuration normalization 2 | # @see http://editorconfig.org/ 3 | 4 | # This is the top-most .editorconfig file; do not search in parent directories. 5 | root = true 6 | 7 | # All files. 8 | [*] 9 | end_of_line = LF 10 | indent_style = space 11 | indent_size = 2 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | insert_final_newline = true 15 | 16 | [composer.json] 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/config/install/block.block.seven_local_actions.yml: -------------------------------------------------------------------------------- 1 | langcode: en 2 | status: true 3 | dependencies: 4 | theme: 5 | - seven 6 | id: seven_local_actions 7 | theme: seven 8 | region: content 9 | weight: -10 10 | provider: null 11 | plugin: local_actions_block 12 | settings: 13 | id: local_actions_block 14 | label: 'Primary admin actions' 15 | provider: core 16 | label_display: '0' 17 | visibility: { } 18 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/config/install/block.block.seven_login.yml: -------------------------------------------------------------------------------- 1 | langcode: en 2 | status: true 3 | dependencies: 4 | module: 5 | - user 6 | theme: 7 | - seven 8 | id: seven_login 9 | theme: seven 10 | region: content 11 | weight: 10 12 | provider: null 13 | plugin: user_login_block 14 | settings: 15 | id: user_login_block 16 | label: 'User login' 17 | provider: user 18 | label_display: visible 19 | visibility: { } 20 | -------------------------------------------------------------------------------- /bolt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 4 | if [ ! -f ${DIR}/vendor/bin/phing ]; then 5 | echo "Phing was not found in this project's bin directory." 6 | echo "Please run composer install." 7 | echo "You may need to remove the vendor directory first." 8 | exit 1 9 | fi 10 | 11 | # This script simply passes all arguments to Phing. 12 | ${DIR}/vendor/bin/phing -f ${DIR}/build/phing/build.xml "$@" 13 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/config/install/block.block.bartik_local_actions.yml: -------------------------------------------------------------------------------- 1 | langcode: en 2 | status: true 3 | dependencies: 4 | theme: 5 | - bartik 6 | id: bartik_local_actions 7 | theme: bartik 8 | region: content 9 | weight: -20 10 | provider: null 11 | plugin: local_actions_block 12 | settings: 13 | id: local_actions_block 14 | label: 'Primary admin actions' 15 | provider: core 16 | label_display: '0' 17 | visibility: { } 18 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/config/install/block.block.seven_content.yml: -------------------------------------------------------------------------------- 1 | langcode: en 2 | status: true 3 | dependencies: 4 | module: 5 | - system 6 | theme: 7 | - seven 8 | id: seven_content 9 | theme: seven 10 | region: content 11 | weight: 0 12 | provider: null 13 | plugin: system_main_block 14 | settings: 15 | id: system_main_block 16 | label: 'Main page content' 17 | provider: system 18 | label_display: '0' 19 | visibility: { } 20 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/config/install/block.block.bartik_content.yml: -------------------------------------------------------------------------------- 1 | langcode: en 2 | status: true 3 | dependencies: 4 | module: 5 | - system 6 | theme: 7 | - bartik 8 | id: bartik_content 9 | theme: bartik 10 | region: content 11 | weight: 0 12 | provider: null 13 | plugin: system_main_block 14 | settings: 15 | id: system_main_block 16 | label: 'Main page content' 17 | provider: system 18 | label_display: '0' 19 | visibility: { } 20 | -------------------------------------------------------------------------------- /template/hooks/samples/domain_access/readme.md: -------------------------------------------------------------------------------- 1 | # Domain Access Update 2 | 3 | Author: Adam Malone 4 | 5 | ### Purpose 6 | 7 | This cloud hook allows domains in domain_access module to be updated following 8 | database copy. This ensures no manual updates to the domains configuration are 9 | necessary after copying a db between environments. 10 | 11 | ### Example Scenario 12 | 13 | ### Installation Steps 14 | 15 | 1. Place file in `/hooks/common/post-db-copy` 16 | -------------------------------------------------------------------------------- /template/bolt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 4 | if [ ! -f ${DIR}/vendor/bin/phing ]; then 5 | echo "Phing was not found in this project's bin directory." 6 | echo "Please run composer install." 7 | echo "You may need to remove the vendor directory first." 8 | exit 1 9 | fi 10 | 11 | # This script simply passes all arguments to Phing. 12 | ${DIR}/vendor/bin/phing -f ${DIR}/build/custom/phing/build.xml "$@" 13 | -------------------------------------------------------------------------------- /template/docroot/autoload.php: -------------------------------------------------------------------------------- 1 | assertFileExists($this->projectDirectory . '/docroot/index.php'); 20 | $this->assertFileExists($this->projectDirectory . '/docroot/modules/contrib'); 21 | $this->assertFileExists($this->projectDirectory . '/docroot/themes/custom'); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /template/docroot/index.php: -------------------------------------------------------------------------------- 1 | handle($request); 20 | $response->send(); 21 | 22 | $kernel->terminate($request, $response); 23 | -------------------------------------------------------------------------------- /template/factory-hooks/pre-settings-php/includes.php.example: -------------------------------------------------------------------------------- 1 | handle($request); 20 | $response->send(); 21 | 22 | $kernel->terminate($request, $response); 23 | -------------------------------------------------------------------------------- /template/scripts/release-notes/pull-request.example.md: -------------------------------------------------------------------------------- 1 | ## [Jira Issue Number]: [Pull request title] 2 | 3 | ### Changes 4 | - [Description for non-devlepers.] 5 | - [Another thing in the PR] 6 | 7 | ### Technical Details 8 | - [More technical description if needed.] 9 | 10 | ### Affected Pages 11 | - [Globally] 12 | - [example url] 13 | - [/product-finder/123] 14 | 15 | ### Key Affected Code 16 | - [example.php] 17 | - [example.scss] 18 | 19 | ### References 20 | - [drupal.org/node/123456] 21 | 22 | ### Notices 23 | - [If there is an important change developers should be aware of such as a change in architecture, the need for database updates, etc, put that information here.] 24 | -------------------------------------------------------------------------------- /template/tests/behat/features/bootstrap/Drupal/FeatureContext.php: -------------------------------------------------------------------------------- 1 | assertFileExists($this->projectDirectory . '/tests/behat/local.yml'); 19 | $this->assertNotContains( 20 | '${local_url}', 21 | file_get_contents("{$this->projectDirectory}/tests/behat/local.yml") 22 | ); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /template/scripts/git-hooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # To enable this hook, developers should place it in .git/hooks/. 4 | # 5 | # You may adapt the message length check. Currently checking it's longer than 6 | # 15 characters. 7 | 8 | regex="^${project.prefix}-[0-9]+(: )[^ ].{15,}\." 9 | if ! grep -iqE "$regex" "$1"; then 10 | echo "Invalid commit message. Commit messages must:" 11 | echo "* Contain the project prefix followed by a hyphen" 12 | echo "* Contain a ticket number followed by a colon and a space" 13 | echo "* Be at least 15 characters long and end with a period." 14 | echo "Valid example: ${project.prefix}-135: Added the new picture field to the article feature." 15 | exit 1; 16 | fi 17 | -------------------------------------------------------------------------------- /template/scripts/drupal/update-scaffold: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | ROOT=$(pwd) 4 | DRUSH=$ROOT/vendor/bin/drush 5 | VERSION=${1:-drupal-8} 6 | DRUPAL_TEMP=$(mktemp -d) 7 | 8 | $DRUSH dl "$VERSION" --root=$DRUPAL_TEMP --destination=$DRUPAL_TEMP --drupal-project-rename=drupal-8 --quiet -y 9 | 10 | rsync -avz --delete $DRUPAL_TEMP/drupal-8/ "$ROOT/docroot" \ 11 | --exclude=.gitkeep \ 12 | --exclude=autoload.php \ 13 | --exclude=composer.json \ 14 | --exclude=composer.lock \ 15 | --exclude=core \ 16 | --exclude=drush \ 17 | --exclude=example.gitignore \ 18 | --exclude=LICENSE.txt \ 19 | --exclude=README.txt \ 20 | --exclude=vendor \ 21 | --exclude=sites \ 22 | --exclude=themes \ 23 | --exclude=profiles \ 24 | --exclude=modules 25 | 26 | rm -rf $DRUPAL_TEMP/drupal-8 27 | -------------------------------------------------------------------------------- /template/tests/behat/integration.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - behat.yml 3 | 4 | integration: 5 | extensions: 6 | Behat\MinkExtension: 7 | # This is an example URL For an integration server. 8 | base_url: https://example-integration-server.prod.acquia-sites.com/ 9 | selenium2: 10 | # This is an example SauceLabs host URL. 11 | wd_host: 4e19c8b-0986-4642-8ffd-c033649db9a2@ondemand.saucelabs.com/wd/hub 12 | browser: "firefox" 13 | capabilities: { "platform": "Windows 7", "browser": "firefox", "max-duration" : 3600} 14 | Drupal\DrupalExtension: 15 | drupal: 16 | # This must be an absolute path. 17 | drupal_root: "/var/www/html/example.integration/docroot" 18 | drush: 19 | alias: '@example.integration' 20 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/minimal/minimal.install: -------------------------------------------------------------------------------- 1 | getEditable('system.theme.global')->set('features.node_user_picture', FALSE)->save(TRUE); 17 | 18 | // Allow visitor account creation, but with administrative approval. 19 | \Drupal::configFactory()->getEditable('user.settings')->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save(TRUE); 20 | } 21 | -------------------------------------------------------------------------------- /template/config/default/.htaccess: -------------------------------------------------------------------------------- 1 | # Deny all requests from Apache 2.4+. 2 | 3 | Require all denied 4 | 5 | 6 | # Deny all requests from Apache 2.0-2.2. 7 | 8 | Deny from all 9 | 10 | # Turn off all options we don't need. 11 | Options -Indexes -ExecCGI -Includes -MultiViews 12 | 13 | # Set the catch-all handler to prevent scripts from being executed. 14 | SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006 15 | 16 | # Override the handler again if we're run later in the evaluation list. 17 | SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003 18 | 19 | 20 | # If we know how to do it safely, disable the PHP engine entirely. 21 | 22 | php_flag engine off 23 | -------------------------------------------------------------------------------- /template/tests/behat/behat.yml: -------------------------------------------------------------------------------- 1 | default: 2 | suites: 3 | default: 4 | paths: 5 | - %paths.base%/features 6 | contexts: 7 | - Drupal\FeatureContext 8 | - Drupal\DrupalExtension\Context\DrupalContext 9 | - Drupal\DrupalExtension\Context\MinkContext 10 | - Drupal\DrupalExtension\Context\MessageContext 11 | - Drupal\DrupalExtension\Context\DrushContext 12 | extensions: 13 | Behat\MinkExtension: 14 | default_session: goutte 15 | javascript_session: selenium2 16 | goutte: ~ 17 | files_path: "%paths.base%/media" 18 | Drupal\DrupalExtension: 19 | blackbox: ~ 20 | api_driver: "drupal" 21 | jarnaiz\JUnitFormatter\JUnitFormatterExtension: 22 | filename: report.xml 23 | outputDir: %paths.base%/build/tests 24 | -------------------------------------------------------------------------------- /template/hooks/templates/post-code-deploy.tmpl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Cloud Hook: post-code-deploy 4 | # 5 | # The post-code-deploy hook is run whenever you use the Workflow page to 6 | # deploy new code to an environment, either via drag-drop or by selecting 7 | # an existing branch or tag from the Code drop-down list. See 8 | # ../README.md for details. 9 | # 10 | # Usage: post-code-deploy site target-env source-branch deployed-tag repo-url 11 | # repo-type 12 | 13 | site="$1" 14 | target_env="$2" 15 | source_branch="$3" 16 | deployed_tag="$4" 17 | repo_url="$5" 18 | repo_type="$6" 19 | 20 | if [ "$source_branch" != "$deployed_tag" ]; then 21 | echo "$site.$target_env: Deployed branch $source_branch as $deployed_tag." 22 | else 23 | echo "$site.$target_env: Deployed $deployed_tag." 24 | fi 25 | -------------------------------------------------------------------------------- /template/readme/acsf-setup.md: -------------------------------------------------------------------------------- 1 | # ACSF Setup 2 | 3 | To configure a project to run on ACSF, perform the following steps after initially setting up Bolt: 4 | 5 | 1. Add the following line to project.yml: `hosting: "acsf"`. This ensures that the correct settings files are added to the deployment artifact. 6 | 1. Execute `./bolt.sh acsf:init` from the project root. 7 | 1. Ensure that `drupal/acsf` is a listed dependency in your composer.json file: `composer require drupal/acsf:~8` 8 | 1. Add the acsf module as a dependency to your installation profile 9 | 10 | ## Factory Hooks and settings.php 11 | 12 | Acquia Cloud Site Factory does not allow changes to `settings.php`. In order to make additions normally done with `settings.php`, factory hooks are used. Please see the [documentation](https://docs.acquia.com/site-factory/tiers/paas/workflow/hooks) for reference. 13 | -------------------------------------------------------------------------------- /template/tests/phpunit/src/TestBase.php: -------------------------------------------------------------------------------- 1 | projectDirectory = dirname(dirname(dirname(__DIR__))); 25 | $this->drupalRoot = $this->projectDirectory . '/docroot'; 26 | $this->config = Yaml::parse(file_get_contents("{$this->projectDirectory}/project.yml")); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /template/hooks/samples/slack/README.md: -------------------------------------------------------------------------------- 1 | # Slack Notification 2 | 3 | Author: Grant Gaudet 4 | 5 | ### Purpose 6 | 7 | This cloud hook posts a notification to Slack chat room after a code deployment 8 | has been performed on Acquia Cloud. 9 | 10 | ### Example Scenario 11 | 12 | 1. A new tag is deployed to the production environment. 13 | 2. A slack notification is posted indicating that a tag has been deployed. 14 | 15 | ### Installation Steps 16 | 17 | Installation Steps (assumes Slack subscription setup and Acquia Cloud Hooks installed in repo): 18 | 19 | * See the API documentation at https://api.slack.com/ get your `TOKEN`. 20 | * Store this variable in `$HOME/slack_settings` file on your Acquia Cloud Server (see slack_settings file). 21 | * Set the execution bit to on e.g. `chmod a+x slack_settings` 22 | * Add `slack.sh` to dev, test, prod or common __post-cody-deploy__ hook. 23 | 24 | 25 | -------------------------------------------------------------------------------- /template/hooks/templates/post-code-update.tmpl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Cloud Hook: post-code-update 4 | # 5 | # The post-code-update hook runs in response to code commits. 6 | # When you push commits to a Git branch, the post-code-update hooks runs for 7 | # each environment that is currently running that branch.. See 8 | # ../README.md for details. 9 | # 10 | # Usage: post-code-update site target-env source-branch deployed-tag repo-url 11 | # repo-type 12 | 13 | site="$1" 14 | target_env="$2" 15 | source_branch="$3" 16 | deployed_tag="$4" 17 | repo_url="$5" 18 | repo_type="$6" 19 | 20 | 21 | if [ "$target_env" = 'dev' ]; then 22 | echo "$site.$target_env: The $source_branch branch has been updated on $target_env. Clearing the cache." 23 | drush @"$site".dev cc all 24 | else 25 | echo "$site.$target_env: The $source_branch branch has been updated on $target_env." 26 | fi 27 | -------------------------------------------------------------------------------- /template/docroot/profiles/custom/README.md: -------------------------------------------------------------------------------- 1 | Installation profiles define additional steps that run after the base installation provided by Drupal core when Drupal is first installed. 2 | 3 | WHAT TO PLACE IN THIS DIRECTORY? 4 | -------------------------------- 5 | 6 | Place custom installation profiles in this directory. Installation profiles are generally provided as part of a Drupal distribution. They only impact the installation of your site. They do not have any effect on an already running site. 7 | 8 | MULTISITE CONFIGURATION 9 | ----------------------- 10 | 11 | In multisite configurations, installation profiles found in this directory are available to all sites during their initial site installation. 12 | 13 | MORE INFORMATION 14 | ---------------- 15 | 16 | Refer to the "Installation profiles" section of the README.txt in the Drupal root directory for further information on extending Drupal with custom profiles. 17 | -------------------------------------------------------------------------------- /template/scripts/bolt/install-alias.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ "`basename "/$SHELL"`" = "zsh" ]; then 4 | DETECTED_PROFILE="$HOME/.zshrc" 5 | elif [ -f "$HOME/.bashrc" ]; then 6 | DETECTED_PROFILE="$HOME/.bashrc" 7 | elif [ -f "$HOME/.bash_profile" ]; then 8 | DETECTED_PROFILE="$HOME/.bash_profile" 9 | elif [ -f "$HOME/.profile" ]; then 10 | DETECTED_PROFILE="$HOME/.profile" 11 | fi 12 | 13 | if [ ! -z "$DETECTED_PROFILE" ]; then 14 | if [ "`grep 'function bolt' $DETECTED_PROFILE`" ]; then 15 | echo "Alias for bolt already exists in $DETECTED_PROFILE" 16 | exit 17 | fi 18 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 19 | cat $DIR/alias >> $DETECTED_PROFILE 20 | 21 | echo "Added alias for bolt to $DETECTED_PROFILE" 22 | echo "Restart your terminal session to use the new command." 23 | else 24 | echo "Could not install bolt alias. No profile found. Tried ~/.zshrc, ~/.bashrc, ~/.bash_profile and ~/.profile." 25 | fi 26 | -------------------------------------------------------------------------------- /template/hooks/README.md: -------------------------------------------------------------------------------- 1 | ## Cloud Hooks 2 | 3 | This directory contains [Acquia Cloud hooks](https://docs.acquia.com/cloud/manage/cloud-hooks). 4 | 5 | ### Directory Structure 6 | 7 | tests 8 | ├── common - contains hooks that will be executed for _all_ environments. 9 | ├── dev - contains hooks that will be executed for _dev_ environment. 10 | ├── prod - contains hooks that will be executed for _prod_ environment. 11 | ├── samples - contains example Cloud Hooks. 12 | ├── templates - contains templates, which may be cloned and used as a starting point for creating your own custom cloud hook scripts. 13 | └── test - contains hooks that will be executed for _test_ environment. 14 | 15 | ### Documentation 16 | 17 | For detailed information on how to implement these hooks, read the [documentation on Acquia.com](https://docs.acquia.com/cloud/manage/cloud-hooks)or visit the [Cloud Hook repository](https://github.com/acquia/cloud-hooks). 18 | -------------------------------------------------------------------------------- /template/build/custom/phing/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /template/hooks/samples/tests/drupal-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Cloud Hook: drupal-tests 4 | # 5 | # Run Drupal simpletests in the target environment using drush test-run. 6 | 7 | site="$1" 8 | target_env="$2" 9 | 10 | # Select the tests to run. Run "drush help test-run" for options. 11 | TESTS="UserRegistrationTestCase" 12 | # To run all tests (very slow!), uncomment this line. 13 | TESTS="--all" 14 | 15 | # Enable the simpletest module if it is not already enabled. 16 | simpletest=`drush @$site.$target_env pm-info simpletest | perl -F'/[\s:]+/' -lane '/Status/ && print $F[2]'` 17 | if [ "$simpletest" = "disabled" ]; then 18 | echo "Temporarily enabling simpletest module." 19 | drush @$site.$target_env pm-enable simpletest --yes 20 | fi 21 | 22 | # Run the tests. 23 | drush @$site.$target_env test-run $TESTS 24 | 25 | # If we enabled simpletest, disable it. 26 | if [ "$simpletest" = "disabled" ]; then 27 | echo "Disabling simpletest module." 28 | drush @$site.$target_env pm-disable simpletest --yes 29 | fi 30 | -------------------------------------------------------------------------------- /template/readme/examples/readme.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | The purpose of these examples is to provide a starting point for common custom development tasks. There are many ways to approach implementing features in Drupal and these examples show some common solutions. 3 | 4 | These modules are working examples. It's recommended that you copy the module and test that it works and then begin to modify the files to fit your need. 5 | 6 | ## Modules 7 | These example modules demonstrate how to create and theme custom components including panels. This also demonstrates how to work with javascript, libraries, and other assets. 8 | 9 | ## Themes 10 | The theming examples focus on the theme build process and foundational structure of the theme. There are many ways to approach frontend theming. For now, the examples do not assume any particular approach to creating the CSS or Javascript or particular markdown. 11 | 12 | As such, this is NOT a base theme. This is intended as a structure to get a project started using common build process tools. 13 | -------------------------------------------------------------------------------- /template/hooks/samples/newrelic/newrelic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This sample a Cloud Hook script to update New Relic whenever there is a new code deployment 4 | 5 | site=$1 # The site name. This is the same as the Acquia Cloud username for the site. 6 | targetenv=$2 # The environment to which code was just deployed. 7 | sourcebranch=$3 # The code branch or tag being deployed. 8 | deployedtag=$4 # The code branch or tag being deployed. 9 | repourl=$5 # The URL of your code repository. 10 | repotype=$6 # The version control system your site is using; "git" or "svn". 11 | 12 | 13 | #Load the New Relic APPID and APPKEY variables. 14 | . $HOME/newrelic_settings 15 | 16 | curl -s -H "x-api-key:$APIKEY" -d "deployment[application_id]=$APPID" -d "deployment[host]=localhost" -d "deployment[description]=$deployedtag deployed to $site:$targetenv" -d "deployment[revision]=$deployedtag" -d "deployment[changelog]=$deployedtag deployed to $site:$targetenv" -d "deployment[user]=$username" https://rpm.newrelic.com/deployments.xml 17 | -------------------------------------------------------------------------------- /template/hooks/samples/hipchat/README.md: -------------------------------------------------------------------------------- 1 | # HipChat Notification 2 | 3 | Author: Grant Gaudet 4 | 5 | ### Purpose 6 | 7 | This cloud hook posts a notification to a HipChat room after a code deployment 8 | has been performed on Acquia Cloud. 9 | 10 | ### Example Scenario 11 | 12 | 1. A new tag is deployed to the production environment. 13 | 2. A HipChat notification is posted indicating that a tag has been deployed. 14 | 15 | ### Installation Steps 16 | 17 | Installation Steps (assumes HipChat subscription setup and Acquia Cloud Hooks installed in repo): 18 | 19 | * See the API documentation at https://www.hipchat.com/docs/apiv2 and https://www.hipchat.com/docs/apiv2/method/send_room_notification 20 | * Visit https://YOURCOMPANY.hipchat.com/rooms/tokens/ROOM_ID create your notification token `AUTH_TOKEN`. 21 | * Store the AUTH_TOKEN and the ROOM_ID in `$HOME/hipchat_settings` file on your Acquia Cloud Server (see hipchat_settings file). 22 | * Set the execution bit to on e.g. `chmod a+x hipchat_settings` 23 | * Add `hipchat.sh` to dev, test, prod or common __post-cody-deploy__ hook. 24 | 25 | 26 | -------------------------------------------------------------------------------- /template/scripts/bolt/update-scaffold: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | GIT_ROOT=$(git rev-parse --show-toplevel) 4 | BOLT_BRANCH=8.x 5 | 6 | # Upstream directories to pull. These will be prefixed with "template/". 7 | BOLT_DIRS=( 8 | "bolt.sh" 9 | "build/core" 10 | "drush.wrapper" 11 | "factory-hooks/post-settings-php/protect_env.php.example" 12 | "factory-hooks/pre-settings-php/includes.php.example" 13 | "hooks/samples" 14 | "hooks/templates" 15 | "scripts/bolt" 16 | "scripts/deploy" 17 | "scripts/drupal" 18 | "scripts/git-hooks/pre-commit" 19 | "scripts/release-notes" 20 | ) 21 | 22 | # Move into repository root. 23 | cd $GIT_ROOT 24 | 25 | echo "Copying down upstream changes to the Bolt template." 26 | 27 | # Iteratively pull down upstream directories. 28 | for i in "${BOLT_DIRS[@]}" 29 | do 30 | svn export https://github.com/acquia/bolt/branches/$BOLT_BRANCH/template/$i $i --force 31 | done 32 | 33 | # Restore execute permissions. 34 | chmod 755 bolt.sh 35 | chmod 755 drush.wrapper 36 | 37 | echo "Changes have been pulled down. Please review and commit desired changes." 38 | -------------------------------------------------------------------------------- /template/docroot/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "important": true, 3 | "adjoining-classes": false, 4 | "known-properties": true, 5 | "box-sizing": false, 6 | "box-model": true, 7 | "overqualified-elements": true, 8 | "display-property-grouping": true, 9 | "bulletproof-font-face": false, 10 | "compatible-vendor-prefixes": false, 11 | "regex-selectors": false, 12 | "errors": false, 13 | "duplicate-background-images": true, 14 | "duplicate-properties": true, 15 | "empty-rules": true, 16 | "selector-max-approaching": false, 17 | "gradients": false, 18 | "fallback-colors": false, 19 | "font-sizes": false, 20 | "font-faces": false, 21 | "floats": false, 22 | "star-property-hack": true, 23 | "outline-none": true, 24 | "import": true, 25 | "ids": true, 26 | "underscore-property-hack": true, 27 | "rules-count": false, 28 | "qualified-headings": true, 29 | "selector-max": false, 30 | "shorthand": true, 31 | "text-indent": true, 32 | "unique-headings": true, 33 | "universal-selector": false, 34 | "unqualified-attributes": true, 35 | "vendor-prefix": true, 36 | "zero-units": true 37 | } 38 | -------------------------------------------------------------------------------- /template/scripts/release-notes/README.md: -------------------------------------------------------------------------------- 1 | # Generate Release Notes Script 2 | 3 | ## Overview 4 | Use a script compiles PR comments for a project into a Markdown file that can 5 | be copy and pasted into GitHub release notes. 6 | 7 | ## Usage 8 | 9 | ### Required Inputs 10 | * **username:** your GitHub username 11 | * **password:** your GitHub password. Note that if you use two factor 12 | authentication you will need to use an [Access Token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) 13 | in lieu of a password. 14 | * **repository:** the name of the GitHub repository (e.g. `https://github.com/acquia-pso/my-repo`) 15 | 16 | ### Simple usage 17 | 18 | php generate-release-notes.php github username:password org:repo-name:branch > release-notes.md 19 | 20 | ### Specify a start date 21 | 22 | php generate-release-notes.php github username:password org:repo-name:branch 1/30/2014 > release-notes.md 23 | 24 | ### Specify a start date and number of PRs 25 | 26 | php generate-release-notes.php github username:password org:repo-name:branch 1/30/2014 50 > release-notes.md 27 | 28 | # Example: Commit Message 29 | -------------------------------------------------------------------------------- /template/tests/phpunit/DrushTest.php: -------------------------------------------------------------------------------- 1 | projectDirectory . '/vendor/bin/drush'; 20 | $command = "$drush_bin status"; 21 | 22 | // Test that drush can be run from the following directories. 23 | $dirs = array( 24 | $this->projectDirectory . '/docroot', 25 | $this->projectDirectory . '/docroot/sites/default', 26 | ); 27 | 28 | foreach ($dirs as $dir) { 29 | chdir($dir); 30 | print "Executing \"$command\" in $dir \n"; 31 | // If it contains the local URI, we know it is correctly loading 32 | // drushrc.php. 33 | $this->assertContains('http://127.0.0.1:8888', shell_exec($command)); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /template/hooks/samples/newrelic/README.md: -------------------------------------------------------------------------------- 1 | # New Relic Deployment Notification 2 | 3 | Author: Erik Webb 4 | 5 | ### Purpose 6 | 7 | This will post a message to New Relic's API when a new code deployment has been made 8 | to an Acquia environment. This allows New Relic to plot releases onto performance 9 | graphs. 10 | 11 | ### Example Scenario 12 | 13 | 1. A new tag is deployed to the production environment. 14 | 2. A POST request is sent to New Relic indicating when the given tag was deployed. 15 | 3. Deployment information is available on New Relic's graphs and charts. 16 | 17 | ### Installation Steps (assumes New Relic subscription setup and Acquia Cloud Hooks installed in repo) 18 | 19 | * Login to New Relic and goto https://rpm.newrelic.com/accounts/(UserID)/applications/(ApplicationID)/deployments/instructions 20 | * From the instructions get your `application_id` and your `x-api-key`. Store these variables and a username you wish to send to New Relic in `$HOME/newrelic_settings` file on your Acquia Cloud Server (see example file). 21 | * Set the execution bit to on i.e. `chmod a+x newrelic_settings` 22 | * Add `newrelic.sh` to dev, test, prod or common __post-cody-deploy__ hook. 23 | 24 | 25 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # ${project.human_name} 2 | 3 | Replace this with a brief description of the ${project.human_name} project. 4 | 5 | Documentation by role: 6 | 7 | * Developer 8 | * [Onboarding](readme/onboarding.md): “how do I get up and running on project work?” 9 | * [Repository architecture](readme/repo-architecture.md): “how is the code organized, and why?” 10 | * [Running project tasks](readme/project-tasks.md): “how do I _____ on my local machine?” 11 | * [Best practices](readme/best-practices.md): "how should I write code?" 12 | * [Workflow](readme/dev-workflow.md): “how do I contribute my code to this project?” 13 | * [Automated testing](tests/README.md): “how do I write / run them, and why should I care?” 14 | * Technical Architect 15 | * [Project Architecture document](readme/architecture.md) 16 | * [Deploying to cloud](readme/deploy.md) 17 | * [Release process](readme/release-process.md) 18 | * [Setting up continuous integration](build/README.md#ci) 19 | * [Open source contribution](readme/os-contribution.md) 20 | 21 | ## Resources 22 | 23 | * JIRA - link me! 24 | * GitHub - link me! 25 | * Acquia Cloud subscription - link me! 26 | * TravisCI - link me! 27 | -------------------------------------------------------------------------------- /template/hooks/samples/rollback/README.md: -------------------------------------------------------------------------------- 1 | # Code Deploy Rollback 2 | 3 | Author: Erik Webb 4 | 5 | ### Purpose 6 | 7 | This hook utilizes the simpletest module to test code base during deployment and automatically 8 | rollback to the last deployed set of code on test failure. Since pre-code-deploy hooks don't exist 9 | yet we store original code source in the origsource variable in the rollback settings file stored in 10 | the $HOME dir. This file also lists drush test-run tests to be run and the number of attempts to make 11 | before giving up. 12 | 13 | ### Example Scenario 14 | 15 | ### Installation Steps 16 | 17 | 18 | Installation Steps (assumes ah cloud hooks installed in Version Control Software) 19 | 20 | * Copy rollback.sh into your dev, stage, prod, or common hooks directory. 21 | * SCP or SFTP rollback_settings to your $HOME dir on your Acquia Host Server. 22 | * $TEST settings are available SimpleTests (or core Testing module in D7+). You may use '--all' for all tests (very slow). See http://drupal.org/simpletest for details. 23 | * Edit rollback_settings to your existing code base ($ORIGSOURCE), test setting ($TEST) and number of attempts ($ATTEMPTS). Ensure execute bits are set on both files. (i.e. chmod a+x rollback_settings and chmod a+x rollback.sh) 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /template/docroot/sites/default/settings/sample-secrets.settings.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Executing commands against multisite "${multisite.name}" 18 | Using settings file ${local.settings.file} 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /template/hooks/samples/hipchat/hipchat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Cloud Hook: post-code-deploy 4 | # 5 | # The post-code-deploy hook is run whenever you use the Workflow page to 6 | # deploy new code to an environment, either via drag-drop or by selecting 7 | # an existing branch or tag from the Code drop-down list. See 8 | # ../README.md for details. 9 | # 10 | # Usage: post-code-deploy site target-env source-branch deployed-tag repo-url 11 | # repo-type 12 | 13 | site="$1" 14 | target_env="$2" 15 | source_branch="$3" 16 | deployed_tag="$4" 17 | repo_url="$5" 18 | repo_type="$6" 19 | 20 | # Load the HipChat webhook URL (which is not stored in this repo). 21 | . $HOME/hipchat_settings 22 | 23 | # Post deployment notice to HipChat 24 | 25 | if [ "$source_branch" != "$deployed_tag" ]; then 26 | curl --header "content-type: application/json" --header "Authorization: Bearer $AUTH_TOKEN" -X POST \ 27 | -d "{\"message\":\"An updated deployment has been made to $site.$target_env using branch $source_branch as $deployed_tag.\"}" $HIPCHAT_WEBHOOK_URL 28 | else 29 | curl --header "content-type: application/json" --header "Authorization: Bearer $AUTH_TOKEN" -X POST \ 30 | -d "{\"message\":\"An updated deployment has been made to $site.$target_env using tag $deployed_tag.\"}" $HIPCHAT_WEBHOOK_URL 31 | fi 32 | 33 | 34 | -------------------------------------------------------------------------------- /template/hooks/samples/slack/slack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Cloud Hook: post-code-deploy 4 | # 5 | # The post-code-deploy hook is run whenever you use the Workflow page to 6 | # deploy new code to an environment, either via drag-drop or by selecting 7 | # an existing branch or tag from the Code drop-down list. See 8 | # ../README.md for details. 9 | # 10 | # Usage: post-code-deploy site target-env source-branch deployed-tag repo-url 11 | # repo-type 12 | 13 | site="$1" 14 | target_env="$2" 15 | source_branch="$3" 16 | deployed_tag="$4" 17 | repo_url="$5" 18 | repo_type="$6" 19 | 20 | # Load the Slack webhook URL (which is not stored in this repo). 21 | . $HOME/slack_settings 22 | 23 | # Post deployment notice to Slack 24 | 25 | if [ "$source_branch" != "$deployed_tag" ]; then 26 | curl -X POST --data-urlencode "payload={\"channel\": \"#your_channel\", \"username\": \"Acquia Cloud\", \"text\": \"An updated deployment has been made to *$site.$target_env* using branch *$source_branch* as *$deployed_tag*.\", \"icon_emoji\": \":acquiacloud:\"}" $SLACK_WEBHOOK_URL 27 | else 28 | curl -X POST --data-urlencode "payload={\"channel\": \"#your_channel\", \"username\": \"Acquia Cloud\", \"text\": \"An updated deployment has been made to *$site.$target_env* using tag *$deployed_tag*.\", \"icon_emoji\": \":acquiacloud:\"}" $SLACK_WEBHOOK_URL 29 | fi 30 | -------------------------------------------------------------------------------- /template/patches/README.md: -------------------------------------------------------------------------------- 1 | # Patches 2 | 3 | All modifications to contributed projects must be performed via a patch and must be applied via composer.json. 4 | 5 | Drupal core and contrib can be patched in `composer.json` using `cweagans/composer-patches`, which is required by default. Patch information should be specified in the JSON array in accordance with the following schema: 6 | 7 | "extra": { 8 | "patches": { 9 | "drupal/core": { 10 | "Ignore front end vendor folders to improve directory search performance": "https://www.drupal.org/files/issues/ignore_front_end_vendor-2329453-116.patch" 11 | } 12 | } 13 | }, 14 | 15 | Patches that can be contributed on Drupal.org should be contributed there. Please follow [Drupal.org's patch naming conventions](https://www.drupal.org/node/1054616#naming-conventions) when creating patches. 16 | 17 | Patches that cannot be contributed publicly are extremely rare. In the unlikely event that such a change must be committed, all project-specific patches should reside in this directory. This ensures one consistent place for patches and avoids accidental patch deletion. 18 | 19 | Patches should be stored in sub-directories based on project name being patched. 20 | 21 | Examples: 22 | 23 | - /patches/drupal/some_patch-1234-1.patch 24 | - /patches/ctools/another_patch_name-9876-12.patch 25 | -------------------------------------------------------------------------------- /template/build/core/phing/build.yml: -------------------------------------------------------------------------------- 1 | behat: 2 | config: ${repo.root}/tests/behat/local.yml 3 | profile: local 4 | # If true, `drush runserver` will be used for executing tests. 5 | run-server: false 6 | # This is used for ad-hoc creation of a server via `drush runserver`. 7 | server-url: http://127.0.0.1:8888 8 | # If true, PhantomJS GhostDriver will be launched with Behat. 9 | launch-phantom: true 10 | # An array of paths with behat tests that should be executed. 11 | paths: 12 | # - ${docroot}/modules 13 | - ${docroot}/profiles 14 | - ${repo.root}/tests/behat 15 | tags: '' 16 | 17 | composer: 18 | bin: ${repo.root}/vendor/bin 19 | 20 | deploy: 21 | dir: ${repo.root}/deploy 22 | 23 | # File and Directory locations. 24 | docroot.relative: ${repo.root.relative}/docroot 25 | docroot: ${repo.root}/docroot 26 | 27 | # Drupal Account Credentials. These are used for installing Drupal. 28 | drupal: 29 | account.name: admin 30 | account.password: admin 31 | account.mail: no-reply@acquia.com 32 | 33 | drush: 34 | bin: ${composer.bin}/drush 35 | cmd: ${drush.bin} @${drush.aliases.local} -r ${docroot} -l ${multisite.name} 36 | root: ${docroot} 37 | 38 | multisite: 39 | # The docroot/sites/default directory is used by default. 40 | name: default 41 | 42 | reports: 43 | localDir: ${repo.root}/reports 44 | remoteDir: reports 45 | -------------------------------------------------------------------------------- /template/build/core/phing/example.multisite.yml: -------------------------------------------------------------------------------- 1 | # Values in this file may override default values set elsewhere. You can pass 2 | # configuration from this file to Phing. E.g., 3 | # ./bolt.sh tests:behat -propertyfile build/custom/phing/example.multisite.yml 4 | 5 | behat: 6 | # @see http://docs.behat.org/en/v2.5/guides/6.cli.html#gherkin-filters 7 | # When tests:behat target is executed, these tags will be passed to Behat. 8 | tags: ~@example-multisite 9 | # When tests:behat target is executed, this Behat profile will be used. 10 | # @see tests/behat/example.local.yml for Behat profile definition. 11 | profile: example-multisite 12 | # This is used for ad-hoc creation of a server via `drush rs` during CI. 13 | # This needs to match a site entry in docroot/sites/sites.php, and should 14 | # be assigned as the base_url in a corresponding Behat profile in 15 | # tests/behat/example.local.yml. 16 | server-url: http://127.0.0.1:8888 17 | 18 | multisite: 19 | # This should correspond the directory name in docroot/sites. E.g., 20 | # docroot/sites/example-multisite.com. 21 | name: example-multisite.com 22 | 23 | project: 24 | profile: 25 | name: example_multisite_profile 26 | # The acquia cloud alias for the site group. This will be used to execute 27 | # against *.dev and *.test aliases for upstream db syncs. 28 | cloud_alias: @example-multisite 29 | -------------------------------------------------------------------------------- /template/tests/phpunit/SettingsTest.php: -------------------------------------------------------------------------------- 1 | drupalRoot); 26 | } 27 | } 28 | 29 | /** 30 | * Test configuration for production environment on ACE. 31 | */ 32 | public function testProd() { 33 | 34 | $this->setupParams('prod'); 35 | require $this->drupalRoot . '/sites/default/settings.php'; 36 | 37 | $this->assertContains($config['system.logging']['error_level'], 'hide'); 38 | } 39 | 40 | /** 41 | * Tests Phing setup:drupal:settings target. 42 | */ 43 | public function testSetupLocalSettings() { 44 | 45 | $this->assertFileExists($this->projectDirectory . '/docroot/sites/default/settings/local.settings.php'); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /template/drush.wrapper: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # DRUSH WRAPPER 4 | # 5 | # A wrapper script which launches the Drush that is in your project's /vendor 6 | # directory. Copy it to the root of your project and edit as desired. 7 | # You may rename this script to 'drush', if doing so does not cause a conflict 8 | # (e.g. with a folder __ROOT__/drush). 9 | # 10 | # Below are options which you might want to add. More info at 11 | # `drush topic core-global-options`: 12 | # 13 | # --local Only discover commandfiles/site aliases/config that are 14 | # inside your project dir. 15 | # --alias-path A list of directories where Drush will search for site 16 | # alias files. 17 | # --config A list of paths to config files 18 | # --include A list of directories to search for commandfiles. 19 | # 20 | # Note that it is recommended to use --local when using a drush 21 | # wrapper script. 22 | # 23 | # See the 'drush' script in the Drush installation root (../drush) for 24 | # an explanation of the different 'drush' scripts. 25 | # 26 | # IMPORTANT: Modify the path below if your 'vendor' directory has been 27 | # relocated to another location in your composer.json file. 28 | # `../vendor/bin/drush.launcher --local $@` is a common variant for 29 | # composer-managed Drupal sites. 30 | # 31 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 32 | cd "`dirname $0`" 33 | 34 | # Only list local aliases and load the ones in drush/site-aliases. 35 | vendor/bin/drush.launcher --local --alias-path=${DIR}/drush/site-aliases "$@" 36 | -------------------------------------------------------------------------------- /template/hooks/samples/scrub/db-scrub-s3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # db-copy Cloud hook: db-scrub-s3 4 | # 5 | # 1. Scrub important information from a Drupal database on copy into dev 6 | # 2. Backup file to user home directory 7 | # 3. Upload sanitized db to Amazon s3 bucket id 8 | # 9 | # Usage: db-scrub-s3.sh site target-env db-name source-env db-name source_env 10 | 11 | site="$1" 12 | target_env="$2" 13 | db_name="$3" 14 | source_env="$4" 15 | file=~/upload.sql 16 | bucket=psotest 17 | 18 | #env check 19 | if [ $2 == "dev" ]; then 20 | 21 | echo "$site.$target_env: Scrubbing database $db_name" 22 | drush @$site.$target_env sql-sanitize -y 23 | 24 | drush @$site.$target_env sql-dump > $file 25 | gzip -qf ~/upload.sql 26 | 27 | file=~/upload.sql.gz 28 | 29 | echo "uploading scrubbed database $file.tgz to s3" 30 | 31 | s3Key=XXXXXXXXXXXXXXXXXXXXXX 32 | s3Secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 33 | file=~/upload.sql.gz 34 | bucket=psotest 35 | resource="/${bucket}/${file}" 36 | contentType="application/gzip" 37 | dateValue=`date -u +"%a, %d %b %Y %k:%M:%S +0000"` 38 | stringToSign="PUT\n\n${contentType}\n${dateValue}\n${resource}" 39 | signature=`echo -en ${stringToSign} | openssl sha1 -hmac ${s3Secret} -binary | base64` 40 | curl -X PUT -T "${file}" \ 41 | -H "Host: ${bucket}.s3.amazonaws.com" \ 42 | -H "Date: ${dateValue}" \ 43 | -H "Content-Type: ${contentType}" \ 44 | -H "Authorization: AWS ${s3Key}:${signature}" \ 45 | https://${bucket}.s3.amazonaws.com/${file} 46 | 47 | fi 48 | 49 | -------------------------------------------------------------------------------- /template/build/core/phing/tasks/local-sync.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /template/docroot/sites/default/settings/base.settings.php: -------------------------------------------------------------------------------- 1 | release-notes.md` 12 | `php generate-release-notes.php github dan:password acquia-pso:client-repo:master > release-notes.md` 13 | 14 | ### Specify a start date 15 | `php generate-release-notes.php github dan:password acquia-pso:client-repo:master 12/31/2014 > release-notes.md` 16 | 17 | ### Specify a start date and number of PRs 18 | `php generate-release-notes.php github dan:password acquia-pso:client-repo:master 12/31/2014 15 > release-notes.md` 19 | 20 | ### Stash and Confluence 21 | Since stash is hosted by a client or service, you must pass in the base path, for example `stash.client.com`. You should not include `https://`. 22 | 23 | #### Simple Usage 24 | `php generate-release-notes.php stash:[base path] [stash username]:[stash password] [stash project]:[stash repository]:[branch] > release-notes.md` 25 | `php generate-release-notes.php stash:stash.client.com dan:password client-project:client-repo:master > release-notes.md` 26 | 27 | ### Specify a start date 28 | `php generate-release-notes.php stash:stash.client.com dan:password client-project:client-repo:master 12/31/2014 > release-notes.md` 29 | 30 | ### Specify a start date and number of PRs 31 | `php generate-release-notes.php stash:stash.client.com dan:password client-project:client-repo:master 12/31/2014 15 > release-notes.md` 32 | 33 | -------------------------------------------------------------------------------- /template/drush/README.md: -------------------------------------------------------------------------------- 1 | # Drush configuration and aliases 2 | 3 | This directory is intended to contain drush configuration that is not site or environment specific. 4 | 5 | Site specific drush configuration lives in `sites/[site-name]`. 6 | 7 | ## Site aliases 8 | 9 | ### For remote environments 10 | 11 | You should add the Drush aliases for any remote environments (such as Acquia Cloud) to the `site-aliases` directory. This allows developers to access remote environments using simple aliases such as `drush @mysite.dev uli`. Note that if you are using Acquia Cloud, developers can also download these aliases manually from their Insight account, but providing them with the project makes everyone’s life a little easier. 12 | 13 | You can find these aliases for Acquia Cloud sites by logging into https://insight.acquia.com and going to the _Credentials_ tab on your user profile. Download and place the relevant alias file into `site-aliases`. 14 | 15 | Note that if the version of Drush that your project uses is significantly ahead of the version available in the remote environment, you’ll need to manually set `$drush_major_version` at the top of your alias files to match the version of Drush on the remote environment. For instance, at the time this document is being written, Drush 9 is in development and only Drush 8 is available on Acquia Cloud, so you’d want to add the following to the top of your aliases: `$drush_major_version = 8;` 16 | 17 | ### For local environment 18 | 19 | It can be helpful to define aliases for a local environment such as `@mysite.local`. This creates consistency with how aliases are already defined for remote environments (such as `@mysite.dev`, `@mysite.test`, and `@mysite.prod`). To create these local aliases, copy `example.local.aliases.drushrc.php` to `local.aliases.drushrc.php` and modify the default values as appropriate for your project. 20 | -------------------------------------------------------------------------------- /template/docroot/robots.txt: -------------------------------------------------------------------------------- 1 | # 2 | # robots.txt 3 | # 4 | # This file is to prevent the crawling and indexing of certain parts 5 | # of your site by web crawlers and spiders run by sites like Yahoo! 6 | # and Google. By telling these "robots" where not to go on your site, 7 | # you save bandwidth and server resources. 8 | # 9 | # This file will be ignored unless it is at the root of your host: 10 | # Used: http://example.com/robots.txt 11 | # Ignored: http://example.com/site/robots.txt 12 | # 13 | # For more information about the robots.txt standard, see: 14 | # http://www.robotstxt.org/robotstxt.html 15 | 16 | User-agent: * 17 | # CSS, JS, Images 18 | Allow: /core/*.css$ 19 | Allow: /core/*.css? 20 | Allow: /core/*.js$ 21 | Allow: /core/*.js? 22 | Allow: /core/*.gif 23 | Allow: /core/*.jpg 24 | Allow: /core/*.jpeg 25 | Allow: /core/*.png 26 | Allow: /core/*.svg 27 | Allow: /profiles/*.css$ 28 | Allow: /profiles/*.css? 29 | Allow: /profiles/*.js$ 30 | Allow: /profiles/*.js? 31 | Allow: /profiles/*.gif 32 | Allow: /profiles/*.jpg 33 | Allow: /profiles/*.jpeg 34 | Allow: /profiles/*.png 35 | Allow: /profiles/*.svg 36 | # Directories 37 | Disallow: /core/ 38 | Disallow: /profiles/ 39 | # Files 40 | Disallow: /README.txt 41 | Disallow: /web.config 42 | # Paths (clean URLs) 43 | Disallow: /admin/ 44 | Disallow: /comment/reply/ 45 | Disallow: /filter/tips/ 46 | Disallow: /node/add/ 47 | Disallow: /search/ 48 | Disallow: /user/register/ 49 | Disallow: /user/password/ 50 | Disallow: /user/login/ 51 | Disallow: /user/logout/ 52 | # Paths (no clean URLs) 53 | Disallow: /index.php/admin/ 54 | Disallow: /index.php/comment/reply/ 55 | Disallow: /index.php/filter/tips/ 56 | Disallow: /index.php/node/add/ 57 | Disallow: /index.php/search/ 58 | Disallow: /index.php/user/password/ 59 | Disallow: /index.php/user/register/ 60 | Disallow: /index.php/user/login/ 61 | Disallow: /index.php/user/logout/ 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore config files 2 | /project.yml 3 | local.* 4 | 5 | # Ignore build artifacts 6 | bin/* 7 | 8 | # OS X 9 | .DS_Store 10 | .AppleDouble 11 | .LSOverride 12 | Icon 13 | 14 | # Thumbnails 15 | ._* 16 | 17 | # Files that might appear on external disk 18 | .Spotlight-V100 19 | .Trashes 20 | 21 | # Windows image file caches 22 | Thumbs.db 23 | ehthumbs.db 24 | 25 | # Folder config file 26 | Desktop.ini 27 | 28 | # Recycle Bin used on file shares 29 | $RECYCLE.BIN/ 30 | 31 | # Eclipse 32 | *.pydevproject 33 | .project 34 | .metadata 35 | tmp/** 36 | tmp/**/* 37 | *.tmp 38 | *.bak 39 | *.swp 40 | *~.nib 41 | local.properties 42 | .classpath 43 | .settings/ 44 | .loadpath 45 | 46 | # External tool builders 47 | .externalToolBuilders/ 48 | 49 | # Locally stored "Eclipse launch configurations" 50 | *.launch 51 | 52 | # CDT-specific 53 | .cproject 54 | 55 | # PDT-specific 56 | .buildpathk 57 | 58 | # Emacs 59 | *~ 60 | \#*\# 61 | /.emacs.desktop 62 | /.emacs.desktop.lock 63 | *.elc 64 | auto-save-list 65 | tramp 66 | .\#* 67 | 68 | # User-specific stuff: 69 | .idea/workspace.xml 70 | .idea/tasks.xml 71 | .idea/dictionaries 72 | .idea/vcs.xml 73 | .idea/jsLibraryMappings.xml 74 | 75 | # Sensitive or high-churn files: 76 | .idea/dataSources.ids 77 | .idea/dataSources.xml 78 | .idea/dataSources.local.xml 79 | .idea/sqlDataSources.xml 80 | .idea/dynamic.xml 81 | .idea/uiDesigner.xml 82 | 83 | #XHProf 84 | xhprof_* 85 | 86 | #Composer vendor 87 | vendor/ 88 | vendor/.git 89 | 90 | #Sass 91 | .sass-cache 92 | *.css.map 93 | 94 | #Netbeans IDE 95 | nbproject 96 | nbproject/* 97 | 98 | #Exports 99 | *.gz 100 | *.sql 101 | *.zip 102 | 103 | # Some files should be excluded from bolt but not from the projects it 104 | # generates, so they must be specified here rather than in template/.gitignore. 105 | template/.idea/.name 106 | -------------------------------------------------------------------------------- /template/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore configuration files that may contain sensitive information. 2 | build/phing/build.properties 3 | local.* 4 | 5 | # Ignore drupal core. 6 | docroot/core 7 | 8 | # Ignore paths that contain user-generated content. 9 | docroot/sites/*/files 10 | docroot/sites/*/private 11 | 12 | # Ignore contrib modules. These should be created during build process. 13 | docroot/modules/contrib 14 | docroot/themes/contrib 15 | docroot/profiles/contrib 16 | docroot/libraries 17 | drush/contrib 18 | 19 | # Ignore build artifacts 20 | /deploy 21 | bin/* 22 | tmp 23 | install/bin 24 | reports 25 | deploy_key 26 | 27 | # Local testing config 28 | tests/behat/local.yml 29 | 30 | # OS X 31 | .DS_Store 32 | .AppleDouble 33 | .LSOverride 34 | Icon 35 | 36 | # Thumbnails 37 | ._* 38 | 39 | # Files that might appear on external disk 40 | .Spotlight-V100 41 | .Trashes 42 | 43 | # Windows image file caches 44 | Thumbs.db 45 | ehthumbs.db 46 | 47 | # Folder config file 48 | Desktop.ini 49 | 50 | # Recycle Bin used on file shares 51 | $RECYCLE.BIN/ 52 | 53 | # Eclipse 54 | *.pydevproject 55 | .project 56 | .metadata 57 | tmp/** 58 | tmp/**/* 59 | *.tmp 60 | *.bak 61 | *.swp 62 | *~.nib 63 | local.properties 64 | .classpath 65 | .settings/ 66 | .loadpath 67 | 68 | # External tool builders 69 | .externalToolBuilders/ 70 | 71 | # Locally stored "Eclipse launch configurations" 72 | *.launch 73 | 74 | # CDT-specific 75 | .cproject 76 | 77 | # PDT-specific 78 | .buildpathk 79 | 80 | # Emacs 81 | *~ 82 | \#*\# 83 | /.emacs.desktop 84 | /.emacs.desktop.lock 85 | *.elc 86 | auto-save-list 87 | tramp 88 | .\#* 89 | 90 | # User-specific stuff: 91 | .idea/ 92 | 93 | #XHProf 94 | xhprof_* 95 | 96 | #Composer vendor 97 | vendor/ 98 | vendor/.git 99 | 100 | #Sass 101 | .sass-cache 102 | *.css.map 103 | 104 | #Netbeans IDE 105 | nbproject 106 | nbproject/* 107 | 108 | -------------------------------------------------------------------------------- /template/build/core/phing/tasks/filesets.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /template/readme/views.md: -------------------------------------------------------------------------------- 1 | # Views 2 | 3 | ## Building Views 4 | 5 | The following are guidelines for building new views. 6 | 7 | * _Caching_ 8 | * For all public facing views, always use some form of caching. A non time-based cache is preferable because it often permits the longest cache lifetimes, and invalidates caches only when necessary. Possible options are: 9 | * [Views content cache](https://www.drupal.org/project/views_content_cache) 10 | * [Views argument cache](https://www.drupal.org/project/views_arg_cache) 11 | * Time based 12 | * _Pagination_ 13 | * Always specify either a fixed number of results or a pager. Never display all results. 14 | * Whenever possible, use Views lite pager rather than a full pager. 15 | * Note that this is unfortunately mutually exclusive with caching due to bugs in Views Lite Pager. @see https://www.drupal.org/node/2285591. 16 | * _Advanced_ 17 | * Always add a semantically descriptive machine name to views displays. E.g., use `press_releases_all` rather than `page_1`. This makes all PHP, CSS, and JS related to the view display more readable. 18 | * _Relationships_ 19 | * Whenever possible, use "require this relationship" for all views relationships. This causes views to perform an inner join rather than a left join, and is almost always faster. 20 | * Never use the `Taxonomy Terms on Node` relationship or filter. Instead, use a relationship or filter for the specific taxonomy reference field. This has a tremendous performance impact. 21 | * _Filters_ 22 | * For all exposed filters, manually set the fitler identifier to something end-user friendly. This should not contain drupalisms. E.g., use `type` rather than `field_type`. 23 | * _No Results Behavior_ 24 | * Always add "No Results behavior" of some type. This is typically text informing that user that no results were found. 25 | 26 | @todos: 27 | 28 | * When to ditch Views in favor of EFQ or straight queries. There's a reason Advanced Forum is slow on big sites. 29 | * Proper views naming and tagging 30 | -------------------------------------------------------------------------------- /template/.travis.yml: -------------------------------------------------------------------------------- 1 | # Note that the example .travis.yml file for child projects lives in /install. 2 | sudo: false 3 | language: php 4 | 5 | php: 6 | - 5.6 7 | 8 | cache: 9 | bundler: true 10 | apt: true 11 | directories: 12 | - "$HOME/.composer/cache" 13 | - "$HOME/.drush/cache" 14 | - "$HOME/.npm" 15 | - "$HOME/.nvm" 16 | - "vendor" 17 | # Cache front end dependecies to dramatically improve build time. 18 | # - "docroot/themes/custom/mytheme/node_modules" 19 | # - "docroot/themes/custom/mytheme/bower_components" 20 | 21 | addons: 22 | ssh_known_hosts: 23 | # - svn-4786.devcloud.hosting.acquia.com 24 | 25 | # @see https://docs.travis-ci.com/user/notifications 26 | notifications: 27 | # - hipchat: [api token]@[room id or name] 28 | # - slack: ':#[channel]' 29 | 30 | before_install: 31 | - composer selfupdate 32 | - phpenv config-rm xdebug.ini 33 | - git config --global user.name "Travis-CI" 34 | - git config --global user.email "noreply@travis-ci.org" 35 | - mysql -e 'CREATE DATABASE drupal;' 36 | 37 | install: 38 | # Load composer dependencies. 39 | - composer install 40 | - export PATH=$PATH:$TRAVIS_BUILD_DIR/vendor/bin 41 | # Install proper version of node for front end tasks. 42 | - nvm install 4.4.1 43 | - nvm use 4.4.1 44 | 45 | before_script: 46 | # Clear drush release history cache, to pick up new releases. 47 | - rm -f ~/.drush/cache/download/*---updates.drupal.org-release-history-* 48 | # Verify that no git diffs (caused by line ending variation) exist. 49 | - git diff --exit-code 50 | 51 | script: 52 | - ./bolt.sh -Dbehat.run-server=true -Dcreate_alias=false -Dbehat.launch-phantom=true build:validate:test 53 | 54 | # Uncomment to enable automatic deployments following merges. 55 | deploy: 56 | # provider: script 57 | # script: ./bolt.sh deploy:artifact -Ddeploy.commitMsg="Automated commit by Travis CI for Build ${TRAVIS_BUILD_ID}" -Ddeploy.branch="${TRAVIS_BRANCH}-build" 58 | # skip_cleanup: true 59 | # on: 60 | # branch: master 61 | -------------------------------------------------------------------------------- /template/readme/os-contribution.md: -------------------------------------------------------------------------------- 1 | # Open Source Contributions 2 | 3 | ## What not to release 4 | * Use-case specific functionality (i.e., stuff no one else will really care about) 5 | * When in doubt, release 6 | * Confidential or security sensitive information 7 | * Definitions will depend upon applicable NDA or security agreements 8 | 9 | ## What to release 10 | 11 | * Patches to core or contrib 12 | * Should always be contributed, if appropriate for public release 13 | * Make use of organization crediting 14 | * Modules 15 | * Ensure that these are propery generalized / abstracted 16 | * Ensure that client information is removed from code 17 | 18 | ## Recommendation 19 | 20 | Individual user (e.g., TA or developer) releases to drupal.org. 21 | 22 | * Team should select who should own the module based on contribution to its 23 | creation and abilty/interest in on-going ownership 24 | * Ensure that maintainer transitioning is included in the process for 25 | off-boarding of staff 26 | * Make use of organization crediting 27 | * Benefits 28 | * Greater community visibility 29 | * Able to make use of D.O packaging and testing bots 30 | * Drawbacks 31 | * organization does not have ownership of the module 32 | 33 | ### Alternatives 34 | 35 | #### Organization ownership on D.O 36 | 37 | Create a drupal.org account to represent the organization. Use this account to 38 | maintain the project. 39 | 40 | * Benefits 41 | * Organization cannot lose control of the module 42 | * Can serve NDA processes 43 | * drawbacks 44 | * Organization users are not really supported on D.O; requires assistance from Drupal Association staff 45 | 46 | #### Releasing on GitHub with D.O project page 47 | 48 | * Benefits 49 | * Organization ownership is guaranteed 50 | * GitHub project flows (Pull Requests, etc.) 51 | * Drawbacks 52 | * Frowned upon by D.O and part of community 53 | - Considerations 54 | * should issues be handled on D.O, GitHub, or both? 55 | * recommendation: issues should be tracked on GitHub to integrate best with the workflow 56 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Note that the example .travis.yml file for child projects lives in /install. 2 | sudo: false 3 | language: php 4 | 5 | php: 6 | - 5.6 7 | 8 | cache: 9 | bundler: true 10 | apt: true 11 | directories: 12 | - "$HOME/.composer/cache" 13 | - "$HOME/.drush/cache" 14 | - "$HOME/.nvm" 15 | - "vendor" 16 | 17 | notifications: 18 | # slack: acquia:KKfgpOkDhcO26Erv5uoZMfdP 19 | 20 | addons: 21 | ssh_known_hosts: 22 | - svn-5223.devcloud.hosting.acquia.com 23 | 24 | before_install: 25 | - nvm install 0.12 26 | - nvm use 0.12 27 | - composer selfupdate 28 | - phpenv config-rm xdebug.ini 29 | # Enable $_ENV variables in PHP. 30 | - echo 'variables_order = "EGPCS"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini 31 | # Ensure that always_populate_raw_post_data PHP setting: Not set to -1 does not happen. 32 | - echo "always_populate_raw_post_data = -1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini 33 | - git config --global user.name "Travis-CI" 34 | - git config --global user.email "noreply@travis-ci.org" 35 | - mysql -e 'CREATE DATABASE drupal;' 36 | 37 | install: 38 | - composer install 39 | - export PATH=$PATH:$TRAVIS_BUILD_DIR/vendor/bin 40 | 41 | before_script: 42 | # Clear drush release history cache, to pick up new releases. 43 | - rm -f ~/.drush/cache/download/*---updates.drupal.org-release-history-* 44 | # Verify that no git diffs (caused by line ending variation) exist. 45 | - git diff --exit-code 46 | 47 | script: 48 | # Generate a new 'bolted' project. 49 | - ./bolt.sh configure 50 | - ./bolt.sh create 51 | # Call targets in the new 'bolted' project. 52 | - ../bolted8/bolt.sh build:validate:test -Dcreate_alias=false -Dbehat.run-server=true -Dbehat.launch-phantom=true 53 | # Deploy build artifact. 54 | - ../bolted8/bolt.sh deploy:artifact -Ddeploy.commitMsg="Automated commit by Travis CI for Build ${TRAVIS_BUILD_ID}" -Ddeploy.branch="8.x-build" 55 | # Validate and run 'bolt' phpunit tests. 56 | - phpcs --standard=../bolted8/vendor/drupal/coder/coder_sniffer/Drupal/ruleset.xml tests 57 | - phpunit tests 58 | -------------------------------------------------------------------------------- /template/hooks/samples/domain_access/domain-fix.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 7 | * 8 | * This file should be placed in /hooks/common/post-db-copy 9 | * and will allow domains in domain_access module to be updated 10 | * following database copy. This ensures no manual updates to 11 | * the domains configuration are necessary after copying a db 12 | * between environments. 13 | */ 14 | 15 | $site = $argv[1]; 16 | $env = $argv[2]; 17 | $db = $argv[3]; 18 | $source = $argv[4]; 19 | 20 | // First ensure the domain module is installed. We do this by checking 21 | // existence of the domain table in the appropriate database. 22 | $domain=`echo "SHOW TABLES LIKE 'domain'" | drush @$site.$env ah-sql-cli --db=$db"`; 23 | 24 | if (!$domain) { 25 | $returns[] = "Domain module not installed, aborting"; 26 | } 27 | else { 28 | 29 | // Build a list of domains that require changing after the db has copied. 30 | // Each element of the $domains array should be keyed the machine name 31 | // and have key/value pairs of environment => URL. 32 | $domains = array( 33 | 'foo_com' => array( 34 | 'dev' => 'dev.foo.com', 35 | 'test' => 'stg.foo.com', 36 | 'prod' => 'foo.com', 37 | ), 38 | 'bar_com' => array( 39 | 'dev' => 'dev.bar.com', 40 | 'test' => 'stg.bar.com', 41 | 'prod' => 'bar.com', 42 | ), 43 | 'example_com' => array( 44 | 'dev' => 'dev.example.com', 45 | 'test' => 'stg.example.com', 46 | 'prod' => 'example.com', 47 | ), 48 | ); 49 | 50 | // Iterate through the domains and update the record to the URL specified. 51 | // If the domain machine name does not exist, the record will be skipped. 52 | foreach ($domains as $domain => $info) { 53 | if (isset($info[$env])) { 54 | $to = $info[$env]; 55 | $returns[] = "Updating domain table to update $domain to $to"; 56 | echo "UPDATE domain SET subdomain = "$to" where machine_name = "$domain" | drush @$site.$env ah-sql-cli --db=$db"; 57 | } 58 | } 59 | } 60 | 61 | // This output will be visible from the insights dashboard to reveal 62 | // which domains have been updated. 63 | foreach ($returns as $output) { 64 | print "$output\n"; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /tests/phpunit/BoltTest.php: -------------------------------------------------------------------------------- 1 | projectDirectory = realpath(dirname(__FILE__) . '/../../'); 21 | $this->config = Yaml::parse(file_get_contents("{$this->projectDirectory}/project.yml")); 22 | $this->new_project_dir = dirname($this->projectDirectory) . '/' . $this->config['project']['machine_name']; 23 | } 24 | 25 | /** 26 | * Tests Phing pt:create target. 27 | */ 28 | public function testBoltCreate() { 29 | 30 | $this->assertFileExists($this->new_project_dir); 31 | $this->assertFileNotExists($this->new_project_dir . '/install'); 32 | $this->assertFileNotExists($this->new_project_dir . '/tests/phpunit/Bolt.php'); 33 | $this->assertFileExists($this->new_project_dir . '/vendor'); 34 | $this->assertNotContains( 35 | 'pt:self-test', 36 | file_get_contents($this->new_project_dir . '/.travis.yml') 37 | ); 38 | $this->assertFileNotExists($this->new_project_dir . '/build/tasks/bolt.xml'); 39 | $this->assertNotContains( 40 | '${project.machine_name}', 41 | file_get_contents($this->new_project_dir . '/docroot/sites/default/settings.php') 42 | ); 43 | $this->assertNotContains( 44 | '${project.human_name}', 45 | file_get_contents($this->new_project_dir . '/readme/architecture.md') 46 | ); 47 | $profile_dir = $this->new_project_dir . '/docroot/profiles/contrib/' . 48 | $this->config['project']['profile']['name']; 49 | 50 | // Test new installation profile. 51 | if (!$this->config['project']['profile']['contrib']) { 52 | $this->assertFileExists($profile_dir . '/' . $this->config['project']['profile']['name'] . '.info.yml'); 53 | $this->assertFileExists($profile_dir . '/' . $this->config['project']['profile']['name'] . '.install'); 54 | $this->assertNotContains( 55 | '${project.profile.name}', 56 | file_get_contents($profile_dir . '/' . $this->config['project']['profile']['name'] . '.install') 57 | ); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /template/build/core/phing/tasks/frontend.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /template/drush/site-aliases/example.acsf.aliases.drushrc.php: -------------------------------------------------------------------------------- 1 | $site_id . '.01live', 27 | 'root' => '/var/www/html/' . $site_id . '.01live/docroot', 28 | 'remote-host' => $prod_web . '.enterprise-g1.hosting.acquia.com', 29 | ); 30 | 31 | $acsf_stage = array( 32 | 'remote-user' => $site_id . '.01test', 33 | 'root' => '/var/www/html/' . $site_id . '.01test/docroot', 34 | 'remote-host' => $dev_web . '.enterprise-g1.hosting.acquia.com', 35 | ); 36 | 37 | $acsf_dev = array( 38 | 'remote-user' => $site_id . '.01dev', 39 | 'root' => '/var/www/html/' . $site_id . '.01dev/docroot', 40 | 'remote-host' => $dev_web . '.enterprise-g1.hosting.acquia.com', 41 | ); 42 | 43 | // These defaults connect to the Acquia Cloud Site Factory. 44 | $acsf_defaults = array( 45 | 'ssh-options' => '-p 22', 46 | 'path-aliases' => array( 47 | '%dump-dir' => '/mnt/tmp/' 48 | ) 49 | ); 50 | 51 | // Create the aliases using the defaults and the list of sites. 52 | foreach ($sites as $site) { 53 | $aliases[$site . '.dev'] = array_merge( 54 | $acsf_defaults, 55 | $acsf_dev, 56 | array( 57 | 'uri' => $site . '.dev-' . $site_id . '.acsitefactory.com', 58 | ) 59 | ); 60 | 61 | $aliases[$site . '.stage'] = array_merge( 62 | $acsf_defaults, 63 | $acsf_dev, 64 | array( 65 | 'uri' => $site . '.test-' . $site_id . '.acsitefactory.com', 66 | ) 67 | ); 68 | 69 | $aliases[$site . '.prod'] = array_merge( 70 | $acsf_defaults, 71 | $acsf_prod, 72 | array( 73 | 'uri' => $site . '.' . $site_id . '.acsitefactory.com', 74 | ) 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /template/build/core/phing/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | You are running Bolt with xdebug enabled. This has a major impact on 14 | runtime performance. 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 51 | 52 | 53 | 56 | 57 | 58 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /template/docroot/sites/example.sites.php: -------------------------------------------------------------------------------- 1 | ..' => 'directory'. As an 24 | * example, to map https://www.drupal.org:8080/mysite/test to the configuration 25 | * directory sites/example.com, the array should be defined as: 26 | * @code 27 | * $sites = array( 28 | * '8080.www.drupal.org.mysite.test' => 'example.com', 29 | * ); 30 | * @endcode 31 | * The URL, https://www.drupal.org:8080/mysite/test/, could be a symbolic link 32 | * or an Apache Alias directive that points to the Drupal root containing 33 | * index.php. An alias could also be created for a subdomain. See the 34 | * @link https://www.drupal.org/documentation/install online Drupal installation guide @endlink 35 | * for more information on setting up domains, subdomains, and subdirectories. 36 | * 37 | * The following examples look for a site configuration in sites/example.com: 38 | * @code 39 | * URL: http://dev.drupal.org 40 | * $sites['dev.drupal.org'] = 'example.com'; 41 | * 42 | * URL: http://localhost/example 43 | * $sites['localhost.example'] = 'example.com'; 44 | * 45 | * URL: http://localhost:8080/example 46 | * $sites['8080.localhost.example'] = 'example.com'; 47 | * 48 | * URL: https://www.drupal.org:8080/mysite/test/ 49 | * $sites['8080.www.drupal.org.mysite.test'] = 'example.com'; 50 | * @endcode 51 | * 52 | * @see default.settings.php 53 | * @see \Drupal\Core\DrupalKernel::getSitePath() 54 | * @see https://www.drupal.org/documentation/install/multi-site 55 | */ 56 | -------------------------------------------------------------------------------- /template/build/core/phing/phingcludes/PhpVariableTask.php: -------------------------------------------------------------------------------- 1 | file; 34 | 35 | // @see http://php.net/manual/en/language.variables.variable.php 36 | $variable = $this->variable; 37 | 38 | // If variable is an array, parse array keys from string. Example value 39 | // would be databases[default][default][database]. 40 | if (strstr($variable, '[')) { 41 | // Split string parts. 42 | $keys = preg_split('~(])?(\\[|$)~', $variable, -1, PREG_SPLIT_NO_EMPTY); 43 | 44 | // Determine the variable name. E.g., $database is variable in example. 45 | $variable_name = array_shift($keys); 46 | $value = $$variable_name; 47 | 48 | // Loop through nested array keys. 49 | foreach ($keys as $key) 50 | { 51 | if (!is_array($value) || !array_key_exists($key, $value)) { 52 | $value[$key] = NULL; 53 | } 54 | $value = &$value[$key]; 55 | } 56 | } 57 | // If this is not an array, simply take variable value. 58 | else { 59 | $value = $$variable; 60 | } 61 | 62 | if (null !== $this->outputProperty) { 63 | $this->project->setProperty($this->outputProperty, $value); 64 | } 65 | 66 | } 67 | 68 | /** 69 | * Sets $this->file property. 70 | * 71 | * @param string $file 72 | * The PHP file from which to read the variable. 73 | */ 74 | public function setFile($file) 75 | { 76 | $this->file = $file; 77 | } 78 | 79 | /** 80 | * Sets $this->variable 81 | * 82 | * @param string $variable 83 | * The PHP variable name. This may be a nested array. 84 | */ 85 | public function setVariable($variable) 86 | { 87 | $this->variable = $variable; 88 | } 89 | 90 | /** 91 | * Sets $this->outputProperty property. 92 | * 93 | * @param string $prop 94 | * The name of the Phing property whose value to set. 95 | */ 96 | public function setOutputProperty($prop) 97 | { 98 | $this->outputProperty = $prop; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /template/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "acquia/${project.machine_name}", 3 | "license": "proprietary", 4 | "type": "project", 5 | "description": "${project.acquia_subname}", 6 | "repositories": [ 7 | { 8 | "type": "composer", 9 | "url": "https://packagist.drupal-composer.org" 10 | } 11 | ], 12 | "require": { 13 | "composer/installers": "^1.0.20", 14 | "drupal/acquia_connector": "8.1.*", 15 | "drupal/acsf": "~8.1", 16 | "drupal/core": "~8", 17 | "drupal/console": "~0.10", 18 | "drupal/memcache" : "8.*", 19 | "drupal/security_review" : "8.*", 20 | "roave/security-advisories": "dev-master", 21 | "drupal-composer/drupal-security-advisories": "8.0.x-dev", 22 | "drupal/lightning": "^8.1.0" 23 | }, 24 | "require-dev": { 25 | "behat/behat": "3.0.*", 26 | "behat/mink": "1.6@stable", 27 | "behat/mink-extension": "*", 28 | "behat/mink-goutte-driver": "*", 29 | "behat/mink-selenium2-driver": "*", 30 | "behat/mink-browserkit-driver": "*", 31 | "drush/drush": "^9.0", 32 | "drupal/drupal-extension": "~3.0", 33 | "drupal/coder": "~8.2", 34 | "phpunit/phpunit": "4.6.*", 35 | "squizlabs/php_codesniffer": "2.*", 36 | "phing/phing": "dev-master#0ef30e55bb5871cb38903cc0ee9d76074118a22c", 37 | "jakoch/phantomjs-installer": "1.9.8", 38 | "jarnaiz/behat-junit-formatter": "^1.2" 39 | }, 40 | "autoload-dev": { 41 | "psr-4": { 42 | "Drupal\\Tests\\PHPUnit\\": "tests/phpunit/src/" 43 | } 44 | }, 45 | "minimum-stability": "dev", 46 | "prefer-stable": true, 47 | "extra": { 48 | "installer-paths": { 49 | "docroot/core": ["type:drupal-core"], 50 | "docroot/modules/contrib/{$name}": ["type:drupal-module"], 51 | "docroot/profiles/contrib/{$name}": ["type:drupal-profile"], 52 | "docroot/themes/contrib/{$name}": ["type:drupal-theme"], 53 | "drush/contrib/{$name}": ["type:drupal-drush"] 54 | }, 55 | "patches": { 56 | "drupal/core": { 57 | "Ignore front end vendor folders to improve directory search performance": "https://www.drupal.org/files/issues/ignore_front_end_vendor-2329453-116.patch" 58 | } 59 | } 60 | }, 61 | "scripts": { 62 | "post-install-cmd": [ 63 | "PhantomInstaller\\Installer::installPhantomJS" 64 | ], 65 | "post-update-cmd": [ 66 | "PhantomInstaller\\Installer::installPhantomJS" 67 | ] 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /template/readme/repo-architecture.md: -------------------------------------------------------------------------------- 1 | # Repository architecture 2 | 3 | “How is the code organized, and why?” 4 | 5 | The repository architecture is driven by a set of core principles: 6 | 7 | * Project dependencies should never be committed directly to the repository 8 | * The code that is deployed to production should be fully validated, tested, sanitized, and free of non-production tools 9 | * Common project tasks should be fully automated and repeatable, independent of environment 10 | 11 | Consequently, there are a few aspects of this project’s architecture and workflow that may be unfamiliar to you. 12 | 13 | * Drupal core, contrib modules, themes, and third parties libraries are not committed to the repository. Contrib directories .gitignored and populated during [build artifact](deploy.md) generation. 14 | * The repository is never pushed directly to the cloud. Instead, changes to the repository on GitHub trigger tests to be run via [Continuous Integration](../build/README.md#ci). Changes that pass testing will automatically cause a [build artifact](deploy.md) to be created and deployed to the cloud. 15 | * [Common project tasks](project-tasks.md) are executed via a build tool (Phing) so that they can be executed exactly the same in all circumstances. 16 | 17 | ## Directory structure 18 | 19 | The following is an overview of the purpose of each top level directory in the project template: 20 | 21 | root 22 | ├── build - Contains build config files for CI solutions. E.g., Phing configuration. 23 | ├── drush - Contain drush configuration that is not site or environment specific. 24 | ├── docroot - The drupal docroot. 25 | ├── hooks - Contains Acquia Cloud hooks. 26 | ├── modules - Contains custom and contrib modules. 27 | ├── patches - Contains private patches to be used by composer.json. 28 | ├── profiles - Contains contrib and custom profiles. 29 | ├── readme - Contains high level project documentation. 30 | ├── reports - Contains output of automated tests; is .gitignored. 31 | ├── scripts - Contains a variety of utility scripts. 32 | ├── sites - Contains sites. 33 | ├── tests - Contains project-level test files and configuration. 34 | ├── themes - Contains custom and contrib themes. 35 | ├── vendor - Contains built composer dependencies; is .gitignored. 36 | 37 | ## Dependency Management 38 | 39 | All project and Drupal (module, themes, libraries) dependencies are managed via Composer. The management strategy is based on [The Drupal Project](github.com/drupal-composer/drupal-project). 40 | 41 | Modules, themes, and other contributed drupal projects can be added as dependencies in the root composer.json file. 42 | 43 | For step-by-step instructions on how to update dependencies, see [Project Tasks](project-tasks.md). 44 | -------------------------------------------------------------------------------- /template/tests/behat/example.local.yml: -------------------------------------------------------------------------------- 1 | # To generate a local.yml file using this the example template, execute: 2 | # `./bolt.sh setup:behat` from the project root. 3 | imports: 4 | - behat.yml 5 | 6 | local: 7 | suites: 8 | default: 9 | paths: 10 | # Set features to repo root so that .feature files belonging to contrib 11 | # modules, themes, and profiles can be discovered. Enable these 12 | # additional paths in build/phing/build.yml. 13 | features: ${repo.root} 14 | bootstrap: ${repo.root}/tests/behat/features/bootstrap 15 | contexts: 16 | - Drupal\FeatureContext: 17 | parameters: 18 | environment: 19 | # absolute path to local directory to store screenshots - do not include trailing slash 20 | screenshot_dir: '/Users/username/Desktop/test' 21 | - Drupal\DrupalExtension\Context\DrupalContext 22 | - Drupal\DrupalExtension\Context\MinkContext 23 | - Drupal\DrupalExtension\Context\MessageContext 24 | - Drupal\DrupalExtension\Context\DrushContext 25 | extensions: 26 | Behat\MinkExtension: 27 | javascript_session: selenium2 28 | # configure the base url for your site 29 | base_url: ${local_url} 30 | # set default command for "Show last response" step. 31 | show_cmd: "open %s" 32 | # ADDITIONAL OPTIONS FOR WEB DRIVERS 33 | # use the following 3 lines to user phantomjs 34 | # browser_name: phantomjs 35 | # selenium2: 36 | # wd_host: "http://localhost:8643/wd/hub" 37 | # browser: chrome 38 | # 39 | # use the following lines to disable SSL authentication for goutte. 40 | # goutte: 41 | # guzzle_parameters: 42 | # redirect.disable: true 43 | # ssl.certificate_authority: system 44 | # curl.options: 45 | # CURLOPT_SSL_VERIFYPEER: false 46 | # CURLOPT_SSL_VERIFYHOST: false 47 | # CURLOPT_CERTINFO: false 48 | # CURLOPT_TIMEOUT: 120 49 | selenium2: 50 | wd_host: http://127.0.0.1:4444/wd/hub 51 | browser: chrome 52 | Drupal\DrupalExtension: 53 | drupal: 54 | # This must be an absolute path. 55 | drupal_root: ${docroot} 56 | drush: 57 | alias: '@self' 58 | 59 | example-multisite: 60 | extensions: 61 | Behat\MinkExtension: 62 | javascript_session: selenium2 63 | # Configure the base url for your site. For multisite, ensure that this 64 | # corresponds to a valid domain entry in sites.php. 65 | base_url: http://127.0.0.1:8889 66 | # set default command for "Show last response" step. 67 | show_cmd: "open %s" 68 | selenium2: 69 | wd_host: http://127.0.0.1:4444/wd/hub 70 | browser: chrome 71 | Drupal\DrupalExtension: 72 | drupal: 73 | # This must be an absolute path. 74 | drupal_root: ${docroot} 75 | drush: 76 | alias: '@self' 77 | -------------------------------------------------------------------------------- /tests/phpunit/DeployTest.php: -------------------------------------------------------------------------------- 1 | projectDirectory = realpath(dirname(__FILE__) . '/../../'); 20 | $this->config = Yaml::parse(file_get_contents("{$this->projectDirectory}/project.yml")); 21 | $this->new_project_dir = dirname($this->projectDirectory) . '/' . $this->config['project']['machine_name']; 22 | $this->deploy_dir = $this->new_project_dir . '/deploy'; 23 | } 24 | 25 | /** 26 | * Tests Phing deploy:build:all target. 27 | */ 28 | public function testBoltDeployBuild() { 29 | 30 | // Ensure deploy directory exists. 31 | $this->assertFileExists($this->deploy_dir); 32 | 33 | // Ensure docroot was built into to deploy directory. 34 | $this->assertFileExists($this->deploy_dir . '/docroot'); 35 | $this->assertFileExists($this->deploy_dir . '/docroot/core'); 36 | $this->assertFileExists($this->deploy_dir . '/docroot/modules/contrib'); 37 | 38 | // Ensure settings files were copied to deploy directory. 39 | $this->assertFileExists($this->deploy_dir . '/docroot/index.php'); 40 | $this->assertFileExists($this->deploy_dir . '/docroot/autoload.php'); 41 | $this->assertFileExists($this->deploy_dir . '/composer.lock'); 42 | $this->assertFileExists($this->deploy_dir . '/docroot/sites/default/settings.php'); 43 | $this->assertFileNotExists($this->deploy_dir . '/docroot/sites/default/settings/local.settings.php'); 44 | 45 | // Ensure hooks were copied to deploy directory. 46 | $this->assertFileExists($this->deploy_dir . '/hooks'); 47 | $this->assertFileExists($this->deploy_dir . '/hooks/README.md'); 48 | 49 | // Ensure deploy directory was sanitized. 50 | $this->assertFileNotExists($this->deploy_dir . '/docroot/LICENSE.txt'); 51 | } 52 | 53 | /** 54 | * Tests Phing deploy:build:push target. 55 | */ 56 | public function testBoltDeployPush() { 57 | 58 | global $_ENV; 59 | $deploy_branch = '8.x-build'; 60 | 61 | foreach ($this->config['git']['remotes'] as $remote) { 62 | $commands = [ 63 | "git remote add temp $remote", 64 | "git fetch temp $deploy_branch", 65 | "git log temp/$deploy_branch", 66 | "git remote rm temp", 67 | ]; 68 | 69 | $log = ''; 70 | foreach ($commands as $command) { 71 | print "Executing \"$command\" \n"; 72 | $log .= shell_exec($command); 73 | } 74 | 75 | // We expect the remote git log to contain a commit message matching 76 | // the current build number, unless this build has not introduced 77 | // any new changes. Example message: 78 | // "Automated commit by Travis CI for Build #$travis_build_id". 79 | if (!empty($_ENV['DEPLOY_UPTODATE'])) { 80 | $this->assertContains('#' . $_ENV['TRAVIS_BUILD_ID'], $log); 81 | } 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /template/hooks/samples/rollback/rollback.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Cloud Hook: tests_rollback 4 | # 5 | # Run Drupal simpletests in the target environment using drush test-run. On failure, 6 | # rollback to last deployed code set 7 | # 8 | # implements Cloud_hook post_code_deploy 9 | # @todo needs to have pre_code_deploy for proper handling of files. 10 | # 11 | 12 | 13 | site="$1" 14 | target_env="$2" 15 | sourcebranch=$3 # The code branch or tag being deployed. 16 | deployedtag=$4 # The code branch or tag being deployed. 17 | repourl=$5 # The URL of your code repository. 18 | repotype=$6 # The version control system your site is using; "git" or "svn". 19 | 20 | #load variable settings from $HOME/rollback_settings 21 | #Check rollback_settings exists; if not alert and exit 22 | if [ -x "$HOME/rollback_settings" ]; then 23 | . $HOME/rollback_settings 24 | else 25 | echo "rollback_settings file not found in $HOME or not able to include (check execution bit)" 26 | exit 1 27 | fi 28 | 29 | #check attempts variable has any number of tries left. To prevent infinite loops. 30 | if [ "$ATTEMPTS" -le 0 ]; then 31 | echo "Maximum Number of attempts exceeded! Exiting." 32 | exit 1 33 | fi 34 | 35 | #now set the variable and append it into the settings file. 36 | ORIGATTEMPTS=$ATTEMPTS 37 | let "ATTEMPTS-=1" 38 | sed -i "s/ATTEMPTS=$ORIGATTEMPTS/ATTEMPTS=$ATTEMPTS/" $HOME/rollback_settings 39 | 40 | #initialize exit code so we can exit with 0 after rollback 41 | extcode=0 42 | 43 | # Enable the simpletest module if it is not already enabled. 44 | simpletest=`drush @$site.$target_env pm-info simpletest | perl -F'/[\s:]+/' -lane '/Status/ && print $F[2]'` 45 | if [ "$simpletest" = "disabled" ]; then 46 | echo "Temporarily enabling simpletest module." 47 | drush @$site.$target_env pm-enable simpletest --yes 48 | fi 49 | 50 | # Run the tests. 51 | CMD=`drush @$site.$target_env test-run $TESTS` 52 | 53 | #test output from drush 54 | if [ $? -ne 0 ]; then 55 | 56 | #sanity check to make sure we have a $origsource to fall back to. 57 | if [ $ORIGSOURCE ]; then 58 | #if simpletests fail tell the user and launch a new job rolling back to the original source 59 | echo "Testing failed on deploy rolling back to $ORIGSOURCE" 60 | echo "Executing: drush @$site.$target_env ac-code-path-deploy $ORIGSOURCE" 61 | drush @$site.$target_env ac-code-path-deploy $ORIGSOURCE 62 | else #something is very wrong should never get here, if we do notify and quit. 63 | echo "Cannot rollback. No fallback source identified." 64 | exit 1 65 | fi 66 | #set exitcode to fail so this code base does not deploy 67 | extcode=1 68 | 69 | else 70 | 71 | #simpletests passed! Inform user then clear and set rollback_settings to new code base 72 | echo "Testing passed on deploy of $deployedtag" 73 | sed -i "s/ORIGSOURCE=$ORIGSOURCE/ORIGSOURCE=$deployedtag/" $HOME/rollback_settings 74 | extcode=0 75 | 76 | fi 77 | 78 | # If we enabled simpletest, disable it. 79 | if [ "$simpletest" = "disabled" ]; then 80 | echo "Disabling simpletest module." 81 | drush @$site.$target_env pm-disable simpletest --yes 82 | fi 83 | 84 | #cleanly exit 85 | exit $extcode 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /template/build/core/phing/phingcludes/FilterFileListByFileSetTask.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * 11 | * 12 | * 13 | */ 14 | require_once 'phing/Task.php'; 15 | 16 | class FilterFileListByFileSetTask extends Task { 17 | 18 | /** 19 | * The return value. 20 | * 21 | * @var null 22 | */ 23 | protected $return_property = null; 24 | 25 | public function setFileList($fileList) 26 | { 27 | $this->fileList = $fileList; 28 | } 29 | 30 | /** 31 | * Nested adder, adds a set of files (nested fileset attribute). 32 | * 33 | * @param FileSet $fs 34 | * @return void 35 | */ 36 | public function addFileSet(FileSet $fs) 37 | { 38 | $this->filesets[] = $fs; 39 | } 40 | 41 | /** 42 | * The Phing property the return code should be assigned to. 43 | * 44 | * @param string $str The Phing property. 45 | * 46 | * @return void 47 | */ 48 | public function setReturnProperty($str) 49 | { 50 | $this->return_property = $str; 51 | } 52 | 53 | 54 | /** 55 | * The main entry point method. 56 | * 57 | * @throws BuildException 58 | * @return bool $return 59 | */ 60 | public function main() { 61 | 62 | if (!isset($this->fileList)) { 63 | throw new BuildException("You must set the file property."); 64 | } 65 | 66 | if (count($this->filesets) == 0) { 67 | throw new BuildException("You must define a fileset."); 68 | } 69 | 70 | $this->fileListFiles = array_map(array($this, 'prependProjectPath'), explode("\n", $this->fileList)); 71 | $this->fileSetFiles = $this->getFilesetFiles(); 72 | $filteredList = array_intersect($this->fileSetFiles, $this->fileListFiles); 73 | 74 | // Return the Behat exit value to a Phing property if specified. 75 | if (!empty($this->return_property)) { 76 | $this->getProject() 77 | ->setProperty($this->return_property, implode($filteredList, ',')); 78 | } 79 | 80 | return (bool) $filteredList; 81 | } 82 | 83 | protected function prependProjectPath($relative_path) { 84 | return $this->project->getBasedir()->getAbsolutePath() . DIRECTORY_SEPARATOR . $relative_path; 85 | } 86 | 87 | /** 88 | * Return the list of files to parse 89 | * 90 | * @see PhpCodeSnifferTask 91 | * 92 | * @return string[] list of absolute files to parse 93 | */ 94 | protected function getFilesetFiles() 95 | { 96 | $files = array(); 97 | 98 | foreach ($this->filesets as $fs) { 99 | $dir = $fs->getDir($this->project)->getAbsolutePath(); 100 | foreach ($fs->getDirectoryScanner($this->project)->getIncludedFiles() as $filename) { 101 | $file_path = $dir . DIRECTORY_SEPARATOR . $filename; 102 | $files[] = $file_path; 103 | } 104 | } 105 | 106 | return $files; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /template/docroot/.gitattributes: -------------------------------------------------------------------------------- 1 | # Drupal git normalization 2 | # @see https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html 3 | # @see https://www.drupal.org/node/1542048 4 | 5 | # Normally these settings would be done with macro attributes for improved 6 | # readability and easier maintenance. However macros can only be defined at the 7 | # repository root directory. Drupal avoids making any assumptions about where it 8 | # is installed. 9 | 10 | # Define text file attributes. 11 | # - Treat them as text. 12 | # - Ensure no CRLF line-endings, neither on checkout nor on checkin. 13 | # - Detect whitespace errors. 14 | # - Exposed by default in `git diff --color` on the CLI. 15 | # - Validate with `git diff --check`. 16 | # - Deny applying with `git apply --whitespace=error-all`. 17 | # - Fix automatically with `git apply --whitespace=fix`. 18 | 19 | # Auto-detect text files, ensure they use LF. 20 | * text=auto eol=lf 21 | 22 | *.css text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 23 | *.engine text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 24 | *.html text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=html 25 | *.inc text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 26 | *.info text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 27 | *.install text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 28 | *.js text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 29 | *.json text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 30 | *.lock text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 31 | *.md text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 32 | *.module text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 33 | *.php text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 34 | *.po text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 35 | *.script text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 36 | *.sh text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 37 | *.sql text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 38 | *.test text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 39 | *.theme text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 40 | *.txt text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 41 | *.xml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 42 | *.yml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 43 | 44 | # Define binary file attributes. 45 | # - Do not treat them as text. 46 | # - Include binary diff in patches instead of "binary files differ." 47 | *.gif -text diff 48 | *.gz -text diff 49 | *.ico -text diff 50 | *.jpg -text diff 51 | *.png -text diff 52 | *.phar -text diff 53 | *.exe -text diff 54 | *.ttf -text diff 55 | -------------------------------------------------------------------------------- /template/build/core/phing/tasks/validate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 67 | 68 | 69 | 70 | 77 | 78 | 79 | 80 | 81 | 82 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /template/build/core/phing/phingcludes/FileInFilesetCondition.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | 20 | include_once 'phing/tasks/system/condition/Condition.php'; 21 | 22 | /** 23 | * Compares two files for equality based on size and 24 | * content. Timestamps are not at all looked at. 25 | * 26 | * @author Siad Ardroumli 27 | * @package phing.tasks.system.condition 28 | */ 29 | class FileInFilesetCondition extends ProjectComponent implements Condition 30 | { 31 | /** 32 | * A php source code filename or directory 33 | * 34 | * @var PhingFile 35 | */ 36 | protected $file; // the source file (from xml attribute) 37 | 38 | /** 39 | * All fileset objects assigned to this task 40 | * 41 | * @var FileSet[] 42 | */ 43 | protected $filesets = array(); // all fileset objects assigned to this task 44 | 45 | /** 46 | * File to be performed syntax check on 47 | * @param PhingFile $file 48 | */ 49 | public function setFile(PhingFile $file) 50 | { 51 | $this->file = $file; 52 | } 53 | 54 | /** 55 | * Nested adder, adds a set of files (nested fileset attribute). 56 | * 57 | * @param FileSet $fs 58 | * @return void 59 | */ 60 | public function addFileSet(FileSet $fs) 61 | { 62 | $this->filesets[] = $fs; 63 | } 64 | 65 | /** 66 | * Return the list of files to parse 67 | * 68 | * @see PhpCodeSnifferTask 69 | * 70 | * @return string[] list of absolute files to parse 71 | */ 72 | protected function getFilesetFiles() 73 | { 74 | $files = array(); 75 | 76 | foreach ($this->filesets as $fs) { 77 | $dir = $fs->getDir($this->project)->getAbsolutePath(); 78 | foreach ($fs->getDirectoryScanner($this->project)->getIncludedFiles() as $filename) { 79 | $file_path = $dir . DIRECTORY_SEPARATOR . $filename; 80 | $files[] = $file_path; 81 | } 82 | } 83 | 84 | return $files; 85 | } 86 | 87 | /** 88 | * comparison method of the interface 89 | * 90 | * @return bool if the files are equal 91 | * @throws BuildException if it all went pear-shaped 92 | */ 93 | public function evaluate() 94 | { 95 | if (!isset($this->file)) { 96 | throw new BuildException("You must set the file property."); 97 | } 98 | 99 | if ($this->file instanceof PhingFile) { 100 | $this->file->getPath(); 101 | } else { 102 | throw new BuildException("Could not load specified file."); 103 | } 104 | 105 | if (count($this->filesets) == 0) { 106 | throw new BuildException("You must define a fileset."); 107 | } 108 | 109 | $files = $this->getFilesetFiles(); 110 | 111 | return array_search($this->file->getPath(), $files); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /template/hooks/samples/scrub/db-scrub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # db-copy Cloud hook: db-scrub 4 | # 5 | # Scrub important information from a Drupal database. 6 | # 7 | # Usage: db-scrub.sh site target-env db-name source-env 8 | 9 | site="$1" 10 | target_env="$2" 11 | db_name="$3" 12 | source_env="$4" 13 | 14 | echo "$site.$target_env: Scrubbing database $db_name" 15 | 16 | (cat < 0); 39 | 40 | -- don't leave e-mail addresses, etc in comments table. 41 | -- UPDATE comments SET name='Anonymous', mail='', homepage='http://example.com' WHERE uid=0; 42 | 43 | -- Scrub webform submissions. 44 | -- UPDATE webform_submitted_data set data='*scrubbed*'; 45 | 46 | -- remove sensitive customer data from custom module 47 | -- TRUNCATE custom_customer_lead_data; 48 | 49 | -- USER PASSWORDS 50 | -- These statements assume you want to preserve real passwords for developers. Change 'rid=3' to the 51 | -- developer or test role you want to preserve. 52 | 53 | -- DRUPAL 6 54 | -- Remove passwords unless users have 'developer role' 55 | -- UPDATE users SET pass=md5('devpassword') WHERE uid IN (SELECT uid FROM users_roles WHERE rid=3) AND uid > 0; 56 | 57 | -- Admin user should not be same but not really well known 58 | -- UPDATE users SET pass = MD5('supersecret!') WHERE uid = 1; 59 | 60 | -- DRUPAL 7 61 | -- Drupal 7 requires sites to generate a hashed password specific to their site. A script in the 62 | -- docroot/scripts directory is provided for doing this. From your docroot run the following: 63 | -- 64 | -- scripts/password-hash.sh password 65 | -- 66 | -- this will generate a hash for the password "password". In the following statements replace 67 | -- $REPLACE THIS$ with your generated hash. 68 | 69 | -- Remove passwords unless users have 'developer role' 70 | -- UPDATE users SET pass='$REPLACE THIS$' WHERE uid IN (SELECT uid FROM users_roles WHERE rid=3) AND uid > 0; 71 | 72 | -- Admin user should not be same but not really well known 73 | -- UPDATE users SET pass='$REPLACE THIS$' WHERE uid = 1; 74 | 75 | -- TRUNCATE accesslog; 76 | -- TRUNCATE access; 77 | -- TRUNCATE cache; 78 | -- TRUNCATE cache_filter; 79 | -- TRUNCATE cache_menu; 80 | -- TRUNCATE cache_page; 81 | -- TRUNCATE cache_views; 82 | -- TRUNCATE cache_views_data; 83 | -- TRUNCATE devel_queries; 84 | -- TRUNCATE devel_times; 85 | -- TRUNCATE flood; 86 | -- TRUNCATE history; 87 | -- TRUNCATE search_dataset; 88 | -- TRUNCATE search_index; 89 | -- TRUNCATE search_total; 90 | -- TRUNCATE sessions; 91 | -- TRUNCATE watchdog; 92 | 93 | 94 | EOF 95 | ) | drush @$site.$target_env ah-sql-cli --db=$db_name 96 | -------------------------------------------------------------------------------- /template/docroot/sites/default/settings/default.local.settings.php: -------------------------------------------------------------------------------- 1 | 13 | array( 14 | 'default' => 15 | array( 16 | 'database' => 'drupal', 17 | 'username' => 'root', 18 | 'password' => '', 19 | 'host' => 'localhost', 20 | 'port' => '3306', 21 | 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', 22 | 'driver' => 'mysql', 23 | 'prefix' => '', 24 | ), 25 | ), 26 | ); 27 | 28 | // Configuration directories. 29 | $dir = dirname(DRUPAL_ROOT); 30 | $config_directories['sync'] = $dir . '/config/default'; 31 | 32 | // Use development service parameters. 33 | $settings['container_yamls'][] = $dir . '/sites/development.services.yml'; 34 | 35 | /** 36 | * Assertions. 37 | * 38 | * The Drupal project primarily uses runtime assertions to enforce the 39 | * expectations of the API by failing when incorrect calls are made by code 40 | * under development. 41 | * 42 | * @see http://php.net/assert 43 | * @see https://www.drupal.org/node/2492225 44 | * 45 | * If you are using PHP 7.0 it is strongly recommended that you set 46 | * zend.assertions=1 in the PHP.ini file (It cannot be changed from .htaccess 47 | * or runtime) on development machines and to 0 in production. 48 | * 49 | * @see https://wiki.php.net/rfc/expectations 50 | */ 51 | assert_options(ASSERT_ACTIVE, TRUE); 52 | \Drupal\Component\Assertion\Handle::register(); 53 | 54 | /** 55 | * Show all error messages, with backtrace information. 56 | * 57 | * In case the error level could not be fetched from the database, as for 58 | * example the database connection failed, we rely only on this value. 59 | */ 60 | $config['system.logging']['error_level'] = 'verbose'; 61 | 62 | /** 63 | * Disable CSS and JS aggregation. 64 | */ 65 | $config['system.performance']['css']['preprocess'] = FALSE; 66 | $config['system.performance']['js']['preprocess'] = FALSE; 67 | 68 | /** 69 | * Disable the render cache (this includes the page cache). 70 | * 71 | * Note: you should test with the render cache enabled, to ensure the correct 72 | * cacheability metadata is present. However, in the early stages of 73 | * development, you may want to disable it. 74 | * 75 | * This setting disables the render cache by using the Null cache back-end 76 | * defined by the development.services.yml file above. 77 | * 78 | * Do not use this setting until after the site is installed. 79 | */ 80 | # $settings['cache']['bins']['render'] = 'cache.backend.null'; 81 | 82 | /** 83 | * Disable Dynamic Page Cache. 84 | * 85 | * Note: you should test with Dynamic Page Cache enabled, to ensure the correct 86 | * cacheability metadata is present (and hence the expected behavior). However, 87 | * in the early stages of development, you may want to disable it. 88 | */ 89 | # $settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null'; 90 | 91 | /** 92 | * Allow test modules and themes to be installed. 93 | * 94 | * Drupal ignores test modules and themes by default for performance reasons. 95 | * During development it can be useful to install test extensions for debugging 96 | * purposes. 97 | */ 98 | $settings['extension_discovery_scan_tests'] = TRUE; 99 | 100 | /** 101 | * Enable access to rebuild.php. 102 | * 103 | * This setting can be enabled to allow Drupal's php and database cached 104 | * storage to be cleared via the rebuild.php page. Access to this page can also 105 | * be gained by generating a query string from rebuild_token_calculator.sh and 106 | * using these parameters in a request to rebuild.php. 107 | */ 108 | $settings['rebuild_access'] = TRUE; 109 | -------------------------------------------------------------------------------- /template/readme/deploy.md: -------------------------------------------------------------------------------- 1 | # Deployment workflow 2 | 3 | "How do I deploy code from my local machine, or GitHub, to the Acquia Cloud?" 4 | 5 | For information on how to deploy to production, see [release-process.md](release-process.md). 6 | 7 | This document outlines the workflow to build a complete Drupal docroot (plus supporting features, such as Cloud Hooks) which can be deployed directly to Acquia Cloud. Collectively, this bundle of code is referred to as the "build artifact". 8 | 9 | The most important thing to remember about this workflow is that the Github and ACE repos are _not_ clones of one another. Github only stores the source code, and ACE only stores the production code (i.e. the build artifacts). 10 | 11 | Currently, this workflow can either be followed manually, or integrated into a CI solution such as Jenkins or Travis. Eventually, Build Steps will enable it to run directly on Acquia Cloud, obviating the need to maintain separate repositories for source code (Github) and production code (ACE). 12 | 13 | ## First time setup 14 | 15 | You should have your Github repository (where this document is stored) checked out locally. Your ACE repository should be empty, or nearly empty. 16 | 17 | Check out a new branch to match whatever branch you are working on in Github (typically `develop`). 18 | 19 | Ensure your ACE remote is listed in project.yml under git:remotes. 20 | 21 | ## Creating the build artifact 22 | 23 | In order to create the build artifact in `/deploy`, simply run 24 | ``` 25 | ./bolt.sh deploy:artifact:build 26 | ``` 27 | 28 | This task is analogous to `setup:build:all` but with a few critical differences: 29 | * The docroot is created at `/deploy/docroot`. 30 | * Only production required to the docroot 31 | * (planned) CSS / JS are compiled in production mode (compressed / minified) 32 | * (planned) Sensitive files, such as CHANGELOG.txt, are removed. 33 | 34 | After the artifact is created, you can inspect it or even run it as a website locally. You may also manually commit and push it to ACE. 35 | 36 | ## Create and deploy the build artifact 37 | 38 | To both create and deploy the build artifact in a single command, run the following command 39 | 40 | ```` 41 | ./bolt.sh deploy:artifact -Ddeploy.branch=develop-build -Ddeploy.commitMsg='BLT-123: The commit message.' 42 | ```` 43 | 44 | This command will commit the artifact to the `develop-build` branch with the specified commit message and push it to the remotes defined in project.yml. 45 | 46 | ## Continuous integration 47 | 48 | Instead of performing these deployments manually, you can enlist the help of a CI tool such as Travis or Jenkins. 49 | 50 | ### Travis CI 51 | 52 | Access to Travis is already provided by Acquia PS, which makes this option appealing on a cost basis. It will automatically deploy new commits after they are merged and tests pass. However, it's somewhat insecure (you have to create an SSH key for deployments that can be accessed by any developer), and it's impossible to schedule regular deployments or perform more advanced integrations. 53 | 54 | For more information on configuring Travis CI, see "Setting Up Travis CI for automated deployments" in [build/README.md](../build/README.md). 55 | 56 | ### Jenkins (Cloudbees) 57 | 58 | Jenkins is more expensive and time-consuming to set up, but offers much more flexibility. For instance, you can add a Slack slash command (such as `/deploy`) that allows your QA team to deploy specific branches to ACE on demand. See the forthcoming README on Jenkins integration for more information. 59 | 60 | Note, we previously used Engineering's Jenkins instance for CI (ci.acquia.com), but this should be avoided going forward. Instead, a starter account with Cloudbees is recommended. There's a two-week free trial, and after that the service is ~$60 per month, and must be paid for on a per-project basis. 61 | -------------------------------------------------------------------------------- /template/readme/release-process.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | This document is a work in progress. 4 | 5 | * [Generating a build artifact](#build-artifact) 6 | * [Branching strategies](#branching) 7 | * [Tagging](#tagging) 8 | * [Release Notes](#release-notes) 9 | * [Deploying tag and executing updates](#deploy-tag) 10 | * [Notifications](#notifications) (slack, hipchat, etc) 11 | 12 | ## Branching strategies 13 | 14 | @todo Document this! 15 | 16 | ## Generating a build artifact 17 | 18 | See [Create and deploy the build artifact](deploy.md#build-artifact) in [deploy.md](deploy.md). 19 | 20 | ## Tagging 21 | 22 | @todo Document this! 23 | 24 | ## Release notes 25 | 26 | Each release should be accompanied by a set of release notes, which can be easily generated using the [Release Notes Script](../scripts/release-notes/README.md). 27 | 28 | This script will automatically aggregate all of the descriptions from Pull Requests since a specified date. The generated tet aggregate can then be copied and pasted into release notes on GitHub. 29 | 30 | ## Deploying tag and executing updates 31 | 32 | Deploying Drupal across environments can be daunting, but if due diligence has been taken with configuration management, the process of deployment is actually quite simple. 33 | 34 | No matter how many environments there are or whatever versioning workflow is being used, the actual deployment process will take approximately the following form (please note the commands are examples): 35 | 36 | 1. Put the site into maintenance mode `drush vset maintenance_mode 1` 37 | 2. Flush Caches to empty the cache tables and ensure maintenance mode is set. `drush cc all` 38 | 3. Perform any necessary backups, notably the database `drush sql-dump > backup-yyyy-mm-dd.sql` 39 | 4. Pull the latest code onto the server `git pull origin/master` 40 | 5. Run update.php `drush updb -y` 41 | 7. Take the site out of maintenance mode `drush vset maintenance_mode 0` 42 | 8. Clear Drupal caches `drush cc all` 43 | 44 | A few things that you should (almost) never do on production: 45 | 1. Revert all features via `drush fra -y`. This poses a site stability risk and also risks wiping a feature that may be been accidentally overridden in production. Feature should be explicitly reverted via a call to `features_revert_module()` in a `hook_update_N()` implementation. 46 | 1. Run `drush cc all`. Specific caches should be targeted whenever possible. 47 | 1. Utilize `drush use`. This introduces the risk that the release master will accidentally run a command against prod after the release. 48 | 49 | There might be some extra steps depending on the infrastructure and the extent of site changes. For example, a major application change might require a flush of other caches in the system such as Varnish or Memcached. 50 | 51 | # Notifications 52 | 53 | You can configure various tools to provide notifications of deployment related events. For instance: 54 | 55 | * [Travis CI](https://docs.travis-ci.com/user/notifications/) can notify you about your build results through email, IRC and/or webhooks. 56 | * Jenkins has plugins to provide build notifications via [Slack](https://wiki.jenkins-ci.org/display/JENKINS/Slack+Plugin), [IRC](https://wiki.jenkins-ci.org/display/JENKINS/IRC+Plugin), and many more services. 57 | * You can use [Acquia Cloud Hooks](https://docs.acquia.com/cloud/manage/cloud-hooks#animated) to provide deployment, db, or code related notification to service such as: 58 | * [New Relic](../hooks/samples/newrelic) 59 | * [Slack](../hooks/samples/slack) 60 | * [HipChat](../hooks/samples/hipchat) 61 | 62 | ## Resources: 63 | 64 | * [Connecting the Tubes: JIRA, GitHub, Jenkins, and Slack](https://dev.acquia.com/blog/connecting-tubes-jira-github-jenkins-and-slack) 65 | -------------------------------------------------------------------------------- /template/tests/phpunit/GitTest.php: -------------------------------------------------------------------------------- 1 | assertFileExists($this->projectDirectory . '/.git'); 17 | $this->assertFileExists($this->projectDirectory . '/.git/hooks/commit-msg'); 18 | $this->assertFileExists($this->projectDirectory . '/.git/hooks/pre-commit'); 19 | $this->assertNotContains( 20 | '${project.prefix}', 21 | file_get_contents($this->projectDirectory . '/.git/hooks/commit-msg') 22 | ); 23 | } 24 | 25 | /** 26 | * Tests operation of scripts/git-hooks/commit-msg. 27 | * 28 | * @param bool $is_valid 29 | * Whether the message is valid. 30 | * @param string $commit_message 31 | * The git commit message. 32 | * @param string $message 33 | * The PHPUnit message to be output for this datapoint. 34 | * 35 | * @dataProvider providerTestGitHookCommitMsg 36 | */ 37 | public function testGitHookCommitMsg($is_valid, $commit_message, $message = NULL) { 38 | $this->assertCommitMessageValidity($is_valid, $commit_message, $message); 39 | } 40 | 41 | /** 42 | * Data provider. 43 | */ 44 | public function providerTestGitHookCommitMsg() { 45 | $prefix = $this->config['project']['prefix']; 46 | return array( 47 | array(FALSE, "This is a bad commit.", 'Missing prefix and ticket number.'), 48 | array(FALSE, "123: This is a bad commit.", 'Missing project prefix.'), 49 | array(FALSE, "{$prefix}: This is a bad commit.", 'Missing ticket number.'), 50 | array(FALSE, "{$prefix}-123 This is a bad commit.", 'Missing colon.'), 51 | array(FALSE, "{$prefix}-123: This is a bad commit", 'Missing period.'), 52 | array(FALSE, "{$prefix}-123: Hello.", 'Too short.'), 53 | array(FALSE, "NOT-123: This is a bad commit.", 'Wrong project prefix.'), 54 | array(TRUE, "{$prefix}-123: This is a good commit.", 'Good commit.'), 55 | array(TRUE, "{$prefix}-123: This is an exceptionally long--seriously, really, really, REALLY long, but still good commit.", 'Long good commit.', 56 | ), 57 | ); 58 | } 59 | 60 | /** 61 | * Tests operation of scripts/git-hooks/pre-commit. 62 | * 63 | * Should assert that code validation via phpcs is functioning. 64 | */ 65 | public function testGitPreCommitHook() { 66 | // Commits must be executed inside of new project directory. 67 | chdir($this->projectDirectory); 68 | $prefix = $this->config['project']['prefix']; 69 | $command = "git commit --amend -m '$prefix-123: This is a good commit.' 2>&1"; 70 | $output = shell_exec($command); 71 | $this->assertNotContains('PHP Code Sniffer was not found', $output); 72 | $this->assertContains('Sniffing staged files via PHP Code Sniffer.', $output); 73 | } 74 | 75 | /** 76 | * Asserts that a given commit message is valid or not. 77 | * 78 | * @param bool $is_valid 79 | * Whether the message is valid. 80 | * @param string $commit_message 81 | * The git commit message. 82 | * @param string $message 83 | * The PHPUnit message to be output for this datapoint. 84 | */ 85 | protected function assertCommitMessageValidity($is_valid, $commit_message, $message = '') { 86 | // Commits must be executed inside of new project directory. 87 | chdir($this->projectDirectory); 88 | 89 | // "2>&1" redirects standard error output to standard output. 90 | $command = "git commit --amend -m '$commit_message' 2>&1"; 91 | print "Executing \"$command\" \n"; 92 | 93 | $output = shell_exec($command); 94 | $invalid_commit_text = 'Invalid commit message'; 95 | $output_contains_invalid_commit_text = (bool) strstr($output, $invalid_commit_text); 96 | $this->assertNotSame($is_valid, $output_contains_invalid_commit_text, $message); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /template/.gitattributes: -------------------------------------------------------------------------------- 1 | # Drupal git normalization 2 | # @see https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html 3 | # @see https://www.drupal.org/node/1542048 4 | 5 | # Normally these settings would be done with macro attributes for improved 6 | # readability and easier maintenance. However macros can only be defined at the 7 | # repository root directory. Drupal avoids making any assumptions about where it 8 | # is installed. 9 | 10 | # Define text file attributes. 11 | # - Treat them as text. 12 | # - Ensure no CRLF line-endings, neither on checkout nor on checkin. 13 | # - Detect whitespace errors. 14 | # - Exposed by default in `git diff --color` on the CLI. 15 | # - Validate with `git diff --check`. 16 | # - Deny applying with `git apply --whitespace=error-all`. 17 | # - Fix automatically with `git apply --whitespace=fix`. 18 | 19 | # Auto-detect text files, ensure they use LF. 20 | * text=auto eol=lf 21 | 22 | *.css text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 23 | *.engine text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 24 | *.html text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=html 25 | *.inc text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 26 | *.info text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 27 | *.install text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 28 | *.js text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 29 | *.json text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 30 | *.lock text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 31 | *.md text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 32 | *.module text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 33 | *.php text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 34 | *.po text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 35 | *.script text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 36 | *.sh text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 37 | *.sql text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 38 | *.test text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 39 | *.theme text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 40 | *.txt text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 41 | *.xml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 42 | *.yml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 43 | 44 | # Define binary file attributes. 45 | # - Do not treat them as text. 46 | # - Include binary diff in patches instead of "binary files differ." 47 | *.gif -text diff 48 | *.GIF -text diff 49 | *.gz -text diff 50 | *.GZ -text diff 51 | *.ico -text diff 52 | *.ICO -text diff 53 | *.jpg -text diff 54 | *.JPG -text diff 55 | *.png -text diff 56 | *.PNG -text diff 57 | *.phar -text diff 58 | *.PHAR -text diff 59 | *.exe -text diff 60 | *.EXE -text diff 61 | *.ttf -text diff 62 | *.TTF -text diff 63 | *.otf -text diff 64 | *.OTF -text diff 65 | *.eot -text diff 66 | *.EOT -text diff 67 | *.woff2 -text diff 68 | *.WOFF2 -text di 69 | *.swf -text diff 70 | *.SWF -text diff 71 | *.db -text diff 72 | *.DB -text diff 73 | *.tar -text diff 74 | *.TAR -text diff 75 | *.pdf -text diff 76 | *.PDF -text diff 77 | *.jar -text diff 78 | *.JAR -text diff 79 | -------------------------------------------------------------------------------- /template/docroot/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 40 | 49 | 50 | 53 | 62 | 63 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /template/build/README.md: -------------------------------------------------------------------------------- 1 | # Build files 2 | 3 | This directory contains configuration files for running common project tasks. These may be used for running tasks locally, or for running automated builds via continuous integration solutions. 4 | 5 | This directory should not contain any test files. Those exist in the [/tests](/tests) directory. 6 | 7 | ## Build Tasks 8 | 9 | A large number of common build tasks are provided via Phing targets. These include tasks for things like code sniffing, executing tests, building dependencies, installing Drupal, etc. 10 | 11 | For a full list of available Phing tasks, run `./bolt.sh -list` from the project's root directory. 12 | 13 | ### Executing Tasks 14 | 15 | * For a full list of the available Phing targets, run `./bolt.sh -list` 16 | * To manually test a Phing target, run the following command matching the the following pattern: `./bolt.sh `. For example `./bolt.sh validate:all` 17 | * To run Phing directly from the binary, simply run `./bin/phing -f build/phing/build.xml ` 18 | 19 | ## Continuous Integration 20 | 21 | Integration with Travis CI is included, although Phing tasks can be used with any CI tool. The default Travis CI build process is as follows: 22 | 23 | 1. Pull request or commit to GitHub triggers Travis CI. 24 | 1. `.travis.yml` is read and executed by Travis CI. The environment is built by installing composer dependencies. 25 | 1. Travis CI begins a a build and calls various Phing targets. 26 | 27 | ### Creating your own custom tasks 28 | 29 | You may add your own custom tasks to the build engine by defining new [Phing](https://www.phing.info/) targets in [build/custom/phing/build.xml] 30 | (custom/phing/build.xml). 31 | 32 | You may override or define custom Phing properties in [build/custom/phing/build.yml](custom/phing/build.yml) 33 | 34 | ### Automated testing using live content 35 | 36 | By default, the Travis CI automated tests install and test your site from scratch. Once you have a production site in a remote environment, it’s recommended to also run automated tests against a copy of your production database, especially in order to functionally test update hooks. 37 | 38 | Automated testing of live content is easy to set up with two simple steps: 39 | 40 | 1. Add the hostname of your staging server to .travis.yml: 41 | 42 | ``` 43 | ssh_known_hosts: 44 | - staging-12345.prod.hosting.acquia.com 45 | ``` 46 | 2. Override the default `build:validate:test` target by adding the following to `build/custom/phing/build.xml`: 47 | 48 | ``` 49 | 50 | 52 | ``` 53 | 54 | ### Setting Up Travis CI for automated deployments 55 | 56 | Travis CI can be used to deploy a fully built site artifact (with the docroot) in the following manner: 57 | 58 | 1. A pull request is merged into the GitHub repository 59 | 2. Travis builds the docroot 60 | 3. Travis commits the docroot to a specific "build" branch and pushes to Acquia Cloud 61 | 62 | To set up this workflow, you must configure Acquia Cloud, GitHub, and Travis CI to work together. Step-by-step instructions are provided below. 63 | 64 | 65 | 1. Generate an SSH key locally. E.g., 66 | 67 | ``` 68 | cd ~/.ssh 69 | ssh-keygen -t rsa -b 4096 70 | ``` 71 | 72 | Do not use a passphrase! 73 | 1. Create a new Acquia Cloud account to be used exclusively as a container for the SSH keys that will grant Travis push access to Acquia Cloud. This can be done by inviting a new team member on the "Teams" tab in Acquia Cloud. You can use an email address like `+travis@acquia.com`. The team member must have SSH push access. 74 | 1. Login the your new Acquia Cloud account and add the public SSH key from the key pair that was generated in step 1 by visiting `https://accounts.acquia.com/account/[uid]/security`. 75 | 1. Add the same public SSH key to the "Deployment Keys" section on your project's GitHub settings page, located at `https://github.com/acquia-pso/[project-name]/settings/keys`. 76 | 1. Add the _private SSH key_ to your project's Travis CI settings located at `https://magnum.travis-ci.com/acquia-pso/[project-name]/settings`. 77 | 1. Uncomment the example deployment steps in your .travis.yml file and customize them to deploy your desired branch. 78 | 1. Add your cloud git repository to the remotes section of your project.yml file: 79 | 80 | ``` 81 | remotes: 82 | - example@svn-14671.prod.hosting.acquia.com:example.git` 83 | ``` 84 | 85 | 1. Add your cloud git repository's server host name to `ssh_known_hosts` in your .travis.yml file. 86 | 87 | ``` 88 | addons: 89 | ssh_known_hosts: 90 | - svn-14671.prod.hosting.acquia.com 91 | ``` 92 | 93 | 1. Commits or merges to the develop branch on GitHub should now trigger a fully built artifact to be deployed to your specified remotes. 94 | 95 | For information on manually deploying your project, read [readme/deploy.md](readme/deploy.md) 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bolt 2 | 3 | [![Build Status](https://travis-ci.org/acquia/bolt.svg?branch=8.x)](https://travis-ci.org/acquia/bolt) 4 | 5 | Bolt is a tool that generates new Drupal projects using a standardized template derived from Acquia Professional Services' best practices. 6 | 7 | ## License 8 | 9 | Copyright (C) 2016 Acquia, Inc. 10 | 11 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. 12 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 14 | 15 | ## Philosophy and Purpose 16 | 17 | Bolt is designed to improve efficiency and collaboration across Drupal projects by providing a common set of tools and standardized structure. It was born out of the need to reduce re-work, project set up time, and developer onboarding time. 18 | 19 | Its explicit goals are to: 20 | 21 | * Provide a standard project template for Drupal based projects 22 | * Provide tools that automate much of the setup and maintenance work for projects 23 | * Document and enforce Drupal standards and best practices via default configuration, automated testing, and continuous integration 24 | 25 | It scope is discretely defined. It is *not* intended to provide: 26 | 27 | * Drupal application features (e.g., workflow, media, layout, pre-fabbed content types, etc.) 28 | * A local hosting environment 29 | * A replacement for good judgement (as with Drupal, it leaves you the freedom to make mistakes) 30 | 31 | ## Creating a new project with Bolt 32 | 33 | It isn’t accurate to say that you can “install” Bolt. Rather, you can use Bolt to generate a new project. Within that project, you can then perform common project tasks like build dependencies, install Drupal, run tests, etc. 34 | 35 | Follow the instructions in [INSTALL.md](INSTALL.md) to generate a new project using Bolt. 36 | 37 | ## Features 38 | 39 | * [Documentation templates](template/README.md) 40 | * [Git Hooks](template/scripts/git-hooks) 41 | * pre-commit: Checks for Drupal coding standards compliance 42 | * commit-msg: Check for proper formatting and syntax 43 | * [Acquia Cloud Hooks](template/hooks). Example integrations for third party services such as: 44 | * Slack 45 | * New Relic 46 | * HipChat 47 | * [Testing Framework](template/tests). 48 | * Behat: default `local.yml` configuration, example tests, `FeatureContext.php` 49 | * PHPUnit: default tests for ensuring proper functioning of Bolt provided components 50 | * [Project tasks](template/readme/project-tasks.md) 51 | * Executing tests and validating code 52 | * Building dependencies 53 | * (Re)installation of Drupal 54 | * Production-safe artifact generation and deployment 55 | * [Continuous Integration](template/build/README.md) 56 | * Travis CI 57 | * GitHub 58 | 59 | ## Keeping Bolt projects up-to-date 60 | 61 | "How do I pull down upstream changes from Bolt to my Bolt-generated project?" 62 | 63 | This is a popular question, and it's difficult to answer. 64 | 65 | Bolt is designed as a "starter kit" rather than a "distribution". It intentionally began with a "fork it and forget it" approach to updates. This is largely due to the fact that Bolt generated files are templates that are meant to be customized, and pulling in upstream updates would wipe out those customizations. 66 | 67 | That said, there are components of Bolt that could be treated as dependencies that receive upstream updates. Those components include: 68 | 69 | * Project tasks 70 | * Scripts 71 | * Acquia Cloud hooks 72 | 73 | The ideal approach would be to split each of these into a separate, versioned projects that could be treated as formal composer.json dependencies, but we don't currently have the resources to maintain all of those projects. 74 | 75 | As a stopgap, you can run the following command to pull in upstream updates to specific files and directories in your Bolt generated project: 76 | 77 | `./bolt.sh setup:bolt:update` 78 | 79 | After running, you can review changes via `git diff` and decide what should be committed. 80 | 81 | # License, support, and contribution 82 | 83 | Bolt is provided as an open source tool in the hope that it will enabled developers to easily generate new Drupal projects that conform to Acquia Professional Services' best practices. 84 | 85 | Please feel free to contribute to the project or file issues via the GitHub issue queue. When doing so, please keep the following points in mind: 86 | 87 | * Bolt is distributed under the GPLv3 license; WITHOUT ANY WARRANTY. 88 | * The project maintainers make no commitment to respond to support requests, 89 | feature requests, or pull requests. 90 | * All contributions to Bolt will be reviewed for compliance with Drupal Coding 91 | Standards and best practices as defined by the project maintainer. 92 | * Feature that are part of the [Road Map](https://github.com/acquia/bolt/wiki/Road-Map) 93 | will be prioritized for inclusion. 94 | 95 | Bolt work is currently being tracked in the [Bolt GitHub issue queue] 96 | (https://github.com/acquia/bolt/issues) and organized via a 97 | [Waffle.io Kanban Board](https://waffle.io/acquia/bolt). 98 | -------------------------------------------------------------------------------- /template/readme/code-review.md: -------------------------------------------------------------------------------- 1 | # Code Review 2 | 3 | "How do I perform a code review?" 4 | 5 | This document provides guidance for performing a review of another developer's code. This should occur on GitHub via a Pull Request. See [dev-workflow.md](dev-workflow.md) for information on how to submit Pull Requests, and how they fit into the development workflow. 6 | 7 | > "You just review the code right?" - Tim Holt 8 | 9 | No. Code review is both an art and a science. All code merged into a project should be reviewed. 10 | 11 | In addition to ensuring that the code being reviewed meets the established standards, the code reviewer must consider whether the work is being accomplished in the best way given the project priorities and constraints. 12 | 13 | It is not possible to create an exhaustive list of all things that should be checked in a code review. Rather, we will enumerate the major considerations that a code reviewer should make and include a few high level examples for each: 14 | 15 | * __Purpose and scope__ Does the code do the right things? 16 | * Does the code meet the requirements of the ticket? 17 | * Does the code affect only what needs to be changed for the 18 | scope of the ticket--nothing more or less? 19 | * Is it clear how functional changes can verified? 20 | * __Implementation__ Does the code achieve its goal in the right way? 21 | * Is the code in the right place? 22 | * Does it correctly leverage the correct APIs, variables, etc? Common issues: 23 | * Use of global $language, LANGUAGE_NONE instead of 'und' 24 | * Use of t() 25 | * Does it follow basic code principles? E.g., 26 | * Functions are logically amotic with low cyclomatic complexity 27 | * Logic is being performed at the correct layer. E.g., no logic in the presentation layer. 28 | * Are its components re-usable? 29 | * Verify [best practices](best-practices.md) are being used. E.g., 30 | * Views 31 | * Features 32 | * Configuration updates 33 | * __Code style and standards__ Does the code meet [Drupal coding standards] 34 | (https://www.drupal.org/coding-standards) and stylistic expectations? 35 | * All code has been validated via [Coder](https://www.drupal.org/project/coder) 36 | * Note that Drupal has coding standards for: 37 | * [PHP](https://www.drupal.org/coding-standards) 38 | * [PHP OOP](https://www.drupal.org/node/608152) 39 | * [SQL](https://www.drupal.org/node/2497) 40 | * [JS](https://www.drupal.org/node/172169) 41 | * [Twig](https://www.drupal.org/node/1823416) 42 | * [CSS](https://www.drupal.org/coding-standards/css) 43 | * [HTML](https://groups.drupal.org/node/6355) 44 | * [YML](https://www.drupal.org/coding-standards/config) 45 | * Classes, properties, methods, etc. are named logically and consistently. 46 | * __Security__ 47 | * Consider most popular vulnerabilities: 48 | * [SQL Injection](https://www.drupal.org/node/101495) 49 | * [XSS](https://docs.acquia.com/articles/introduction-cross-site-scripting-xss-and-drupal) 50 | * [CSRF](https://www.drupal.org/node/178896) 51 | * Ensure that Drupal security best practices are being used: 52 | * [D7](https://drupal.org/writing-secure-code) 53 | * [D8](https://www.drupal.org/node/2489544) 54 | * Verify that any contrib modules being added have stable releases and do not have outstanding [security advisories](https://www.drupal.org/security/contrib). 55 | * __Performance__ How does the code impact site performance? 56 | * Code should [implement caching](best-practices.md#caching) whenever possible 57 | * Caution with using `$_SESSION`, which invalidates page cache 58 | * Code should not be needlessly expensive 59 | * Caution with full node/entity loads, particularly in loops 60 | * Use of Entity API, in particular `entity_metadata_wrapper()` as a way to 61 | access and traverse entity properties and fields. Make sure to wrap usages 62 | in `try { ... } catch (EntityMetadataWrapperException $e) { ... }` 63 | * Caution with `hook_init()` and `hook_boot()` 64 | * __Test coverage__ Does the pull request include required [automated tests](../tests/README.md)? 65 | * All application functionality should be covered by a functional test via either Behat or PHPUnit 66 | * All custom libraries should be covered using unit tests via PHPUnit 67 | * __Documentation__ 68 | * Minimum documentation requirements set forth by Drupal Coding Standard should be met. 69 | * The code itself should be correctly self-documenting: [Code Tells You How, Comments Tell You Why](http://blog.codinghorror.com/code-tells-you-how-comments-tell-you-why/) 70 | * Additional user-facing documentation is included where necessary 71 | * Configuration management 72 | * All configuration should be managed in code. Databases are never pushed upstream. 73 | * All required configuration changes should be managed in code via update hooks. In most cases, it should not be necessary for the Release Master to run anything beyond `drush updb` when running a release. 74 | 75 | ## Resources 76 | 77 | * [A Quick Guide for Code Reviews](https://www.lullabot.com/articles/a-quick-guide-for-code-reviews) 78 | * [How to review Drupal code](http://colans.net/blog/how-review-drupal-code) 79 | -------------------------------------------------------------------------------- /template/readme/onboarding.md: -------------------------------------------------------------------------------- 1 | # Onboarding 2 | 3 | Here is a quick-start guide to getting your local development environment set up and getting oriented with the project standards and workflows. 4 | 5 | ## Required SAAS Access: 6 | 7 | Please ask the project's engagement manager for access to the following SAAS services: 8 | 9 | * JIRA 10 | * GitHub repository 11 | * Acquia Cloud subscription 12 | 13 | ## System Requirements 14 | 15 | You should be able to use the following tools on the command line of your native operating system: 16 | 17 | * [Git](https://git-scm.com/) 18 | * [Composer](https://getcomposer.org/download/) 19 | * PHP 5.3.9+ (PHP 5.6 recommended). PHP installation instructions: 20 | * [OSX](http://justinhileman.info/article/reinstalling-php-on-mac-os-x/) 21 | * [Windows](http://php.net/manual/en/install.windows.php) 22 | * [Linux](http://php.net/manual/en/install.unix.debian.php) 23 | 24 | ### Operating Systems 25 | 26 | We highly recommend that you *do not use Windows* directly for development. Many development tools (e.g., drush, gulp, etc.) are not built or tested for Windows compatibility. Furthermore, most CI solutions (e.g., Travis CI, Drupal CI, etc.) do not permit testing on Windows OS. Similarly, Bolt cannot be fully tested on Windows and is unsupported on this platform. 27 | 28 | If you must use Windows, we recommend that: 29 | * You have administrator access to your machine 30 | * You execute the necessary command line functions a bash emulator such as: 31 | * [Git Bash](https://git-for-windows.github.io/) 32 | * [cmder](http://cmder.net/) 33 | * [cygwin](https://www.cygwin.com/) 34 | * Run Bolt inside of a Drupal-VM instance 35 | 36 | ### Networking considerations 37 | 38 | Building project dependencies requires that your local machine make HTTP and HTTPS requests to various software providers on the internet. Please ensure that your local and network level security settings permit this to happen. 39 | 40 | If you need to make requests via a proxy server, please [configure git to use a proxy](http://stackoverflow.com/a/19213999). This will cover all git based requests made by Composer. 41 | 42 | ## Initial Setup 43 | 44 | 1. [Fork](https://help.github.com/articles/fork-a-repo) the primary GitHub repository 45 | 1. Clone your fork to your local machine: 46 | 47 | ``` 48 | git clone git@github.com:username/project-repo.git -b develop 49 | git remote add upstream git@github.com:acquia-pso/project-repo.git 50 | ``` 51 | 52 | 1. Checkout the `develop` branch. `git checkout develop` 53 | 1. Run `composer install` (you must already have Composer installed). 54 | 1. Run `./bolt.sh setup:drupal:settings` This will generate 55 | `docroot/sites/default/settings/local.settings.php` and 56 | `docroot/sites/default/local.drushrc.php`. Update these with your local 57 | database credentials and your local site URL. 58 | 1. Run `./bolt.sh setup`. This will build all project dependencies and install 59 | drupal. 60 | 1. Create and edit your local drush alias file. Copy `drush/site-aliases/example.local.aliases.drushrc.php` to `drush/site-aliases/local.aliases.drushrc.php`. Edit the new alias file with your local path. 61 | 62 | After this initial setup, you should only need to run `./bolt.sh setup:build:all` when composer.json is updated, and `./bolt.sh setup:drupal:install` when you need to reinstall the site. 63 | 64 | For a full list of available project tasks, run `./bolt.sh -l`. See [Project Tasks](project-tasks.md) for more information. 65 | 66 | ### Local Git Configuration 67 | 68 | For readability of commit history, set your name and email address properly: 69 | 70 | git config user.name "Your Name" 71 | git config user.email your-email-address@example.com 72 | 73 | Ensure that your local email address correctly matches the email address for your Jira account. 74 | 75 | ## Updating you local environment 76 | 77 | The project is configured to update the local environment with a local drush alias and a remote alias as defined in `project.yml`. Given that these aliases match, those in `drush/site-aliases/`, you can update the site with Bolt. 78 | 79 | [Local Development Tasks](project-tasks.md#local-tasks) 80 | 81 | ## GitHub Configuration 82 | 83 | In order to more easily identify developers in a project, please be sure to set a name and profile picture in your GitHub profile. 84 | 85 | When working with GitHub, the [hub](https://github.com/github/hub) utility can be helpful when managing forks and pull requests. Installing hub largely depends on your local environment, so please follow the [installation instructions](https://github.com/github/hub#installation) accordingly. 86 | 87 | ## Configure Local Environment 88 | 89 | Please see [Local Development](local-development.md) for detailed information on setting up a local \*AMP stack. 90 | 91 | When you have completed setting up your local \*AMP stack, please have the following information ready and available: 92 | 93 | * The intended local URL of the site 94 | * The local database credentials 95 | 96 | ## Next steps 97 | 98 | Review review the following documentation: 99 | 100 | * [Repository architecture](repo-architecture.md): “how is the code organized, and why?” 101 | * [Running project tasks](project-tasks.md): “how do I _____ on my local machine?” 102 | * [Workflow](dev-workflow.md): “I wrote code, how does it get from here to there?” 103 | * [Automated testing](../tests/README.md): “how do I write / run them, and why should care?” 104 | -------------------------------------------------------------------------------- /template/readme/project-tasks.md: -------------------------------------------------------------------------------- 1 | # Project Tasks 2 | 3 | “how do I _____ on my local machine?” 4 | 5 | * [(re)Install Drupal](#install-drupal) 6 | * [Update dependencies (module, theme, core, etc.)](#update-dependency) 7 | * [Patch a project](#patch) 8 | * [Deploy to cloud](#deploy) 9 | * [Run tests & code validation](#tests) 10 | * [Build frontend assets](#frontend) 11 | 12 | ## (re)Install Drupal 13 | 14 | Pre-requisites to installation: 15 | 16 | 1. Ensure that `docroot/sites/default/settings/local.settings.php` exists by executing `./bolt.sh setup:drupal:settings`. 17 | 1. Verify that correct local database credentials are set in `local.settings.php`. 18 | 1. Ensure that project dependencies have already been built via `./bolt.sh setup:build:all` 19 | 20 | To re-install Drupal, execute: `./bolt.sh setup:drupal:install`. Note that this will drop the existing database tables and install Drupal from scratch! 21 | 22 | ## Update dependencies (core, profile, module, theme, libraries) 23 | 24 | Composer should be used to manage Drupal core, all contributed dependencies, and most third party libraries. The primary exception to this is front end libraries that may be managed via a front-end specific dependency manager, such as [Bower](http://bower.io/) or [NPM](https://www.npmjs.com/). 25 | 26 | ### Contributed projects and third party libraries 27 | 28 | To install or update contributed dependencies or third party libraries, simply update the dependency version(s) in composer.json and run `composer install` or `composer update`. 29 | 30 | All contributed projects hosted on drupal.org, including Drupal core, profiles, modules, and themes, can be found on [Drupal packagist](https://packagist.drupal-composer.org/). Most non-Drupal libraries can be found on [Packagist](http://packagist.com/). For any required packaged not hosted on one of those two sites, you can define your own array of [custom repositories](https://getcomposer.org/doc/05-repositories.md#repository) for Composer to search. 31 | 32 | Note that Composer versioning is not identical to drupal.org versioning. See: 33 | 34 | * [Composer Versions](https://getcomposer.org/doc/articles/versions.md) - Read up on how to specify versions. 35 | * [Drupal packagist site](https://packagist.drupal-composer.org/) - Find packages and their current versions. 36 | * [Drupal packagist project](https://github.com/drupal-composer/drupal-packagist) - Submit issues and pull requests to the engine that runs Drupal packagist. 37 | * [Drupal packagist project](https://github.com/drupal-composer/drupal-packagist) - Submit issues and pull requests to the engine that runs Drupal packagist. 38 | * [Drupal Composer package naming conventions](https://www.drupal.org/node/2471927) 39 | * [Packagist](http://packagist.com/) - Find non-drupal libraries and their current versions. 40 | 41 | ### Drupal core 42 | 43 | To update drupal core: 44 | 45 | 1. Update the entry for `drupal/core` in the root composer.json. 46 | 2. Run `composer update`. 47 | 3. Run `./scripts/drupal/update-scaffold`. This will update the core files not included in `drupal/core`. 48 | 4. Use git to review changes to committed files. E.g., changes to .htaccess, robots.txt, etc. 49 | 5. Add and commit desired changes. 50 | 51 | ## Patch a project 52 | 53 | Please see [patches/README.md](../patches/README.md) for information on patch naming, patch application, and patch contribution guidance. 54 | 55 | ## Deploy to cloud 56 | 57 | Please see [Deploy](deploy.md) for a detailed description of how to deploy to Acquia Cloud. 58 | 59 | ## Run tests & code validation 60 | 61 | Please see [tests/README.md](../tests/README.md) for information on running tests. 62 | 63 | To execute PHP codesniffer and PHP lint against the project codebase, run: `./bolt.sh validate:all` 64 | 65 | ## Build front end assets 66 | 67 | Ideally, you will be using a theme that uses SASS/SCSS, a styleguide, and other tools that require compilation. Like dependencies, the compiled assets should not be directly committed to the project repository. Instead, they should be built during the creation of a production-ready build artifact. 68 | 69 | Bolt only natively supports the [Acquia PS Thunder](https://github.com/acquia-pso/thunder) base theme. 70 | 71 | To install Thunder's dependencies: 72 | 73 | 1. See [Acquia PS Thunder](https://github.com/acquia-pso/thunder) for system requirements. 74 | 1. Execute `/.task frontend:install`. 75 | 76 | To build Thunder's assets, execute: 77 | 78 | `/.task frontend:build`. 79 | 80 | ## Updating you local environment 81 | 82 | The project is configured to update the local environment with a local drush alias and a remote alias as defined in `project.yml`. Given that these aliases match, those in `drush/site-aliases/`, you can update the site with Bolt. Please see [drush/README.md](../drush/README.md) for details on how to create these aliases. 83 | 84 | ### Refresh: Rebuild the codebase, copy the database, and run updates 85 | 86 | This all in one command will make sure your local is in sync with the remote site. 87 | 88 | `./bolt.sh local:refresh` 89 | 90 | ### Sync: Copy the database from the remote site 91 | 92 | `./bolt.sh local:sync` 93 | 94 | ### Update: Run update tasks locally 95 | 96 | `./bolt.sh local:update` 97 | 98 | These tasks can be seen in `build/core/phing/tasks/local-sync.xml`. An additional script can be added at `/hooks/dev/post-db-copy/dev-mode.sh` which would run at the end of this task. 99 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | ## Creating a new project with Bolt 2 | 3 | The following high-level steps will be required to generate a new, fully functioning site using Bolt: 4 | 5 | 1. Ensure your native OS meets minimum requirements 6 | 1. Clone Bolt to your local machine 7 | 1. Generate and modify configuration files for your new project 8 | 1. Use Bolt’s “installer” to generate a new site 9 | 1. Setup a local *AMP stack 10 | 1. Build your new project’s dependencies and install locally 11 | 12 | ## System Requirements 13 | 14 | You should be able to use the following tools on the command line of your native operating system: 15 | 16 | * [Git](https://git-scm.com/) 17 | * [Composer](https://getcomposer.org/download/) 18 | * PHP 5.3.9+ (PHP 5.6 recommended). PHP installation instructions: 19 | * [OSX](http://justinhileman.info/article/reinstalling-php-on-mac-os-x/) 20 | * [Windows](http://php.net/manual/en/install.windows.php) 21 | * [Linux](http://php.net/manual/en/install.unix.debian.php) 22 | 23 | ## Prepare Bolt installer 24 | 25 | * Clone Bolt to your local machine on your native OS: 26 | `git clone https://github.com/acquia/bolt.git` 27 | * From the Bolt repository’s root directory, run `composer install`. This will build the dependencies required for Bolt’s “installer”. 28 | 29 | # Generate and modify configuration files 30 | 31 | From the Bolt repository’s root directory, run `./bolt.sh configure`. This will create your project-specific configuration files. After running, the following files should exist in the Bolt root directory: 32 | 33 | * project.yml 34 | * local.drushrc.php 35 | * local.settings.php 36 | 37 | You will need to open these files and modify their values with settings for your project. At a minimum, you must set the following configuration items: 38 | 39 | * Local site URL: `$options[‘uri’]` in local.drushrc.php 40 | * Local site DB credentials: `$databases` in local.settings.php 41 | 42 | At this point, you likely have not configured your local *AMP stack for your new site. That’s ok. Simply enter the local URL and local DB credentials that you intend to use when your *AMP stack is up and running. 43 | 44 | ## Create a new project 45 | 46 | Bolt’s “installer” will do the following: 47 | * Create new project directory (sibling of the Bolt repository) 48 | * Copies Bolt template files to the new directory 49 | * Replaces tokens in copied files with project-specific strings 50 | * Removes installation artifacts 51 | 52 | Run `./bolt.sh create` to do all the things! 53 | 54 | Once it’s completed, __change directories to your new project directory. All subsequent steps will happen inside your new project. You have left the Bolt repository behind.__ 55 | 56 | ## Modifying project files 57 | 58 | This is an optional step. Important files that you may want to modify include: 59 | 60 | * composer.json. Note that Drupal core, contrib, and third party dependencies are all managed here. 61 | * Project’s root README.md. 62 | * Other project documentation in the readme directory. 63 | 64 | Note that all of the steps from this point forward are the same steps that would be used by a newly onboarded developer setting up your existing project on their local machine for the first time. 65 | 66 | ## Set up your \*AMP stack 67 | 68 | Before building your project dependencies and installing Drupal, you must have a fully functional \*AMP stack on your local machine. Bolt intentionally does not provide this local development environment--that is outside of the scope of Bolt’s intended responsibilities. It does, however, make recommendations for which tools you should use to manage your stack. 69 | 70 | Please see [Local Development](template/readme/local-development.md) for more information on setting up your \*AMP stack: 71 | * [Acquia Dev Desktop](template/readme/local-development.md#using-acquia-dev-desktop-for-bolt-generated-projects) 72 | * [Drupal VM](template/readme/local-development.md#using-drupal-vm-for-bolt-generated-projects) 73 | * [Other](https://github.com/acquia/bolt/blob/8.x/template/readme/local-development.md#alternative-local-development-environments) 74 | 75 | When you have completed setting up your local \*AMP stack, double check that the following pieces of information are still correct: 76 | 77 | * Local site URL: `$options[‘uri’]` in docroot/sites/default/local.drushrc.php 78 | * Local site DB credentials: `$databases` in docroot/sites/default/settings/local.settings.php 79 | 80 | ## Build your project’s dependencies and install Drupal 81 | 82 | Run the following command from the project root: `./bolt.sh setup`. This will do a lot of things for you, including: 83 | 84 | * Building dependencies 85 | * Installing local git hooks 86 | * Generating local.yml for Behat 87 | * Installing Drupal locally 88 | 89 | When this task is complete, you should have a fully functioning Drupal site on your local machine. You can login to the site by running `drush uli`. 90 | 91 | Note that all common project tasks are executed through `bolt.sh` in your project’s root directory. This file simply passes arguments through to Phing, which manages all task automation. For a full list of available tasks, run `./bolt.sh -l`. 92 | 93 | ## Next Steps 94 | 95 | Now that your new project works locally, you’ll want to integrate with with your SAAS tools (GitHub, TravisCI, Jenkins, etc.) and your Acquia Cloud subscription. 96 | 97 | See the following documents for more detailed instructions on those tasks: 98 | 99 | * Configure your CI solution @todo link 100 | * Deploy to Acquia Cloud @todo link 101 | -------------------------------------------------------------------------------- /template/scripts/release-notes/generate-release-notes.php: -------------------------------------------------------------------------------- 1 | example-release-notes.md' . PHP_EOL 6 | . 'example: php generate-release-notes.php github dan:password acquia-pso:test-repo:master 4/10/2014 > example-release-notes.md' . PHP_EOL 7 | . 'example: php generate-release-notes.php stash:stash.client.com dan:password client-project:test-repo:master 4/10/2014 100 > example-release-notes.md' . PHP_EOL . PHP_EOL 8 | . 'note: by default, PRs are gathered from 30 days previous and up to 100 PRs' . PHP_EOL; 9 | exit; 10 | } 11 | 12 | // Parse Service 13 | $service_array = explode(':', $argv[1]); 14 | 15 | $service = array( 16 | 'type' => $service_array[0], 17 | ); 18 | 19 | if (count($service_array) > 1) { 20 | $service['base_path'] = $service_array[1]; 21 | } 22 | 23 | unset($service_array); 24 | 25 | // Set Username / Password 26 | $user_array = explode(':', $argv[2]); 27 | 28 | $user = array( 29 | 'name' => $user_array[0], 30 | 'password' => $user_array[1], 31 | ); 32 | 33 | unset($user_array); 34 | 35 | // Split Project / Repo / Branch into variables. 36 | $repo_array = explode(':', $argv[3]); 37 | 38 | $repository = array( 39 | 'project' => $repo_array[0], 40 | 'repository' => $repo_array[1], 41 | 'branch' => $repo_array[2], 42 | ); 43 | 44 | unset($repo_array); 45 | 46 | // Parse date. 47 | $since = ($argc < 5) ? strtotime('30 days ago') : strtotime($argv[4]); 48 | 49 | // Default to pulling 100 PRs. 50 | $limit = ($argc < 6) ? 100 : $argv[5]; 51 | 52 | // Print the header. 53 | print '# Release notes for ' . date("F j, Y") . PHP_EOL . PHP_EOL; 54 | 55 | // Proceed based on service. 56 | switch ($service['type']) { 57 | case 'github': 58 | process_github(); 59 | break; 60 | 61 | case 'stash': 62 | process_stash(); 63 | break; 64 | } 65 | 66 | function process_github() { 67 | global $repository, $since, $limit; 68 | 69 | // Create a date like 2014-12-23T00:00:00Z. 70 | $since_github = date('Y-m-d', $since) . 'T00:00:00Z'; 71 | 72 | // We can only get 100 results at a time, so we need to split the calls into chunks of 100. 73 | $calls = ceil($limit / 100); 74 | 75 | $url = 'https://api.github.com/repos/' . $repository['project'] . '/' . $repository['repository'] . '/pulls?state=closed&since=' . $since_github . '&per_page=' . $limit . '&base=' . $repository['branch']; 76 | 77 | for ($page = 1; $page <= $calls; $page++) { 78 | 79 | $prs = fetch_pr($url . '&page=' . $page); 80 | 81 | // Print each Pull Request. 82 | foreach ($prs as $pr) { 83 | // We don't want to print PRs that are not merged. 84 | if (is_null($pr['merged_at'])) { 85 | continue; 86 | } 87 | 88 | // Check our date is within the time period. 89 | $closed_date = strtotime($pr['closed_at']); 90 | 91 | if ($closed_date < $since) { 92 | continue; 93 | } 94 | 95 | print_pr_compact($pr['title'], $pr['body'], $closed_date, $pr['html_url']); 96 | } 97 | } 98 | } 99 | 100 | function process_stash() { 101 | global $service, $repository, $since, $limit; 102 | 103 | $url = 'https://' . $service['base_path'] . '/rest/api/1.0/projects/' . $repository['project'] . '/repos/' . $repository['repository'] . '/pull-requests?state=merged' . '&limit=' . $limit . '&at=refs/heads/' . $repository['branch']; 104 | 105 | $json = fetch_pr($url); 106 | 107 | // Print each Pull Request. 108 | foreach ($json['values'] as $pr) { 109 | // Check our date is within the time period. 110 | // Stash uses epoch time with milliseconds. 111 | $closed_date = date($pr['updatedDate'] / 1000); 112 | 113 | if ($closed_date < $since) { 114 | continue; 115 | } 116 | 117 | $link = 'https://' . $service['base_path'] . $pr['link']['url']; 118 | 119 | print_pr($pr['title'], $pr['description'], $closed_date, $link); 120 | } 121 | } 122 | 123 | function fetch_pr($url) { 124 | global $user; 125 | // Download the json file. 126 | $ch = curl_init(); 127 | 128 | curl_setopt($ch, CURLOPT_HEADER, 0); 129 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 130 | curl_setopt($ch, CURLOPT_USERPWD, $user['name'] . ':' . $user['password']); 131 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 132 | curl_setopt($ch, CURLOPT_USERAGENT, 'Acquia-PS'); 133 | curl_setopt($ch, CURLOPT_URL, $url); 134 | 135 | $json_raw = curl_exec($ch); 136 | $chinfo = curl_getinfo($ch); 137 | 138 | // We bail if we don't get a successful connection. 139 | if ($chinfo['http_code'] !== 200) { 140 | print 'HTTP Error: ' . $chinfo['http_code'] . PHP_EOL; 141 | print 'URL: ' . $url . PHP_EOL; 142 | print $json_raw . PHP_EOL; 143 | exit; 144 | } 145 | 146 | curl_close($ch); 147 | 148 | // Decode the JSON. 149 | return json_decode($json_raw, TRUE); 150 | } 151 | 152 | function print_pr($title, $description, $date, $link) { 153 | // Print the PR Title. 154 | print '## ' . $title . PHP_EOL; 155 | // Print the PR Time and URL. 156 | print date("F j, Y", $date) . ' ([' . $link . ']' . '(' . $link . '))' . PHP_EOL . PHP_EOL; 157 | // Print the PR Body. 158 | print $description . PHP_EOL . PHP_EOL; 159 | } 160 | 161 | function print_pr_compact($title, $description, $date, $link) { 162 | $date_formatted = date("F j, Y", $date); 163 | print "* $date_formatted: [$title]($link) \n"; 164 | } 165 | 166 | ?> 167 | -------------------------------------------------------------------------------- /template/readme/dev-workflow.md: -------------------------------------------------------------------------------- 1 | # Development Workflow 2 | 3 | “How do I contribute code to this project?” 4 | 5 | First off, take a moment to review our [Best Practices](best-practices.md)before writing or submitting any code. 6 | 7 | ## Git Workflow 8 | 9 | No direct changes should be pushed to the Acquia repository. The process of syncing these repositories is managed transparently in the background. 10 | 11 | The recommended workflow resembles a [Gitflow Workflow](https://www.atlassian.com/git/workflows#!workflow-gitflow) with the follow specifics - 12 | 13 | * All development is performed against a `develop` branch. 14 | * Completed features are merged into a `release` branch until a new release needs to be made. Additional QA testing should be made against this branch and fixed inline, if needed. 15 | * Each commit to the `master` branch is tagged with a release number, named either based on sprints (e.g. `24.0`) or date (e.g. `2014-08-19.0`). 16 | * Any hotfixes are merged directly into a `hotfix` branch, which can then be merged to `master`. 17 | 18 | ## Beginning work locally 19 | 20 | 1. Pull a ticket in JIRA 21 | 1. Create a new local feature branch named according to the following pattern: 22 | `abc-123-short-desc` Where "ABC" is the Jira prefix of your Jira project and "123" is the ticket number for which the work is being performed. 23 | 1. Make your code changes. 24 | 1. Commit your changes. Each commit should be logically atomic, and your commit messages should follow the pattern: "ABC-123 A grammatically correct sentence ending within punctuation." 25 | 26 | ## Creating a Pull Request 27 | 28 | For any work, pull requests must be created for individual tasks and submitted for review. Before submitting a pull request, be sure to [sync the local branch](https://help.github.com/articles/syncing-a-fork) with the upstream primary branch - 29 | 30 | git checkout develop 31 | git pull upstream develop 32 | git push origin develop 33 | git checkout -b XXX- develop 34 | 35 | If you created many small commits locally while working through a ticket, you should clean the history so that it can be easily reviewed. You can combine these commits using `git rebase`. 36 | 37 | git rebase -i upstream/master 38 | 39 | Pull requests should never contain merge commits from upstream changes. 40 | 41 | Push your feature branch to your fork of the upstream repository, and submit a Pull Request from your-fork/feature-branch to canonical-repo/develop. You may optionally use [Hub](https://github.com/github/hub) to submit your pull request from the command line. 42 | 43 | hub pull-request 44 | 45 | In order to enforce consistency on a project, a pull request template can also be configured using `hub` - 46 | 47 | git config --global --add hub.pull-request-template-path ~/.pr-template 48 | 49 | ## Resolving merge conflicts 50 | 51 | Merge conflicts result when multiple developers submit PRs modifying the same code and Git cannot automatically resolve the conflict. For instance, if two developers add update hooks to the same module at the same time, these will necessarily conflict, because update hooks must be numbered in a defined sequence. 52 | 53 | Developers are responsible for fixing merge conflicts on their own PRs. Follow this process to resolve a merge conflict: 54 | 55 | 1. Fetch upstream history: `git fetch upstream` 56 | 2. Check out the branch against which you opened your PR (e.g. master): `git checkout master` 57 | 3. Make sure it matches upstream: `git reset --hard upstream/master` 58 | 4. Check out your feature branch: `git checkout feature/foo` 59 | 5. Merge master (this is where the magic happens): `git merge master` 60 | 6. At this point, Git will complain about a merge conflict. Run `git status` to find the conflicting file(s). 61 | 7. Edit the files to fix the conflict. The resources at the end of this section provide more information on this process. 62 | 8. Use `git add` to add all of the files you fixed. 63 | 9. Finally, run `git commit` to finish the merge, and `git push origin feature/foo` to update the PR. 64 | 65 | Additional resources: 66 | 67 | - https://confluence.atlassian.com/bitbucket/resolve-merge-conflicts-704414003.html 68 | - https://githowto.com/resolving_conflicts 69 | 70 | ## Integration (merging pull requests) 71 | 72 | Two versions of the integration workflow are recommended - 73 | 74 | 1. Integration manager 75 | 1. Peer review 76 | 77 | **In either workflow, no one should ever commit their own code to the primary working branch.** 78 | 79 | ### Integration Manager 80 | 81 | This model requires one (or more) lead developers to take the responsibility of merging all pull requests. This ensures consistency in quality control as well as identifying any potential issues with related, open pull requests. 82 | 83 | A small group of one or more person(s) is selected to be integrators. All commits are reviewed by this group. If work is done by an integrator, their work should be reviewed by a fellow integrator (as if they were a developer). 84 | 85 | ### Peer Review 86 | 87 | This model removes the bottleneck of designated integrators, but still eliminates commits directly to the working branch. In short, every commit is reviewed by a developer other than the one submitting the original commit. 88 | 89 | ## Continuous Integration 90 | 91 | After a Pull Request has been submitted or merged, our continuous integration solution will automatically build a site artifact, install an ephemeral instance of Drupal, and execute tests against it. For more information on the build process, please see the [build directory](../build/README.md). 92 | 93 | ## Deployment on Cloud 94 | 95 | Once work has been merged on GitHub and tested via the CI solution, a separate production-ready built artifact will be built and deployed to Acquia Cloud. This can be done either manually or automatically. 96 | 97 | Please see [deploy.md](deploy.md) for more information. 98 | 99 | ## Release Process 100 | 101 | A designated Release Master will perform the release to production. This is typically the project’s Technical Architect. See the [Release Process document](release-process.md) for detailed information. 102 | --------------------------------------------------------------------------------