Automating our Drupal site relaunch

Recently, our unit relaunched one of our news websites current. it. psu.edu as news. it. psu.edu. With the relaunch came a new branding, a new responsive layout, as well as significant changes to the structure of our articles. Managing changes like these isn’t the easiest thing in the world to do. Here is an overview of the approach we took and how we automated our relaunch.

Starting over

The first thing that we discussed was the option of rebuilding the website from scratch and importing content from the old website. Truth be told, I actually prefer this method in many scenarios. I think that it’s an opportunity to evaluate all aspects of the website that can be improved upon. No website is 100% perfect, there are always things that you wish you could do differently and starting from scratch is certainly a way of tackling those issues easily.

When we made the jump from Drupal 6 to Drupal 7 on current. it. psu.edu, it was a no brainer for us to start from scratch rather than dealing with the upgrade path. At the time, there were a number of issues with the content administration portion of the site that needed fixed so it made sense to start fresh.

In the end, we determined that we couldn’t afford a lengthy rebuild and that we would just deprecate some of the old features of the site as best we could. This left some cruft for us that we will have to deal with later but it allowed us to stay on schedule.

Git

Our team uses a semi Git-Flow model(http://nvie.com/posts/a-successful-git-branching-model/) when developing code. We usually have a master and develop branch, each with its own server. Knowing that the relaunch was not our only focus and that it would probably span across weeks or possibly months, we decided to create a release branch called “itnews” and gave it its own development site on our server; that way we could still make any changes to the current. it. psu.edu site without interfering with code related to the relaunch and at any time our staff could see how the changes were coming along.

Github

As the project got closer to the deadline, we were getting a little overwhelmed with the todo lists in Basecamp. It was difficult to categorize and prioritize them, even for our small team. Github had just revamped their “Github Issues” so we started using that. We created a milestone called “IT News Relaunch” and began porting our todo’s from Basecamp into Issues and tagging them with the new milestone. This made tracking bugs and collaborating on changes MUCH easier.

By adding the issue number in our git commits we could see exactly each others progress and allowed us to collaborate with our designer more effectively. If our designer created an issue called “ISSUE #34: Make header semi transparent on homepage”, I could make the changes in code, with a commit message that said, “Made header transparent on homepage when above an image.#34”. That commit would then be displayed on issue #34 page. I could then include a screenshot of the new header in the issue page where our designer could approve it or give me feedback. If he were to approve it, I could close out the issue and it would update our progress on the “IT News Relaunch” milestone.

Features

We’ve been using features to manage configuration changes since the beginning. Although features comes with it’s own set of headaches, it’s really the only way to track significant configuration changes so that they can be shared with other developers and applied to existing sites. If our changes were managed by features, we knew that we could run ‘drush features-revert -all’ each time we did a ‘git pull’ and see any changes each other had made on the site.

Our methodology for features is each new content type or new ‘section’ of a website gets it’s own feature, as well as a few miscellaneous ones. This allowed the other developer and me to work on different portions of the site without stepping on each others toes. If you can minimize merge conflicts in git it will make your life a lot easier.

Update Hooks

While features was helping us with the configuration management, we needed help moving content around. In our Article content type we were deprecating an old ‘summary’ body field in favor of a new ‘Deck’ text field. For this we decided it would be easiest to write a custom update hook.

We decided to create a module called itnews_relaunch that would only be used during the transition period and disabled after the relaunch was complete. Here is the code that was in the module:

/**
 * Implements hook_install().
 * 
 * Move content from the deprecated ‘summary’ field
 * to the new ‘deck’ field.
 */
function itnews_launch_install() {
  $query = new EntityFieldQuery();
  $query->entityCondition(‘entity_type’, ‘node’)
    ->entityCondition(‘bundle’, ‘article’)
    ->fieldCondition(‘field_article_summary_sentence’, ‘value’, ”, ‘!=’);
  $result = $query->execute();
  if (isset($result[‘node’])) {
    $news_items_nids = array_keys($result[‘node’]);
    $news_items = entity_load(‘node’, $news_items_nids);
  }
  foreach ($news_items as $key => $item) {
    $summary = $item->field_article_summary_sentence[‘und’][0][‘value’];
    $summary_plaintext = drupal_html_to_text($summary);
    $nodewrapper = entity_metadata_wrapper(‘node’, $item);
    $nodewrapper->field_article_deck->set($summary_plaintext);
    $nodewrapper->save();
  }
}

In this case, since it was a brand new module, our custom code had to reside in an install hook instead of an update hook. In retrospect we probably should have used an update hook in an existing feature or module so that we could ensure that the code would never be run again.

Drush

The real key to this whole process was Drush. I’m not exaggerating when I say that I can’t imagine managing a transition of this complexity without Drush. In addition to the usual development drush script that runs every time we pull the production database down to our development enviroments (which enables development features, sets up stage file proxy, and disables our single sign-on modules) we also added a “launch.sh” bash file. The last thing that you want as a developer is to be concerned with the actual launch process, you want that to be as automated as possible. You don’t want to find yourself in the position of troubleshooting a white screen on a live site post launch; it just ruins your weekend.

We boiled down our entire relaunch into a set of Drush commands inside of a bash script. This was our launch.sh file:

drush updatedb -y
drush fr-all -y
drush en itnews_images -y
drush en itnews_video -y
drush en itnews_asidebox -y
drush en itnews_theme -y
drush en itnews_context_layouts -y
drush en textbook_editor -y
drush en itnews_viewmodes -y
drush en itnews_aurora -y
drush vset –yes theme_default itnews_aurora
drush vset –yes site_frontpage “it-news-homepage”
drush fr-all -y
drush updatedb -y
drush en itnews_launch -y
drush cc all

As we added new features in our Drupal code, we would add them to our Drush list. Things we needed to change in the database but didn’t want to track them in features would be added as drush commands. Having this file at our disposal allowed us to pull down the production database to our dev server and simulate a relaunch by running this script.

Launch Day

Because we utilized Drush and Features to do the heavy lifting, launch day was about as smooth as you can get.

After looking at our analytics we decided relaunch on a Saturday morning, website traffic is typically down and it would give us enough time to work through any issues by Monday when traffic spiked again.

Saturday morning I finished up the last of the Github issues that were in the “IT News Relaunch” milestone(it felt good to see the full 100% completed meter next to the milestone), did one final test on the dev server, merged the “itnews” branch into master, put the website into maintenance mode, did a ‘git pull’ on the live server, ran ‘bash launch.sh’, and walked away. Watching the code do all the work for me was wonderful. I sat there with my coffee and listened to music.

After a few minutes the script was complete. I took the website out of maintenance mode and visited the site on a few different browsers to make sure everything was ok. Sure enough it was perfect.

Feedback

So what do you think? Is there anything that you use that makes this process run more smoothly? I’m constantly chasing that automation dragon :)