If you’re like me, your first experience pushing files onto a web server were either through a web-based file manager like cPanel or a File Transfer Protocol (FTP) client like Transmit or Filezilla. Connect to the server, drag your file(s) over, and wait for the transfer to complete.
However, as soon as I started working with anything more complex than static HTML files, deploying my code became far more complex: what happens if I miss a file that’s required by others, or a semicolon in a global include and it white-screens the whole site? What if a crucial step gets missed during the process?
These “cowboy-coding” issues only get worse as more people, environments, and dependencies get involved. As a result, it gets harder and harder to keep making progress while juggling all of these moving parts. Worst of all, releasing code becomes a big deal and a constant source of anxiety.
As our applications, sites, and stores become more modernized, we should be modernizing our deployments, too. From version control to continuous delivery, a modern release process can relieve anxiety around deployments.
Tracking Changes With Version Control
The first step in moving away from ad-hoc updates and cowboy-coding is by getting your site under version control, using a tool like Git.
Using version control means that you’ll be able to see what has changed, who made the changes, and even work on multiple sets of changes at the same time by using branches. As a result, work isn’t being overwritten and any conflicts between files are clearly highlighted.
If you haven’t worked with Git before, have no fear: we’ve written both an introduction to Git as well as a post about more advanced Git workflows.
Deciding What to Track
As we move our site under version control, what we don’t keep track of is almost as important as what we do:
For example, if you’re using a CSS preprocessor like Sass, the generated CSS files should not be tracked under version control. Not only are they easily reproducible, they are difficult to read and a common source of merge conflicts when multiple developers are involved.
When it comes to dependencies (libraries, WordPress plugins, etc.), take advantage of tools like Composer and WPackagist rather than bundling code that you aren’t responsible for in your repository.
Additionally, a Git repository should never contain things like passwords, private SSH keys, or any other confidential information that would be considered secrets, as every developer with a copy of the repository would then have that sensitive information on their computers.
Structuring Your Repository
When setting up a Git repository for a WordPress or WooCommerce site, it’s generally best to treat wp-content/ as the root of the repository, since you generally won’t be touching files above this directory.
We have a free repository template available on GitHub to get you started.
An introduction to CI/CD
When it comes to deploying software, there are two important terms to understand: Continuous Integration (CI) and Continuous Delivery (CD).
These two terms are closely related, so much that they’re often referred to collectively as “CI/CD”, and the path through which our changes flow thus becomes the “CI/CD pipeline”. This pipeline usually takes the following form:
- Build the release: install dependencies (Composer, npm, etc.), then build artifacts (Webpack, Grunt, Sass, etc.)
- Test the build: run unit tests, check coding standards, perform static code analysis, etc.
- Deploy the release to one or more environments
Continuous Integration is the process of continuously testing our code to ensure that changes do not break existing functionality, so that our new changes cleanly integrate with the existing codebase. Anytime new changes are pushed, checks are run to ensure we’re not “breaking the build”.
In order for continuous integration to be useful, these checks must be automated. For example, if you have a suite of unit tests, you may choose to run this test suite every time a new pull request is opened, alerting you to possible breakages before code lands in production.
Continuous integration isn’t limited to unit tests, however, as there are a number of “code-free” checks that can be run automatically against your code, including:
- Coding standards checks (PHP_CodeSniffer, PHP Coding Standards Fixer)
- Static code analysis (PHPStan, Psalm)
Running these checks automatically on every push also ensures that all code is being run through the same checks, preventing code that doesn’t pass from getting released.
Continuous Delivery, on the other hand, is the idea that we should be able to “deliver” (deploy) our code at any given moment. In order to accomplish this, we must have a scripted deployment process that, with the click of a button, will seamlessly move our code into production.
Having your deployments scripted means that you can deploy both regularly and consistently; every deployment should work the same as the one before it. As a result, your team can deploy more regularly with a higher level of confidence and fewer worries that someone missed a step along the way. For some teams, it’s not uncommon to deploy dozens (or even hundreds) of times a day!
Depending on your site, you may even want to look into “the other CD”, Continuous Deployment; it’s very similar to continuous delivery, but under this model every push to a branch gets deployed automatically. This can be extremely powerful when using a branched version control scheme (such as Github Flow), but may be undesirable if you need to schedule release windows or do all work in the main branch.
Deploying a WordPress or WooCommerce Site With CI/CD
Now that we have a grasp of the basic terminology, let’s take a look at deploying a typical WordPress or WooCommerce site:
For this exercise, we’ll be using Branch, a CI/CD tool designed around the needs of WordPress developers from the same folks behind WP Pusher. Best of all, Branch has built-in support for deploying to Nexcess!
To get started, sign up for Branch by connecting your GitHub, GitLab, or Bitbucket account, then creating your first site.
Next, we’ll want to configure all of the steps necessary to build our site. Branch offers a number of “recipes” for common actions (installing Composer dependencies, running Webpack, etc.), but also gives us the ability to add any number of custom steps.
Once we’ve outlined the steps necessary to build our site, we can move onto the next stage of our pipeline: testing.
If you have an automated test suite for your site already, you can simply tell Branch to run whatever commands are necessary. Even if you don’t already have tests, Branch makes it a breeze to add in linting, coding standards, and compatibility checks.
Now that we’ve installed our dependencies, built everything, and passed our tests, it’s time to get our code into production!
Branch contains recipes for deploying to Nexcess (as well as other major hosting providers), and connecting the two platforms is painless:
- Select your site in the Branch dashboard, click “Settings”, then grab your Branch site’s public SSH key
- Add this public key to the list of keys within the Nexcess portal
Once Branch is able to communicate with your Nexcess site, we can select the “Nexcess” deployment recipe and fill in a few details:
- The hostname and username for the site (available via the Nexcess portal on your site’s “Access” screen)
- The web root that we’re deploying to. If our git repo is meant to serve as the wp-content/ directory, this value should be “public_html/wp-content”.
- The files we wish to deploy (generally the default, “*”, is sufficient)
- The git branch to deploy to this environment
The “Git branch” setting is especially important, as this lets you specify different deployments for different branches. For example, you might have a “staging” branch that deploys to your staging environment, letting you test changes before making them live.
It’s worth noting that Branch uses the continuous deployment model by default, where the pipeline runs with each push to the given branch. If you would prefer more of a continuous delivery model (where some manual action must be taken), you might consider maintaining a “production” branch that only gets merged into when you’re ready to release.
At this point, Branch should be configured to build and deploy your git repository to Nexcess! You may trigger your first deployment either by clicking the “Run Deployment” button on your site’s “Pipelines” page or by pushing to your Git repository.
Customizing Your Release Process
One of the really nice features of Branch is the ability to configure additional steps after a successful deployment, such as automatically clearing your site’s object cache after a deployment. This can be accomplished using the WP-CLI recipe under “Other."
The host and username will generally be the same as we used in the deployment step, and you can chain as many commands as necessary.
If you’re still struggling with cowboy-coding antics and/or anxiety-riddled releases, take a look at Branch and make deployments a breeze!