- Date
My weekend release snafu
sna•fu
noun
a confused or chaotic state; a mess.
This past weekend I released v1.2.0 of WPGraphQL.
And 1.2.1, and 1.2.2, and 1.2.3, and 1.2.4, and 1.2.5.
I made some changes to the Github repo that caused deploys to not behave as intended, and to call it a “snafu” might be an understatement.
Plugin distribution
For the first 4 years of WPGraphQL, the plugin was not distributed on the WordPress.org plugin repository, one of the most common distribution channels for WordPress plugins. The plugin has been versioned on Github and primarily distributed on Github and Packagist.org. Users that wanted to install WPGraphQL would either clone the plugin or download the zip from Github, or use Composer to install the plugin from packagist.org.
Vendor Dependencies
Since downloading a Zip from Github was a pretty common way for folks to get the plugin, and I wanted users to be able to download the Zip, install it to WordPress and be immediately productive, without having to run composer commands to install dependencies. So, I made the decision to version the plugins external dependencies in the repository, even against the advice of Composer.
For quite some time the plan was to deploy the plugin to WordPress.org after the v1.0 release, and then stop versioning the Composer dependencies as Github would no longer be the primary method of distribution.
WPGraphQL reached v1.0 in November and has been distributed on WordPress.org since, so I began to work on implementing the plan to no longer version the vendor dependencies in the Git repo.
Github Workflows
I already had a Github Workflow that installed the vendor dependencies and deployed to WordPress.org using the fantastic WordPress deploy action from 10up.
This workflow was in place starting in v1.0 of the plugin.
The workflow installs composer dependencies, then deploys the plugin to WordPress.org.
I was pretty sure that since the Workflow already included the composer install --no-dev
step prior to the deploy action that I was already good to go. All I needed to do was add a new part of the workflow to create a Zip file of the plugin, including the installed dependencies, and upload that compiled Zip to the release as a release asset, so that users that still want to be able to download a zip from Github could do so.
I added that new part of the workflow.
The next step was remove the vendor directory and tell .gitignore
that I no longer want to version that directory. This would allow me and other contributors to install the vendor dependencies while working locally, but not worry about committing them to the repo. So, I updated the .gitignore to ignore the vendor directory.
Broken release!
I released v1.2.0. And shortly after was told that it was breaking things for users.
Users were reporting seeing the following screen:
I checked out the deploy action to see if it failed for some reason.
Updating Deploy Action
Github was reporting that my arguments for the “generate-zip” option on the 10up deploy action were not accurate.
I thought perhaps this was maybe causing something to not work quite right. So I checked the 10up action docs and it appeared this option perhaps wasn’t needed, so I removed the option, re-released, and watched the deploy process.
Still no luck. WordPress.org was missing files.
Aha!
The error that was reported to me made it clear that WordPress.org was excluding the vendor directory from the plugin, but I wasn’t sure why, as the workflow runs composer install
before deploying.
I dug into the code for the 1oup action, and realized that if a .distignore
isn’t present, then tit uses the git archive
command, which ignores files from the `.gitignore` and the `.gitattributes` files.
Aha!
This means that when I added the vendor
directory to the .gitignore
file to stop versioning the directory, the deploy action was leaving that directory out of what gets deployed to WordPress.org. So my step in the workflow that runs composer install
was being nullified by the update to the .gitignore
file.
I did more investigating and found that the 10up action reads the .distignore
file, if it exists. This was the missing piece!
I can use a .gitignore
to ignore files used in local development from being versioned in Git, but separately configure what to ignore for distribution.
So, I added a .distignore
file that ignores a lot of files that are useful for development but are not needed to run the plugin, and I configured this file to NOT ignore the vendor
directory.
Success!
Now the plugin was deploying to WordPress.org with the vendor dependencies.
Fixed! But, still broken.
I had confirmation that installing from WordPress.org was working for users. It was fixed!
But now I was now getting reports that users installing the plugin from Composer, specifically as a dependency of Trellis / Bedrock were running into the same wp_die()
screen that folks reported seeing when installing from WordPress.org where the vendor directory was missing.
So this seemed to mean that installing the plugin from Composer was also excluding the vendor dependencies?
Ooph!
I spun up a Trellis environment locally. It was super easy by the way – I typically use localwp.com for my local WordPress installs, but Trellis made it a breeze to get a local WordPress install running. Kudos to Ben and the other contributors of the project! ????.
From my Trellis-built WordPress environment, I installed WPGraphQL from WordPress.org, and it worked fine. ????
I deleted the plugin and installed from wpackagist (a wordpress specific Composer repository) and it worked fine. ????
But then, I installed the plugin from packagist.org, and I was met with the wp_die()
screen others had reported. ????
Composer Dependencies!
It turns out that Composer installs the dependencies in the vendor directory of the parent project. I knew this, but my brain didn’t want to connect these dots.
This means that this code here was problematic.
Since the vendor directory was previously always installed in the wp-graphql/vendor
directory, as it was versioned with the plugin, the file_exists()
check was always true.
Now that the vendor directory isn’t versioned in the plugin, it can be installed anywhere within the project, so this check isn’t always true anymore.
When installing WPGraphQL from Packagist, the dependencies are not going to be installed in the wp-graphql/vendor
, but instead in the vendor
directory of the project that’s including WPGraphQL as a dependency.
So, I was able to update this part of the code to use the autoload from the WPGraphQL plugin if it exists, which it will when installing from WordPress.org or downloading the Zip from the Github release, and otherwise check for the existence of the dependency class (GraphQL\GraphQL
) to make sure dependencies are installed whether in the plugin or the parent project.
Back in business!
Now, the plugin deploys to WordPress.org fine, can be installed with Composer from WPackagist and Packagist, and follows the recommendation of Composer to not version the dependencies in the Git repo.