One of the most common requests / questions we get is to support CI/CD for multisite codebases. This comes up regularly for our customers who have Site Factory (or are running / considering multisite on Acquia Cloud). It's a non-trivial problem to solve for sure. Thankfully, there are some best practices that I can recommend to get you up and running in no time.
Multisite in General
Multisite is a fascinating paradigm in the Drupal world. I wrote about it a couple of years ago on my personal blog. The bottom line, is that Multisite gives you some significant advantages when it comes to managing more than one site. BUT with those advantages come the potential for immense pain if you do not follow proper governance and configuration best practices. If you want to have a hundred different sites that all look different, have different / bespoke capabilities, target different audiences, and fundamentally do different things, then multisite probably isn't a great fit for you. Why? Well, multisite is at its core the reusing and sharing of a common codebase to enable common functionality across a shared set of sites. This doesn't mean they all have to "look exactly the same" or do "exactly the same thing." But the more ubiquitous you can make a multisite platform the easier it is to build, manage, and maintain (that's for sure). And I can say with absolute certainty that some of the most challenging engagements I worked on while on Acquia's professional services team involved customer multisite codebases that had been built with no governance or configuration management strategies in place.
Introduction to Multisite in CI/CD
Why did I give the above background? It has a direct impact on your ability to use a CI/CD tool with a multisite codebase. Let's get into that topic next.
If all you want is a pipeline that can build out your hosting artifact, it doesn't really matter if you're using Acquia Cloud or Acquia Site Factory. The underlying codebase is virtually identical and Code Studio will automatically build the necessary hosting artifact regardless. So if that's your underlying goal, you're already good to go!
However, if you want Code Studio to actually install Drupal, testing your features, and help validate that the new code change you made isn't going to break your site(s)--which by the way is HIGHLY recommended and one of the major value propositions of Code Studio--then we need to think a little bit more about the multisite implications.
Out of the box, Code Studio will install one Drupal site and test that site. At face value, that may not sound terribly useful if you have seventy-five sites in your Site Factory instance. I would argue the contrary though. You don't necessarily want to have to wait for Code Studio to install seventy-five different instance of Drupal, run seventy-five configuration imports, run seventy-five different test suites, etc. That would take hours for every code change.
This is where multisite strategy (and governance) really come into play. If you have a multisite codebase that has a (mostly) ubiquitous set of features, that means that most of the sites on your codebase will share the same features. It's even better if you can say with a straight face that "if a site uses a given feature, it works the same way as all the other sites that use the same feature." Sure, you may have sites that don't use Feature X, but any that do use it exactly the same way. Why? It's a ton easier to maintain and test.
Example: Hero Banner Block
Let's imagine that you have built out a hero banner block that some percentage of your sites use (but not all). This block can be either a static banner or a rotating carousel depending on how much media is placed in it. The block receives slightly different styling and different icons depending on the theme, but the baseline configuration for the block (including the fields for the block config entity and the content layouts the block is placed into by default) are the same everywhere.
Since everything uses the block in the same way, I can write a single set of tests for this feature. I can provide some default content for this feature. And I can test it exactly once and have a high degree of confidence that it will pass/fail appropriately. Why? I don't need to test 30 variations of the same thing (if it's used on thirty sites). If it works once and it's the same, it will work everywhere. If it fails once and it's the same, it will fail everywhere.
Building out a Testing Platform
If we apply this practice across your multisite platform, what we will end up is something I call a "representative site." The goal is to have your "default" site in Code Studio pull in content and features from across your platform. What you will end up with may be a fictional site (it may contain content and features that do not really exist together in the wild) but it will still be representational of your platform and give you a high degree of confidence that the features in your platform are functional.
In the past I've heavily relied on a few contributed modules to make this work:
- Default Content: this module allows you to export real content into code in a module. When you enable the module, the content is automatically created / imported into the site.
- Config Split: this module allows you to define environment specific config splits. I use config split to define a test split (to be only used inside my CI/CD environment) and I enable my custom module that contains all of my default content. This supercharges my ability to test features because not only is the configuration present, but so is content.
If you don't already have a configuration management strategy in place in your codebase, I'd do some background reading on the topic as it will make your life a lot simpler.
The biggest implication of doing the representative site approach is that your developers will need to ensure that any new features that are built are represented. This shouldn't be a difficult thing to do, but it may be a subtle change in workflow.
Really, what we're doing is changing the thinking to be about testing "features" as opposed to testing "specific sites" or applications of a feature. Its not that significant of a deviation, but it may require different thinking.
To get started with Multisite / Site Factory in Code Studio, you first need to make sure you can work with a multisite codebase outside of Site Factory. This could be done locally using Lando / DDev / etc. or in Cloud IDE (although Cloud IDE currently has some limitations with regards to multisite compatibility).
Once you have your codebase working, it's time to start building out your default site. You want to make sure that a
drush site-install will result in the your representational site. In this case, I would use my custom module that I wrote for testing (see https://github.com/Drupal4Gov/Drupal-GovCon-2017/tree/develop/docroot/modules/custom/capitalcamp_testing as an example of this) to enable all of the various features I need on the site. From here, then it's a matter of writing your tests against the representative site to ensure things are functioning the way you want. I often use behat, but phpunit, nightwatch, or your favorite test suite should work fine.
At the end of the day, most of the challenges of testing a multisite platform come down to challenges with Drupal multisite. Code Studio is well equipped out of the box to support your needs, but you will need to do some careful planning on how best to implement the approach. While you can certainly customize the Code Studio (or any other CI/CD) build to do multisite site installs, this will slow down your build process exponentially and may not serve you well in the long-haul. Remember, if you're testing in a site-specific context (as opposed to a feature context) it's very possible you will miss bugs/problems because you're simply looking in the wrong place.