Pantheon Discord Webhook Integration

<p><span class="drop-cap">A</span>s part of the tools we use at easytechgreen as part of development workflow are Discord and <a href="http://pantheon.io/">Pantheon.io</a>.</p> <p>Something important in our development process is that the whole team be aware when deployments are carried out in the different environments. This is why we needed to make an integration between the two things so that when we deploy in Pantheon a notification should be sent to a particular Discord channel.</p> <p>Luckily this is quite easy to do using:</p> <ul> <li>Webhook on Disctord</li> <li>And Pantheon Quicksilver.</li> </ul> <h2>Creatimg a Webhook</h2> <p>Setting up the webhook to be use to send notification is an easy task. We just need to go through the following steps:</p> <h3>Step 1 Edit the Channel</h3> <p>Open the channel Settings and head into the Integrations tab</p> <img alt="Open Discord channel settings " data-entity-type="file" data-entity-uuid="fa7b0dfe-8c0b-4dca-a082-aed43681bd46" src="/sites/default/files/inline-images/Screen%20Shot%202022-09-11%20at%2009.58.01.png" class="align-center" width="2196" height="1224" loading="lazy" /> <h3>Step 2 Create the Webhook</h3> <p>Click the "Create Webhook" button to create a new webhook!</p> <img alt="Create a new webhook in the Integracion section" data-entity-type="file" data-entity-uuid="68881d2d-475f-482d-81da-c120d2f27acf" src="/sites/default/files/inline-images/Screen%20Shot%202022-09-11%20at%2002.04.21.png" class="align-center" width="2104" height="1342" loading="lazy" /> <p>We'll have a few options here. You can:</p> <ul> <li><strong>Edit the avatar:</strong> By clicking the avatar next to the Name in the top left</li> <li><strong>Choose what channel the Webhook posts to:</strong> By selecting the desired text channel in the dropdown menu.</li> <li><strong>Name your Webhook:</strong> Good for distinguishing multiple webhooks for multiple different services.</li> </ul> <p>We now have our own handy URL that we are going to use to receive messages from pantheon.</p> <img alt="Copy the Webhook URL" data-entity-type="file" data-entity-uuid="7f700768-860f-4d33-843f-67defd4106ee" src="/sites/default/files/inline-images/Screen%20Shot%202022-09-11%20at%2002.04.48.png" class="align-center" width="2104" height="1342" loading="lazy" /> <h2>Quicksilver Side</h2> <p>Quicksilver hooks into platform workflows to automate your Pantheon WebOps workflow. This allows the platform to run selected scripts automatically every hour, or when a team member triggers the corresponding workflow.</p> <p>You can read the <a href="https://pantheon.io/docs/quicksilver#quicksilver-and-the-deploy-hook">Quicksilver doc</a> and then check a look to some <a href="https://github.com/pantheon-systems/quicksilver-examples/">scripts examples</a> on the pantheon git repository that you can use to chat-ops, database sanitization, deployment logging, and automated testing operations with a CI serve.</p> <h3>Deploy and Code Sync Hook</h3> <p><a href="https://bitbucket.org/kurobits/quicksilver-examples/src/master/discord_notification/">Our script </a> will hook the deploy and the code_sync Quicksilver workflow into the stage after. So to trigger it execution, we need to add into <strong>pantheon.yml</strong> the following lines.</p> <pre> <code class="language-xml">workflows: sync_code: after: - type: webphp description: Post deployment notification to Discord script: private/scripts/discord_notification.php deploy: after: - type: webphp description: Post deployment notification to Discord script: private/scripts/discord_notification.php </code></pre> <p>If you are not using Quicksilver yet just deploy your <strong><code>pantheon.yml</code></strong> file into an environment.</p> <h3>Script</h3> <p>Quicksilver support webphp scripting which runs through the same runtime environment as the website. So we develop the following script and put it in <strong>web/private/scripts</strong></p> <pre> <code class="language-php">&lt;?php // Important constants :) $pantheon_yellow = 'EFD01B'; $botname = 'Pantheon'; $avatar_url = "https://images.g2crowd.com/uploads/product/image/large_detail/large_detail_4e32e9799b7e0d8bb92c633229b79463/pantheon.png"; $timestamp = date("c", strtotime("now")); // Create new webhook in your Discord channel settings and copy&amp;paste URL $url = '&lt;Discord Webhook Url'&gt;; // Pantheon $wf_type = $_POST['wf_type']; // Compose message. // Message Formatting -- https://discordapp.com/developers/docs/reference#message-formatting switch ($wf_type) { case 'deploy': // Find out what tag we are on and get the annotation. $deploy_tag = `git describe --tags`; $deploy_message = $_POST['deploy_message']; // Title $title = 'Deploy to ' . $_ENV['PANTHEON_ENVIRONMENT']; $title_url = 'https://dashboard.pantheon.io/sites/' . PANTHEON_SITE . '#' . PANTHEON_ENVIRONMENT . '/deploys'; // Prepare the slack payload as per: $text = 'Deploy to ' . $_ENV['PANTHEON_ENVIRONMENT']; $text .= ' environment of ' . $_ENV['PANTHEON_SITE_NAME'] .' by ' . $_POST['user_email'] .' complete!'; // Build an array of fields to be rendered with Slack Attachments as a table // attachment-style formatting: // https://api.slack.com/docs/attachments $fields = [ [ 'name' =&gt; 'Deploy Note', 'value' =&gt; $deploy_message, 'inline' =&gt; 'false' ] ]; break; case ($wf_type == 'sync_code' || $wf_type == 'sync_code_with_build'): // Get the committer, hash, and message for the most recent commit. $committer = `git log -1 --pretty=%cn`; $email = `git log -1 --pretty=%ce`; $message = `git log -1 --pretty=%B`; $hash = `git log -1 --pretty=%h`; $title = 'Code Sync to ' . $_ENV['PANTHEON_ENVIRONMENT']; $title_url = 'https://dashboard.pantheon.io/sites/' . PANTHEON_SITE . '#' . PANTHEON_ENVIRONMENT . '/deploys'; $text = 'Code sync to the ' . $_ENV['PANTHEON_ENVIRONMENT'] . ' environment of ' . $_ENV['PANTHEON_SITE_NAME'] . ' by ' . $_POST['user_email'] . "!\n"; $fields = [ [ 'name' =&gt; 'Commit', 'value' =&gt; rtrim($hash) . ' by ' . rtrim($committer), 'inline' =&gt; 'true' ], [ 'name' =&gt; 'Commit Message', 'value' =&gt; $message, 'inline' =&gt; 'false' ] ]; break; case 'clear_cache': $title = 'Cleared caches on ' . $_ENV['PANTHEON_ENVIRONMENT']; $fields = [ 'name' =&gt; 'Cleared caches', 'value' =&gt; 'Cleared caches on the ' . $_ENV['PANTHEON_ENVIRONMENT'] . ' environment of ' . $_ENV['PANTHEON_SITE_NAME'] . "!\n", 'inline' =&gt; 'false' ]; break; default: $title = 'Default wf on ' . $_ENV['PANTHEON_ENVIRONMENT']; $text = $_POST['qs_description']; $field=""; break; } // // Create the message to post in discord $message = [ // Bot Name "username" =&gt; $botname, // Bot avatar "avatar_url" =&gt; $avatar_url, // Embeds Array "embeds" =&gt; [ [ "title" =&gt; $title, // Url to the dashboard on pantheon "url" =&gt; $title_url, "type" =&gt; "rich", "description" =&gt; $text, "timestamp" =&gt; $timestamp, // Embed left border color in HEX "color" =&gt; hexdec($pantheon_yellow), "fields" =&gt; $fields, "footer" =&gt; [ "text" =&gt; "easyhtechgreen", "icon_url" =&gt; "https://www.drupal.org/files/druplicon-small.png" ], ] ] ]; // Post message to discord _discord_notification($url, $message); /** * Send a notification to Discord */ function _discord_notification($url, $discord_message) { $payload = json_encode($discord_message); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); // Watch for messages with `terminus workflow:watch &lt;siteid&gt;` print("\n==== Posting to Discord ====\n"); $result = curl_exec($ch); print("RESULT: $result"); // $payload_pretty = json_encode($post,JSON_PRETTY_PRINT); // Uncomment to debug JSON // print("JSON: $payload_pretty"); // Uncomment to Debug JSON print("\n===== Post Complete! =====\n"); curl_close($ch); }</code></pre> <p>We need to add the URL from the Webhook created in Discord to our script and we are almost ready to go.</p> <pre> <code class="language-php">// Create new webhook in your Discord channel settings and copy&amp;paste URL $url = '&lt;Discord Webhook Url'&gt;;</code></pre> <h3>Message</h3> <p>To create our message we can access to some variables that are made available through the<strong> <code>$_POST</code></strong> global variable, the <strong><code>$_ENV</code></strong> and <code><strong>$_SERVER</strong> </code>objects. You can check what this variables include at the <a href="https://pantheon.io/docs/quicksilver#variables">quiclsilver documentation</a>.</p> <p>But here some of the variable we are using in our script</p> <img alt="We show the quicksilver variables we are using in our script." data-entity-type="file" data-entity-uuid="37584965-4d66-402d-bf84-349e8a75c8cf" src="/sites/default/files/inline-images/Screen%20Shot%202022-09-11%20at%2016.54.51.png" class="align-center" width="1416" height="822" loading="lazy" /> <p>Once we have the information we need to send to Discord we need to create the message following an specific structure tha you can check at the <a href="https://discord.com/developers/docs/resources/webhook">Discord WebHook Doc</a></p> <p>But in a nutshell, we create a message with this one structure:</p> <p><strong>username</strong> - overrides the predefined username of the webhook and we put here our botname</p> <p><strong>avatar_url</strong> - overrides the predefined avatar of the webhook</p> <p><strong>embeds</strong> - array of embed objects. In comparison with bots, webhooks can have more than one custom embed</p> <ul> <li><strong>color</strong> - color code of the embed. You have to use Decimal numeral system, not Hexadecimal.</li> <li><strong>title</strong> - title of embed</li> <li><strong>url</strong> - url of embed. If title was used, it becomes hyperlink</li> <li><strong>description</strong> - description text</li> <li><strong>fields</strong> - array of embed field objects <ul> <li><strong>name</strong> - name of the field</li> <li><strong>value</strong> - value of the field</li> <li><strong>inline</strong> - if true, fields will be displayed in the same line, 3 per line, 4th+ will be moved to the next line</li> </ul> </li> <li><strong>footer</strong> - embed footer object <ul> <li><strong>text</strong> - footer text, doesn't support Markdown</li> <li><strong>icon_url</strong> - url of footer icon</li> </ul> </li> <li><strong>timestamp</strong> - ISO8601 timestamp (yyyy-mm-ddThh:mm:ss.msZ)</li> </ul> <h2>Ready to go</h2> <p>Finally, we can try our script and start to receive messages from pantheon into our discord channel. So push your code to pantheon and see what happens. :-)</p> <p>Before pushing your code, you can open a new terminal and run the following command</p> <pre> <code class="language-bash">$ terminus workflow:watch &lt;siteid&gt;</code></pre> <p>to check if our script is working as expected.</p> <p><strong>V<strong>oilà!! We have our beautiful message in Discord 🤖</strong></strong></p> <img alt="Our message from pantheon is already in discord. " data-entity-type="file" data-entity-uuid="a6efd64e-1b5e-45cf-be7f-2e6de762fbdb" src="/sites/default/files/inline-images/Screen%20Shot%202022-09-11%20at%2009.47.39.png" class="align-center" width="2706" height="1688" loading="lazy" /> <p>        You can download this script and other examples from <a href="https://bitbucket.org/kurobits/quicksilver-examples/src/master/">our repo</a></p>

Related blog posts

Lando + Composer FTW

This is just one of those moments when I realized something obvious. I just wanted to share it.

Hand-picked content at the top of a chronologically sorted view: Option 2, Entity queues

Following the one way or another series we’ll solve the problem of overriding the default order of a view with hand picked contents through Entity queues.

Hand-picked content at the top of a chronologically sorted view: Option 1, make it Sticky!

This is the first of the One way or another series. A set of blog posts where we explore different ways to implement similar features. Our topic today is: Sticky content on top of lists!