<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: mattbloomfield</title>
    <description>The latest articles on DEV Community by mattbloomfield (@mattbloomfield).</description>
    <link>https://dev.to/mattbloomfield</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F287180%2Fd9f46f28-9a78-4697-b743-ef52da618d71.jpeg</url>
      <title>DEV Community: mattbloomfield</title>
      <link>https://dev.to/mattbloomfield</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mattbloomfield"/>
    <language>en</language>
    <item>
      <title>CraftCMS &amp; Docksal: A Local Dev Match Made in Heaven</title>
      <dc:creator>mattbloomfield</dc:creator>
      <pubDate>Fri, 02 Apr 2021 15:25:02 +0000</pubDate>
      <link>https://dev.to/mattbloomfield/craftcms-docksal-a-local-dev-match-made-in-heaven-35nl</link>
      <guid>https://dev.to/mattbloomfield/craftcms-docksal-a-local-dev-match-made-in-heaven-35nl</guid>
      <description>&lt;p&gt;If you've ever joined a new team you know the pain it can be to get a project successfully running locally on your machine. Without Docker there will be an untold number of non-documented configurations and it will inevitably take days to complete your setup. With docker, future updates can be complex and difficult with a myriad of options you don't need. &lt;/p&gt;

&lt;p&gt;Having recently found myself in this conundrum I decided to find ways to make local development easy to setup and easy to maintain. After a search across various solutions, Docksal was the clear winner. &lt;/p&gt;

&lt;p&gt;If you're not familiar with it, &lt;a href="https://docs.docksal.io/getting-started/"&gt;Docksal&lt;/a&gt; allows you to simply and easily setup a dockerized, orchestrated environment without ever having to deal with docker compose. In addition, their CLI container comes pre-installed with many of the tools you will need to run common CMSs on popular hosting platforms.&lt;/p&gt;

&lt;p&gt;In my case, I am using platform.sh for hosting. Platform.sh is a non-opinionated linux hosting solution that essentially gives you yaml-based configuration to spin up new environments and works seamlessly with git to spin up new environments for PRs and branches. Docksal has &lt;code&gt;platform&lt;/code&gt;, Platform.sh's CLI, pre-installed so it works great out of the box. &lt;/p&gt;

&lt;p&gt;Docksal also has a CLI, &lt;code&gt;fin&lt;/code&gt;, which is easily customizable to suit your needs. &lt;/p&gt;




&lt;h1&gt;
  
  
  Basic Setup
&lt;/h1&gt;

&lt;p&gt;Our setup uses MySQL 5.7, Redis, &amp;amp; PHP 7.4. &lt;/p&gt;

&lt;p&gt;To get started using docksal create a &lt;code&gt;.docksal&lt;/code&gt; directory at the root of your CraftCMS repo. Within it you'll need a &lt;code&gt;docksal.yml&lt;/code&gt; and &lt;code&gt;docksal.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Docksal comes standard with three containers: A database, a web server, and a CLI. You can specify which versions of PHP, MySQL, etc. within your docksal.env. To add new services, use your docksal.yml.&lt;/p&gt;

&lt;p&gt;Here is a simple docksal.env. Any variable created here will be accessible within your &lt;code&gt;cli&lt;/code&gt; container and within any custom commands you write.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .docksal/docksal.env&lt;/span&gt;

&lt;span class="c"&gt;# Run `fin restart` anytime you change these values&lt;/span&gt;

&lt;span class="nv"&gt;PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"project_name"&lt;/span&gt;

&lt;span class="c"&gt;# Docksal Defaults&lt;/span&gt;
&lt;span class="nv"&gt;DOCKSAL_STACK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default
&lt;span class="nv"&gt;DOCROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"web"&lt;/span&gt;
&lt;span class="nv"&gt;DB_IMAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"docksal/mysql:5.7"&lt;/span&gt;
&lt;span class="nv"&gt;CLI_IMAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"docksal/cli:php7.4"&lt;/span&gt;
&lt;span class="nv"&gt;COMPOSER_DEFAULT_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2

&lt;span class="c"&gt;# Platform.sh&lt;/span&gt;
&lt;span class="nv"&gt;HOSTING_PLATFORM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;platformsh
&lt;span class="nv"&gt;HOSTING_SITE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxxxxxxxxx
&lt;span class="nv"&gt;HOSTING_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production

&lt;span class="c"&gt;# MySQL&lt;/span&gt;
&lt;span class="nv"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'db_name'&lt;/span&gt;
&lt;span class="nv"&gt;MYSQL_PORT_MAPPING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'33061:3306'&lt;/span&gt;
&lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"root"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is a simple docksal.yml that brings in redis as a service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .docksal/docksal.yml&lt;/span&gt;

&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.1"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wodby/redis:4.0&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_MAXMEMORY=256m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case we use S3 for asset storage, so I'm leveraging the AWS CLI in my cli container. To pass the environment variables into the cli container I add this to my &lt;code&gt;docksal.yml&lt;/code&gt; under &lt;code&gt;services&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="s"&gt;cli&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You probably also have secrets you don't want committed to your repository because they are either sensitive or personalized. For that you can use a &lt;code&gt;docksal-local.env&lt;/code&gt;. Add this to your &lt;code&gt;.gitignore&lt;/code&gt; and use it just as you use the previous file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .docksal/docksal-local.env&lt;/span&gt;

&lt;span class="c"&gt;# Run `fin restart` anytime you change these values&lt;/span&gt;
&lt;span class="nv"&gt;SECRET_PLATFORMSH_CLI_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nv"&gt;DEV_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nv"&gt;INTERNAL_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nv"&gt;DB_PW_STAGING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nv"&gt;DB_PW_PROD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="c"&gt;# note how these are used in the yml above&lt;/span&gt;
&lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="c"&gt;# note how these are used in the yml above&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have your configuration intact, go ahead and run &lt;code&gt;fin project start&lt;/code&gt;. &lt;code&gt;fin&lt;/code&gt; is the Docksal CLI and is quite powerful. &lt;/p&gt;

&lt;p&gt;If you are going my route of using AWS for asset storage, you'll also want to add a &lt;code&gt;.docksal/services/cli/startup.sh&lt;/code&gt; script to install the AWS CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .docksal/services/cli/startup.sh&lt;/span&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;awscli &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;groff &lt;span class="nt"&gt;-y&lt;/span&gt;
aws configure &lt;span class="nb"&gt;set &lt;/span&gt;region us-east-1 &lt;span class="nt"&gt;--profile&lt;/span&gt; default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anytime you make changes to your configuration files you can run &lt;code&gt;fin restart&lt;/code&gt; to restart your containers. If you make changes to the images referenced you may need to run &lt;code&gt;fin project reset &amp;lt;container&amp;gt;&lt;/code&gt; e.g. &lt;code&gt;fin project reset cli&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Commands
&lt;/h2&gt;

&lt;p&gt;This is all fine and dandy, but the real magic comes in the form of custom commands. We use these ALL THE TIME. &lt;/p&gt;

&lt;p&gt;Go ahead and create a &lt;code&gt;commands&lt;/code&gt; directory under &lt;code&gt;.docksal&lt;/code&gt;. Any file you place in this directory will be a new command that &lt;code&gt;fin&lt;/code&gt; can run. &lt;/p&gt;

&lt;p&gt;You can pretty much use any language to write these commands, but I have stuck with bash for now. &lt;/p&gt;

&lt;p&gt;One example could be to have an &lt;code&gt;init&lt;/code&gt; command that gets docksal running, then installs composer and npm dependencies within the CLI container. Note that these commands will not be dependent on your local npm/composer installs but on what exists in the cli container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .docksal/commands/init&lt;/span&gt;

&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nv"&gt;BLUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;x1B[34m
&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;x1B[33m
&lt;span class="nv"&gt;GREEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;x1B[32m
&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;x1B[31m
&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;x1b[0m

&lt;span class="c"&gt;## Removes any previous containers this preject may have created, then starts and executes npm install/composer install&lt;/span&gt;
&lt;span class="c"&gt;## Usage: fin init&lt;/span&gt;

&lt;span class="c"&gt;# Forces whole job to error on failure&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;REMOVING ANY OLD CONTAINERS&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
fin project &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;STARTING PROJECT CONTAINERS&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
fin project start

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;RUNNING NPM INSTALL&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
fin &lt;span class="nb"&gt;exec &lt;/span&gt;npm &lt;span class="nb"&gt;install

echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;RUNNING COMPOSER INSTALL&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RESET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
fin &lt;span class="nb"&gt;exec &lt;/span&gt;composer &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most useful of these commands is probably the &lt;a href="https://gist.github.com/mattbloomfield/08ae5d8bda27672b3205b2ad3df5d085"&gt;&lt;code&gt;setup&lt;/code&gt; command which allows new devs to get up and running within minutes&lt;/a&gt;. It leverages a lot of the jobs below.&lt;/p&gt;

&lt;p&gt;Other custom commands I have written and use often: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://gist.github.com/mattbloomfield/92103e409a5d6f6ea8105be641d3ae6b"&gt;Sync Database &amp;amp; Files from Remote (with local asset strategy)&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/95cd9e65382f98a9412d93b81df0b318"&gt;Dependent on this sync_files job&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/e20c86edd61a745723343e123667f3a5"&gt;Sync Database &amp;amp; Files from Remote (with AWS S3 asset strategy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gist.github.com/mattbloomfield/91dad103676742833575fb887617e5a3"&gt;Sync Database &amp;amp; Files between Remotes (with local asset strategy&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/271112ae2de1dcdb5585e5fd14d55f94"&gt;Dependent on this push_files job&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/4a1ab88a13bdf98860753caf1a0500b5"&gt;Sync Database &amp;amp; Files between Remotes (with AWS S3 asset strategy)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/a1c65b525633916ba51c5c82bd599b9a"&gt;Livestream Logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/5ad494843f647b3dfa6582a222db8dda"&gt;Replicate a Deploy Locally&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/7d8f61e4f40f4e9d1ec065d2a8a9bc14"&gt;SSH into Platform Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/cf80a3e3487651e04dd7305ca8e8562d"&gt;Dump Local Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/ac893e54ba897a643ff2ecd11468c6ce"&gt;Activate Custom Git Hooks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We use a lambda function to store our local .env file for CraftCMS since it can securely hold secrets. We then request it using a custom command and secure key - basically minimizing the number of tokens we are passing around in Slack/Email. This custom command is found here: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mattbloomfield/1fd8ad143e5b5f394ac7fe061cf5f74d"&gt;Refresh Local .env&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the &lt;a href="https://gist.github.com/mattbloomfield/b037cad5b341c8cd51e4bacb20f9ef1a"&gt;node.js-powered Lambda Function is here&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Accessing the CLI container
&lt;/h2&gt;

&lt;p&gt;Sometimes you need to ssh into the CLI container to run certain things, e.g. craft commands like &lt;code&gt;php craft db/migrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This can be done using the &lt;code&gt;fin bash&lt;/code&gt; command. &lt;/p&gt;

&lt;h2&gt;
  
  
  Platform.sh Token confusion.
&lt;/h2&gt;

&lt;p&gt;It's always best to run platform commands within the CLI container. This is done by prepending the command with &lt;code&gt;fin&lt;/code&gt;. This is because the CLI container comes pre-installed with the &lt;code&gt;platform&lt;/code&gt; CLI. If it prompts you to log in, &lt;a href="https://docs.platform.sh/development/cli/api-tokens.html"&gt;generate an API token&lt;/a&gt; and store it in your &lt;code&gt;.docksal/docksal-local.env&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;And there you have it! You're all ready to start developing on CraftCMS using Docksal to supercharge your local setup. &lt;/p&gt;

&lt;p&gt;If you like this approach let me know in the comments! If you've found something better, let me know that as well. &lt;/p&gt;

</description>
      <category>craftcms</category>
      <category>platformsh</category>
      <category>docker</category>
      <category>setup</category>
    </item>
    <item>
      <title>Automating CraftCMS Database Backups on Platform.sh</title>
      <dc:creator>mattbloomfield</dc:creator>
      <pubDate>Fri, 02 Apr 2021 13:10:05 +0000</pubDate>
      <link>https://dev.to/mattbloomfield/automating-craftcms-database-backups-on-platform-sh-4k22</link>
      <guid>https://dev.to/mattbloomfield/automating-craftcms-database-backups-on-platform-sh-4k22</guid>
      <description>&lt;p&gt;Congrats, you just released your very first CraftCMS site. Great! You're done! &lt;/p&gt;

&lt;p&gt;Wait... you forgot to setup backups! Of course, some hosting providers take their own database snapshots; but often they are inaccessible except in case of catastrophic issues. What if you just want to jump back a day or week and know what's going on. &lt;/p&gt;

&lt;p&gt;Well fortunately for us, it's not difficult to setup database backups on our own. &lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;To setup backups there are three things you'll need: 1) Some type of CRON system; 2) A computing server that will run shell scripts; 3) A storage location. &lt;/p&gt;

&lt;p&gt;In my case I'm going to use Rundeck for CRON, a standard Linux server for compute, and Amazon S3 for storage. You can adapt from there, however. &lt;/p&gt;

&lt;h2&gt;
  
  
  Storage Location
&lt;/h2&gt;

&lt;p&gt;We're going to start at the end and work backwards here. If you're using S3, jump into the AWS Console and create a new bucket for CraftCMS backups. &lt;/p&gt;

&lt;p&gt;Be sure to keep it as a private bucket or else anyone could access your database backups of potentially private information. &lt;/p&gt;

&lt;p&gt;You may &lt;a href="https://aws.amazon.com/blogs/aws/archive-s3-to-glacier/"&gt;also want to enable Glacier&lt;/a&gt; as well to limit your costs. I typically push backups to glacier after a week. &lt;/p&gt;

&lt;h2&gt;
  
  
  Compute Server
&lt;/h2&gt;

&lt;p&gt;Now let's write your script! &lt;a href="https://gist.github.com/mattbloomfield/2162d281063a72afa2942e35e88f04a6"&gt;I've posted mine here&lt;/a&gt; for you to copy if you'd like. The main point here is to SSH into the location and export the database, save it locally, then push it to S3. &lt;/p&gt;

&lt;p&gt;If you're using my script - you'll need to update some variables to work for you. &lt;/p&gt;

&lt;p&gt;This script leverages the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html"&gt;AWS CLI&lt;/a&gt;, which greatly simplifies this process. You could do this via API as well, but if you can use the CLI I highly recommend it. You could also store your backups on a mounted network drive wherever your compute server lives as well. &lt;/p&gt;

&lt;p&gt;The SSH User &amp;amp; Host will be easy to find in the Platform.sh GUI. Once you SSH in you can &lt;code&gt;echo $PLATFORM_RELATIONSHIPS | base64 --decode | json_pp&lt;/code&gt; to see your database credentials. &lt;/p&gt;

&lt;h2&gt;
  
  
  CRON Setup
&lt;/h2&gt;

&lt;p&gt;Finally, let's trigger the backups at the frequency you choose. I would recommend once a day as a default, increasing or decreasing depending on publication frequency. &lt;/p&gt;

&lt;p&gt;In my case &lt;a href="https://docs.rundeck.com/docs/manual/03-getting-started.html"&gt;I used Rundeck&lt;/a&gt; because I already use it for heaps of other things. However, if you don't have Rundeck installed you could &lt;a href="https://opensource.com/article/17/11/how-use-cron-linux"&gt;just use the crontab&lt;/a&gt;. Either way, just set it up to hit your backup shell script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;## In crontab, each night at midnight: &lt;/span&gt;
0 0 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; sh /var/scripts/craft_backups/my_script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;And that's it! You've got stable backups stored in S3 for easy access anytime you need. &lt;/p&gt;

</description>
      <category>database</category>
      <category>craftcms</category>
      <category>platformsh</category>
      <category>devops</category>
    </item>
    <item>
      <title>Automate Pull Request Testing using Cypress Dashboard, Github Actions, and Platform.sh</title>
      <dc:creator>mattbloomfield</dc:creator>
      <pubDate>Fri, 26 Mar 2021 14:31:42 +0000</pubDate>
      <link>https://dev.to/mattbloomfield/automate-pull-request-testing-using-cypress-dashboard-github-actions-and-platform-sh-22m</link>
      <guid>https://dev.to/mattbloomfield/automate-pull-request-testing-using-cypress-dashboard-github-actions-and-platform-sh-22m</guid>
      <description>&lt;p&gt;I work on a small team and we manage dozens of websites. With a host of requests coming in from Product Managers it's important that we work quickly without introducing new bugs into the code. &lt;/p&gt;

&lt;p&gt;Of course, if you have a QA team you can rely on them to double-check issues, but we don't have that luxury. And even if you do, no QA engineer has ever complained about a layer of automated tests. &lt;/p&gt;

&lt;h1&gt;
  
  
  Enter Cypress Testing
&lt;/h1&gt;

&lt;p&gt;If you're not familiar with Cypress, it's one of the newest and most popular testing frameworks to hit the scene recently. It's a lot like using selenium, with, so far, none of the annoyances. It even lets you record your own tests by clicking around your app and then later adding assertions! It literally writes the code! &lt;/p&gt;

&lt;p&gt;You can run it locally while developing - which is great! - but I wanted to be able to ensure that before each PR is merged we could see test results to ensure it wouldn't bork our main development branch. &lt;/p&gt;

&lt;p&gt;This guide will not walk you through how to setup Cypress, but &lt;a href="https://docs.cypress.io/guides/getting-started/installing-cypress" rel="noopener noreferrer"&gt;check out the Getting Started pages&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You'll also need to create a Cypress Dashboard account for this to work, since we'll be using the Record Key provided by that service. &lt;/p&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;p&gt;It's worth noting that I'm working with CraftCMS sites that use npm/node for preprocessing CSS/JS. So in addition to NPM dependencies I've also got Composer and all its PHP dependencies. &lt;/p&gt;

&lt;p&gt;I'm also running everything in Docker containers locally, which are basically mirrored by Platform.sh's deployment containers. &lt;/p&gt;

&lt;p&gt;We are using Platform.sh for hosting, which is a great, docker-based solution for hosting fullstack applications where you need a database, runtime environment, and a server. &lt;/p&gt;

&lt;h1&gt;
  
  
  Triggers, Environments, and Integrations
&lt;/h1&gt;

&lt;p&gt;There are probably lots of posts about setting up Cypress. But it took a lot of work and a lot of coordination with the Cypress DevRel team (who are fantastic) and Platform.sh support to be able to get this whole thing hooked up. Hopefully this post helps some other poor sap tasked with setting this up. The process is fairly specific to Platform.sh for hosting, but other hosting providers may provide similar tools. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2006ut2e7jjpqxubqwoj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2006ut2e7jjpqxubqwoj.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essentially we have three separate systems that all need to communicate with each other. The PR is created by a developer in Github. Upon creation, we need to provision a new docker environment in Platform.sh with a dedicated URL. This takes a few minutes to build and propagate. Once it's ready, Cypress tests need to be triggered, but they also need the URL of the Platform.sh environment. Cypress also needs a runtime environment with Node.js installed to run the tests. And once those are complete, it needs to talk back to the Github PR. &lt;/p&gt;

&lt;p&gt;So how do we make this work? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2vkfrhldi3s9vuy9cnt5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2vkfrhldi3s9vuy9cnt5.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Platform.sh Integrations
&lt;/h2&gt;

&lt;p&gt;The first step is pretty native to Platform.sh, but your hosting provider probably offers this as well. Using the Platfrom CLI you can create an integration that triggers a new environment on creation of every Pull Request in Github. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.platform.sh/integrations/source/github.html" rel="noopener noreferrer"&gt;Platform.sh has great docs on this integration&lt;/a&gt;, so I'll just say this is the basic command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;platform integration:add &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PLATFORMSH_PROJECT_ID &lt;span class="nt"&gt;--token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;GITHUB-USER-TOKEN &lt;span class="nt"&gt;--repository&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;USER/REPOSITORY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is what my settings look like (found by running &lt;code&gt;platform integration:get &amp;lt;integration_id&amp;gt;&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+---------------------------------+-------------------------------------------------------------------------------------+
| Property                        | Value                                                                               |
+---------------------------------+-------------------------------------------------------------------------------------+
| id                              | xxxxxxxx                                                                       |
| type                            | github                                                                              |
| base_url                        |                                                                                     |
| repository                      | &amp;lt;GH_Org_Name/GH_Repo_Name&amp;gt;                                                             |
| fetch_branches                  | true                                                                                |
| prune_branches                  | true                                                                                |
| build_pull_requests             | true                                                                                |
| build_draft_pull_requests       | false                                                                               |
| build_pull_requests_post_merge  | true                                                                                |
| pull_requests_clone_parent_data | true                                                                                |
| hook_url                        | &amp;lt;Platform_Generated_URL&amp;gt; |
+---------------------------------+-------------------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have that built out - you're halfway there! And it's pretty easy...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30flc6dz42fw81a6fsbn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30flc6dz42fw81a6fsbn.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Github Actions (and API)
&lt;/h2&gt;

&lt;p&gt;Now that we have an environment created, let's create a Github Action to spin up a new linux environment with Node.js installed and run our Cypress tests from there. &lt;/p&gt;

&lt;p&gt;I had never used Github Actions before so this took a bit work. And truthfully, there are a lot of Cypress examples out there that all point you in different directions and don't seem up to date with each other. So I'll provide exactly what worked for me.&lt;/p&gt;

&lt;p&gt;In your repository, create a new directory called &lt;code&gt;.github&lt;/code&gt; (if you don't already have one) and then within that directory another called &lt;code&gt;workflows&lt;/code&gt;, and within that a file named &lt;code&gt;cypress.yml&lt;/code&gt;. This file is where we will program our Action. Go ahead and paste in the following, being sure to modify your inputs. &lt;/p&gt;

&lt;p&gt;This job will create a new environment using ubuntu 16.04, then &lt;code&gt;npm install&lt;/code&gt; your dependencies, then &lt;code&gt;cypress run&lt;/code&gt; all your tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/cypress.yml &lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Manually Triggered Cypress Tests with installation job&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Testing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Domain'&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://www.uschamber.com'&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Merge&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Comment'&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Running&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Cypress&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Tests'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cypress-run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-16.04&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="c1"&gt;# Install NPM dependencies, cache them correctly&lt;/span&gt;
      &lt;span class="c1"&gt;# and run all Cypress tests&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cypress run&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cypress-io/github-action@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;CYPRESS_RECORD_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CYPRESS_RECORD_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;CYPRESS_baseUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.inputs.baseUrl }}&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;COMMIT_INFO_MESSAGE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.inputs.title }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;a href="https://gist.github.com/mattbloomfield/cf831a3075b188805083fc822a83cc9c" rel="noopener noreferrer"&gt;see the gist here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Notice the &lt;code&gt;on&lt;/code&gt; section - this seems to be a little-known fact about Actions - you can actually pass variables in from a remote source. This is perfect for us because we want to give it the URL of the Pull Request environment, not our production URL! &lt;/p&gt;

&lt;p&gt;Truthfully, I'm not sure we need the COMMIT_INFO_MESSAGE, but if I figure that out I'll update it later. &lt;/p&gt;

&lt;p&gt;Also note that we are using some secrets. Secrets can be added to your repository under the Settings &amp;gt; Secrets UI. Grab your Cypress Record Key from Cypress Dashboard (log in at cypress.io for a free account), then drop it in as a secret called &lt;code&gt;CYPRESS_RECORD_KEY&lt;/code&gt;. The &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; is automatically created by Github, so don't worry about that one. &lt;/p&gt;

&lt;p&gt;Now that we've gotten this far, go ahead and trigger your script! You can hit it manually under the Actions Tab of your repository: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrplm3vbf8x2ahkk2x80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrplm3vbf8x2ahkk2x80.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it errors out, follow the error messages to hopefully debug your way out of the issue. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u827vac57ksh47080wg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u827vac57ksh47080wg.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Platform.sh Activity Scripts
&lt;/h2&gt;

&lt;p&gt;Now that we have a manual action set up we need a trigger. And of course, we don't want it triggered when the Pull Request is created, but instead once the environment is created. &lt;/p&gt;

&lt;p&gt;Enter Activity Scripts. Platform.sh allows you to basically hook into the deploy process of its containers and run any JavaScript after the fact. &lt;/p&gt;

&lt;p&gt;Quick note on these: The scripts only run ES5, and they are incredibly difficult to debug. I really hope Platform.sh updates them in the future to work with promises and ES6+. It would also be really nice to trigger them without pushing arbitrary code. &lt;/p&gt;

&lt;p&gt;Rather than pasting the code here - &lt;a href="https://gist.github.com/mattbloomfield/afa0c9cc6ad08aaac8e97bcd2879c78c" rel="noopener noreferrer"&gt;I'll link to the gist&lt;/a&gt; that you can copy.&lt;/p&gt;

&lt;p&gt;In order for this script to work you'll need to &lt;a href="https://github.com/settings/tokens" rel="noopener noreferrer"&gt;create a Github Token&lt;/a&gt; and store it in your Platform.sh environment variables as &lt;code&gt;GITHUB_AUTH&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Github Token permissions for your reference: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixereql0sgww04uxwy6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixereql0sgww04uxwy6e.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;To understand the activity script, you'll need to understand that Platform.sh has a different git strategy than Github. &lt;/p&gt;

&lt;p&gt;This script gets the base URL from Platform.sh, grabs the Platform.sh branch name (&lt;code&gt;pr-x&lt;/code&gt;) and then hits the Github Pull Request API to get the source branch name &lt;code&gt;feature-x&lt;/code&gt;, then hits the Github Actions API and hits our &lt;code&gt;cypress.yml&lt;/code&gt; action with the branch name and environment URL. &lt;/p&gt;

&lt;p&gt;If you want to debug the script you can use the &lt;code&gt;platform integration:log &amp;lt;integration_id&amp;gt;&lt;/code&gt; to get the latest run. It will show you anything that was printed to the stdout. &lt;/p&gt;

&lt;h2&gt;
  
  
  Cypress Dashboard
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2ui1auk0gxo4euj7pjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2ui1auk0gxo4euj7pjz.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The final step in the whole strategy is to post the results of the test right back to the PR. Luckily, Cypress Dashboard handles this for us. Remember how we grabbed the RecordID earlier in the Action script? &lt;/p&gt;

&lt;p&gt;Navigate to &lt;a href="https://dashboard.cypress.io/organizations" rel="noopener noreferrer"&gt;cypress.io&lt;/a&gt; and check your Project Settings. Fill out the Github Integrations section, and you're DONE. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1rms5kjttd1v343k59h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1rms5kjttd1v343k59h.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing
&lt;/h1&gt;

&lt;p&gt;Now give it a whirl! Open a new PR, watch the environment automatically build in Platform.sh, then check the log for the script to see it trigger Github Actions, then watch the actions run, then see it post a status and comment to your Github Pull Request. &lt;/p&gt;

&lt;p&gt;This has helped our team go much faster! Hopefully it helps your team too. &lt;/p&gt;




&lt;p&gt;&lt;em&gt;Shout out to Kevin Old @ Cypress who proactively reached out to me on Twitter when I was at wits end and dealt with all my questions on making continuous testing a reality for us.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>deployment</category>
      <category>php</category>
      <category>craftcms</category>
    </item>
  </channel>
</rss>
