<?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: 🌈 eric sorenson 🎹🔈🎚</title>
    <description>The latest articles on DEV Community by 🌈 eric sorenson 🎹🔈🎚 (@ahpook).</description>
    <link>https://dev.to/ahpook</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%2F363270%2F81f6f1b7-371f-4fc9-8f99-71a42a076fbc.jpg</url>
      <title>DEV Community: 🌈 eric sorenson 🎹🔈🎚</title>
      <link>https://dev.to/ahpook</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ahpook"/>
    <language>en</language>
    <item>
      <title>Deployment Rollbacks via FireHydrant Runbook</title>
      <dc:creator>🌈 eric sorenson 🎹🔈🎚</dc:creator>
      <pubDate>Tue, 24 Nov 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/relay/deployment-rollbacks-via-firehydrant-runbook-2jp1</link>
      <guid>https://dev.to/relay/deployment-rollbacks-via-firehydrant-runbook-2jp1</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mHPdactU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/2af27cbed92142e9574be5446392ff04/6e670/firehydrant-hero.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mHPdactU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/2af27cbed92142e9574be5446392ff04/6e670/firehydrant-hero.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://firehydrant.io"&gt;FireHydrant&lt;/a&gt; has a sophisticated set of response actions for coordinating communications, activities, and retrospectives for incidents that affect your services. &lt;a href="https://relay.sh"&gt;Relay&lt;/a&gt; helps by automating remediations that involve orchestrating actions across your infrastructure. In this example workflow, an incident that affects an application deployed on Kubernetes can trigger a rollback to a previous version automatically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://relay.sh/static/0577e8560ade4fff3973e25173d5b283/56e1b/firehydrant-graph.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rHxJGmaF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/0577e8560ade4fff3973e25173d5b283/56e1b/firehydrant-graph.png" alt="Graph from relay showing the workflow steps" title="Graph from relay showing the workflow steps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The workflow makes a couple of assumptions about your infrastructure that will need to be true to work out of the box; we’d &lt;a href="https://github.com/puppetlabs/relay/issues/new"&gt;love to work with you&lt;/a&gt; if you need additional flexibility! Specifically, it maps FireHydrant “Services” to Kubernetes &lt;a href="https://cloud.google.com/kubernetes-engine/docs/concepts/deployment"&gt;deployments&lt;/a&gt;, and FireHydrant Environments to Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/"&gt;namespaces&lt;/a&gt;. Your deployment and rollback process is likely different from the one modelled here, but this should provide a good starting point for automating incident response activity with Relay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting the Services
&lt;/h2&gt;

&lt;p&gt;In order to enable two-way communication between FireHydrant and Relay, we’ll need to do some work on both sides: Relay posting to FireHydrant requires a FireHydrant API key, and FireHydrant triggering Relay workflows uses a dynamically-generated Relay webhook URL.&lt;/p&gt;

&lt;p&gt;First, add the Relay workflow to your account &lt;a href="https://app.relay.sh/create-workflow?workflowName=firehydrant-rollback&amp;amp;initialContentURL=https%3A%2F%2Fraw.githubusercontent.com%2Fpuppetlabs%2Frelay-workflows%2Fmaster%2Ffirehydrant-rollback%2Ffirehydrant-rollback.yaml"&gt;using this link&lt;/a&gt;. When you click “Save”, Relay will both create the webhook URL you’ll need and prompt that you’re missing a Secret and a Connection - we’ll get to those in a moment.&lt;/p&gt;

&lt;p&gt;In FireHydrant, we’ll create a Runbook that will trigger the workflow by sending a webhook to Relay. Create a new Runbook and add a &lt;strong&gt;Send a Webhook&lt;/strong&gt; step. For the &lt;strong&gt;Endpoint URL&lt;/strong&gt; , paste the webhook address from the Relay’s &lt;strong&gt;Settings&lt;/strong&gt; sidebar. The &lt;strong&gt;HMAC Secret&lt;/strong&gt; field is an arbitrary string (not currently used). For the &lt;strong&gt;JSON Payload&lt;/strong&gt; field, paste the following template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "incident_id": "{{ incident.id }}",
  "name": "{{ incident.name }}",
  "summary": "{{ incident.summary }}",
  "service": "{{ incident.services[0].name | downcase }}",
  "environment": "{{ incident.environments[0].name | downcase }}",
  "channel_id": "{{ incident.channel_id }}",
  "channel_name": "{{ incident.channel_name }}"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a FireHydrant API key for Relay to post information back into the incident timeline. Under &lt;strong&gt;Integrations&lt;/strong&gt; - &lt;strong&gt;Bot users&lt;/strong&gt; in FireHydrant, create a new &lt;strong&gt;Bot user&lt;/strong&gt; with a memorable name and description. Save the resulting API token into a Relay secret on the Relay workflow’s &lt;strong&gt;Settings&lt;/strong&gt; sidebar named &lt;code&gt;apiKey&lt;/code&gt; (case-sensitive).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://relay.sh/static/a7f2f46b01ba758ce4bf728fc30bcd24/765bd/firehydrant-bot-user.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HilTDhJN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/a7f2f46b01ba758ce4bf728fc30bcd24/765bd/firehydrant-bot-user.png" alt="The Integrations - Bot Users screen in FireHydrant" title="The Integrations - Bot Users screen in FireHydrant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  GCP Authentication Setup
&lt;/h2&gt;

&lt;p&gt;This workflow uses a GCP Connection type on Relay’s end, which requires a &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/authentication/#service-account-tokens"&gt;service account&lt;/a&gt;configured on your cluster. Follow the GCP guide to API Server Authentication’s &lt;a href="https://cloud.google.com/kubernetes-engine/docs/how-to/api-server-authentication#service_in_other_environments"&gt;“Service in other environments”&lt;/a&gt; section to set one up. This workflow will require the service account have the role &lt;code&gt;roles/container.developer&lt;/code&gt; attached to it; if you re-use the connection for other workflows it may require additional permissions. Once you’ve gotten the service account JSON file downloaded, add a GCP Connection in Relay, name it &lt;code&gt;relay-service-account&lt;/code&gt; and paste the contents of the JSON file into the dialog. Under the hood, Relay stores this securely in our Vault service and makes the contents available to workflow containers through the &lt;a href="https://relay.sh/docs/using-workflows/managing-connections/"&gt;!Connection custom type&lt;/a&gt; in the workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://relay.sh/static/eac574df6085b89b4c8297f1f450c736/21062/firehydrant-new-connection.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g0QP-0ah--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/eac574df6085b89b4c8297f1f450c736/21062/firehydrant-new-connection.png" alt="The New Connection dialog in Relay for GCP connections" title="The New Connection dialog in Relay for GCP connections"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For non-GCP clusters, you can use Relay’s Kubernetes connection type, which requires less setup. GCP rotates access tokens every hour, making them unsuitable for automated use. The Kubernetes connection type needs an access token, the cluster URL, and the CA certificate for the cluster; there are more detailed instructions accompanying &lt;a href="https://github.com/puppetlabs/relay-workflows/tree/master/kubectl-apply-on-dockerhub-push"&gt;this deployment workflow example&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Services and Environments
&lt;/h2&gt;

&lt;p&gt;One of the FireHydrant’s big benefits is its awareness of your infrastructure. It takes a little bit of up-front work, but if you invest the time to map out your services and environments, you can dramatically streamline your incident response. In this example, we’ve enumerated the microservices that make up our Sock Shop application and associated them with different runbooks. Fortunately for the demo, the &lt;code&gt;sockshop-frontend&lt;/code&gt; service is a simple stateless Deployment in GKE, which makes new releases easy to manage with the &lt;code&gt;kubectl rollout&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://relay.sh/static/4e55b2fd3f9325a310d6e96ec059acab/44e31/firehydrant-sockshop-service.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KKznQqAV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/4e55b2fd3f9325a310d6e96ec059acab/44e31/firehydrant-sockshop-service.png" alt="The Infrastructure - Services screen in FireHydrant" title="The Infrastructure - Services screen in FireHydrant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similarly, the Environments section lets you enumerate the instances of your service, to better characterize the impact of an incident, help assign owners for remediation actions, and message outage information to the appropriate audiences. Check out this FireHydrant &lt;a href="https://help.firehydrant.io/en/articles/4192249-inventory-management-functionalities-services-and-environments"&gt;helpdesk article on inventory management&lt;/a&gt; for more details on infrastructure organization. For our purposes, the goal of defining environments is to map them onto Kubernetes namespaces where our application is running. (For production workloads, it’s more likely that your environments map to distinct clusters; that’s totally possible to handle in Relay but is beyond the scope of this introduction!)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://relay.sh/static/112131d19063b6d0ea71998e484b28b4/38095/firehydrant-environments.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Sa1Gopry--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/112131d19063b6d0ea71998e484b28b4/38095/firehydrant-environments.png" alt="The Infrastructure - Environments screen in FireHydrant" title="The Infrastructure - Environments screen in FireHydrant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Incident Creation and Response
&lt;/h2&gt;

&lt;p&gt;Now for the exciting part. Let’s say an update bumped the image on the frontend pods from a pinned version to &lt;code&gt;latest&lt;/code&gt; and everything broke.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% kubectl set image deployment/sockshop-frontend nginx-1=nginx:latest \
   --record --namespace production deployment.apps/sockshop-frontend
image updated
% kubectl rollout history deployment sockshop-frontend --namespace production
deployment.apps/sockshop-frontend
REVISION CHANGE-CAUSE
1 kubectl set image deployment/sockshop-frontend nginx:1.18.0=nginx:latest --record=true --namespace=production
2 kubectl set image deployment/sockshop-frontend nginx-1=nginx:latest --record=true --namespace=production

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But unbeknownst to the deployer, all was not well. After some troubleshooting, we determined that the application was degraded and rollout was to blame. In FireHydrant, the on-call person declares an incident and indicates the service and environment that were affected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://relay.sh/static/d8a03ae55caf835fe15319c9c7a666c6/f6909/firehydrant-new-incident.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7eAbw8RR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/d8a03ae55caf835fe15319c9c7a666c6/f6909/firehydrant-new-incident.png" alt="Create a new Incident in FireHydrant, with the sockshop-frontend service affected in the production environment" title="Create a new Incident in FireHydrant, with the sockshop-frontend service affected in the production environment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the incident is created, we can attach the &lt;code&gt;rollback-via-relay&lt;/code&gt; Runbook that contains our webhook to the incident. The benefit of doing it this way is that the credentials are stored in Relay rather than needing a comamnd-line &lt;code&gt;kubectl&lt;/code&gt; setup as above, and you don’t have to remember the exact syntax to type if something’s broken at 4AM! The correct steps are stored in the workflow, reducing the possibility for an error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://relay.sh/static/0c281766fe6e25263be45e97b5c00be8/cfc60/firehydrant-attach.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IleJItqY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/0c281766fe6e25263be45e97b5c00be8/cfc60/firehydrant-attach.png" alt="In the Remediation tab, attach the rollback-via-relay runbook" title="In the Remediation tab, attach the rollback-via-relay runbook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The incident timeline and associated Slack channel show these action taking place, and in Relay we can see the webhook come in, the workflow kick off, and ultimately post back into the timeline with the output of the rollback command. Thanks to FireHydrant’s &lt;a href="https://help.firehydrant.io/en/articles/2862753-integrating-with-slack"&gt;awesome Slack integration&lt;/a&gt;, the updates roll into the channel in real time and chat messages are mirrored back into the incident so teams can coordinate their activities and keep a record of what happened. In this case, the rollback worked and we can resolve the issue quickly!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://relay.sh/static/676b42348ee67865222436c3d02c6599/f843c/firehydrant-slack-resolved.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mjIE_uTW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/676b42348ee67865222436c3d02c6599/f843c/firehydrant-slack-resolved.png" alt="Slack channel showing incident updates from Relay and a successful rollback" title="Slack channel showing incident updates from Relay and a successful rollback"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion and Next Steps
&lt;/h2&gt;

&lt;p&gt;FireHydrant’s Runbook based system for coordinating actions in response to incidents is extremely powerful. The more you teach it about your infrastructure, the faster you’ll be able to respond when something goes wrong. And linking it to Relay via Runbooks enables another level of automated response and remediation. In this example, we were able to roll back a deployment without someone needing to run manual commands and potentially making things worse!&lt;/p&gt;

&lt;p&gt;There are lots of &lt;a href="https://relay.sh/workflows/"&gt;existing Relay workflows&lt;/a&gt; that can act as building blocks or examples to construct your own incident response workflow. By combining them with clear processes codified in FireHydrant, responders can solve issues more quickly, reduce downtime, and get back to higher-value work.&lt;/p&gt;

&lt;p&gt;To try this out for yourself, sign up for free &lt;a href="https://firehydrant.io"&gt;FireHydrant&lt;/a&gt; account and &lt;a href="https://relay.sh"&gt;Relay&lt;/a&gt; accounts, and get started automating!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Relay and Open Source</title>
      <dc:creator>🌈 eric sorenson 🎹🔈🎚</dc:creator>
      <pubDate>Tue, 23 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/relay/relay-and-open-source-2490</link>
      <guid>https://dev.to/relay/relay-and-open-source-2490</guid>
      <description>&lt;h2&gt;
  
  
  Relay and the open source community
&lt;/h2&gt;

&lt;p&gt;Relay is deliberately built to be easy to extend. The more &lt;a href="https://relay.sh/docs/how-it-works/#definitions"&gt;steps&lt;/a&gt; there are in the world the better it is for everyone who wants to write a workflow. It’s sort of like fax machines or MySpace: you’ll want to use the same technology that the people you’re communicating with use. OK, maybe the fax machine isn’t not a great analogy… the point is, nourishing a healthy open-source ecosystem and community around Relay is super important to its success.&lt;/p&gt;

&lt;p&gt;In this post I’ll talk about the different aspects of Relay’s open source DNA: the ecosystem model, the codebase itself, and upstream projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Relay Ecosystem
&lt;/h3&gt;

&lt;p&gt;First and foremost, Relay is about &lt;a href="https://relay.sh/docs/how-it-works/#workflow-execution"&gt;workflows&lt;/a&gt;. Relay workflows are a well-defined YAML dialect that’s readily sharable. The first batch of workflows we’ve been writing to exercise the system and demonstrate its capabilities are on the &lt;a href="https://relay.sh/workflows/"&gt;Workflows section of the website&lt;/a&gt; with READMEs for example usage and a one-click button to add them to your account. The code for all of them is &lt;a href="https://github.com/puppetlabs/relay-workflows"&gt;collected in the puppetlabs/relay-workflows repo&lt;/a&gt;. We’d love to see pull requests with bug fixes or improvements, new workflows you’ve written to solve problems with Relay, or &lt;a href="https://github.com/puppetlabs/relay/issues/new"&gt;requests for features&lt;/a&gt;. The workflow syntax is &lt;a href="https://relay.sh/docs/reference/relay-workflows/"&gt;documented at relay.sh/docs&lt;/a&gt; along with instructions on how to &lt;a href="https://relay.sh/docs/setting-up-editor/"&gt;set up VSCode&lt;/a&gt; to do automatic syntax validation and completion.&lt;/p&gt;

&lt;p&gt;Relay workflows make use of containers to both respond to incoming events and to run as steps to accomplish the task you’re trying to automate. Step and Trigger container definitions that interact with a particular tool or service can be bundled up into what we call an Integration. The &lt;a href="https://relay.sh/integrations/"&gt;Integrations library on the website&lt;/a&gt; has a browsable, taxonomized list of the currently supported integrations.&lt;/p&gt;

&lt;p&gt;We expect the current list will cover a lot of common Relay use cases, but there’s no way it’s going to cover &lt;em&gt;all&lt;/em&gt; of them. If you run into the situation where there’s an integration with a service you use, but not a specific Step or Trigger that does what you want, we’d love to hear about it! Many of the features marked “Coming soon” on the integration pages just need some prioritization and tweaking to get out the door, and your vote counts to help get them on the list. Plus, all of the integrations are aggregated together under the &lt;a href="https://github.com/relay-integrations"&gt;relay-integrations Github organization&lt;/a&gt;, and by now it should go without saying that we welcome any PRs or issues on them.&lt;/p&gt;

&lt;p&gt;To make a new integration, or if you want to go further than tweaking the existing containers, there’s a long-form &lt;a href="https://relay.sh/docs/integrating-with-relay/"&gt;Integrating with Relay&lt;/a&gt; guide that breaks down the different container types, the &lt;a href="https://pypi.org/project/relay-sdk"&gt;Python SDK&lt;/a&gt;, and best practices for integrating with the internal Relay service APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Relay Codebase
&lt;/h3&gt;

&lt;p&gt;Speaking of documentation, the entire &lt;a href="https://github.com/puppetlabs/relay-docs/"&gt;Relay documentation site&lt;/a&gt; is available on Github. If you run across anything in the docs that doesn’t seem right, from typos to examples that don’t work, we’d welcome corrections in the form of PRs or issues. Sending pull requests into the docs can be a great way to get involved with a project. Docs are generally on a quicker release cycle than the codebase and everybody benefits from having improved documentation.&lt;/p&gt;

&lt;p&gt;If you’re a Go developer, whether aspirational (like me!) or expert, the &lt;a href="https://github.com/puppetlabs/relay"&gt;Relay CLI tool&lt;/a&gt; could present a fun opportunity to dig into a relatively constrained codebase and improve the Relay development experience. I’ve written at length about our &lt;a href="https://relay.sh/blog/command-line-ux-in-2020/"&gt;philosophy of CLI design&lt;/a&gt;, something I personally am pretty passionate about, and it’s been really gratifying to see those design principles come to life in the Relay CLI. There are a few issues &lt;a href="https://github.com/puppetlabs/relay/labels/cli"&gt;tagged with CLI&lt;/a&gt; to get started, and of course we welcome your ideas too.&lt;/p&gt;

&lt;p&gt;Going deeper into the architecture, the Kubernetes execution backend for the service is published at &lt;a href="https://github.com/puppetlabs/relay-core"&gt;puppetlabs/relay-core&lt;/a&gt;. There are some intriguing possibilities for this codebase, like adding a local executor that could use minikube to run workflows locally. The metadata service would also be useful to have as a self-hosted version, because it would allow better validation and testing of step definitions while you’re developing workflows.&lt;/p&gt;

&lt;p&gt;Of potential interest to front-end folks, the &lt;a href="https://github.com/puppetlabs/design-system"&gt;Puppet Design System&lt;/a&gt; is an open source collection of &lt;a href="https://reactjs.org"&gt;React components&lt;/a&gt; that the Relay web app (among other Puppet products) uses to provide gorgeous, modern look-and-feel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upstream
&lt;/h3&gt;

&lt;p&gt;Relay makes heavy use of upstream open source technology. We try to be good citizens of these projects by contributing bug fixes and enhancements back upstream. This helps everybody because we don’t end up maintaining forks or carrying our own patches, the code gets more eyes on it, and the rest of the community can make use of the features too.&lt;/p&gt;

&lt;p&gt;The projects we’re most heavily involved in are &lt;a href="https://tekton.dev"&gt;Tekton pipelines&lt;/a&gt;, which we’ve &lt;a href="https://relay.sh/blog/whats-going-on-with-tekton-part-1/"&gt;blogged about&lt;/a&gt; &lt;a href="https://relay.sh/blog/whats-going-on-with-tekton-part-2/"&gt;extensively&lt;/a&gt; and &lt;a href="https://www.getambassador.io/"&gt;Ambassador&lt;/a&gt;, who posted a &lt;a href="https://blog.getambassador.io"&gt;detailed technical blog post&lt;/a&gt; describing how Relay uses Knative and Ambassador together to run your Trigger containers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;To wrap things up, I’d like to acknowledge that open source is tough to get right. Communities are valuable, fragile things, which need lots of love and attention to flourish. We’re deeply committed to investing in community for Relay, but acknowledge up front that we won’t always get it right. We pledge to listen and improve based on your feedback. You can email the team at &lt;a href="mailto:relay@puppet.com"&gt;relay@puppet.com&lt;/a&gt; or jump on slack.puppet.com to chat in #relay. Please keep the lines of communication open and let’s build some awesome automation together!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>3 Commandments for CLI Design</title>
      <dc:creator>🌈 eric sorenson 🎹🔈🎚</dc:creator>
      <pubDate>Wed, 08 Apr 2020 22:31:24 +0000</pubDate>
      <link>https://dev.to/ahpook/3-commandments-for-cli-design-49a3</link>
      <guid>https://dev.to/ahpook/3-commandments-for-cli-design-49a3</guid>
      <description>&lt;h2&gt;
  
  
  In the beginning…
&lt;/h2&gt;

&lt;p&gt;In Neal Stephenson’s 1999 essay &lt;a href="https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html"&gt;“In the Beginning Was The Command Line”&lt;/a&gt;, he describes how using Command-Line Interface (CLI) utilities is simpler and requires less code than a Graphical User Interface (GUI). They’re tiny, they do one thing really well, and they are meant to work in conjunction with other small, single-purpose tools to accomplish complicated tasks quickly.&lt;/p&gt;

&lt;p&gt;However, the old-school Unix utilities are not without their problems. The passage of time and inevitable feature creep have led to situations like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The humble &lt;code&gt;ls&lt;/code&gt; command now has more options than there are letters in the alphabet! Plus, despite the proliferation of features, many advanced and useful options are off by default to preserve backwards compatibility. Other core utilities are in similar situations: &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;tar&lt;/code&gt; are stuck with arcane, user-hostile syntaxes, and the &lt;code&gt;man&lt;/code&gt; pages for modern distributions are littered with comments like this one from the BSD-derived macOS 10.15 grep manual: “This implementation supports those options; however, their use is strongly discouraged.” (Discouraged? By whom? &lt;em&gt;Why?&lt;/em&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Fast Forward
&lt;/h2&gt;

&lt;p&gt;Fortunately, though much remains constant in the world of command-line tools, much has changed. There’s a buzz of activity in the open-source world around re-examining the core user experience of CLIs with fresh eyes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://relay.sh"&gt;Relay.sh&lt;/a&gt; is an automation platform for event-driven devops workflows and we’re deeply committed to building awesome command-line experiences. I started writing down these principles as we began rethinking the command line tool for Relay. To me, the key UX principles that underpin the best of the new breed of projects in this vein are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Enable Progressive Discovery&lt;/em&gt; — users are trying to solve a problem, but might start out knowing very little about the tool. The tool should guide them to a solution in iterative steps and provide plain-language help along the way. Users resorting to Google or StackOverflow is an anti-pattern here.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Go Upscale, Intelligently&lt;/em&gt; — the best tools infer the context they’re running in take advantage of modern capabilities if they can. For example, colorized text can greatly add to usability and aesthetics, but if the tool is being run in a pipeline, colors should be off to avoid polluting the output stream.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Be a Good CLI Citizen&lt;/em&gt; — there are a number of hard-fought CLI best practices that good tools follow, both to match users’ expectations and to peacefully co-exist with the rest of the ecosystem. It’s important for tool authors to be aware of these conventions, comply with as many as possible, and be deliberate about any significant divergence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the rest of the post I’ll provide some examples of each of these principles using CLI tools I’ve fallen in love with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable Progressive Discovery
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pulumi.io"&gt;Pulumi&lt;/a&gt; is an infrastructure-as-code tool that allows developers to create and manage cloud infrastructure using general-purpose programming languages. While Pulumi programs can be written in Python, Typescript, .Net and so forth, the user interaction loop centers on using the &lt;code&gt;pulumi&lt;/code&gt; CLI tool to interface between the local code repository and the Pulumi service. It’s a fantastic example of modern CLI design that exemplifies all of the principles I mentioned, but I’m going to focus on the way it enables progressive discovery.&lt;/p&gt;

&lt;p&gt;First, installing it is a breeze because the website has helpful instructions for all the major OSes with a one-click copy-to-clipboard command to get you started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hTZe12WA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1340/1%2AweICV9gULn8iIA3b-rnmUg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hTZe12WA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1340/1%2AweICV9gULn8iIA3b-rnmUg.png" alt="Instructions on how to install the Pulumi command for different operating systems"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve got it installed, simply running the &lt;code&gt;pulumi&lt;/code&gt; command with no arguments gives you helpful hints on what to do next in order to begin working with it. I’ve annotated the output of running &lt;code&gt;pulumi&lt;/code&gt; with no arguments to illustrate this principle.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A_7OhlBT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AcYk9xsnvw53cijyhAUm4YA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A_7OhlBT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AcYk9xsnvw53cijyhAUm4YA.png" alt="Annotated output of the ‘pulumi’ command, indicating that users do not need to know how to use it in order to be successful."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output not only shows, right at the top, the first thing you ought to run if you’re new, it provides some hints as to what the second and third steps might be after you’ve begun. It links to the detailed docs on the website, invites exploration and discovery by giving the complete list of available commands, and has a reference section to show the flags which modify the program’s behavior in consistent ways, regardless of what subcommand you’re using.&lt;/p&gt;

&lt;p&gt;Once you’ve gotten started and are working with a “stack” (a collection of resources that make up one application instance), the idea of progressive discovery shows up again. Running the &lt;code&gt;pulumi stack&lt;/code&gt; subcommand without additional arguments doesn’t error out; instead it provides a reasonable guess as to what you meant: “show me information about the current stack”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ehYrBYrM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AidW9hXxRqW7hMcIk68XymA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ehYrBYrM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AidW9hXxRqW7hMcIk68XymA.png" alt="Running ‘pulumi stack’ outputs info about the current stack and suggests additional commands you might want to run."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to providing metadata about the stack and a nicely-formatted hierarchical representation of its resources, the output has links to the web app for more info and again shows hints about what to do next if this isn’t what you were looking for.&lt;/p&gt;

&lt;p&gt;All in all, this experience is pretty delightful. It makes working with &lt;code&gt;pulumi&lt;/code&gt; positive and enjoyable, and rather than feeling like a cut-down version of a web app it feels like a powerful first-class way of interacting with the service.&lt;/p&gt;
&lt;h2&gt;
  
  
  Go Upscale, Intelligently
&lt;/h2&gt;

&lt;p&gt;My former colleague from Danger and all-around good human C J Silverio tweeted recently:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--5simX4pe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/857590885743116288/izm__c9I_normal.jpg" alt="Ceej is sheltering under cats profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Ceej is sheltering under cats
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @ceejbot
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      The rustlang ecosystem scene that’s making me happy right now: the retakes on ancient unix cli tools, with new approaches to info display.&lt;br&gt;&lt;br&gt;bat&lt;br&gt;dua&lt;br&gt;exa
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      03:19 AM - 22 Feb 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1231055940939472897" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1231055940939472897" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      3
      &lt;a href="https://twitter.com/intent/like?tweet_id=1231055940939472897" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      30
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;This sent me down a rabbit hole of investigation and discovery. There’s indeed a vibrant community working in this space, and the ones CJ mentions are replacements for (respectively) &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;du&lt;/code&gt;, and &lt;code&gt;ls&lt;/code&gt;. (There’s even a &lt;a href="https://github.com/palash25/wc-rs"&gt;rewrite of the &lt;code&gt;wc&lt;/code&gt; command&lt;/a&gt; from the Stephenson essay!) I came out the other side of the rabbit hole with a new set of aliases for &lt;a href="https://github.com/ahpook/dotfiles/blob/master/.zshrc#L84-L92"&gt;my .zshrc&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# if rust stuff is found, use it&lt;/span&gt;
&lt;span class="nv"&gt;RBIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.cargo/bin
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$RBIN&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$RBIN&lt;/span&gt;/bat &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;f &lt;span class="k"&gt;in &lt;/span&gt;less more &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do 
     &lt;/span&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bat &lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="k"&gt;done&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$RBIN&lt;/span&gt;/dua &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;alias du&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dua
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$RBIN&lt;/span&gt;/rg  &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;alias grep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rg
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$RBIN&lt;/span&gt;/exa &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;alias ls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;exa
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$RBIN&lt;/span&gt;/fd  &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;fd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;find
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These tools vary in their implementation but all of them exemplify the “Go Upscale” principle: they are aware of the affordances that modern terminal programs have and make use of them to provide upgraded experiences. To focus on one example, the lowly &lt;code&gt;cat&lt;/code&gt; program is one of the oldest and most useful Unix utilities. Its name is short for “concatenate” and it can be used for all kinds of input and output stream manipulations, but it’s pretty primitive. &lt;code&gt;bat&lt;/code&gt; (&lt;a href="https://github.com/sharkdp/bat"&gt;here’s its homepage on github&lt;/a&gt;) retains the usefulness of the original but adds colorized and line-numbered output, syntax highlighting for over a hundred file types, and cool features like git awareness. So &lt;code&gt;bat README.md&lt;/code&gt; in &lt;a href="https://github.com/lyraproj/hiera"&gt;my local hiera repository&lt;/a&gt; shows me:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tfMgq6xs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUX_JhvilmBkGTPUGNbxzDA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tfMgq6xs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUX_JhvilmBkGTPUGNbxzDA.png" alt="a README.md file showing markdown-aware syntax highlighting, line numbers, and git-aware annotations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The subtly shaded line numbers and line-drawn formatting, the &lt;code&gt;+&lt;/code&gt; markers for uncommitted lines, and the helpful Markdown syntax highlighting are all super cool. But the thing that allowed me to &lt;code&gt;alias cat=bat&lt;/code&gt; in my shell without fear of breaking scripts is that &lt;code&gt;bat&lt;/code&gt; detects when it’s not printing to a terminal and turns all of that pretty-printing off so it retains compatibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be a Good CLI Citizen
&lt;/h2&gt;

&lt;p&gt;There’s a set of conventions and practices that high quality CLI tools share, which enable them to interact seamlessly with each other and, more importantly, allow a user to extrapolate lessons and habits learned from one tool into new contexts. This leads to a quicker sense of mastery and user delight because things feel “intuitive” (in reality, nothing about computers is truly intuitive to humans — there’s just experiences that confirm or confound our expectations based on previous encounters).&lt;/p&gt;

&lt;p&gt;It’s tough to focus on a single tool as an example. Some of these conventions are defined in Jeff Dickey’s &lt;a href="https://medium.com/@jdxcode/12-factor-cli-apps-dd3c227a0e46"&gt;great post “12 Factor CLI Apps”&lt;/a&gt; about the Heroku CLI design philosophy, others from the GNU &lt;code&gt;coreutils&lt;/code&gt; doc &lt;a href="https://www.gnu.org/software/coreutils/manual/html_node/Opening-the-software-toolbox.html"&gt;“Opening the software tool box”&lt;/a&gt;, and some are arguably matters of taste. &lt;em&gt;Please comment if you think I’ve gotten something wrong or missed an important one!&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Expect to operate as part of a pipeline and adjust behavior accordingly. Like the bat example above, turn off any fancy formatting if output isn’t a terminal so downstream tools see plain-text output for easy processing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t cross the streams! Closely related to pipeline operation, output should go to stdout and errors to stderr, so errors won’t be swallowed by redirection or intermingled with actual output.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provide tabular and structured output formats for lists of data. For extracting only parts of a record, make it easy for users to split on whitespace to get just single fields. And no modern tool that outputs a lot of records in a table ought to be without a json output option.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For sophisticated CLIs, such as those which interact with remote services like Pulumi, think deeply about your command’s information architecture, then stick with it. A complex command invocation is like a grammatical sentence: it’s usually got a subject, a verb, and an object. For nontrivial commands there’s a hierarchy of these nouns and verbs that users put together to solve a problem. Either use a verb-object construction like &lt;code&gt;kubectl get pods&lt;/code&gt;, where get is a top-level verb and the targets vary, or subject-verb construction like &lt;code&gt;gcloud container clusters list&lt;/code&gt; (“clusters” is a subcommand of “container” and “list” is the verb).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observe control conventions. Users frequently get things wrong, and sometimes that happens after they’ve hit the enter key on a command. The convention is that &lt;code&gt;^C&lt;/code&gt; (control-C) interrupts execution and exits the program, cleanly if possible. Similarly, &lt;code&gt;^Z&lt;/code&gt; (control-Z) suspends a program so that it can be paused or put in the background. Good CLI commands should honor these signals and behave predictably when they come in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t litter the filesystem. Use package managers and follow their conventions for the target operating system wherever possible. Similarly, follow conventions like &lt;a href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html"&gt;XDG-Spec&lt;/a&gt; for guidance on where to install configuration files, docs, and supporting libraries. This kind of consistent packaging may take some additional work up front but it pays off in the long run when your software can be installed, upgraded, and config-managed alongside the rest of the user’s toolchain.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  END OF FILE
&lt;/h2&gt;

&lt;p&gt;When you’re done inputting a file into cat or its equivalents, a &lt;code&gt;^D&lt;/code&gt; (control-D) character indicates to the terminal that the end of the file’s been reached. Similarly, when ending a blog post it’s customary to summarize the points you’ve made and provide a stirring call to action for the reader. So, to recap the three top level design principles for modern command line interaction design:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable progressive discovery to lead users down a low-friction path to solving their problem with your tool.&lt;/li&gt;
&lt;li&gt;Upgrade capabilities to take advantage of modern terminal emulation, so users get the advantage of colors, graphics, and interaction.&lt;/li&gt;
&lt;li&gt;Understand and implement the conventions for well-behaved tools in your space, users can get to a sense of mastery quicker and avoid unpleasant surprises.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As I mentioned at the top, I’m working on a product called &lt;a href="https://relay.sh"&gt;Relay&lt;/a&gt; that hopefully embodies these principles. Check out the &lt;a href="https://medium.com/relay-sh/building-the-future-of-devops-automation-c25d6cf45ed1"&gt;introductory blog post&lt;/a&gt; to learn more and follow along as we develop our open-source CLI at &lt;a href="https://github.com/puppetlabs/relay"&gt;github.com/puppetlabs/relay&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>design</category>
      <category>programming</category>
      <category>ux</category>
    </item>
    <item>
      <title>3 Commandments for CLI Design</title>
      <dc:creator>🌈 eric sorenson 🎹🔈🎚</dc:creator>
      <pubDate>Wed, 08 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/relay/3-commandments-for-cli-design-4mpg</link>
      <guid>https://dev.to/relay/3-commandments-for-cli-design-4mpg</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NsRBPlcG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/wikipedia/commons/d/d8/Hands_of_God_and_Adam.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NsRBPlcG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/wikipedia/commons/d/d8/Hands_of_God_and_Adam.jpg" alt="Close crop of the Sistine Chapel ceiling painting with God and Adam’s fingers"&gt;&lt;/a&gt;photo: Wikimedia Commons (public domain)&lt;/p&gt;

&lt;h2&gt;
  
  
  In the beginning…
&lt;/h2&gt;

&lt;p&gt;In Neal Stephenson’s 1999 essay &lt;a href="https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html"&gt;“In the Beginning Was The Command Line”&lt;/a&gt;, he describes how using Command-Line Interface (CLI) utilities is simpler and requires less code than a Graphical User Interface (GUI). They’re tiny, they do one thing really well, and they are meant to work in conjunction with other small, single-purpose tools to accomplish complicated tasks quickly.&lt;/p&gt;

&lt;p&gt;However, the old-school Unix utilities are not without their problems. The passage of time and inevitable feature creep have led to situations like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The humble &lt;code&gt;ls&lt;/code&gt; command now has more options than there are letters in the alphabet! Plus, despite the proliferation of features, many advanced and useful options are off by default to preserve backwards compatibility. Other core utilities are in similar situations: &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;tar&lt;/code&gt; are stuck with arcane, user-hostile syntaxes, and the &lt;code&gt;man&lt;/code&gt; pages for modern distributions are littered with comments like this one from the BSD-derived macOS 10.15 &lt;code&gt;grep&lt;/code&gt; manual: “This implementation supports those options; however, their use is strongly discouraged.” (Discouraged? By whom? &lt;em&gt;Why?&lt;/em&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Fast Forward
&lt;/h2&gt;

&lt;p&gt;Fortunately, though much remains constant in the world of command-line tools, much has changed. There’s a buzz of activity in the open-source world around re-examining the core user experience of CLIs with fresh eyes. Not only are the tiny, single-purpose tools getting a refresh, but a new generation of CLIs are emerging that provide entry points into complex cloud services and system tools. The best of these enable power users while retaining the user interaction paradigms that make the small tools great.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/"&gt;Relay.sh&lt;/a&gt; is an automation platform for event-driven devops workflows and we’re deeply committed to building awesome command-line experiences. I started writing down these principles as we began rethinking the command line tool for Relay. To me, the key UX principles that underpin the best of the new breed of projects in this vein are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enable Progressive Discovery&lt;/strong&gt; — users are trying to solve a problem, but might start out knowing very little about the tool. The tool should guide them to a solution in iterative steps and provide plain-language help along the way. Users resorting to Google or StackOverflow is an anti-pattern here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go Upscale, Intelligently&lt;/strong&gt; — the best tools infer the context they’re running in take advantage of modern capabilities if they can. For example, colorized text can greatly add to usability and aesthetics, but if the tool is being run in a pipeline, colors should be off to avoid polluting the output stream.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be a Good CLI Citizen&lt;/strong&gt; — there are a number of hard-fought CLI best practices that good tools follow, both to match users’ expectations and to peacefully co-exist with the rest of the ecosystem. It’s important for tool authors to be aware of these conventions, comply with as many as possible, and be deliberate about any significant divergence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the rest of the post I’ll provide some examples of each of these principles using CLI tools I’ve fallen in love with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable Progressive Discovery
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://pulumi.io"&gt;Pulumi&lt;/a&gt; is an infrastructure-as-code tool that allows developers to create and manage cloud infrastructure using general-purpose programming languages. While Pulumi programs can be written in Python, Typescript, .Net and so forth, the user interaction loop centers on using the &lt;code&gt;pulumi&lt;/code&gt; CLI tool to interface between the local code repository and the Pulumi service. It’s a fantastic example of modern CLI design that exemplifies all of the principles I mentioned, but I’m going to focus on the way it enables progressive discovery.&lt;/p&gt;

&lt;p&gt;First, installing it is a breeze because the website has helpful instructions for all the major OSes with a one-click copy-to-clipboard command to get you started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FLWr0tem--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/6e1cd75f707509f21b45b58371729c7b/d67fd/1weICV9gULn8iIA3b-rnmUg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FLWr0tem--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/6e1cd75f707509f21b45b58371729c7b/d67fd/1weICV9gULn8iIA3b-rnmUg.png" alt="Instructions on how to install the Pulumi command for different operating systems" title="Instructions on how to install the Pulumi command for different operating systems"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve got it installed, simply running the &lt;code&gt;pulumi&lt;/code&gt; command with no arguments gives you helpful hints on what to do next in order to begin working with it. I’ve annotated the output of running &lt;code&gt;pulumi&lt;/code&gt; with no arguments to illustrate this principle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TLie_g_P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/6e25a1017dcbec637642f307748da06c/5a190/1cYk9xsnvw53cijyhAUm4YA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TLie_g_P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/6e25a1017dcbec637642f307748da06c/5a190/1cYk9xsnvw53cijyhAUm4YA.png" alt="Annotated output of the ‘pulumi’ command, indicating that users do not need to know how to use it in order to be successful." title="Annotated output of the ‘pulumi’ command, indicating that users do not need to know how to use it in order to be successful."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output not only shows, right at the top, the first thing you ought to run if you’re new, it provides some hints as to what the second and third steps might be after you’ve begun. It links to the detailed docs on the website, invites exploration and discovery by giving the complete list of available commands, and has a reference section to show the flags which modify the program’s behavior in consistent ways, regardless of what subcommand you’re using.&lt;/p&gt;

&lt;p&gt;Once you’ve gotten started and are working with a “stack” (a collection of resources that make up one application instance), the idea of progressive discovery shows up again. Running the &lt;code&gt;pulumi stack&lt;/code&gt; subcommand without additional arguments doesn’t error out; instead it provides a reasonable guess as to what you meant: “show me information about the current stack”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Qm8vXMxe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/5d5ce7e1a2d9d22aae9091a037faab55/5a190/1idW9hXxRqW7hMcIk68XymA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qm8vXMxe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/5d5ce7e1a2d9d22aae9091a037faab55/5a190/1idW9hXxRqW7hMcIk68XymA.png" alt="Running ‘pulumi stack’ outputs info about the current stack and suggests additional commands you might want to run." title="Running ‘pulumi stack’ outputs info about the current stack and suggests additional commands you might want to run."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to providing metadata about the stack and a nicely-formatted hierarchical representation of its resources, the output has links to the web app for more info and again shows hints about what to do next if this isn’t what you were looking for.&lt;/p&gt;

&lt;p&gt;All in all, this experience is pretty delightful. It makes working with &lt;code&gt;pulumi&lt;/code&gt; positive and enjoyable, and rather than feeling like a cut-down version of a web app it feels like a powerful first-class way of interacting with the service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go Upscale, Intelligently
&lt;/h2&gt;

&lt;p&gt;My former colleague from Danger and all-around good human &lt;a href="https://twitter.com/ceejbot"&gt;C J Silverio&lt;/a&gt; tweeted recently:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The rustlang ecosystem scene that’s making me happy right now: the retakes on ancient unix cli tools, with new approaches to info display.  &lt;/p&gt;

&lt;p&gt;bat&lt;br&gt;&lt;br&gt;
dua&lt;br&gt;&lt;br&gt;
exa&lt;/p&gt;

&lt;p&gt;— Ceej is sheltering under cats (@ceejbot) &lt;a href="https://twitter.com/ceejbot/status/1231055940939472897?ref_src=twsrc%5Etfw"&gt;February 22, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This sent me down a rabbit hole of investigation and discovery. There’s indeed a vibrant community working in this space, and the ones CJ mentions are replacements for (respectively) &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;du&lt;/code&gt;, and &lt;code&gt;ls&lt;/code&gt;. (There’s even &lt;a href="https://github.com/palash25/wc-rs"&gt;a rewrite of the &lt;code&gt;wc&lt;/code&gt; command&lt;/a&gt; from the Stephenson essay!) I came out the other side of the rabbit hole with a new set of aliases for&lt;a href="https://github.com/ahpook/dotfiles/blob/master/.zshrc#L84-L92"&gt;my .zshrc&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# if rust stuff is found, use it
RBIN=$HOME/.cargo/bin
if [[-d $RBIN]]; then
  [[-f $RBIN/bat]] &amp;amp;&amp;amp; for f in less more cat ; do
     alias $f=bat ;
  done
  [[-f $RBIN/dua]] &amp;amp;&amp;amp; alias du=dua
  [[-f $RBIN/rg]] &amp;amp;&amp;amp; alias grep=rg
  [[-f $RBIN/exa]] &amp;amp;&amp;amp; alias ls=exa
  [[-f $RBIN/fd]] &amp;amp;&amp;amp; alias find=fd
fi

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These tools vary in their implementation but all of them exemplify the “Go Upscale” principle: they are aware of the affordances that modern terminal programs have and make use of them to provide upgraded experiences. To focus on one example, the lowly &lt;code&gt;cat&lt;/code&gt; program is one of the oldest and most useful Unix utilities. Its name is short for “concatenate” and it can be used for all kinds of input and output stream manipulations, but it’s pretty primitive. &lt;code&gt;bat&lt;/code&gt; (&lt;a href="https://github.com/sharkdp/bat"&gt;here’s its homepage on github&lt;/a&gt;) retains the usefulness of the original but adds colorized and line-numbered output, syntax highlighting for over a hundred file types, and cool features like git awareness. So &lt;code&gt;bat README.md&lt;/code&gt; in my &lt;a href="https://github.com/lyraproj/hiera"&gt;local hiera repository&lt;/a&gt; shows me:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zy6m0b4X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/981028b7ec3774c0ebabb8542b1326a4/f8067/1UX_JhvilmBkGTPUGNbxzDA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zy6m0b4X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/981028b7ec3774c0ebabb8542b1326a4/f8067/1UX_JhvilmBkGTPUGNbxzDA.png" alt="a README.md file showing markdown-aware syntax highlighting, line numbers, and git-aware annotations" title="a README.md file showing markdown-aware syntax highlighting, line numbers, and git-aware annotations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The subtly shaded line numbers and line-drawn formatting, the &lt;code&gt;+&lt;/code&gt; markers for uncommitted lines, and the helpful Markdown syntax highlighting are all super cool. But the thing that allowed me to &lt;code&gt;alias cat=bat&lt;/code&gt; in my shell without fear of breaking scripts is that &lt;code&gt;bat&lt;/code&gt; detects when it’s not printing to a terminal and turns all of that pretty-printing off so it retains compatibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be a Good CLI Citizen
&lt;/h2&gt;

&lt;p&gt;There’s a set of conventions and practices that high quality CLI tools share, which enable them to interact seamlessly with each other and, more importantly, allow a user to extrapolate lessons and habits learned from one tool into new contexts. This leads to a quicker sense of mastery and user delight because things feel “intuitive” (in reality, nothing about computers is truly intuitive to humans — there’s just experiences that confirm or confound our expectations based on previous encounters).&lt;/p&gt;

&lt;p&gt;It’s tough to focus on a single tool as an example. Some of these conventions are defined in &lt;a href="https://twitter.com/jdxcode"&gt;Jeff Dickey&lt;/a&gt;’s great post &lt;a href="https://medium.com/@jdxcode/12-factor-cli-apps-dd3c227a0e46"&gt;“12 Factor CLI Apps”&lt;/a&gt; about the Heroku CLI design philosophy, others from the GNU coreutils doc “&lt;a href="https://www.gnu.org/software/coreutils/manual/html_node/Opening-the-software-toolbox.html"&gt;Opening the software tool box”&lt;/a&gt;, and some are arguably matters of taste. &lt;strong&gt;Please comment if you think I’ve gotten something wrong or missed an important one!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expect to operate as part of a pipeline and adjust behavior accordingly. Like the &lt;code&gt;bat&lt;/code&gt; example above, turn off any fancy formatting if output isn’t a terminal so downstream tools see plain-text output for easy processing.&lt;/li&gt;
&lt;li&gt;Don’t cross the streams! Closely related to pipeline operation, output should go to stdout and errors to stderr, so errors won’t be swallowed by redirection or intermingled with actual output.&lt;/li&gt;
&lt;li&gt;Provide tabular and structured output formats for lists of data. For extracting only parts of a record, make it easy for users to split on whitespace to get just single fields. And no modern tool that outputs a lot of records in a table ought to be without a json output option.&lt;/li&gt;
&lt;li&gt;For sophisticated CLIs, such as those which interact with remote services like Pulumi, think deeply about your command’s information architecture, then stick with it. A complex command invocation is like a grammatical sentence: it’s usually got a subject, a verb, and an object. For nontrivial commands there’s a hierarchy of these nouns and verbs that users put together to solve a problem. Either use a verb-object construction like &lt;code&gt;kubectl get pods&lt;/code&gt; , where &lt;code&gt;get&lt;/code&gt; is a top-level verb and the targets vary, or subject-verb construction like &lt;code&gt;gcloud container clusters list&lt;/code&gt; (“clusters” is a subcommand of “container” and “list” is the verb).&lt;/li&gt;
&lt;li&gt;Observe control conventions. Users frequently get things wrong, and sometimes that happens after they’ve hit the enter key on a command. The convention is that &lt;code&gt;^C&lt;/code&gt; (control-C) interrupts execution and exits the program, cleanly if possible. Similarly, &lt;code&gt;^Z&lt;/code&gt; (control-Z) suspends a program so that it can be paused or put in the background. Good CLI commands should honor these signals and behave predictably when they come in.&lt;/li&gt;
&lt;li&gt;Don’t litter the filesystem. Use package managers and follow their conventions for the target operating system wherever possible. Similarly, follow conventions like &lt;a href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html"&gt;XDG-Spec&lt;/a&gt; for guidance on where to install configuration files, docs, and supporting libraries. This kind of consistent packaging may take some additional work up front but it pays off in the long run when your software can be installed, upgraded, and config-managed alongside the rest of the user’s toolchain.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  END OF FILE
&lt;/h2&gt;

&lt;p&gt;When you’re done inputting a file into &lt;code&gt;cat&lt;/code&gt; or its equivalents, a &lt;code&gt;^D&lt;/code&gt; (control-D) character indicates to the terminal that the end of the file’s been reached. Similarly, when ending a blog post it’s customary to summarize the points you’ve made and provide a stirring call to action for the reader. So, to recap the three top level design principles for modern command line interaction design:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable progressive discovery to lead users down a low-friction path to solving their problem with your tool.&lt;/li&gt;
&lt;li&gt;Upgrade capabilities to take advantage of modern terminal emulation, so users get the advantage of colors, graphics, and interaction.&lt;/li&gt;
&lt;li&gt;Understand and implement the conventions for well-behaved tools in your space, users can get to a sense of mastery quicker and avoid unpleasant surprises.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As I mentioned at the top, I’m working on a product called &lt;a href="https://dev.to/"&gt;Relay&lt;/a&gt; that hopefully embodies these principles. Check out the &lt;a href="https://dev.to/blog/building-the-future-of-devops-automation"&gt;introductory blog post&lt;/a&gt; to learn more and follow along as we develop our open-source CLI at &lt;a href="https://github.com/puppetlabs/relay"&gt;puppetlabs/relay&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Thanks to Lee Briggs.&lt;/small&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What’s Going on With Tekton? (Part 1)</title>
      <dc:creator>🌈 eric sorenson 🎹🔈🎚</dc:creator>
      <pubDate>Wed, 25 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/relay/what-s-going-on-with-tekton-part-1-1gc4</link>
      <guid>https://dev.to/relay/what-s-going-on-with-tekton-part-1-1gc4</guid>
      <description>&lt;p&gt;&lt;a href="///static/6322c6066301a32b23c4af4373589aaa/5a46d/1_F4MYnD7LzXbLPzAVr2QNzg.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7eCjoNnz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/6322c6066301a32b23c4af4373589aaa/5a46d/1_F4MYnD7LzXbLPzAVr2QNzg.png" alt="Tekton logo" title="Tekton logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://tekton.dev"&gt;Tekton&lt;/a&gt; is a powerful tool for building continuous delivery pipelines using modern infrastructure. The project has been moving very quickly and has added a lot of awesome features recently, but due to the (necessary and wise) cancellation of conferences through the spring and summer of 2020 they have not gotten the attention they deserve. We’ve been working with Tekton as an upstream component of our devops automation service &lt;a href="https://dev.to/"&gt;relay.sh&lt;/a&gt;, so I thought our new blog be a great chance to get the word out.&lt;/p&gt;

&lt;p&gt;This 2-part blog series aims to give an overview of some core concepts for background and then dive into some more advanced technical topics and updates for Tekton. If you’re brand new to Tekton, check out Christie Wilson and Kim Lewandowski’s talk on &lt;a href="https://www.youtube.com/watch?v=TQJ_pdTxZr0&amp;amp;t=1s"&gt;“Next Generation CI/CD with GKE and Tekton”&lt;/a&gt; from Google Cloud Next 2019. If you want to skip ahead, you can &lt;a href="https://dev.to/blog/whats-going-on-with-tekton-part-2"&gt;go straight to Part 2&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who’s Using Tekton?
&lt;/h2&gt;

&lt;p&gt;It’s important to note that Tekton is more of a platform for building CD tools around, rather than a user facing product. The most advanced example of products built on Tekton is probably &lt;a href="http://jenkins-x.io"&gt;Jenkins X&lt;/a&gt;, a re-imagining of the ubiquitous Jenkins CI tool for cloud native applications. Jenkins X provides the user-facing GUI, a higher-level YAML dialect for describing pipelines, and a powerful GitOps workflow. To borrow git’s terminology, Jenkins X is the “porcelain”, while Tekton provides the “plumbing”: the pipeline execution engine that’s responsible for ordering the steps in a pipeline, launching pods that get the build/test/deploy work done, passing state and secrets around, etc. Ethan Jones at Cloudbees &lt;a href="https://jenkins-x.io/blog/2020/03/11/tekton/"&gt;wrote a great blog post&lt;/a&gt; describing the history of the projects and the rationale behind the Jenkins X team’s decision to consolidate on Tekton as the one-and-only execution engine.&lt;/p&gt;

&lt;p&gt;Similarly, here at Puppet, we’ve been using Tekton as the plumbing under the service formerly known as Project Nebula — now out of incubation and renamed &lt;a href="https://dev.to/"&gt;Relay&lt;/a&gt; — for the last year. Relay lets you define workflows of operations tasks and trigger them by linking Relay to external services that you already use, like Github or PagerDuty. The goal is to fill in what we see as an emerging category of &lt;a href="https://medium.com/relay-sh/rise-of-the-apis-1d13d6968e73"&gt;&lt;em&gt;event-driven&lt;/em&gt; devops automation&lt;/a&gt;, now that desired-state and ad-hoc automation are well understood. When an event comes in to the service, Relay launches a container to figure out how to handle it (we’re calling this a trigger action). It can extract values from the incoming event and use them to fill in parameters in a workflow, which is launched as a Tekton pipeline on GCP. Similar to Jenkins X, workflows are &lt;a href="https://github.com/puppetlabs/nebula-workflow-examples"&gt;written in simple YAML&lt;/a&gt; that the service translates into Tekton CRDs; Tekton then handles dependencies, ordering, and state management between workflow steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Brief History of the (Tekton) Universe
&lt;/h2&gt;

&lt;p&gt;Tekton is a project that evolved from an internal Google tool that used &lt;a href="https://knative.dev/"&gt;Knative&lt;/a&gt; to build and deploy software. In 2018, it was spun out as an independent project and donated to the Continuous Delivery Foundation, similar to Kubernetes’ donation to the CNCF.&lt;/p&gt;

&lt;p&gt;The core component, Tekton Pipelines, runs as a controller in a Kubernetes cluster. It registers several custom resource definitions which represent the basic Tekton objects with the Kubernetes API server, so the cluster knows to delegate requests containing those objects to Tekton. These primitives are fundamental to the way Tekton works, and once you’ve got Tekton and the Tekton Dashboard up and running, you can view them like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; kubectl get crd | rg tekton | cut -f 1 -d ' '
clustertasks.tekton.dev
conditions.tekton.dev
extensions.dashboard.tekton.dev
pipelineresources.tekton.dev
pipelineruns.tekton.dev
pipelines.tekton.dev
taskruns.tekton.dev
tasks.tekton.dev

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If the nomenclature here feels confusing, don’t feel bad — it is complicated! Each tool in the space uses slightly different terms; this is something we’re working on standardizing in the &lt;a href="https://github.com/cdfoundation/sig-interoperability"&gt;CDF Interoperability SIG&lt;/a&gt;. (We’d love your input!) Tekton’s usage of these terms — and the CRDs which implement the hierarchy of objects — maps closely to this list of CRDs (via the &lt;a href="https://github.com/cdfoundation/sig-interoperability/blob/master/docs/vocabulary.md"&gt;sig-interop Vocabulary definitions doc&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step&lt;/strong&gt; : a specific function to perform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task&lt;/strong&gt; : is a collection of sequential steps you would want to run as part of your continuous integration flow. A task will run inside a pod on your cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ClusterTask&lt;/strong&gt; : Similar to Task, but with a cluster scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline&lt;/strong&gt; : stateless, reusable, parameterized collection of tasks. Tasks are linked together in a Pipeline, which describes the end-to-end deployment for an application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PipelineRun&lt;/strong&gt; : an instantiation of a Pipeline definition, filling in the Pipeline’s parameters with concrete values&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline Resource&lt;/strong&gt; : objects that will be input to or output from tasks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger&lt;/strong&gt; : Triggers is a Kubernetes Custom Resource Definition (CRD) controller that allows you to extract information from event payloads (a “trigger”) to create Kubernetes resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notable omissions from this list are “Steps”, which don’t have their own CRD because they’re the smallest unit of execution which are always contained inside a Task; plus Conditions and Dashboard Extensions, which are still optional and experimental — but very exciting! We’ll talk about these more in part 2.&lt;/p&gt;

&lt;p&gt;If you’re working on an in-house CD platform, and especially if you’re looking at ways to deliver cloud-native applications with a toolchain that looks and feels like the apps it’s managing, Tekton could be a good fit. &lt;a href="https://dev.to/blog"&gt;Read on if these capabilities sound intriguing…&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What’s Going on With Tekton? (Part 2)</title>
      <dc:creator>🌈 eric sorenson 🎹🔈🎚</dc:creator>
      <pubDate>Wed, 25 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/relay/what-s-going-on-with-tekton-part-2-3p7f</link>
      <guid>https://dev.to/relay/what-s-going-on-with-tekton-part-2-3p7f</guid>
      <description>&lt;h2&gt;
  
  
  The Story So Far…
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.toblog/whats-going-on-with-tekton-part-1"&gt;Part 1&lt;/a&gt; of this two-part blog, I talked about how we’re using Tekton Pipelines in building &lt;a href="https://dev.to/"&gt;relay.sh&lt;/a&gt;, how &lt;a href="https://jenkins-x.io"&gt;Jenkins X&lt;/a&gt; is using it, and a brief history of the project and its terminology. In this part, I’ll dig into some of the cool advancements and features in the core Pipelines project and the broader ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ‘tkn‘ CLI tool
&lt;/h2&gt;

&lt;p&gt;There’s been a ton of work lately going into the &lt;code&gt;tkn&lt;/code&gt; command-line interface. I wanted to introduce it first, not just because there’ve been a number of very cool improvements in it recently, but also because we at Puppet are heavily invested in awesome command-line user experiences for our users, and &lt;code&gt;tkn&lt;/code&gt; exhibits some great UX patterns that are worth looking at, even if you’re not using it directly.&lt;/p&gt;

&lt;p&gt;You can install &lt;code&gt;tkn&lt;/code&gt; via Homebrew or tarball; check out the &lt;a href="https://github.com/tektoncd/cli"&gt;README in the tektoncd/cli repo&lt;/a&gt; for the details. It uses the kubernetes client API, so if &lt;code&gt;kubectl get pods --namespace=tekton-pipelines&lt;/code&gt; works for you, so will &lt;code&gt;tkn&lt;/code&gt;. The first cool thing about the CLI that it supports both bash and zsh command completion, so typing &lt;code&gt;tkn &amp;lt;Tab&amp;gt;&lt;/code&gt; will show you the list of subcommands it supports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; tkn &amp;lt;Tab&amp;gt;
 -- command --
clustertask -- Manage clustertasks
completion -- Prints shell completion scripts
condition -- Manage conditions
eventlistener -- Manage eventlisteners
help -- Help about any command
pipeline -- Manage pipelines
pipelinerun -- Manage pipelineruns
resource -- Manage pipeline resources
task -- Manage tasks
taskrun -- Manage taskruns
triggerbinding -- Manage triggerbindings
triggertemplate -- Manage triggertemplates
version -- Prints version information

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Many of these subcommands map directly back to the terminology and underlying CRDs I mentioned in the opening. It’s important to note that, by design, the &lt;code&gt;tkn&lt;/code&gt; CLI is primarily a &lt;em&gt;read-only&lt;/em&gt; interface, not a &lt;em&gt;read-write&lt;/em&gt; one, so creation and editing of the objects still needs to go through &lt;code&gt;kubectl&lt;/code&gt;. That’s because the creation of Tekton objects boils down to feeding YAML descriptions into the Kubernetes cluster API; modulo introducing a higher-order language like Relay or Jenkins X, there’s not much &lt;code&gt;tkn&lt;/code&gt; can add over raw &lt;code&gt;kubectl apply -f mypipeline.yaml&lt;/code&gt;. There are, however, several commands for controlling existing objects that are substantially nicer to use than their &lt;code&gt;kubectl&lt;/code&gt; equivalents. For example, &lt;code&gt;tkn pipeline start&lt;/code&gt; will kick off a new run of an existing pipeline, without you needing to craft a new YAML file for each one.&lt;/p&gt;

&lt;p&gt;In addition to execution, the detailed output you get from &lt;code&gt;tkn&lt;/code&gt; is vastly improved over the&lt;code&gt;kubectl describe&lt;/code&gt; equivalents. For example, after running an &lt;a href="https://github.com/tektoncd/pipeline/blob/master/examples/v1beta1/pipelineruns/conditional-pipelinerun.yaml"&gt;example pipeline using conditions&lt;/a&gt; (more on those in a moment), I can get a compact list of recent runs and see useful information about the one I’m most interested in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; tkn taskrun list
NAME STARTED DURATION STATUS
condtional-pr-then-check-gtp96 27 minutes ago 7 seconds Succeeded
condtional-pr-then-check-gtp96-file-exists-v9m2t 27 minutes ago 14 seconds Succeeded
condtional-pr-first-create-file-4n9zh 27 minutes ago 22 seconds Succeeded
steps-run-in-order-p6v7q 5 hours ago 9 seconds Succeeded
echo-hello-world-task-run 1 day ago 9 seconds Succeeded

&amp;gt; tkn taskrun describe condtional-pr-first-create-file-4n9zh [0/3547]
Name: condtional-pr-first-create-file-4n9zh
Namespace: default
Task Ref: create-readme-file
Service Account: default

🌡️ Status

STARTED DURATION STATUS
4 hours ago 22 seconds Succeeded

[...]

🦶 Steps

NAME STATUS
 ∙ write-new-stuff Completed
 ∙ create-dir-workspace-868lz Completed
 ∙ source-copy-pipeline-git-bpt22 Completed
 ∙ source-mkdir-pipeline-git-4lg5b Completed

🚗 Sidecars

No sidecars

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(Yes, the emoji are part of the output! 😺)&lt;/p&gt;

&lt;p&gt;The equivalent &lt;code&gt;kubectl describe&lt;/code&gt; commands would spew out some verbose, unhelpful output and require lots of &lt;code&gt;awk&lt;/code&gt;-ward manipulation in order to see the same level of usable info we see here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipeline Improvements: Conditions
&lt;/h2&gt;

&lt;p&gt;I mentioned above that the sample pipeline run we’re looking at makes use of Conditions. Conditions landed recently and are a welcome addition to Pipeline capabilities. Conditions extend Tekton’s core concept — launching task-specific containers and managing their success or failure — to enable decision-making in the middle of a pipeline run. Normally, a container’s entrypoint exiting with a non-zero exit code indicates that something went horribly wrong — it couldn’t clone a git repository, or unit tests failed, perhaps — but a container flagged as a condition failing just means that other Tasks marked as dependent on that container’s success will not be executed.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/tektoncd/pipeline/blob/master/examples/v1beta1/pipelineruns/conditional-pipelinerun.yaml"&gt;pipeline run that generated the output above&lt;/a&gt; contains a condition that shows the utility and potential power of the feature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: tekton.dev/v1alpha1
kind: Condition
metadata:
  name: file-exists
spec:
  params:
    - name: 'path'
  resources:
    - name: workspace
      type: git
  check:
    image: alpine
    script: 'test -f $(resources.workspace.path)/$(params.path)'

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This Condition uses the &lt;code&gt;alpine&lt;/code&gt; image to run a really simple inline script to make sure a given file exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: conditional-pipeline
spec:
  resources:
    - name: source-repo
      type: git
  params:
    - name: 'path'
      default: 'README.md'
  tasks:
    - name: first-create-file
      taskRef:
        name: create-readme-file
      resources:
        outputs:
          - name: workspace
            resource: source-repo
    - name: then-check
      conditions:
        - conditionRef: 'file-exists'
          params:
            - name: 'path'
              value: '$(params.path)'
          resources:
            - name: workspace
              resource: source-repo
              from: [first-create-file]
      taskRef:
        name: echo-hello

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The Pipeline then creates a &lt;code&gt;README.md&lt;/code&gt; file on line 14, then uses &lt;code&gt;file-exists&lt;/code&gt; condition (starting on line 22) to test whether the file was created successfully. If so, it executes the &lt;code&gt;echo-hello&lt;/code&gt; task. Both of these individual tasks are defined as separate Task objects to enable reuse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: create-readme-file
spec:
  resources:
    outputs:
      - name: workspace
        type: git
  steps:
    - name: write-new-stuff
      image: ubuntu
      script: 'touch $(resources.outputs.workspace.path)/README.md'
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: echo-hello
spec:
  steps:
    - name: echo
      image: ubuntu
      script: 'echo hello'

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There’s an elegance to this design that, to me anyway, expresses one of the coolest parts of working with Kubernetes. It distills a problem down to a set of declarative resources: has this container run? If not, run it. Then builds upwards: Did it exit successfully? If so, proceed with the next task.&lt;/p&gt;

&lt;p&gt;The specification is &lt;a href="https://github.com/tektoncd/pipeline/blob/master/docs/conditions.md"&gt;described in the Conditions doc&lt;/a&gt; and there are several more conditional &lt;a href="https://github.com/tektoncd/pipeline/tree/master/examples/v1beta1/pipelineruns"&gt;examples in the tektoncd/pipeline repo&lt;/a&gt;. Make sure you’re running the latest version as some of the implementation details are still solidifying as Tekton moves towards its beta release in early 2020.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dashboard and Trigger Deliciousness
&lt;/h2&gt;

&lt;p&gt;One of the best things about the Tekton community is the weekly working group calls. They’re open to anyone who joins the tekton-dev Google group (check out the details &lt;a href="https://github.com/tektoncd/community/blob/master/working-groups.md"&gt;in the tektoncd/community repo&lt;/a&gt;), stay on-topic more than 95% of meetings I’ve seen, and present a really powerful and positive example of how multi-vendor open source ought to work. On any given Wednesday, there’ll be representatives from Google, VMware, IBM, Red Hat (well, a different part of IBM, anyway!), eBay, Apple, D2iQ, and many other vendor and end user organizations. While some of these companies’ agendas might diverge, the team overall works in a remarkably healthy and cooperative manner to get stuff done: from collaborative comments on design docs to encouraging messages on pull requests, from my perspective Tekton is a burgeoning open-source success story.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/625791c0a379e2d7a448c96c2dd760a6/41d3b/1bYeir6qqqDqQvxWhOFyFLw.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5lfRF8TG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/625791c0a379e2d7a448c96c2dd760a6/41d3b/1bYeir6qqqDqQvxWhOFyFLw.png" alt="Contributor encouragement … and kittens!" title="Contributor encouragement … and kittens!"&gt;&lt;/a&gt;&lt;em&gt;Contributor encouragement … and kittens!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On a recent working group call, Andrea Frittoli from IBM did a two-fer demo, showing not only how &lt;a href="https://dashboard.dogfooding.tekton.dev/"&gt;Tekton dogfoods Tekton for its own build and deployment pipeline&lt;/a&gt;, but how far the Tekton Dashboard has come in displaying the inner workings of the infrastructure.&lt;/p&gt;

&lt;p&gt;Dashboard is an graphical add-on to Tekton, primarily developed by IBM folks as an upstream component of the &lt;a href="https://kabanero.io"&gt;Kabanero.io&lt;/a&gt; project, which (as you might expect) provides a graphical view into what’s going on across your Tekton deployment. I’ll give a brief rundown of Dashboard’s capabilities here; for an in-depth look, check out Adam Roberts’ blog post on the IBM developer blog &lt;a href="https://developer.ibm.com/blogs/why-nows-a-great-time-to-use-the-tekton-dashboard/"&gt;“Why Now’s a Great Time to Use the Tekton Dashboard”&lt;/a&gt; (for whatever value of “now” happens to be true for you!)&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/68c28ddebf1f406a17fbb794e18cfb0a/84f4d/1W65Bj746jObgefl9nSv6jg.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xLnQaf6Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/68c28ddebf1f406a17fbb794e18cfb0a/5a190/1W65Bj746jObgefl9nSv6jg.png" alt="Tekton dashboard showing event listener resources" title="Tekton dashboard showing event listener resources"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from the sidebar, the Dashboard has kept pace with the new CRDs that the platform implements. One that’s particularly interesting is the highlighted &lt;code&gt;EventListeners&lt;/code&gt; resources — the ones in the dogfooding repo are “raw” resources, but there’s an &lt;a href="https://github.com/tektoncd/experimental/blob/master/webhooks-extension/docs/GettingStarted.md"&gt;extension to the Dashboard&lt;/a&gt; that allows you to easily configure webhook events from external services so you can (for example) send Tekton an event when a Github PR is merged.&lt;/p&gt;

&lt;p&gt;The Dashboard’s webhooks extension provides a friendly interaction layer into the Triggers system, but even without it the &lt;a href="https://github.com/tektoncd/triggers"&gt;Tekton Triggers&lt;/a&gt; project is very cool. It allows Tekton to become responsive to events that originate outside of your Kubernetes cluster. This makes it much easier to integrate Tekton into your broader infrastructure, instead of requiring explicit requests against the k8s cluster API to trigger task and pipeline runs. The &lt;code&gt;EventListeners&lt;/code&gt; , as in the screenshot above, provide an endpoint for external systems to talk to. As events come in, &lt;code&gt;TriggerBindings&lt;/code&gt; transform fields form them into parameters for&lt;code&gt;TriggerTemplates&lt;/code&gt;. The templates, in turn, generate resources like the Task and Pipeline runs that we’ve already seen. This level of dynamic instantiation truly levels Tekton’s capabilities up to the point where it can handle modeling the complexity of modern deployment scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  The End
&lt;/h2&gt;

&lt;p&gt;As you can tell by the length of this post, I’m really excited about all of the advancement in Tekton. As part of Relay, we’ve been trying to both keep abreast of the new features and contribute back wherever we can (in fact the cute kitten pic was from one of our pull requests!). The &lt;code&gt;tkn&lt;/code&gt; CLI is an awesome example of using a familiar shell-based paradigm to interact with an API-driven service, Conditions bring a much-needed level of expressiveness to pipeline definitions, and we believe deeply in the &lt;a href="https://dev.to/blog/building-the-future-of-devops-automation"&gt;future of event-driven automation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here are some links to follow up with the Tekton community and the related projects I mentioned in this series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://github.com/tektoncd/community"&gt;tektoncd/community&lt;/a&gt; repo has links to our Slack workspace and mailing lists.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://jenkins-x.io/community/"&gt;Jenkins X community page&lt;/a&gt; has office hours and contact info.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://kabanero.io"&gt;Kabanero project&lt;/a&gt; is a spicy way to get teams deploying Kubernetes apps faster.&lt;/li&gt;
&lt;li&gt;We’d love to get your input on which &lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSdwFjdpkX_DtAZveqY7uEPAsKhroutJXVSbfXRtVzYDmmpSRQ/viewform?usp=send_form"&gt;services and tools you’d like to connect with Relay&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
