<?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: Montana Mendy</title>
    <description>The latest articles on DEV Community by Montana Mendy (@montana).</description>
    <link>https://dev.to/montana</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%2F489340%2F9a350e6e-9400-4a63-a6cd-45003207e9a7.jpeg</url>
      <title>DEV Community: Montana Mendy</title>
      <link>https://dev.to/montana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/montana"/>
    <language>en</language>
    <item>
      <title>Getting started with an open source NSA tool to construct distributed graphs </title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Sat, 26 Feb 2022 23:33:16 +0000</pubDate>
      <link>https://dev.to/montana/getting-started-with-an-open-source-nsa-tool-to-construct-distributed-graphs-1ja1</link>
      <guid>https://dev.to/montana/getting-started-with-an-open-source-nsa-tool-to-construct-distributed-graphs-1ja1</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N8CMB3UP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b2aba9aev1esjj68qkhg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N8CMB3UP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b2aba9aev1esjj68qkhg.png" alt="Image description" width="528" height="76"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Datawave is a Java-based ingest and query framework that leverages Apache Accumulo to provide fast, secure access to your data. Datawave supports a wide variety of use cases, including but not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data fusion across structured and unstructured datasets&lt;/li&gt;
&lt;li&gt;Construction and analysis of distributed graphs&lt;/li&gt;
&lt;li&gt;Multi-tenant data architectures, with tenants having distinct security requirements and data access patterns&lt;/li&gt;
&lt;li&gt;Fine-grained control over data access, integrated easily with existing user-authorization services and PKI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is the basic structure of Datawave:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oRItbHOf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5k65x8rst498h5asbv2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oRItbHOf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5k65x8rst498h5asbv2w.png" alt="Image description" width="638" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a graphic I made that get's a little more in-depth:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tPPWxFWJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0xq5kuykxpkcsx0r4sho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tPPWxFWJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0xq5kuykxpkcsx0r4sho.png" alt="Flowchart" width="880" height="1194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you know how the architecture flows a bit better let's start with installing Datawave, then we'll get into Edges. &lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with NSA's Datawave
&lt;/h2&gt;

&lt;p&gt;Before we start, NB: You should have an understanding of using simple Bash scripting, Linux commands like &lt;code&gt;grep&lt;/code&gt; &lt;code&gt;awk&lt;/code&gt; and using piping. &lt;/p&gt;

&lt;h2&gt;
  
  
  What you'll need
&lt;/h2&gt;

&lt;p&gt;Linux, Bash, and an Internet connection to &lt;code&gt;wget&lt;/code&gt; tarballs (tar.gz)that you should be able to ssh to localhost without a passphrase.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that the quickstart Hadoop install will set up passphrase-less ssh for you automatically, unless it detects that you already have a &lt;code&gt;private/public&lt;/code&gt; key pair generated&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Familiarize yourself with &lt;code&gt;swap&lt;/code&gt; and/or &lt;code&gt;swapping&lt;/code&gt; if you haven't already. You'll need this. &lt;a href="https://wiki.gentoo.org/wiki/Swap"&gt;https://wiki.gentoo.org/wiki/Swap&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Datawave through the CLI in 5 commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"source DW_SOURCE/contrib/datawave-quickstart/bin/env.sh"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc                                                              
allInstall                                                                   
datawaveWebStart &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; datawaveWebTest   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we're adding sources to our &lt;code&gt;.bashrc&lt;/code&gt; this can be true too if you're using &lt;code&gt;zsh&lt;/code&gt;.                                     &lt;/p&gt;

&lt;p&gt;The four commands above will complete the entire quickstart installation. However, it’s a good idea to at least skim over the sections below to get an idea of how the setup works and how to customize it for your own preferences.&lt;/p&gt;

&lt;p&gt;To keep things simple, DataWave, Hadoop, Accumulo, ZooKeeper, and Wildfly will be installed under your &lt;code&gt;DW_SOURCE/contrib/datawave-quickstart&lt;/code&gt; directory, and all will be owned by / executed as the current user, hence why a bash script in the background was being ran. &lt;/p&gt;

&lt;h2&gt;
  
  
  Overriding your default binaries
&lt;/h2&gt;

&lt;p&gt;On some occasions you may need to override the default binaries (not in all machines, or setups). Let's open up Vim, and do this in case you do need to end up overriding your binaries. To override the quickstarts default version of a particular binary, simply override the desired &lt;code&gt;DW_*_DIST_URI&lt;/code&gt; value as shown below. URIs may be local or remote. Local file URI values must be prefixed with &lt;code&gt;file://&lt;/code&gt;, so let's start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vi ~/.bashrc

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_DIST_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;file:///my/local/binaries/hadoop-x.y.z.tar.gz
     &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_DIST_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://some.apache.mirror/accumulo/1.x/accumulo-1.x-bin.tar.gz
     &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DW_ZOOKEEPER_DIST_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://some.apache.mirror/zookeeper/x.y/zookeeper-x.y.z.tar.gz
     &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DW_WILDFLY_DIST_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;file:///my/local/binaries/wildfly-10.x.tar.gz
     &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DW_JAVA_DIST_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;file:///my/local/binaries/jdk-8-update-x.tar.gz
     &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DW_MAVEN_DIST_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;file:///my/local/binaries/apache-maven-x.y.z.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We just grabbed Apache Hadoop, Accumulo, Zookeeper, Wildfly, and Maven. Now if this seems like a lot, we can always bootstrap your environment with a bash script, this doesn't give you as much flexibility (unless you want to add it), but it is quicker, add your own shebang line at the top. Make sure you make this bash script executable, when done copy/pasting, run &lt;code&gt;chmod u+x bootstrap_datawave.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SERVICE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_SOURCE&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SERVICE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/../../../../.."&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_ACCUMULO_AUTHS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_ACCUMULO_AUTHS&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;PUBLIC&lt;/span&gt;&lt;span class="p"&gt;,PRIVATE,FOO,BAR,DEF,A,B,C,D,E,F,G,H,I,DW_USER,DW_SERV,DW_ADMIN,JBOSS_ADMIN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Import DataWave Web test user configuration&lt;/span&gt;

&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SERVICE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bootstrap-user.sh"&lt;/span&gt;

&lt;span class="c"&gt;# Selected Maven profile for the DataWave build&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROFILE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;dev&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Maven command&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_COMMAND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_COMMAND&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;mvn&lt;/span&gt;&lt;span class="p"&gt; -P&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROFILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt; -Ddeploy -Dtar -Ddist -Dservices -DskipTests clean install --builder smart -T1.0C&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Home of any temp data and *.properties file overrides for this instance of DataWave&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_DATA_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_CLOUD_DATA&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/datawave"&lt;/span&gt;

&lt;span class="c"&gt;# Temp dir for persisting our dynamically-generated ${DW_DATAWAVE_BUILD_PROFILE}.properties file&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROPERTIES_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_DATA_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/build-properties"&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_STATUS_LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROPERTIES_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/build-progress.tmp"&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_TARBALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*/datawave-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROFILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-*-dist.tar.gz"&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_WEB_TARBALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*/datawave-ws-deploy-application-*-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROFILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_KEYSTORE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_KEYSTORE&lt;/span&gt;&lt;span class="k"&gt;:-${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SOURCE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/web-services/deploy/application/src/main/wildfly/overlay/standalone/configuration/certificates/testServer.p12&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_KEYSTORE_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_KEYSTORE_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;ChangeIt&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_KEYSTORE_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_KEYSTORE_TYPE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;PKCS12&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_TRUSTSTORE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_TRUSTSTORE&lt;/span&gt;&lt;span class="k"&gt;:-${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SOURCE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/web-services/deploy/application/src/main/wildfly/overlay/standalone/configuration/certificates/ca.jks&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_TRUSTSTORE_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_TRUSTSTORE_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;ChangeIt&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;DW_DATAWAVE_TRUSTSTORE_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_TRUSTSTORE_TYPE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;JKS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Accumulo shell script for initializing whatever we may need in Accumulo for DataWave&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;createAccumuloShellInitScript&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c"&gt;# Allow user to inject their own script into the env...&lt;/span&gt;
   &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_SHELL_INIT_SCRIPT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &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;return &lt;/span&gt;0

   &lt;span class="c"&gt;# Create script and add 'datawave' VFS context, if enabled...&lt;/span&gt;

   &lt;span class="nv"&gt;DW_ACCUMULO_SHELL_INIT_SCRIPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"
   createnamespace datawave
   createtable datawave.queryMetrics_m
   createtable datawave.queryMetrics_s
   setauths -s &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_ACCUMULO_AUTHS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_VFS_DATAWAVE_ENABLED&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;false&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="nv"&gt;DW_ACCUMULO_SHELL_INIT_SCRIPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_SHELL_INIT_SCRIPT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
   config -s table.classpath.context=datawave"&lt;/span&gt;
   &lt;span class="k"&gt;fi

   &lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_SHELL_INIT_SCRIPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_SHELL_INIT_SCRIPT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
   quit
   "&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;createBuildPropertiesDirectory&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROPERTIES_DIR&lt;/span&gt;&lt;span class="k"&gt;}&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
      if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROPERTIES_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
         &lt;/span&gt;error &lt;span class="s2"&gt;"Failed to create directory &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROPERTIES_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
         &lt;span class="k"&gt;return &lt;/span&gt;1
      &lt;span class="k"&gt;fi
   fi
   return &lt;/span&gt;0
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;setBuildPropertyOverrides&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="c"&gt;# DataWave's build configs (*.properties) can be loaded from a variety of locations based on the 'read-properties'&lt;/span&gt;
   &lt;span class="c"&gt;# Maven plugin configuration. Typically, the source-root/properties/*.properties files are loaded first to provide&lt;/span&gt;
   &lt;span class="c"&gt;# default values, starting with 'default.properties', followed by '{selected-profile}.properties'. Finally,&lt;/span&gt;
   &lt;span class="c"&gt;# ~/.m2/datawave/properties/{selected-profile}.properties is loaded, if it exists, allowing you to override&lt;/span&gt;
   &lt;span class="c"&gt;# defaults as needed&lt;/span&gt;

   &lt;span class="c"&gt;# With that in mind, the goal of this function is to generate a new '${DW_DATAWAVE_BUILD_PROFILE}.properties' file under&lt;/span&gt;
   &lt;span class="c"&gt;# DW_DATAWAVE_BUILD_PROPERTIES_DIR and *symlinked* as ~/.m2/datawave/properties/${DW_DATAWAVE_BUILD_PROFILE}.properties,&lt;/span&gt;
   &lt;span class="c"&gt;# to inject all the overrides that we need for successful deployment to source-root/contrib/datawave-quickstart/&lt;/span&gt;

   &lt;span class="c"&gt;# If a file having the name '${DW_DATAWAVE_BUILD_PROFILE}.properties' already exists under ~/.m2/datawave/properties,&lt;/span&gt;
   &lt;span class="c"&gt;# then it will be renamed automatically with a ".saved-by-quickstart-$(date)" suffix, and the symlink for the new&lt;/span&gt;
   &lt;span class="c"&gt;# file will be created as required&lt;/span&gt;

   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_BASENAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROFILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.properties
   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROPERTIES_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/.m2/datawave/properties
   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

   &lt;span class="o"&gt;!&lt;/span&gt; createBuildPropertiesDirectory &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Failed to override properties!"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1

   &lt;span class="c"&gt;# Create symlink directory if it doesn't exist&lt;/span&gt;
   &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Failed to create symlink directory &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1

   &lt;span class="c"&gt;# Copy existing source-root/properties/${DW_DATAWAVE_BUILD_PROFILE}.properties to our new $BUILD_PROPERTIES_FILE&lt;/span&gt;
   &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SOURCE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/properties/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROFILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.properties"&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Aborting property overrides! Failed to copy &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_PROFILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.properties"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1

   &lt;span class="c"&gt;# Apply overrides as needed by simply appending them to the end of the file...&lt;/span&gt;

   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"#"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"######## Begin overrides for datawave-quickstart ########"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"#"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WAREHOUSE_ACCUMULO_HOME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ACCUMULO_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WAREHOUSE_INSTANCE_NAME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_INSTANCE_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WAREHOUSE_JOBTRACKER_NODE=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_RESOURCE_MANAGER_ADDRESS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"INGEST_ACCUMULO_HOME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ACCUMULO_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"INGEST_INSTANCE_NAME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_INSTANCE_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"INGEST_JOBTRACKER_NODE=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_RESOURCE_MANAGER_ADDRESS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"BULK_INGEST_DATA_TYPES=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_BULK_DATA_TYPES&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"LIVE_INGEST_DATA_TYPES=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_LIVE_DATA_TYPES&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PASSWORD=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ZOOKEEPER_HOME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ZOOKEEPER_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"HADOOP_HOME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HADOOP_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"MAPRED_HOME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HADOOP_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WAREHOUSE_HADOOP_CONF=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HADOOP_CONF_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"INGEST_HADOOP_CONF=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HADOOP_CONF_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"HDFS_BASE_DIR=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_HDFS_BASEDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"MAPRED_INGEST_OPTS=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_MAPRED_INGEST_OPTS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"LOG_DIR=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_LOG_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FLAG_DIR=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_FLAGFILE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FLAG_MAKER_CONFIG=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_FLAGMAKER_CONFIGS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"BIN_DIR_FOR_FLAGS=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bin"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"KEYSTORE=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_KEYSTORE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"KEYSTORE_TYPE=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_KEYSTORE_TYPE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"KEYSTORE_PASSWORD=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_KEYSTORE_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"TRUSTSTORE=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_TRUSTSTORE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"TRUSTSTORE_PASSWORD=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_TRUSTSTORE_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"TRUSTSTORE_TYPE=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_TRUSTSTORE_TYPE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FLAG_METRICS_DIR=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_FLAGMETRICS_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"accumulo.instance.name=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_INSTANCE_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"accumulo.user.password=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"cached.results.hdfs.uri=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_DFS_URI&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"type.metadata.hdfs.uri=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_DFS_URI&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"mapReduce.hdfs.uri=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_DFS_URI&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"bulkResults.hdfs.uri=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_DFS_URI&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"jboss.log.hdfs.uri=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_DFS_URI&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"lock.file.dir=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_LOCKFILE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"server.keystore.password=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"mysql.user.password=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"jboss.jmx.password=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"jboss.managed.executor.service.default.max.threads=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_WILDFLY_EE_DEFAULT_MAX_THREADS&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;48&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hornetq.cluster.password=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hornetq.system.password=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ACCUMULO_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"mapReduce.job.tracker=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_RESOURCE_MANAGER_ADDRESS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"bulkResults.job.tracker=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_HADOOP_RESOURCE_MANAGER_ADDRESS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"EVENT_DISCARD_INTERVAL=0"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ingest.data.types=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_LIVE_DATA_TYPES&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_BULK_DATA_TYPES&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"JOB_CACHE_REPLICATION=1"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"EDGE_DEFINITION_FILE=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_EDGE_DEFINITIONS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"DATAWAVE_INGEST_HOME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PASSWORD_INGEST_ENV=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_PASSWD_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hdfs.site.config.urls=file://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HADOOP_CONF_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/core-site.xml,file://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HADOOP_CONF_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/hdfs-site.xml"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"table.shard.numShardsPerDay=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_NUM_SHARDS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

   generateTestDatawaveUserServiceConfig

   &lt;span class="c"&gt;# Apply DW_JAVA_HOME_OVERRIDE, if needed...&lt;/span&gt;
   &lt;span class="c"&gt;# We can override the JAVA_HOME location for the DataWave deployment, if necessary. E.g., if we're deploying&lt;/span&gt;
   &lt;span class="c"&gt;# to a Docker container or other, where our current JAVA_HOME isn't applicable&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_JAVA_HOME_OVERRIDE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&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="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"JAVA_HOME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_JAVA_HOME_OVERRIDE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;else
      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"JAVA_HOME=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;JAVA_HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;fi&lt;/span&gt;

   &lt;span class="c"&gt;# Apply DW_ROOT_DIRECTORY_OVERRIDE, if needed...&lt;/span&gt;
   &lt;span class="c"&gt;# We can override any instances of DW_DATAWAVE_SOURCE_DIR within the build config in order to relocate&lt;/span&gt;
   &lt;span class="c"&gt;# the deployment, if necessary. E.g., used when building the datawave-quickstart Docker image to reorient&lt;/span&gt;
   &lt;span class="c"&gt;# the deployment under /opt/datawave/ within the container&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ROOT_DIRECTORY_OVERRIDE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&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="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s~&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SOURCE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;~&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_ROOT_DIRECTORY_OVERRIDE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;~g"&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;fi&lt;/span&gt;

   &lt;span class="c"&gt;# Create the symlink under ~/.m2/datawave/properties&lt;/span&gt;

   setBuildPropertiesSymlink &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;setBuildPropertiesSymlink&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c"&gt;# Replace any existing ~/.m2/datawave/properties/${BUILD_PROPERTIES_BASENAME} file/symlink with&lt;/span&gt;
   &lt;span class="c"&gt;# a symlink to our new ${BUILD_PROPERTIES_FILE}&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&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
       if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&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;info &lt;span class="s2"&gt;"Unlinking existing symbolic link: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;unlink&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
               &lt;/span&gt;warn &lt;span class="s2"&gt;"Failed to unlink &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;readlink&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; from &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
           &lt;span class="k"&gt;fi
       else
           &lt;/span&gt;&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;backupFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.saved-by-quickstart.&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y-%m-%d-%H%M%S&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
           info &lt;span class="s2"&gt;"Backing up your existing ~/.m2/**/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; file to ~/.m2/**/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;backupFile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;backupFile&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
               &lt;/span&gt;error &lt;span class="s2"&gt;"Failed to backup &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Aborting properties file override. Please fix me!!"&lt;/span&gt;
               &lt;span class="k"&gt;return &lt;/span&gt;1
           &lt;span class="k"&gt;fi
       fi
   fi

   if &lt;/span&gt;&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_SYMLINK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
       &lt;/span&gt;info &lt;span class="s2"&gt;"Override for &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; successful"&lt;/span&gt;
   &lt;span class="k"&gt;else
       &lt;/span&gt;error &lt;span class="s2"&gt;"Override for &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD_PROPERTIES_BASENAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; failed"&lt;/span&gt;
       &lt;span class="k"&gt;return &lt;/span&gt;1
   &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveBuildSucceeded&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;success&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 7 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DW_DATAWAVE_BUILD_STATUS_LOG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"BUILD SUCCESS"&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;success&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&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
       return &lt;/span&gt;1
   &lt;span class="k"&gt;fi
   return &lt;/span&gt;0
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;buildDataWave&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; mavenIsInstalled &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; mavenInstall &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Maven install failed. Please correct"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1
   &lt;span class="k"&gt;fi&lt;/span&gt;

   &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"--verbose"&lt;/span&gt; &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;local &lt;/span&gt;&lt;span class="nv"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;

   &lt;span class="o"&gt;!&lt;/span&gt; setBuildPropertyOverrides &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Aborting DataWave build"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1

   &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_STATUS_LOG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &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;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DW_DATAWAVE_BUILD_STATUS_LOG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

   info &lt;span class="s2"&gt;"DataWave build in progress: '&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_COMMAND&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;
   info &lt;span class="s2"&gt;"Build status log: &lt;/span&gt;&lt;span class="nv"&gt;$DW_DATAWAVE_BUILD_STATUS_LOG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;verbose&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;true&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="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SOURCE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_COMMAND&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_STATUS_LOG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;else&lt;/span&gt;
       &lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SOURCE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_COMMAND&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;&amp;gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_BUILD_STATUS_LOG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;fi

   if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; datawaveBuildSucceeded &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
       &lt;/span&gt;error &lt;span class="s2"&gt;"The build has FAILED! See &lt;/span&gt;&lt;span class="nv"&gt;$DW_DATAWAVE_BUILD_STATUS_LOG&lt;/span&gt;&lt;span class="s2"&gt; for details"&lt;/span&gt;
       &lt;span class="k"&gt;return &lt;/span&gt;1
   &lt;span class="k"&gt;fi

   &lt;/span&gt;info &lt;span class="s2"&gt;"DataWave build successful"&lt;/span&gt;
   &lt;span class="k"&gt;return &lt;/span&gt;0
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;getDataWaveTarball&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c"&gt;# Looks for a DataWave tarball matching the specified pattern and, if found, sets the global 'tarball'&lt;/span&gt;
   &lt;span class="c"&gt;# variable to its basename for the caller as expected.&lt;/span&gt;

   &lt;span class="c"&gt;# If no tarball is found matching the specified pattern, then the DataWave build is kicked off&lt;/span&gt;

   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;tarballPattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nv"&gt;tarball&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;

   &lt;span class="c"&gt;# Check if the tarball already exists in the plugin directory.&lt;/span&gt;
   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;tarballPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SERVICE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;tarballPattern&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;tarballPath&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&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="nv"&gt;tarball&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;tarballPath&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;fi&lt;/span&gt;

   &lt;span class="o"&gt;!&lt;/span&gt; buildDataWave &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Please correct this issue before continuing"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1

   &lt;span class="c"&gt;# Build succeeded. Set global 'tarball' variable for the specified pattern and copy all tarballs into place&lt;/span&gt;

   &lt;span class="nv"&gt;tarballPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SOURCE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;tarballPattern&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;tarballPath&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Failed to find '&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;tarballPattern&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' tar file after build"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1

   &lt;span class="nv"&gt;tarball&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;tarballPath&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

   &lt;span class="c"&gt;# Current caller (ie, either bootstrap-web.sh or bootstrap-ingest.sh) only cares about current $tarball,&lt;/span&gt;
   &lt;span class="c"&gt;# but go ahead and copy both tarballs into datawave service dir to satisfy next caller as well&lt;/span&gt;

   &lt;span class="o"&gt;!&lt;/span&gt; copyDataWaveTarball &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_TARBALL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Failed to copy DataWave Ingest tarball"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1
   &lt;span class="o"&gt;!&lt;/span&gt; copyDataWaveTarball &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_WEB_TARBALL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Failed to copy DataWave Web tarball"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1

   &lt;span class="k"&gt;return &lt;/span&gt;0
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;copyDataWaveTarball&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;dwTarball&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SOURCE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dwTarball&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&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="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dwTarball&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SERVICE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; error &lt;span class="s2"&gt;"Failed to copy '&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dwTarball&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1
   &lt;span class="k"&gt;else
       &lt;/span&gt;error &lt;span class="s2"&gt;"No tar file found matching '&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;
       &lt;span class="k"&gt;return &lt;/span&gt;1
   &lt;span class="k"&gt;fi
   return &lt;/span&gt;0
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Bootstrap DW ingest and webservice components as needed&lt;/span&gt;

&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SERVICE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bootstrap-ingest.sh"&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SERVICE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bootstrap-web.sh"&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveIsRunning&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    datawaveIngestIsRunning &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;0
    datawaveWebIsRunning &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;0
    &lt;span class="k"&gt;return &lt;/span&gt;1
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveStart&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    datawaveIngestStart
    datawaveWebStart
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveStop&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    datawaveIngestStop
    datawaveWebStop
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveStatus&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    datawaveIngestStatus
    datawaveWebStatus
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveIsInstalled&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    datawaveIngestIsInstalled &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;0
    datawaveWebIsInstalled &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;0
    &lt;span class="k"&gt;return &lt;/span&gt;1
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveUninstall&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   datawaveIngestUninstall
   datawaveWebUninstall

   &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_UNINSTALL_RM_BINARIES_FLAG_LONG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_UNINSTALL_RM_BINARIES_FLAG_SHORT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &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;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SERVICE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.tar.gz
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveInstall&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   datawaveIngestInstall
   datawaveWebInstall
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawavePrintenv&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nb"&gt;echo
   echo&lt;/span&gt; &lt;span class="s2"&gt;"DataWave Environment"&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt;
   &lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; posix &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"DATAWAVE_|WILDFLY|JBOSS"&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawavePidList&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   datawaveIngestIsRunning
   datawaveWebIsRunning
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_WEB_PID_LIST&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_PID_LIST&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&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="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_WEB_PID_LIST&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_INGEST_PID_LIST&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveBuildDeploy&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   datawaveIsRunning &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; info &lt;span class="s2"&gt;"Stopping all DataWave services"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; datawaveStop
   datawaveIsInstalled &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; info &lt;span class="s2"&gt;"Uninstalling DataWave"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; datawaveUninstall &lt;span class="nt"&gt;--remove-binaries&lt;/span&gt;

   resetQuickstartEnvironment
   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DW_REDEPLOY_IN_PROGRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
   &lt;/span&gt;datawaveInstall
   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DW_REDEPLOY_IN_PROGRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;datawaveBuild&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   info &lt;span class="s2"&gt;"Building DataWave"&lt;/span&gt;
   &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DW_DATAWAVE_SERVICE_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/datawave&lt;span class="k"&gt;*&lt;/span&gt;.tar.gz
   resetQuickstartEnvironment
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let's try Datawave out finally
&lt;/h2&gt;

&lt;p&gt;So let's find some Wikipedia data based on page title, with a --verbose flag to see the cURL command in action with Datawave:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;datawaveQuery &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"PAGE_TITLE:AccessibleComputing OR PAGE_TITLE:Anarchism"&lt;/span&gt; &lt;span class="nt"&gt;--verbose&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next let's grab TV show data from &lt;code&gt;API.TVMAZE.COM&lt;/code&gt;(graph edge queries):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;datawaveQuery &lt;span class="nt"&gt;--logic&lt;/span&gt; EdgeQuery &lt;span class="nt"&gt;--syntax&lt;/span&gt; JEXL &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"SOURCE == 'kevin bacon' &amp;amp;&amp;amp; TYPE == 'TV_COSTARS'"&lt;/span&gt; &lt;span class="nt"&gt;--pagesize&lt;/span&gt; 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, let's do our graph edge queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;datawaveQuery &lt;span class="nt"&gt;--logic&lt;/span&gt; EdgeQuery &lt;span class="nt"&gt;--syntax&lt;/span&gt; JEXL &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"SOURCE == 'william shatner' &amp;amp;&amp;amp; TYPE == 'TV_CHARACTERS'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's try doing one more &lt;code&gt;EdgeQuery&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;datawaveQuery &lt;span class="nt"&gt;--logic&lt;/span&gt; EdgeQuery &lt;span class="nt"&gt;--syntax&lt;/span&gt; JEXL &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"SOURCE == 'westworld' &amp;amp;&amp;amp; TYPE == 'TV_SHOW_CAST'"&lt;/span&gt;  &lt;span class="nt"&gt;--pagesize&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was cool right? To formulate some of your own graph/edge queries run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;datawaveQuery &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give you a broader scope on how Edges work. &lt;/p&gt;

&lt;h2&gt;
  
  
  Edges
&lt;/h2&gt;

&lt;p&gt;One of the things I thought was, "&lt;code&gt;EdgeQueryLogic&lt;/code&gt; in Datawave needs a better date range filter".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mdm7so8S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qeco6kzdk010xfb0ittm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mdm7so8S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qeco6kzdk010xfb0ittm.png" alt="Image description" width="880" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So to be clear, currently as it stands &lt;code&gt;EdgeQueryLogic&lt;/code&gt; currently uses a column qualifier range filter to skip keys that are not within a specified date range. We need to be able to incorporate seeks such that the filter will skip over entries not within the date range. This is expected to be significantly faster when there are large gaps in sequence of edges for a source value that are not within the date range.&lt;/p&gt;

&lt;p&gt;As you can see, this can come up short. An example subroutine that would help with Edge queries, would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;seekToStartKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Key&lt;/span&gt; &lt;span class="n"&gt;topKey&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;
   &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;seeked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startDate&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Date is before start date.  Seek to same key with date set to start date&lt;/span&gt;
    &lt;span class="nc"&gt;Key&lt;/span&gt; &lt;span class="n"&gt;newKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EdgeKeyUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSeekToFutureKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topKey&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startDate&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;PartialKey&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EdgeKeyUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSeekToFuturePartialKey&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;fastReseek&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newKey&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endDate&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endDate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;PartialKey&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EdgeKeyUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSeekToNextKey&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;fastReseek&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;followingKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;seeked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seeked&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This now is getting into the core Datawave architecture. I've now helped you install it, run some queries on Wikipedia, and use an API for TV shows to demonstrate Edge querying. &lt;/p&gt;

&lt;h2&gt;
  
  
  Datawave Architecture
&lt;/h2&gt;

&lt;p&gt;As you can imagine with things like ZooKeeper, Hadoop of course you'll be using things like &lt;code&gt;MapReduce&lt;/code&gt; and &lt;code&gt;Pig&lt;/code&gt;, below is the more-or-less the architecture of Datawave: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j3TnicOH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uid5w32zzdnlz333v21k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j3TnicOH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uid5w32zzdnlz333v21k.png" alt="Image description" width="880" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this architecture, you might be thinking -- "What about run away queries?" Good question.  &lt;/p&gt;

&lt;p&gt;Your query can get into a state where the &lt;code&gt;QueryIterator&lt;/code&gt; will not terminate. This is an edge case where yielding occurs, and the &lt;code&gt;FinalDocument&lt;/code&gt; is returned as a result. This will get us into an infinite loop where the upon rebuilding the iterator, it will yield again and again. &lt;/p&gt;

&lt;p&gt;Two things are required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The yield callback is checked in the &lt;code&gt;FinalDocumentIterator&lt;/code&gt; and the yield is passed through appropriately.&lt;/li&gt;
&lt;li&gt;The underlying iterator is no longer checked once the final document is returned.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is just mainly another NB, this can happen, and if it does there's ways to do command jujitsu to get out of it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We used &lt;code&gt;EdgeQuerying&lt;/code&gt; got info from Wikipedia and gave it conditionals, and used some API's via REST to do some cool things, these are just some of the VERY few things Datawave can do, and that I've personally have done myself. I may do a part 2 series on this. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Montana Mendy&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nsa</category>
      <category>datawave</category>
      <category>visualization</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Paralleling Code Coverage using Coveralls and Travis</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Wed, 23 Feb 2022 15:36:25 +0000</pubDate>
      <link>https://dev.to/montana/paralleling-coverage-using-coveralls-and-travis-1e56</link>
      <guid>https://dev.to/montana/paralleling-coverage-using-coveralls-and-travis-1e56</guid>
      <description>&lt;p&gt;Hey developer friends, &lt;/p&gt;

&lt;p&gt;A short one today -- but an important one. &lt;/p&gt;

&lt;p&gt;Let's say you have multiple environments you want to have coverage, first let's enable Coveralls for your repo, so if you haven't done so yet -- head over to coveralls.io and Auth the Coveralls app to up your GitHub account, and then sync your repos with Coveralls. &lt;/p&gt;

&lt;p&gt;You'll want to have a &lt;code&gt;.travis.yml&lt;/code&gt; file that looks similar to mine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;sudo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node_js&lt;/span&gt;
&lt;span class="na"&gt;node_js&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node"&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;COVERALLS_PARALLEL=true&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;COVERALLS_FLAG_NAME=test-1 make test-coveralls-1&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;COVERALLS_FLAG_NAME=test-2 make test-coveralls-2&lt;/span&gt;
&lt;span class="na"&gt;notifications&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;webhooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://coveralls.io/webhook&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see we are running multiple &lt;code&gt;COVERALLS_FLAG_NAME&lt;/code&gt;, this is using the Coveralls webhook to parallelize your coverage. If at first you don't see Coveralls covering your code, you may want to add your &lt;code&gt;env var&lt;/code&gt; from Coveralls to Travis CI and name it something like &lt;code&gt;COVERALLS_TOKEN&lt;/code&gt;. &lt;/p&gt;

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

&lt;p&gt;Here's my repo so you can follow step by step! &lt;a href="https://github.com/Montana/coveralls-node-travis" rel="noopener noreferrer"&gt;https://github.com/Montana/coveralls-node-travis&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creating a base build of  Snapcraft in Travis CI </title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Thu, 17 Feb 2022 23:04:16 +0000</pubDate>
      <link>https://dev.to/montana/creating-a-base-build-of-snapcraft-in-travis-ci-4a4m</link>
      <guid>https://dev.to/montana/creating-a-base-build-of-snapcraft-in-travis-ci-4a4m</guid>
      <description>&lt;p&gt;Sometimes you want to see how things work under the hood, and this is why I put together quickly how I used Snapcraft with Travis CI to get a LXD up and running, and download VLC and then get info on that version of VLC all inside Travis CI. &lt;/p&gt;

&lt;p&gt;First let's start with out &lt;code&gt;snapchat.yaml&lt;/code&gt;. This is how mine looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;montana&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v0.58.10-1.dev&lt;/span&gt;
&lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Im just testing out snapd with Travis&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
 &lt;span class="s"&gt;My name is Montana Mendy and I'm a Software Engineer at Travis CI, I'm trying new things with Travis CI and the Brave Browser.&lt;/span&gt;
&lt;span class="na"&gt;grade&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stable&lt;/span&gt;
&lt;span class="na"&gt;confinement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;strict&lt;/span&gt;

&lt;span class="na"&gt;architectures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;build-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amd64&lt;/span&gt;

&lt;span class="na"&gt;parts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;brave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;plugin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dump&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/brave/brave-browser/releases/download/v0.58.10/brave-browser-dev_0.58.10_amd64.deb&lt;/span&gt;
    &lt;span class="na"&gt;source-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deb&lt;/span&gt;
    &lt;span class="c1"&gt;# Correct path to icon.&lt;/span&gt;
    &lt;span class="na"&gt;override-pull&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;snapcraftctl pull&lt;/span&gt;
      &lt;span class="s"&gt;rm -rf etc/cron.daily/ &lt;/span&gt;
      &lt;span class="s"&gt;rm -rf usr/bin/brave-browser-dev&lt;/span&gt;
      &lt;span class="s"&gt;chmod 4555 opt/brave.com/brave-dev/brave-sandbox&lt;/span&gt;
      &lt;span class="s"&gt;unlink opt/brave.com/brave-dev/brave-browser&lt;/span&gt;
      &lt;span class="s"&gt;sed -i 's|Icon=brave-browser|Icon=/opt/brave.com/brave-dev/product_logo_128\.png|g' usr/share/applications/brave-browser-dev.desktop&lt;/span&gt;
    &lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;desktop-gtk3&lt;/span&gt;
    &lt;span class="na"&gt;stage-packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gir1.2-gnomekeyring-1.0&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libasound2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libgconf-2-4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libgl1-mesa-glx&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libglu1-mesa&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libgnome-keyring0&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libcap2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libgcrypt20&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libnotify4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libnspr4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libnss3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libpulse0&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libxtst6&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;libxss1&lt;/span&gt;

&lt;span class="na"&gt;apps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;brave&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bin/desktop-launch $SNAP/opt/brave.com/brave-dev/brave-browser-dev&lt;/span&gt;
    &lt;span class="na"&gt;desktop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;usr/share/applications/brave-browser-dev.desktop&lt;/span&gt;
    &lt;span class="c1"&gt;# Correct the TMPDIR path for Chromium Framework/Electron to&lt;/span&gt;
    &lt;span class="c1"&gt;# ensure libappindicator has readable resources.&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;TMPDIR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;
    &lt;span class="na"&gt;plugs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;alsa&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;avahi-observe&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;browser-sandbox&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;camera&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cups-control&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;desktop&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gsettings&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;home&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mount-observe&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;network&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;opengl&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;password-manager-service&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pulseaudio&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;remove-media&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;screen-inhibit-control&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;unity7&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;upower-observe&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;x11&lt;/span&gt;

&lt;span class="na"&gt;plugs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;browser-sandbox&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;interface&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;browser-support&lt;/span&gt;
    &lt;span class="na"&gt;allow-sandbox&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;gtk-3-themes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;interface&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;content&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$SNAP/data-dir/themes&lt;/span&gt;
    &lt;span class="na"&gt;default-provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gtk-common-themes&lt;/span&gt;
  &lt;span class="na"&gt;icon-themes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;interface&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;content&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$SNAP/data-dir/icons&lt;/span&gt;
    &lt;span class="na"&gt;default-provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gtk-common-themes&lt;/span&gt;
  &lt;span class="na"&gt;sound-themes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;interface&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;content&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$SNAP/data-dir/sounds&lt;/span&gt;
    &lt;span class="na"&gt;default-provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gtk-common-themes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is for the Brave Browser, but I've added things like &lt;code&gt;pulseaudio&lt;/code&gt; to the Snap &lt;code&gt;plugs&lt;/code&gt;. So let's push that into a directory called &lt;code&gt;snap&lt;/code&gt;. Now let's head back to your root directory and make your &lt;code&gt;.travis.yml&lt;/code&gt;, and this is what I coded out for my &lt;code&gt;.travis.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shell&lt;/span&gt;
&lt;span class="na"&gt;dist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xenial&lt;/span&gt;
&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux&lt;/span&gt;
&lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;edge&lt;/span&gt; 

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;LC_ALL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;C.UTF-8&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;LANG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;C.UTF-8&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;SNAPCRAFT_ENABLE_SILENT_REPORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;y&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;SNAPCRAFT_BUILD_INFO&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;SNAPCRAFT_BUILD_ENVIRONMENT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lxd'&lt;/span&gt;

&lt;span class="na"&gt;addons&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;snaps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;snapcraft&lt;/span&gt;
      &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stable&lt;/span&gt;
      &lt;span class="na"&gt;confinement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;classic&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lxd&lt;/span&gt;
      &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stable&lt;/span&gt;

&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo usermod --append --groups lxd $USER&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo /snap/bin/lxd.migrate -yes&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo /snap/bin/lxd waitready&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo /snap/bin/lxd init --auto&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo apt install snapd&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo snap install hello-world&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo snap install nethack&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;snap version&lt;/span&gt; 
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;snap list&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;snap connections nethack&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;snap services lxd&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo snap install --channel=edge vlc&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;which vlc&lt;/span&gt; 
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;snapcraft extensions&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;snap connections vlc&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo systemctl enable --now snapd.socket&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo journalctl -xeb | grep -i snap&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So let's trigger a build by using &lt;code&gt;powerline&lt;/code&gt; in Vim, and if your build is successful it should look something like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YfuFPdIN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jbrgu8g8vqaytvdca02k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YfuFPdIN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jbrgu8g8vqaytvdca02k.png" alt="Image description" width="880" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Somethings you'll want to keep in mind with Snapcraft Multipass has 2 CPU's assigned to it, this can be variable depending on your settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SNAPCRAFT_BUILD_ENVIRONMENT_CPU&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8 
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SNAPCRAFT_BUILD_ENVIRONMENT_MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can put those in your &lt;code&gt;script:&lt;/code&gt; hook in your &lt;code&gt;.travis.yml&lt;/code&gt; file. &lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating between bases
&lt;/h2&gt;

&lt;p&gt;A base snap is a special kind of snap that provides a run-time environment with a minimal set of libraries that are common to most Linux distributions. Think of it as a minimal Gentoo install. At the simplest level, in your &lt;code&gt;snapcraft.yaml&lt;/code&gt; file you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- base: core18
+ base: core20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, only one of the base keywords need to be updated. &lt;/p&gt;

&lt;h2&gt;
  
  
  Enforcing Snap Policies
&lt;/h2&gt;

&lt;p&gt;One thing you may want to consider when making this, is enforcing some security policies, the way you do that is, yes you guessed it another &lt;code&gt;.yaml&lt;/code&gt; file, so let's call this one &lt;code&gt;snap.yaml&lt;/code&gt; and it would look a little like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;name: montana
version: 1.0
apps:
  bar:
    &lt;span class="nb"&gt;command&lt;/span&gt;: mendy
  baz:
    &lt;span class="nb"&gt;command&lt;/span&gt;: dig
    daemon: simple
    plugs: &lt;span class="o"&gt;[&lt;/span&gt;network]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run this with your Travis CI build and don't like what you see you can always set a &lt;code&gt;snap disconnect&lt;/code&gt; conditional so you can disconnect. Don't forget you can add a Cron job directly from Snapcraft by adding this line in your &lt;code&gt;.travis.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;snap &lt;span class="nb"&gt;set &lt;/span&gt;system refresh.timer&lt;span class="o"&gt;=&lt;/span&gt;fri5,23:00-01:00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's now a cron that will refresh Snap at a time of my choosing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In some sense setting up Snapcraft for Travis CI was really fun, and got to see hands on how LXD containers are built from the ground up, setting your own policies, enforcing them and even picking your own plugins so you have a great foundation to build on when you're ready. &lt;/p&gt;

&lt;p&gt;Here's my repository: &lt;a href="https://github.com/Montana/travis-snap-lxd"&gt;https://github.com/Montana/travis-snap-lxd&lt;/a&gt;&lt;/p&gt;

</description>
      <category>snapcraft</category>
      <category>continiousintegration</category>
      <category>continiousdelivery</category>
      <category>testing</category>
    </item>
    <item>
      <title>Start Maxwell with Namespaced Topic Kafka Producer (Look for Idle Listeners in Kafka)
</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Thu, 02 Dec 2021 17:01:46 +0000</pubDate>
      <link>https://dev.to/montana/start-maxwell-with-namespaced-topic-kafka-producer-look-for-idle-listeners-in-kafka-3nbg</link>
      <guid>https://dev.to/montana/start-maxwell-with-namespaced-topic-kafka-producer-look-for-idle-listeners-in-kafka-3nbg</guid>
      <description>&lt;p&gt;After running through the prerequisites, you will have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A AWS Aurora instance&lt;/li&gt;
&lt;li&gt;A Maxwell image named osheroff/maxwell&lt;/li&gt;
&lt;li&gt;AKafka service named kafka, listening on &lt;code&gt;kafka:9092&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start Maxwell with Namespaced Topic Kafka Producer&lt;br&gt;
This is a slight variation of the prerequisite, AWS Aurora to Maxwell Kafka Producer. &lt;/p&gt;

&lt;p&gt;In the prerequisite we ran Maxwell with the default Kafka Producer configuration which will produce messages on the Maxwell topic. &lt;/p&gt;

&lt;p&gt;You'll want to get the number of messages in a Maxwell topic, you can run: &lt;code&gt;bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic mytopic --time -1 --offsets 1 | awk -F ":" '{sum += $3} END {print sum}'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this example we are overriding the &lt;code&gt;MAXWELL_OPTIONS&lt;/code&gt; environment variable and specifying a dynamic topic name, so that Maxwell will route messages from each table to topics by the same name, namespaced by the database name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MYSQL_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AURORA_USERNAME &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AURORA_PASSWORD &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MYSQL_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AURORA_HOST &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--link&lt;/span&gt; kafka &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;KAFKA_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;kafka &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;KAFKA_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;9092 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;MAXWELL_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--kafka_topic=maxwell_%{database}_%{table}
    --name maxwell &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
    osheroff/maxwell
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XtaTJxHu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ayjhfw6i07lxjwmk7ih1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XtaTJxHu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ayjhfw6i07lxjwmk7ih1.png" alt="Image description" width="880" height="740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a graphical way of looking at things when it comes to &lt;code&gt;Consumers&lt;/code&gt;. Now let's get back to Maxwell. &lt;/p&gt;

&lt;p&gt;This will be the output of Maxwell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;17:44:34,901 INFO  ProducerConfig - ProducerConfig values: 
    request.timeout.ms &lt;span class="o"&gt;=&lt;/span&gt; 30000
    retry.backoff.ms &lt;span class="o"&gt;=&lt;/span&gt; 100
    buffer.memory &lt;span class="o"&gt;=&lt;/span&gt; 33554432
    ssl.truststore.password &lt;span class="o"&gt;=&lt;/span&gt; null
    batch.size &lt;span class="o"&gt;=&lt;/span&gt; 16384
    ssl.keymanager.algorithm &lt;span class="o"&gt;=&lt;/span&gt; SunX509
    receive.buffer.bytes &lt;span class="o"&gt;=&lt;/span&gt; 32768
    ssl.cipher.suites &lt;span class="o"&gt;=&lt;/span&gt; null
    ssl.key.password &lt;span class="o"&gt;=&lt;/span&gt; null
    sasl.kerberos.ticket.renew.jitter &lt;span class="o"&gt;=&lt;/span&gt; 0.05
    ssl.provider &lt;span class="o"&gt;=&lt;/span&gt; null
    sasl.kerberos.service.name &lt;span class="o"&gt;=&lt;/span&gt; null
    max.in.flight.requests.per.connection &lt;span class="o"&gt;=&lt;/span&gt; 5
    sasl.kerberos.ticket.renew.window.factor &lt;span class="o"&gt;=&lt;/span&gt; 0.8
    bootstrap.servers &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;kafka:9092]
    client.id &lt;span class="o"&gt;=&lt;/span&gt; 
    max.request.size &lt;span class="o"&gt;=&lt;/span&gt; 1048576
    acks &lt;span class="o"&gt;=&lt;/span&gt; 1
    linger.ms &lt;span class="o"&gt;=&lt;/span&gt; 0
    sasl.kerberos.kinit.cmd &lt;span class="o"&gt;=&lt;/span&gt; /usr/bin/kinit
    ssl.enabled.protocols &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;TLSv1.2, TLSv1.1, TLSv1]
    metadata.fetch.timeout.ms &lt;span class="o"&gt;=&lt;/span&gt; 60000
    ssl.endpoint.identification.algorithm &lt;span class="o"&gt;=&lt;/span&gt; null
    ssl.keystore.location &lt;span class="o"&gt;=&lt;/span&gt; null
    value.serializer &lt;span class="o"&gt;=&lt;/span&gt; class org.apache.kafka.common.serialization.StringSerializer
    ssl.truststore.location &lt;span class="o"&gt;=&lt;/span&gt; null
    ssl.keystore.password &lt;span class="o"&gt;=&lt;/span&gt; null
    key.serializer &lt;span class="o"&gt;=&lt;/span&gt; class org.apache.kafka.common.serialization.StringSerializer
    block.on.buffer.full &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false
    &lt;/span&gt;metrics.sample.window.ms &lt;span class="o"&gt;=&lt;/span&gt; 30000
    metadata.max.age.ms &lt;span class="o"&gt;=&lt;/span&gt; 300000
    security.protocol &lt;span class="o"&gt;=&lt;/span&gt; PLAINTEXT
    ssl.protocol &lt;span class="o"&gt;=&lt;/span&gt; TLS
    sasl.kerberos.min.time.before.relogin &lt;span class="o"&gt;=&lt;/span&gt; 60000
    timeout.ms &lt;span class="o"&gt;=&lt;/span&gt; 30000
    connections.max.idle.ms &lt;span class="o"&gt;=&lt;/span&gt; 540000
    ssl.trustmanager.algorithm &lt;span class="o"&gt;=&lt;/span&gt; PKIX
    metric.reporters &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    compression.type &lt;span class="o"&gt;=&lt;/span&gt; none
    ssl.truststore.type &lt;span class="o"&gt;=&lt;/span&gt; JKS
    max.block.ms &lt;span class="o"&gt;=&lt;/span&gt; 60000
    retries &lt;span class="o"&gt;=&lt;/span&gt; 0
    send.buffer.bytes &lt;span class="o"&gt;=&lt;/span&gt; 131072
    partitioner.class &lt;span class="o"&gt;=&lt;/span&gt; class org.apache.kafka.clients.producer.internals.DefaultPartitioner
    reconnect.backoff.ms &lt;span class="o"&gt;=&lt;/span&gt; 50
    metrics.num.samples &lt;span class="o"&gt;=&lt;/span&gt; 2
    ssl.keystore.type &lt;span class="o"&gt;=&lt;/span&gt; JKS

17:44:34,952 INFO  AppInfoParser - Kafka version : 0.9.0.1
17:44:34,952 INFO  AppInfoParser - Kafka commitId : 23c69d62a0cabf06
17:44:35,012 INFO  Maxwell - Maxwell v1.7.0 is booting &lt;span class="o"&gt;(&lt;/span&gt;MaxwellKafkaProducer&lt;span class="o"&gt;)&lt;/span&gt;, starting at BinlogPosition[mysql-bin-changelog.000002:84337]
17:44:35,680 INFO  MysqlSavedSchema - Restoring schema &lt;span class="nb"&gt;id &lt;/span&gt;1 &lt;span class="o"&gt;(&lt;/span&gt;last modified at BinlogPosition[mysql-bin-changelog.000002:3521]&lt;span class="o"&gt;)&lt;/span&gt;
17:44:38,991 INFO  OpenReplicator - starting replication at mysql-bin-changelog.000002:84337
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cCDT9VcS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ocflofhj1gfqfxbqq7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cCDT9VcS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ocflofhj1gfqfxbqq7w.png" alt="Image description" width="880" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The process is now waiting for new data events and looking for idle Kafka listeners. &lt;/p&gt;

&lt;p&gt;Start a &lt;code&gt;consumer&lt;/code&gt; (in another terminal window). This command will start an unnamed instance of Spotify/Kafka linked to the Kafka service, start a consumer, display existing messages from the Maxwell topic, and wait for new messages until you quit (which destroys the container):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--link&lt;/span&gt; kafka spotify/kafka /opt/kafka_2.11-0.10.1.0/bin/kafka-console-consumer.sh &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; kafka:9092 &lt;span class="nt"&gt;--topic&lt;/span&gt; maxwell_&lt;span class="o"&gt;{&lt;/span&gt;AURORA_DATABASE&lt;span class="o"&gt;}&lt;/span&gt;_&lt;span class="o"&gt;{&lt;/span&gt;AURORA_TABLE&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--from-beginning&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Connect to the AWS Aurora instance, insert some records, and update some records. Data events from Maxwell will be printed in the Consumer terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="err"&gt;{"&lt;/span&gt;database":"AURORA_DATABASE","table":"AURORA_TABLE","type":"update","ts":1484606003,"xid":1655558,"commit":true,"data":{"id":4,"first_name":"Mendy","last_name":"Montana"},"old":{"first_name":"Montana"}}
&lt;span class="err"&gt;{"&lt;/span&gt;database":"AURORA_DATABASE","table":"AURORA_TABLE","type":"update","ts":1484606435,"xid":1658343,"commit":true,"data":{"id":4,"first_name":"Montana","last_name":"Mendy"},"old":{"first_name":"Tim"}}
&lt;span class="err"&gt;{"&lt;/span&gt;database":"AURORA_DATABASE","table":"AURORA_TABLE","type":"update","ts":1484606451,"xid":1658455,"commit":true,"data":{"id":4,"first_name":"Tim","last_name":"Mendy"},"old":{"first_name":"Montana"}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>apache</category>
      <category>kafka</category>
      <category>maxwell</category>
      <category>auroa</category>
    </item>
    <item>
      <title>Travis CI Pipelines: 2 Approaches to Source Control Branching</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Wed, 17 Feb 2021 13:22:23 +0000</pubDate>
      <link>https://dev.to/travisci/travis-ci-pipelines-2-approaches-to-source-control-branching-49d2</link>
      <guid>https://dev.to/travisci/travis-ci-pipelines-2-approaches-to-source-control-branching-49d2</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fHVIhpdB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ei48t0tm808v3q0zyai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fHVIhpdB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ei48t0tm808v3q0zyai.png" alt="Alt Text" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feature branching is a game-changing aspect of modern software development. Being able to have a developer implement a new feature in a body of code in a safe, independent, isolated manner using Git branching is an overall positive approach to the way companies make software.&lt;/p&gt;

&lt;p&gt;Over the years, two techniques of feature branching have emerged. One is what I call &lt;em&gt;branching from repo&lt;/em&gt;. The other is &lt;em&gt;branching from fork&lt;/em&gt;. Let’s explore each technique, as well as their benefits and tradeoffs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branching from repo
&lt;/h2&gt;

&lt;p&gt;Branching from repo is a pattern in which feature branches are created off an existing branch in a business’s repository and then assigned to or assumed by a particular developer for implementation. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r8T6lEl---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jtqhvq3vbdgo53y5riit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r8T6lEl---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jtqhvq3vbdgo53y5riit.png" alt="Alt Text" width="703" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Figure 1: The branching from repo pattern is used to implement feature branches created from a particular branch in a business’s repository.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The branching from repo pattern is confined to creating feature branches that are within the boundaries of a particular business’s repository. Thus, only personnel or services that have the proper permissions for working that repository can create a particular feature branch. &lt;/p&gt;

&lt;p&gt;The important thing to understand about branching from repo is that all the work that goes with creating the feature branch, developing the feature’s code, and then issuing the pull request for the completed code is done from within the boundary of the given repository. Those people on the “outside” have no ability to contribute changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branching from fork
&lt;/h2&gt;

&lt;p&gt;In the branching from fork pattern, a developer interested in adding to and improving upon code in a given repository forks the code into their own repository. Then, the developer creates branches against the forked code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nmdtVqc8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zl3l7fmor9gzbv8j44o1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nmdtVqc8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zl3l7fmor9gzbv8j44o1.png" alt="Alt Text" width="880" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Figure 2: Developers use the branching from fork pattern to fork code from the business’s repository into the developer’s external repository to then create a feature branch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once work on a given branch is complete, the developer makes a pull request to merge the code back into the originating repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--03kCAhz4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2j79olt1ala6owgkspi4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--03kCAhz4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2j79olt1ala6owgkspi4.jpg" alt="Alt Text" width="880" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Figure 3: GitHub supports pull requests for merging code between repositories in separate accounts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The important thing to understand about the branching from fork pattern is that it allows any developer to make improvements to code in an external repository in a controlled manner. All that’s required is view access to a repository of interest and then the cloning of the code.&lt;/p&gt;

&lt;p&gt;Once the code is cloned, the developer is free to work on improvements according to their own software development process. The original repository is independent of the forked code; the only intersection between the two is when the pull request is made from the forked repository back to the originating repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages and tradeoffs
&lt;/h2&gt;

&lt;p&gt;Both patterns have advantages and trade-offs. Let’s examine them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Branching from repo is well suited to private governance
&lt;/h3&gt;

&lt;p&gt;Branching from repo is well suited for companies that want to keep their software development process private and subject only to their own development and project management practices.&lt;/p&gt;

&lt;p&gt;Typically, a feature branch is created to accommodate a request that exists in a company’s backlog of work. In some cases, a feature branch can be created ad hoc, but usually, they are created by a governing authority within the company, such as a project manager or tech lead. Either the feature branch is created directly or as an ancillary action taken by automation within a project management platform such as Jira. As such, branching from repo allows project managers and tech leads to exert a lot of control over who can work on code. Also, the governing authority can determine the status of the feature branch by viewing the code as well as the branch’s commit history.&lt;/p&gt;

&lt;p&gt;The trade-off is that branching from repo requires that those working on the code have a known relationship to the repository from within the source control management service hosting the code. For example, if the code is hosted on GitHub, a developer must have permission to make commits to the feature branch. Typically, this means inviting the developer to be a direct contributor to the repository or a member of an organization associated with the project. While this degree of formality provides control, it also excludes the general public from working on the code in an ad hoc manner, so there is less opportunity to benefit from the informal interest of others. Fortunately, branching from fork addresses this shortcoming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Branching from fork is well suited to open-source development
&lt;/h3&gt;

&lt;p&gt;Branching from fork is well suited for volunteer-based open-source development. Branching from repo is pretty much a “We’re assigning you some code to work” approach. On the other hand, branching from fork says, “Here’s some code. Feel free to work on it, but you need to figure out what you want to work on to make it better.”&lt;/p&gt;

&lt;p&gt;In order for a developer to improve code using branching from fork, they need to identify possible improvements. This can take many forms. For instance, a developer can find problems to solve by going over the list of open issues in the source control management service that’s hosting the code. Once an issue is identified, the developer can address it according to their own development style and timeframe.&lt;/p&gt;

&lt;p&gt;In addition to addressing known issues, a developer can implement, in an unsolicited manner, a feature they would like to see in the code. There’s no need to ask for permission. All that needs to be done is to implement the feature and then submit a pull request back to the original project. At that point, it’s up to the project’s maintainers to use the improvement. If the unsolicited feature is not accepted, it still exists in the fork and is available to interested parties there.&lt;/p&gt;

&lt;p&gt;One drawback of branching by fork is that making contributions can require a good deal of work. Regardless of whether the developer is working on a known issue, implementing an existing feature request, or offering an unsolicited improvement, they will still need to learn the code. That learning curve can be significant, particularly if the developer has limited access to others who are willing to help. Sometimes the help required to fill in the gaps might be available, but many times it’s not. If the documentation is poor or the code is cryptic, figuring out how to make a meaningful improvement can take a lot of time. As those who have worked with volunteers can attest, the best volunteer experience is the one that’s the easiest. The more difficult the undertaking, the greater the risk of losing the volunteer’s sense of investment.&lt;/p&gt;

&lt;p&gt;Conversely, a developer working on a feature request according to the branching from repo pattern will usually be a member of the business or organization that owns the repository. Thus, they will usually enjoy the support of other members who have experience working with the code. There’s both formal and tribal knowledge that’s available, so things are easier.&lt;/p&gt;

&lt;p&gt;Another drawback of branching from fork is that since anybody can make a contribution, anybody will. This means that the code submitted via a pull request will vary in quality: Some of it will be quite good, but some of it will be quite bad. This creates more work for those who actually have to review pull requests in order to make sure that a submission meets quality standards. While a certain degree of quality control can be accomplished using automation, there are still aspects of the pull request that will require human inspection, particularly if the code is complex.&lt;/p&gt;

&lt;p&gt;In short, branching from fork allows more people to work on code in their own manner, but making meaningful contributions is harder for all parties involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;The beauty of being able to branch source code is that it allows developers to work on code in a safe, controllable manner. Modern software development depends on branching.&lt;/p&gt;

&lt;p&gt;The beauty of forking is that it provides a way for independent parties to work on an entire repository hosted in a source control management platform, such as GitHub or BitBucket, in an independent manner without affecting the original repository. Combining branching and forking creates a new dimension in software development.&lt;/p&gt;

&lt;p&gt;Whether you use the branching from repo technique or the branching from fork technique, the important thing is that both methods provide developers a significant degree of independence while ensuring that the code that eventually makes its way into production will be the highest quality possible.&lt;/p&gt;

</description>
      <category>news</category>
      <category>feature</category>
      <category>infrastructure</category>
      <category>community</category>
    </item>
    <item>
      <title>Configuring Travis CI to Run a Deno Project</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Wed, 17 Feb 2021 12:52:42 +0000</pubDate>
      <link>https://dev.to/travisci/the-cookbook-build-matrix-46ip</link>
      <guid>https://dev.to/travisci/the-cookbook-build-matrix-46ip</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jSZztBxE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ugqcvjknxpcn04bvegp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jSZztBxE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ugqcvjknxpcn04bvegp.png" alt="Alt Text" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nothing lasts forever in the world of ephemeral computing. It’s the nature of the beast. Today, more companies are maximizing their IT budgets by practicing the principles of infrastructure as code (IaC). They’re creating and destroying virtual assets on demand in order to meet the needs of the moment. &lt;/p&gt;

&lt;h1&gt;
  
  
  Getting started
&lt;/h1&gt;

&lt;p&gt;I am a big fan of Deno. I am also a big fan of Travis CI. What’s not to like? Deno is a powerful new programming framework that picks up where Node.js left off. Travis CI is a CI/CD platform that integrates easily with the projects stored in my GitHub repo. They’re both very cool.&lt;/p&gt;

&lt;p&gt;But there’s a problem: Travis CI does not support Deno out of the box. Let's see what we can do.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://deno.land"&gt;Deno&lt;/a&gt; is still in its infancy, so it makes sense that it is not quite yet on the Travis CI radar. Still, no biggie. Travis CI is flexible enough to allow me to build support for Deno right into the CI/CD workflow that kicks off when my Deno project runs on Travis CI. In fact, getting Deno to run on Travis CI was pretty easy, and the results are very useful, so allow me to share.&lt;/p&gt;

&lt;p&gt;First I’m going to cover the overall process for deploying to Travis CI and running a workflow defined in a &lt;code&gt;.travis.yml&lt;/code&gt; file. Then I’ll show you the custom &lt;code&gt;.travis.yml&lt;/code&gt; file I wrote that has Travis CI install Deno and run the unit tests for my Deno project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Travis CI 101
&lt;/h2&gt;

&lt;p&gt;Travis CI runs a CI/CD process right out of the box as part of its signup process. The first time you come to travic-ci.org, you’ll be asked to log in to Travis CI using your GitHub or BitBucket credentials. (The Bitbucket signup is in beta.)&lt;/p&gt;

&lt;p&gt;The signup process asks you to declare repositories on the source code management (SCM) service, into which a webhook will be installed. Once a webhook is installed on the given repository, Travis CI will receive notifications about events that happen in that repository. For example, when a developer commits code into a repository that has a webhook installed, Travis CI will be notified about the commit.&lt;/p&gt;

&lt;p&gt;Travis CI will clone the contents of that repo into a virtual machine instance running in the Travis CI domain. Once the runner VM has the contents of the cloned repository, it will look for a special file named travis.yml that contains instructions for provisioning the VM and about tasks to perform once the runner VM is provisioned. Figure 1 below describes the process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nxwqTdg---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jmyrqju3qw7b5jauabm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nxwqTdg---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jmyrqju3qw7b5jauabm.png" alt="Alt Text" width="880" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Figure 1: The Travis CI Workflow&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you can see in callout 1 above, the first step in the workflow process is that a developer commits updated code to the repository of interest in the SCM service running in the cloud. A webhook in the repository “sees” the commit and emits an event message that is captured by Travis CI, as shown at callout 2. Travis CI clones the repository’s code into a VM in its domain and then looks for the &lt;code&gt;.travis.yml&lt;/code&gt; file in the cloned files. The &lt;code&gt;.travis.yml&lt;/code&gt; file is identified, and the configuration and instructions in &lt;code&gt;.travis.yml&lt;/code&gt; are executed, as shown at callout 3.&lt;/p&gt;

&lt;p&gt;The process is straightforward, and it’s quite powerful in that we can construct the &lt;code&gt;.travis.yml&lt;/code&gt; file to define custom configuration and execute tasks that are special, too. In fact, we’re going to use &lt;code&gt;travis.yml&lt;/code&gt; to install the Deno language on the runner VM and then execute the unit tests that are part of my Deno project. This is very cool because, remember, as of this writing Travis CI does not support Deno out of the box.&lt;/p&gt;

&lt;p&gt;Let’s take a look at how support for Deno is implemented.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Travis CI to support Deno
&lt;/h2&gt;

&lt;p&gt;As mentioned above, the way you get Travis CI to do what you want it to do in its CI/CD process is to construct a &lt;code&gt;.travis.yml&lt;/code&gt; file according to the format defined in the Travis CI build config specification.&lt;/p&gt;

&lt;p&gt;The way I got Travis CI to support Deno was to do a bit of a hack in my project’s &lt;code&gt;.travis.yml&lt;/code&gt; file. The entire contents of &lt;code&gt;.travis.yml&lt;/code&gt; are shown below in listing 1. Let’s take a look at the details on a line-by-line basis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
&lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pwd&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -fsSL https://deno.land/x/install/install.sh | sh&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ls -l $HOME/.deno&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export DENO_INSTALL="$HOME/.deno"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export PATH="$DENO_INSTALL/bin:$PATH"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deno run https://deno.land/std/examples/welcome.ts&lt;/span&gt;   
&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cd ./simplecalc/test/&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sh run_test.sh&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cd ../../fortune_cookies/test&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sh run_test.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Listing 1: .travis.yml &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Travis CI allows you to define a &lt;a href="https://config.travis-ci.com/ref/language"&gt;language&lt;/a&gt; that gets implemented in the VM runner. It supports a &lt;a href="https://docs.travis-ci.com/user/languages/"&gt;variety of languages&lt;/a&gt; out of the box, but sadly, Deno isn’t one of them. Thus, at Line 1 in the travis.yml file above, I set the value of the &lt;code&gt;language&lt;/code&gt; attribute to &lt;code&gt;default&lt;/code&gt;. It really doesn’t matter which &lt;code&gt;language&lt;/code&gt; I define, because I am going to install Deno anyway.&lt;/p&gt;

&lt;p&gt;At line 2 at the os attribute, I set the runner VM’s operating system to Ubuntu. Travis CI supports the macOS and Windows operating system too, but I use Ubuntu because my code is intended to run on Linux.&lt;/p&gt;

&lt;p&gt;Travis CI allows you to configure the runner VM with a variety of services. For example, I could apply values to the services attribute that will install MySQL, Redis and Memcached to the runner VM automatically. In my case, I need to have Docker installed because one of my unit tests requires that a web server programmed under Deno be up and running as a Docker container. So at Lines 3 and 4, I set docker as a service.&lt;/p&gt;

&lt;p&gt;At line 2 at the &lt;a href="https://config.travis-ci.com/ref/os"&gt;os&lt;/a&gt; attribute, I set the runner VM’s operating system to Ubuntu. Travis CI supports the macOS and Windows operating system too, but I use Ubuntu because my code is intended to run on Linux.&lt;/p&gt;

&lt;p&gt;Travis CI allows you to configure the runner VM with a variety of &lt;a href="https://config.travis-ci.com/ref/job/services"&gt;services&lt;/a&gt;. For example, I could apply values to the services attribute that will install &lt;a href="https://www.mysql.com/"&gt;MySQL&lt;/a&gt;, &lt;a href="https://redislabs.com/"&gt;Redis&lt;/a&gt; and &lt;a href="https://www.memcached.org/"&gt;Memcached&lt;/a&gt; to the runner VM automatically. In my case, I need to have &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; installed because one of my unit tests requires that a web server programmed under Deno be up and running as a Docker container. So at Lines 3 and 4, I set Docker as a service.&lt;/p&gt;

&lt;p&gt;Lines 5 through 7 set the &lt;a href="https://config.travis-ci.com/ref/job/branches"&gt;branches&lt;/a&gt; attribute to tell Travis CI to use the code in the master branch of the cloned repository. You can set Travis CI to process specific branches in a given repo, but in this case, the code I’m interested in unit testing is in the master branch.&lt;/p&gt;

&lt;p&gt;Lines 8 through 14 are where Deno support is implemented. I add the command line tasks required to download Deno. Once downloaded, the task will install Deno and then check that Deno is running. This is all defined under the &lt;code&gt;before_install&lt;/code&gt; attribute, which indicates the stage before installation in the &lt;a href="https://docs.travis-ci.com/user/job-lifecycle"&gt;Travis CI job lifecycle&lt;/a&gt;. The install stage is the time when all dependencies are installed, so in this case, I am telling Travis CI to install Deno before any other download and configuration happens.&lt;/p&gt;

&lt;p&gt;Line 9 tells Travis CI to output the present working directory &lt;a href="https://en.wikipedia.org/wiki/Pwd"&gt;(pwd)&lt;/a&gt;. I do this to provide debugging information that might be useful later.&lt;/p&gt;

&lt;p&gt;Line 10 runs the &lt;code&gt;curl&lt;/code&gt; command that downloads and executes the shell (sh) script that does the actual work of installing Deno.&lt;/p&gt;

&lt;p&gt;Line 11 lists the contents of the .deno directory. I do this to provide debugging information. When the Deno installation is run, it creates a .deno directory in the user’s &lt;code&gt;$HOME&lt;/code&gt; directory where the Deno binaries and dependencies are stored.&lt;/p&gt;

&lt;p&gt;Line 12 creates an environment variable, &lt;code&gt;DENO_INSTALL&lt;/code&gt; which describes the location of the Deno binary and dependencies.&lt;/p&gt;

&lt;p&gt;Line 14 runs the simple “Hello World” Deno application, which is downloaded directly from the Deno home site. I do this just to confirm that Deno is up and running properly.&lt;/p&gt;

&lt;p&gt;Lines 15 through19 run the unit tests for the various subjects that are part of my main projects. (See figure 2, below.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7nP2d8ul--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x0yy6wub4j71xn3zggpy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7nP2d8ul--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x0yy6wub4j71xn3zggpy.png" alt="Alt Text" width="880" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Figure 2: An excerpt from the console output created with travis.yml running my project’s unit tests&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s it. As you can see, I got Deno up and running under Travis CI using a trivial amount of code in the &lt;code&gt;.travis.yml&lt;/code&gt; file. Being able to do so much with such a small amount of code attests to the power that Travis CI brings to the CI/CD experience.&lt;/p&gt;

&lt;p&gt;You can view the code for this Deno project on GitHub &lt;a href="https://github.com/reselbob/denodemo"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join the initiative
&lt;/h2&gt;

&lt;p&gt;Travis CI provides the power and flexibility to make just about any CI/CD workflow possible. The platform’s versatility is reason enough for enterprises to consider adopting it. But when it comes to running Deno under Travis CI, there’s more!&lt;/p&gt;

&lt;p&gt;Travis CI supports implementing &lt;a href="https://docs.travis-ci.com/user/languages/community-supported-languages"&gt;community-based languages&lt;/a&gt;. Thus, it’s entirely possible to get Deno incorporated into the array of languages that Travis CI supports once the &lt;a href="https://docs.travis-ci.com/user/languages/community-supported-languages#adding-a-new-language"&gt;infrastructure&lt;/a&gt; is in place. All that’s required is for three members of the Deno community to commit to becoming maintainers and keeping the language support active. That being said, I am actively looking for people who want to become maintainers. &lt;/p&gt;

&lt;p&gt;Making Deno work out of the box with Travis CI is a win-win for all parties. If you’re interested, &lt;a href="https://www.linkedin.com/in/bobreselman"&gt;contact me on LinkedIn&lt;/a&gt;. It will be a great adventure, and the result of our endeavor will benefit many for years to come.&lt;/p&gt;

</description>
      <category>news</category>
      <category>feature</category>
      <category>infrastructure</category>
      <category>community</category>
    </item>
    <item>
      <title>The Cookbook: Build Matrix</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Thu, 11 Feb 2021 10:53:30 +0000</pubDate>
      <link>https://dev.to/travisci/the-cookbook-build-matrix-3okj</link>
      <guid>https://dev.to/travisci/the-cookbook-build-matrix-3okj</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vl7ZVHu6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rhaovmrn9c32jo54xy4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vl7ZVHu6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rhaovmrn9c32jo54xy4b.png" alt="Alt Text" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A build matrix in Travis is made up by several multiple jobs that run in parallel. This can be useful in many cases, but the two primary reasons we see people use matricies is for reducing the overall build execution time and running tests against different versions of runtimes or dependencies to get the best version of the build. Let's learn about Build Matricies in Travis CI. &lt;/p&gt;

&lt;h1&gt;
  
  
  Build Matrix and setting up the .travis.yml
&lt;/h1&gt;

&lt;p&gt;As you know by now, you need to tell Travis which language environment to select for your project. You can do so using the &lt;code&gt;language&lt;/code&gt; key option, in this Cookbook we'll be using PHP. You can specify which PHP versions will the tests be executed. Not introducing patch versions tells Travis to use the latest available, which is sometimes referred to &lt;code&gt;edge&lt;/code&gt;, or if it's the stable version, you guessed it, it's called &lt;code&gt;stable&lt;/code&gt;. So let's start building out our &lt;code&gt;.travis.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php&lt;/span&gt;

&lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5.3.3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5.4&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5.5&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5.6&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hhvm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Env Vars
&lt;/h1&gt;

&lt;p&gt;Let's tell Travis to do multiple runs/builds with different sets of &lt;code&gt;env var&lt;/code&gt; values. To do so, add an &lt;code&gt;env key&lt;/code&gt;. Each segment is understood as a different environment and tests are run separately as such. We are going to use &lt;code&gt;PHP_SEGMENT_TEST&lt;/code&gt; later in the file to run tester with the argument of &lt;code&gt;-p&lt;/code&gt; and &lt;code&gt;hhvm&lt;/code&gt; option in HHVM environment, so in your &lt;code&gt;.travis.yml&lt;/code&gt; file, add the &lt;code&gt;env&lt;/code&gt; segment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PHP_SEGMENT_TESTRUN="php-cgi"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PHP_SEGMENT_TEST="hhvm"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now simple math would have it, the combination of five PHP versions and the two &lt;code&gt;env vars&lt;/code&gt; generates a total of 10 runs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Dependency installation using Composer
&lt;/h1&gt;

&lt;p&gt;You'll obviously have an install segment in your &lt;code&gt;.travis.yml&lt;/code&gt;. Each sub-segment means one single command. Composer installs your dev dependencies by default. You should use --no-interaction so Composer doesn't ask questions Travis can't answer, and can continue the build. &lt;/p&gt;

&lt;p&gt;You'll want the latest build, so in you &lt;code&gt;.travis.yml&lt;/code&gt; make sure you run the &lt;code&gt;update&lt;/code&gt; flag at &lt;code&gt;before_install&lt;/code&gt;, so it would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;composer self-update&lt;/span&gt;

&lt;span class="na"&gt;install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;composer install --no-interaction&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  The Build Matrix
&lt;/h1&gt;

&lt;p&gt;Depending on the configuration above (different segments and sub segments), a build matrix wil be generated. The matrix contains all combinations the environment settings. A single combination is called a job and is run separately. You can modify the matrix in matrix section.&lt;/p&gt;

&lt;p&gt;If you want to exclude a job, use the &lt;code&gt;exclude&lt;/code&gt; key. In our case, we don't want to use -p hhvm parameter for standard PHP versions and -p php-cgi for HHVM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5.3.3&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PHP_SEGMENT_TEST="hhvm"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5.4&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TPHP_SEGMENT_TEST="hhvm"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5.5&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PHP_SEGMENT_TEST="hhvm"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5.6&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PHP_SEGMENT_TEST="hhvm"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hhvm&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PHP_SEGMENT_TESTRUN="php-cgi"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To your pleasure, you can define jobs that are allowed to fail without causing the whole build to shown as failed. To do so, declare allow_failures. For our sake, we allow HHVM to fail, lets do this via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allow_failures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hhvm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I only specified the PHP version, not the environment variables. This means all jobs with HHVM version will be allowed to fail/retry (if that is an option you have in your &lt;code&gt;.travis.yml&lt;/code&gt;. Anyway, nevermind the environment variables values. It works with &lt;code&gt;exclude&lt;/code&gt; also.&lt;/p&gt;

&lt;h1&gt;
  
  
  Running the scripts/tests
&lt;/h1&gt;

&lt;p&gt;Tests are run in script segment of the &lt;code&gt;.travis.yml&lt;/code&gt;. Let's assume your tests are in &lt;code&gt;scripts/&lt;/code&gt; folder in your file tree and you provide your own &lt;code&gt;php.ini&lt;/code&gt; in the same folder. Additionally, we can tell &lt;code&gt;TESTER&lt;/code&gt; to display information about skipped tests with the &lt;code&gt;-s&lt;/code&gt; flag and to use value of earlier declared &lt;code&gt;TESTER_SEGMENT_TEST&lt;/code&gt; as PHP binary with the -p flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vendor/bin/tester -p $TESTER_SEGMENT_TEST -s -c ./tests/php.ini ./tests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the build &lt;code&gt;fails&lt;/code&gt; we want to use &lt;code&gt;after_failure&lt;/code&gt; to get the exact values via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;after_failure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Prints *.actual files contents (if not revert) &lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;for i in $(find ./tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Other services
&lt;/h1&gt;

&lt;p&gt;Travis comes with multiple popular services and has no shortages of them, (e.g. MySQL, Redis, Docker) pre-installed. However, if you need to use for example Redis storage, you can tell Travis in services section via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis-server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  DB Init
&lt;/h1&gt;

&lt;p&gt;Depending on what database you chose to use, it can vary -- in this example we are using &lt;code&gt;MySQL&lt;/code&gt;. MySQL runs on 127.0.0.1 and you can log in using travis or root as username. Say you have a DB setup script, and it's in &lt;code&gt;tests/montana/testbase.sql.&lt;/code&gt;, here's a sample segment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mysql -u root -e 'CREATE DATABASE testbase;'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mysql -u root testbase &amp;lt; tests/montana/testbase.sql&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  .travis.yml in it's final form
&lt;/h1&gt;

&lt;p&gt;After a lot of this segment config, this is what you're left with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php&lt;/span&gt;

&lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5.3.3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5.4&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5.5&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5.6&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hhvm&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TESTER_SEGMENT_TEST="php-cgi"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TESTER_SEGMENT_TESTRUN="hhvm"&lt;/span&gt;

&lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allow_failures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hhvm&lt;/span&gt;

  &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5.3.3&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TESTER_SEGMENT_TEST="hhvm"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5.4&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TESTER_SEGMENT_TEST="hhvm"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5.5&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TESTER_SEGMENT_TEST="hhvm"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5.6&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TESTER_SEGMENT_TEST="hhvm"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hhvm&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TESTER_SEGMENT_TESTRUN="php-cgi"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis-server&lt;/span&gt;

&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;composer self-update&lt;/span&gt;

&lt;span class="na"&gt;install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;composer install --no-interaction --prefer-source&lt;/span&gt;

&lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mysql -u root -e 'CREATE DATABASE testbase;'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mysql -u root testbase &amp;lt; tests/montana/testbase.sql&lt;/span&gt;

&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vendor/bin/tester -p $TESTER_SEGMENT_TEST -c ./tests/php.ini -s ./tests/&lt;/span&gt;

&lt;span class="na"&gt;after_failure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# to find actual variables if needed, a verbose esque way of doing things&lt;/span&gt;
  &lt;span class="c1"&gt;# Prints *.actual files content&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;for i in $(find ./tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Activate webhook
&lt;/h1&gt;

&lt;p&gt;Go to &lt;a href="http://www.travis-ci.com"&gt;www.travis-ci.com&lt;/a&gt;, and flip switch to &lt;code&gt;ON&lt;/code&gt; for all repositories you'd like to enable. Travis will now add your repository to queue after every pushed commit or created pull-request. After a short while, your repository will be tested. Now if you'd like the opposite, there's a bash script I've created, which I will attach right below this - as some people find this more efficient:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env sh&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello from Montana at Travis"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TRAVIS_PULL_REQUEST&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TRAVIS_PULL_REQUEST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"false"&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;surge &lt;span class="nt"&gt;--project&lt;/span&gt; ./dist &lt;span class="nt"&gt;--domain&lt;/span&gt; auto-deploy-test.surge.sh
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is a PR, not deploying"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To know if your build is successful either check the GitHub status, or generate a status image. &lt;/p&gt;

&lt;h1&gt;
  
  
  Congratulations
&lt;/h1&gt;

&lt;p&gt;This is Travis's Build Matrix in a nutshell, it can seem a bit confusing but after going over it a few times, it will start to make sense.&lt;/p&gt;

</description>
      <category>news</category>
      <category>feature</category>
      <category>infrastructure</category>
      <category>community</category>
    </item>
    <item>
      <title>The Cookbook: Jekyll</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Mon, 25 Jan 2021 08:24:54 +0000</pubDate>
      <link>https://dev.to/travisci/the-cookbook-jekyll-5f7a</link>
      <guid>https://dev.to/travisci/the-cookbook-jekyll-5f7a</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oMNCzSmP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/x44n0xl7zbu324as5cef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oMNCzSmP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/x44n0xl7zbu324as5cef.png" alt="Header" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Pages are an amazing way to host Jekyll pages, but in some cases, you might be interested in running your Jekyll page on a different host (like Azure Web Apps, Heroku, AWS). In this Cookbook let's setup a DevOps Build Pipeline that takes commits, run smoke screen testing, and actually deploying. &lt;/p&gt;

&lt;h1&gt;
  
  
  Getting started with Jekyll
&lt;/h1&gt;

&lt;p&gt;Ideally with Jekyll, you want a compile script (obviously in bash) that traverses to an &lt;code&gt;out/&lt;/code&gt; directory. For sake of this example, you can call the bash script anything but I'm going to call it &lt;code&gt;jekyll.sh&lt;/code&gt;. Your project may require something different, for example &lt;code&gt;npm build&lt;/code&gt; or something to that extent.&lt;/p&gt;

&lt;p&gt;When creating the file tree/structure, let's make sure the &lt;code&gt;out/&lt;/code&gt; directory contains almost or essentially everything you want deployed to &lt;code&gt;gh-pages&lt;/code&gt;. In a case like this, you will 95% of the time have a &lt;code&gt;index.html&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;Check this script into your project. Now this is just an example, now let's say the script just reads (remember, your script might just read &lt;code&gt;npm build&lt;/code&gt;:&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Bash
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;#!/bin/bash/env sh &lt;/span&gt;

&lt;span class="c"&gt;# only let the script proceed when started not by a pull request (PR)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$TRAVIS_PULL_REQUEST&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"true"&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="c"&gt;# you can make this more strict via "==="&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"this is a PR, exiting now"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# enable error reporting to the console &amp;amp; log that into a file entitled "log.txt" &lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="c"&gt;# build site with jekyll, by default to `_site' folder&lt;/span&gt;

bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll build

&lt;span class="c"&gt;# find ./_site -name "*.html" -exec bundle exec htmlbeautifier {} \;&lt;/span&gt;

bundle &lt;span class="nb"&gt;exec &lt;/span&gt;htmlproof ./_site &lt;span class="nt"&gt;--disable-external&lt;/span&gt; &lt;span class="nt"&gt;--check-html&lt;/span&gt; &lt;span class="nt"&gt;--verbose&lt;/span&gt;

&lt;span class="c"&gt;# cleanup using `rm -rf`&lt;/span&gt;

&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ../Montana.github.io.master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Travis and adding Travis to your project
&lt;/h2&gt;

&lt;p&gt;We assume you have one, but if not get a Travis account at &lt;a href="https://travis-ci.com/"&gt;https://travis-ci.com/&lt;/a&gt;. Turn on Travis for the repo in question, using the Travis GUI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypted credentials
&lt;/h2&gt;

&lt;p&gt;If you read the Cookbook Series: Encryption, you can most likely skip over this, but if you haven't - when you deploy using Travis, ideally you want to deploy &lt;code&gt;gh-pages&lt;/code&gt; without checking in the necessary credentials to your repo, this can be done using &lt;a href="https://docs.travis-ci.com/user/encrypting-files/"&gt;encryption&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next up, you'll want to generate a SSH key. The advice I always give is to &lt;em&gt;never&lt;/em&gt; reuse SSH keys. To generate a new SSH key, you'll want to open a terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"your_email@example.com"&lt;/span&gt; &lt;span class="c"&gt;# in my case "ssh-keygen -t rsa -b 4096 -C "montana@travis-ci.org"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll be prompted to do a few things, one thing you want to remember is you &lt;em&gt;do not&lt;/em&gt; want to include a password, just press &lt;code&gt;enter&lt;/code&gt; when prompted, then follow the next prompt and continue. You'll now want to add the deploy key to your repo, and remember &lt;em&gt;do not&lt;/em&gt; reuse SSH keys. You can do this via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://github.com/&amp;lt;github_username&amp;gt;/&amp;lt;your_repo&amp;gt;/settings/keys &lt;span class="c"&gt;# add the deploy key to your repo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time to encrypt the key that was generated using the Travis CLI client. So now let's demonstrate on how we would add your deploy key to your specified repo. &lt;/p&gt;

&lt;h2&gt;
  
  
  Adding your encrypted vars
&lt;/h2&gt;

&lt;p&gt;First, let's open an editor so we can view the &lt;code&gt;dpl key&lt;/code&gt;, so let's run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;github_deploy_key.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use &lt;code&gt;touch&lt;/code&gt;, so instead of &lt;code&gt;cat&lt;/code&gt;, it would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;github_deploy_key.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that you have the key, make sure the proper repo is conditioned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://github.com/&amp;lt;github_username&amp;gt;/&amp;lt;your_repo&amp;gt;/settings/keys &lt;span class="c"&gt;# add the deploy key to your repo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's use Travis again from the CLI again to login:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;travis login &lt;span class="nt"&gt;--org&lt;/span&gt; &lt;span class="nt"&gt;--auto&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll then want to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;travis encrypt-file &lt;span class="s1"&gt;'github_deploy_key'&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you add your &lt;code&gt;PUBLIC&lt;/code&gt; key as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="s1"&gt;'github_deploy_key.enc'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bash script I've coded below automates the above process essentially, I did this to make it a bit easier on the Travis CI user, for the sake of time lets say this bash script I created is called &lt;code&gt;dpl_key&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash/env sh &lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&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="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"GITHUB_TOKEN environment variable is missing"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Travis dpl_key generator"&lt;/span&gt; 
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This generates a public/private dpl_key, add the public key as a deploy key
  with write access to the origin remote github repo, encrypt the private key as
  github_deploy_key.enc and add the configuration necessary to use it in your .travis.yml file"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Give it a shot:"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  GITHUB_TOKEN=&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;cat ~/secret/GITHUB_TOKEN&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt; ./generate_travis_deploy_key"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"where ~/secret/GITHUB_TOKEN is a file containing a github token with write access to the current repository : (origin)"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"You must have the Travis executable installed on your system and available in the PATH"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;exit
&lt;/span&gt;&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git config &lt;span class="nt"&gt;--get&lt;/span&gt; remote.origin.url&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;reponame&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;/ &lt;span class="nt"&gt;-f2&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-f1&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# generate a new private and public key&lt;/span&gt;

ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096 &lt;span class="nt"&gt;-f&lt;/span&gt; github_deploy_key &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; 1&amp;gt;/dev/null

&lt;span class="nv"&gt;pubkey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;github_deploy_key.pub&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# add the PUBLIC key to the github repository as a deploy key with write access&lt;/span&gt;

curl https://github.com/&amp;lt;github_username&amp;gt;/&amp;lt;your_repo&amp;gt;/settings/keys &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: token &lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--data&lt;/span&gt; @- &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
{
  "title": "travis deploy key",
  "key": "&lt;/span&gt;&lt;span class="nv"&gt;$pubkey&lt;/span&gt;&lt;span class="sh"&gt;",
  "read_only": false
}
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# use travis to encrypt the private key as github_deploy_key.enc and remove the private key&lt;/span&gt;

travis encrypt-file github_deploy_key &lt;span class="nt"&gt;--add&lt;/span&gt; &lt;span class="nt"&gt;--no-interactive&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; /tmp/github_deploy_key &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;--pro&lt;/span&gt;
git add github_deploy_key.enc

&lt;span class="c"&gt;# cleaning&lt;/span&gt;

&lt;span class="nb"&gt;rm &lt;/span&gt;github_deploy_key
&lt;span class="nb"&gt;rm &lt;/span&gt;github_deploy_key.pub

&lt;span class="c"&gt;# bash script by montana mendy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  .travis.yml
&lt;/h2&gt;

&lt;p&gt;So, this is a &lt;code&gt;.travis.yml&lt;/code&gt; file I've created, as you can see if you use my config it will automate the deployment for you, if you'd like to deploy manually, then just remove the line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;generic&lt;/span&gt; &lt;span class="c1"&gt;# this doesn't install any environment at all &lt;/span&gt;

&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bash chmod +x ./dpl_key.sh&lt;/span&gt; &lt;span class="c1"&gt;# will give proper permissions via chmod to both scripts &lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bash chmod +x ./jekyll.sh&lt;/span&gt;

&lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;before_deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;openssl aes-256-cbc -K $encrypted_0a644212b3ae3_key -iv $encrypted_0a644212b3ae3_key -in deploy_key.enc -out deploy_key -d&lt;/span&gt;


&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pages&lt;/span&gt;
  &lt;span class="na"&gt;local_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;out&lt;/span&gt;
  &lt;span class="na"&gt;deploy_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_key&lt;/span&gt;
  &lt;span class="na"&gt;edge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should have 3 files, the ones we have talked about, &lt;code&gt;jekyll.sh&lt;/code&gt;, &lt;code&gt;deploy_key.enc&lt;/code&gt; and your &lt;code&gt;.travis.yml&lt;/code&gt;. Make sure you've logged into Travis, let Travis know about the repo via syncing, once you push to GitHub it will compile and deploy your source, either using my bash script or doing it step by step. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you learned some niche ways on deploying source while using Travis, until next time! &lt;/p&gt;

</description>
      <category>news</category>
      <category>feature</category>
      <category>infrastructure</category>
      <category>community</category>
    </item>
    <item>
      <title>The Build, Test, Nuke Pattern</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Thu, 21 Jan 2021 03:22:46 +0000</pubDate>
      <link>https://dev.to/travisci/the-build-test-nuke-pattern-30c3</link>
      <guid>https://dev.to/travisci/the-build-test-nuke-pattern-30c3</guid>
      <description>&lt;h1&gt;
  
  
  The Build, Test, Nuke Pattern
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;A Tutorial on Testing Etiquette in the Age of Ephemeral Computing&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nothing lasts forever in the world of ephemeral computing. It’s the nature of the beast. Today, more companies are maximizing their IT budgets by practicing the principles of infrastructure as code (IaC). They’re creating and destroying virtual assets on demand in order to meet the needs of the moment.&lt;/p&gt;

&lt;p&gt;Paying only for what you use makes sense technically and financially. IaC offers a lot of benefits, but it does take some getting used to, particularly with regard to resource management.&lt;/p&gt;

&lt;p&gt;There’s a certain etiquette involved when a lot of people are using a common set of resources. In a way, being part of an IaC environment is similar to using the laundry room in an apartment building. You need to be aware that other people are using the washers, dryers and folding tables. Thus, you need to keep moving your clothes along from washer to dryer in a timely manner, and you need to clean up after yourself, always.&lt;/p&gt;

&lt;p&gt;The same is true in ephemeral computing. There is nothing more irritating than testing on a virtual machine that is all clogged up with useless applications and components left behind from previous tests. Not only do such remnants take up valuable computing resources, but they might also compromise the outcome of your testing. &lt;/p&gt;

&lt;p&gt;When running tests in an ephemeral, IaC environment, a good pattern to follow is one that I call the Build, Test, Nuke pattern. Let’s explore the pattern using an example from a set of unit tests I created in my &lt;a href="https://github.com/reselbob/denodemo"&gt;Deno demonstration project&lt;/a&gt; and ran on Travis CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Build, Test, Nuke
&lt;/h2&gt;

&lt;p&gt;The structure of the Build, Test, Nuke pattern is to divide the testing event into three stages. In the first stage, Build, your testing script gets the source code from a source control management service, such as GitHub, and builds the required dependencies into a deployment unit, such as a Docker container. In the second stage, Test, the script tests the artifact. Then, in the third stage, Nuke, your script destroys the deployment artifacts used in the testing, removing them from both memory and disk. (See figure 1 below.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hEzeeSwo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2czkgqcjdpfbb653z9cv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hEzeeSwo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2czkgqcjdpfbb653z9cv.png" alt="Nuke" width="787" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Figure 1: The Build, Test, Nuke pattern&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The benefit of the pattern is apparent. Your scripts are using only the resources needed, when they’re needed. For a small application, using the pattern might seem trivial. But, when you get into an application that has a dozen dependencies running in separate processes that put pressure on both memory and network IO, leaving them up and running after testing is done can be a significant risk. Destroying everything when testing is over addresses this risk head-on.&lt;/p&gt;

&lt;p&gt;Now that we’ve covered the concept behind the Build, Test, and Nuke pattern, let’s take a look at how it’s implemented when running a set of unit tests under Travis CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting Build, Nuke, Test into Action
&lt;/h2&gt;

&lt;p&gt;As mentioned above, I use the Build, Nuke and Test pattern in a set of HTTP tests I created for an application in my &lt;a href="https://deno.land/"&gt;Deno&lt;/a&gt; demonstration project, which you can find [here].(&lt;a href="https://github.com/reselbob/denodemo"&gt;https://github.com/reselbob/denodemo&lt;/a&gt; The application is called &lt;a href="https://github.com/reselbob/denodemo/tree/master/simplecalc_"&gt;SimpleCalc&lt;/a&gt;. SimpleCalc is an API that exposes the math operations &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;subtract&lt;/code&gt;, &lt;code&gt;multiply&lt;/code&gt; and &lt;code&gt;divide&lt;/code&gt;. The API runs as a web application over HTTP.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Deno?
&lt;/h2&gt;

&lt;p&gt;Deno is a next-generation programming framework developed by Ryan Dahl, the creator of Node.js. Deno runs using the V8 JavaScript, as does Node.js, but Deno uses the Typescript language to program. Deno also improves upon Node.js in other ways, such as the way dependencies are stored and runtime permissions are granted. For more information about Deno, visit the website at: &lt;a href="https://deno.land/"&gt;https://deno.land/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The way the HTTP test works is the script creates the web server that hosts the SimpleCalc API in a &lt;a href="https://www.docker.com/resources/what-container"&gt;Docker&lt;/a&gt; &lt;a href="https://www.docker.com/resources/what-container"&gt;container&lt;/a&gt;. Then, once the SimpleCalc API server is up and running, a set of Deno tests are run. After the tests are run, the test script destroys both the container in which the SimpleCalc API server is running and the &lt;a href="https://stackoverflow.com/questions/23735149/what-is-the-difference-between-a-docker-image-and-a-container"&gt;container image&lt;/a&gt; that’s used to create the container for the SimpleCalc API. (You can think of a container image as the template that describes the container that will run in memory.)&lt;/p&gt;

&lt;p&gt;Listing 1 below shows the Bash script that creates the container, runs the HTTP tests, and then destroys the container and container image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ..

docker build &lt;span class="nt"&gt;-t&lt;/span&gt; mydenoserver &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; simplecalc &lt;span class="nt"&gt;-p&lt;/span&gt; 7700:7700 mydenoserver

deno &lt;span class="nb"&gt;test&lt;/span&gt;  &lt;span class="nt"&gt;--allow-net&lt;/span&gt; &lt;span class="nt"&gt;--allow-env&lt;/span&gt; &lt;span class="nt"&gt;--allow-read&lt;/span&gt; &lt;span class="nt"&gt;--allow-write&lt;/span&gt; &lt;span class="nt"&gt;--reload&lt;/span&gt;

docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; simplecalc
docker rmi &lt;span class="nt"&gt;-f&lt;/span&gt; mydenoserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Listing 1: The Bash script that implements the Build, Test and Nuke pattern&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice that the Build phase takes place at lines 4 and 5. The script uses the Docker &lt;a href="https://docs.docker.com/engine/reference/commandline/build/"&gt;build&lt;/a&gt; command to create a container image named mydenoserver using the default &lt;a href="https://github.com/reselbob/denodemo/blob/master/simplecalc/Dockerfile"&gt;Dockerfile&lt;/a&gt; stored along with the source code. (See line 4 above.) Then, at line 5, the script executes &lt;a href="https://docs.docker.com/engine/reference/commandline/run/"&gt;docker run&lt;/a&gt; to run a container named &lt;code&gt;simplecalc&lt;/code&gt; using the container image &lt;code&gt;mydenoserver&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Line 7 in listing 1 above invokes the unit tests that are stored in the test directory of the &lt;code&gt;SimpleCalc&lt;/code&gt; app source code files. (The Deno test looks for test files in a directory named &lt;code&gt;test&lt;/code&gt; by default.)&lt;/p&gt;

&lt;p&gt;Listing 2 below shows an excerpt from the test file &lt;a href="https://github.com/reselbob/denodemo/blob/master/simplecalc/test/api_tests.ts"&gt;api_tests.ts&lt;/a&gt;. Notice at line 9 that the test accesses the SimpleCalc API’s add operation by way of the webserver running at &lt;a href="http://0.0.0.0:7700/sum/8,4,3"&gt;http://0.0.0.0:7700/sum/8,4,3&lt;/a&gt;. The IP address 0.0.0.0 indicates the source address for the local computer on which the test is running. The SimpleCalc API is listening for traffic on port 7700. The /sum/8,4.3 segment of the URL is special to the SimpleCalc API. It describes the sum operation and an array of integers that will be summed up by the operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;assertEquals&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/std/testing/asserts.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The test, Can add from API, is an excerpt from a set of many tests&lt;/span&gt;
&lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Can add from API&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`http://0.0.0.0:7700/sum/8,4,3`&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Listing 2: An excerpt from the test of HTTP tests that exercise the SimpleCalc API.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The important thing to know about listing 2 above is that it describes a test that is run against a container that hosts the web server, and that container was created on demand as part of the testing process.&lt;br&gt;
After the test is completed, the Bash script controlling the entire process will issue these two commands as shown below, as well as above in listing 1 at lines 9 and 10:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; simplecalc
docker rmi &lt;span class="nt"&gt;-f&lt;/span&gt; mydenoserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the commands that remove both the container and the container image from the host environment. These two lines fulfill the last part of the Build, Test, Nuke pattern. As you can see, the container and the container image are removed completely from the virtual machine host.&lt;/p&gt;

&lt;p&gt;Listing 3 below shows the &lt;code&gt;.travis.yml&lt;/code&gt; file that gets run when new or adjusted code is committed to the demonstration Deno project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
&lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pwd&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -fsSL https://deno.land/x/install/install.sh | sh&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ls -l $HOME/.deno&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export DENO_INSTALL="$HOME/.deno"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export PATH="$DENO_INSTALL/bin:$PATH"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deno run https://deno.land/std/examples/welcome.ts&lt;/span&gt;

&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cd ./simplecalc/test/&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sh run_test.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Listing 3: The Travis.yml file that installs Deno executes the script run_test.sh, which implements the Build, Test, Nuke pattern in the Travis runtime environment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of the nice features of Travis CI is that I can register the Deno demonstration project that’s hosted on GitHub with Travis. Once registered, Travis will install a webhook in the GitHub repo that makes it so when code is committed to the repo, the repo will be cloned automatically into a Travis CI virtual machine dedicated to my testing session. Travis looks for the &lt;code&gt;.travis.yml&lt;/code&gt; in the source code and then, once identified, will configure the virtual machine according to settings in the &lt;code&gt;.travis.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;In this case, the instructions to install Deno are at lines 8 through 14 in listing 3 above. The instruction to navigate to the directory that has the Bash script that controls the testing process is at line 17. The instruction to execute the Bash script is at line 18.&lt;/p&gt;

&lt;p&gt;Remember, the Bash script contains all the instructions to execute the Build, Test, and Nuke pattern. Mission accomplished!&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;The Build, Test, and Nuke pattern is simple and powerful. Using it consistently as part of your CI/CD process will help you run your tests as a reliable, good neighbor in the host runtime environment, whether they’re running on your local machine, under Travis or anywhere else in the cloud.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>container</category>
      <category>testing</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>The Cookbook: Fable</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Mon, 18 Jan 2021 11:03:44 +0000</pubDate>
      <link>https://dev.to/travisci/the-cookbook-fable-n73</link>
      <guid>https://dev.to/travisci/the-cookbook-fable-n73</guid>
      <description>&lt;p&gt;Fable produces readable JavaScript code compatible with ES2015 standards and popular tooling like Webpack, which you've probably heard of if you've ever used React. Let's start this Fable. &lt;/p&gt;

&lt;h2&gt;
  
  
  Build Fable with Travis CI
&lt;/h2&gt;

&lt;p&gt;Hey builders let's get to building Fable with Travis CI! Let's start out with your &lt;code&gt;.travis.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minimal&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;

&lt;span class="na"&gt;sudo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;

&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker pull vbfox/fable-build&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CI"&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker run -v "${PWD}:/app" -w "/app" vbfox/fable-build bash -c "yarn &amp;amp;&amp;amp; yarn postinstall &amp;amp;&amp;amp; yarn build"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's sometimes issues with &lt;code&gt;Fable&lt;/code&gt; for whatever reason with syntax errors, so you may want to take the time and &lt;code&gt;lint&lt;/code&gt; your &lt;code&gt;.travis.yml&lt;/code&gt; file, you can do this via running &lt;code&gt;travis lint&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;package.json&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;package.json&lt;/code&gt; contains something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webpack-dev-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webpack -p"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postinstall"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"paket restore &amp;amp;&amp;amp; paket generate-load-scripts -f netstandard2.0 -t fsx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"predeploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gh-pages -d docs"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see &lt;code&gt;webpack&lt;/code&gt; is being triggered there as well. That's it - you've now built Fable in Travis CI! Phew, that was easier than we thought.&lt;/p&gt;

</description>
      <category>news</category>
      <category>feature</category>
      <category>infrastructure</category>
      <category>community</category>
    </item>
    <item>
      <title>The Cookbook: Branch Flow</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Tue, 12 Jan 2021 03:29:35 +0000</pubDate>
      <link>https://dev.to/travisci/the-cookbook-branch-flow-1ek6</link>
      <guid>https://dev.to/travisci/the-cookbook-branch-flow-1ek6</guid>
      <description>&lt;p&gt;It's important when using multiple branches in your repository to define which branches to build to, and which branches not to build to. Let's get started.&lt;/p&gt;

&lt;h1&gt;
  
  
  Branch Flow
&lt;/h1&gt;

&lt;p&gt;Travis CI uses the &lt;code&gt;.travis.yml&lt;/code&gt; file from your project structure, once you've configured your flow via the &lt;code&gt;.travis.yml&lt;/code&gt; file, you can trigger a build by pushing changes through the CLI using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add &lt;span class="nb"&gt;.&lt;/span&gt; 
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Travis build branch"&lt;/span&gt; 
git remote add origin remote repository URL
git remote &lt;span class="nt"&gt;-v&lt;/span&gt; 
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can tell Travis to build multiple branches using &lt;code&gt;blacklists&lt;/code&gt; or &lt;code&gt;whitelists&lt;/code&gt;. More specifically you can define which branches to build using a &lt;code&gt;whitelist&lt;/code&gt;, or on the flip side you can use &lt;code&gt;blacklist&lt;/code&gt;. You can blacklist branches that you do not want to be built via the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# blacklist (branches you don't want to be built) &lt;/span&gt;
&lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;except&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;legacy&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;edge&lt;/span&gt;

&lt;span class="c1"&gt;# whitelist&lt;/span&gt;
&lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;stable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you specify both &lt;code&gt;whitelist&lt;/code&gt; and &lt;code&gt;blacklist&lt;/code&gt;, only takes precedence over except. By default, let's say you have a &lt;code&gt;gh-pages&lt;/code&gt; branch, that branch is not built unless you add it to the &lt;code&gt;whitelist&lt;/code&gt; explicitly. When deploying to your version control, or if you're using Apache SVN (Subversion), in some cases, it may reset your working directory, it does this via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a cursory cautionary move, you can add &lt;code&gt;skip_cleanup&lt;/code&gt; to your &lt;code&gt;.travis.yml&lt;/code&gt; file. So after, your &lt;code&gt;yml&lt;/code&gt; file might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;skip_cleanup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there's anything you want to add before you deploy, you can obviously add &lt;code&gt;before_deploy&lt;/code&gt;. This is also true for an inverse method, for after deployment via &lt;code&gt;after_deploy&lt;/code&gt;. &lt;/p&gt;

</description>
      <category>news</category>
      <category>feature</category>
      <category>infrastructure</category>
      <category>community</category>
    </item>
    <item>
      <title>Deploying and Using WebAssembly Under Deno on the Server Side Using Travis CI</title>
      <dc:creator>Montana Mendy</dc:creator>
      <pubDate>Thu, 07 Jan 2021 11:05:23 +0000</pubDate>
      <link>https://dev.to/travisci/deploying-and-using-webassembly-under-deno-on-the-server-side-using-travis-ci-5h6o</link>
      <guid>https://dev.to/travisci/deploying-and-using-webassembly-under-deno-on-the-server-side-using-travis-ci-5h6o</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8cddl3o7qpwnwty52jmo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8cddl3o7qpwnwty52jmo.png" alt="Header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Containers are a game changer in software development. They provide the operational isolation found in virtual machines without the overhead. Whereas it can take a virtual machine minutes to spin up, you can have a container up and running in seconds, or even in some cases milliseconds.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting started
&lt;/h1&gt;

&lt;p&gt;Containers have become central to modern distributed application architecture, particularly now that container orchestration technologies such as Kubernetes and Docker Swarm have become commonplace in the enterprise. However, as popular as container technology is for implementing isolated processes for use in a distributed application, there is an alternative. That alternative is &lt;a href="https://webassembly.org/" rel="noopener noreferrer"&gt;WebAssembly&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;WebAssembly is a compiled binary that operates inside a runtime unit called a WebAssembly VM, or virtual machine. WebAssembly has been around for a while on the client side, and all the major web browsers support it. But you can also run it on the server side. All you need is to have a programming framework that supports server-side WebAssembly VM.&lt;/p&gt;

&lt;p&gt;Deno — an emerging language from Ryan Stahl, the creator of Node.js — supports WebAssembly. Deno uses the V8 JavaScript runtime found in Chrome on the server side, as does Node.js. The WebAssembly VM is built right into V8, so Deno supports WebAssembly.&lt;/p&gt;

&lt;p&gt;In this tutorial, I am going to show how to use Travis CI to build a WebAssembly binary written in Rust, and then run a demonstration application I wrote in Deno that uses the WebAssembly as an internal component.&lt;/p&gt;

&lt;p&gt;This tutorial is high-level, and you don’t need to know the details of Rust or Deno to get benefit from reading it. The hope is that the tutorial will spur your interest to delve further into the technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the demonstration application
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/reselbob/deno-wasm" rel="noopener noreferrer"&gt;demonstration project&lt;/a&gt; that accompanies this article is a Deno application that uses a WebAssembly binary. The Deno code uses logic in the WebAssembly to do a calculation. The calculation that the WebAssembly binary provides is encapsulated into a function named cube(). The function cubes a number that is provided as a parameter. For example, when the number 3 is passed to the function, as cube(3), the function returns 27.&lt;/p&gt;

&lt;p&gt;As shown in figure 1 below, the WebAssembly (WASM) binary is written in the programming language &lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;. Rust is a compiled language. A programmer writes some code in text and stores it in a file named lib.rs. The code is passed to the Rust WASM compiler. The result is a WebAssembly binary that’s used by the Deno code.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Figure 1: Deno uses a WebAssembly binary programmed in Rust.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s the high-level view. Let’s take a look at some of the detail involved in creating the WebAssembly binary in Rust and then consuming the binary in Deno.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examining the WebAssembly code
&lt;/h2&gt;

&lt;p&gt;The work required to create a WebAssembly binary in Rust is consolidated using Rust’s &lt;code&gt;crate&lt;/code&gt; packaging technology.&lt;/p&gt;

&lt;p&gt;The Rust programming community provides a packaging ecosystem similar to &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;npm&lt;/a&gt; for Node.js and to Java’s &lt;a href="https://maven.apache.org/what-is-maven.html" rel="noopener noreferrer"&gt;Maven&lt;/a&gt;. Packages under Rust are called &lt;code&gt;crates&lt;/code&gt;. The standard file that describes a crate is named &lt;a href="https://doc.rust-lang.org/cargo/reference/manifest.html" rel="noopener noreferrer"&gt;&lt;code&gt;Cargo.toml&lt;/code&gt;&lt;/a&gt;. It’s similar to the way Node.js uses &lt;a href="https://docs.npmjs.com/files/package.json" rel="noopener noreferrer"&gt;package.json&lt;/a&gt; to describe a Node.js package. (I’ll explain the &lt;code&gt;Cargo.toml&lt;/code&gt; file for the demonstration Rust binary in a moment.)&lt;/p&gt;

&lt;p&gt;The way you install Rust packages from an external Rust package repository is to use the command &lt;a href="https://doc.rust-lang.org/cargo/commands/cargo-install.html" rel="noopener noreferrer"&gt;cargo install &lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Creating a WebAssembly in Rust can be a detail-laden undertaking. To simplify the process, we’re going to use an external package called wasm-pack. &lt;a href="https://rustwasm.github.io/wasm-pack/book/" rel="noopener noreferrer"&gt;wasm-pack&lt;/a&gt; will execute against the Cargo.toml file that defines the WebAssembly binary we’re going to create. (Keep in mind that the standalone WebAssembly binary is considered a package.)&lt;/p&gt;

&lt;p&gt;Listing 1 below shows the Cargo.toml file that describes the Rust project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"cube_it"&lt;/span&gt;
&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.9.0"&lt;/span&gt;
&lt;span class="n"&gt;edition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2018"&lt;/span&gt;
&lt;span class="n"&gt;authors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Bob Reselman &amp;lt;reselbob@gmail.com&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"A small project to demonstrate how to run to create a WebAssembly binary"&lt;/span&gt;
&lt;span class="n"&gt;license&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"MIT/Apache-2.0"&lt;/span&gt;
&lt;span class="n"&gt;repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://github.com/reselbob/deno-wasm"&lt;/span&gt;

&lt;span class="cs"&gt;# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;wasm&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bindgen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.2"&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"cdylib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"rlib"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Listing 1: The Cargo.toml file&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lines 1 through 12 above provide typical metadata about the project. Notice in line 1 that the arbitrary name of the package is &lt;code&gt;cube_it&lt;/code&gt;. This makes sense because the WebAssembly binary that this package definition creates has a function that will cube a number.&lt;/p&gt;

&lt;p&gt;Lines 13 and 14 indicate that the Rust project will use an additional package, wasm-bindgen. The purpose of wasm-bindgen is to provide interoperability between the Rust binary and JavaScript code. Deno programming is done in TypeScript. However, at runtime TypeScript &lt;a href="https://encyclopedia2.thefreedictionary.com/transpile" rel="noopener noreferrer"&gt;transpiles&lt;/a&gt; into JavaScript. Using &lt;code&gt;wasm-bindgen&lt;/code&gt; allows the Rust code to access JavaScript functions such as logging and the JavaScript DOM model, so &lt;code&gt;wasm-bindgen&lt;/code&gt; is defined in &lt;code&gt;Cargo.toml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lines 16 and 17 assign the library &lt;a href="https://doc.rust-lang.org/nightly/edition-guide/rust-2018/platform-and-target-support/cdylib-crates-for-c-interoperability.html" rel="noopener noreferrer"&gt;cdylib&lt;/a&gt; to crate-type. This provides interoperability with C code. In addition, crate-type is assigned the value &lt;a href="https://doc.rust-lang.org/reference/linkage.html" rel="noopener noreferrer"&gt;rlib&lt;/a&gt; to indicate that a Rust library will be produced.&lt;/p&gt;

&lt;p&gt;Listing 2 below shows the Rust code for the function &lt;code&gt;cube(x: u32)&lt;/code&gt;. The function will reside in the file &lt;code&gt;lib.rs&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Listing 2: The Rust code in &lt;code&gt;lib.rs&lt;/code&gt; that publishes the cube function&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The logic in the function &lt;code&gt;cube(x: u32)&lt;/code&gt; will be consumed by the Deno code.&lt;/p&gt;

&lt;p&gt;Once the Rust package is declared in &lt;code&gt;Cargo.toml&lt;/code&gt; and the &lt;code&gt;cube()&lt;/code&gt; function is defined in &lt;code&gt;lib.rs&lt;/code&gt;, we’ll need to create the Deno code to consume the WebAssembly binary that’s created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running WebAssembly under Deno
&lt;/h2&gt;

&lt;p&gt;Listing 3 below shows the contents of the file &lt;a href="https://github.com/reselbob/deno-wasm/blob/master/main.ts" rel="noopener noreferrer"&gt;&lt;code&gt;main.ts&lt;/code&gt;&lt;/a&gt;. This file contains the Deno code that consumes the WebAssembly binary that contains the function &lt;code&gt;cube()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;wasmCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;     &lt;span class="n"&gt;Deno&lt;/span&gt;&lt;span class="nf"&gt;.readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./rust_for_deno/target/wasm32-unknown-unknown/release/cube_it.wasm"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;wasmModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;WebAssembly&lt;/span&gt;&lt;span class="nf"&gt;.Module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wasmCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;wasmInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;WebAssembly&lt;/span&gt;&lt;span class="nf"&gt;.Instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wasmModule&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wasmInstance&lt;/span&gt;&lt;span class="py"&gt;.exports&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="nf"&gt;.log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="nf"&gt;.log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="nf"&gt;.log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="nf"&gt;.log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Listing 3: The Deno code that consumes the WebAssembly binary&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lines 1 through 5 do the work of loading the WebAssembly into the V8 virtual machine and making the &lt;code&gt;cube()&lt;/code&gt; function accessible to the Deno code. Lines 7 through 10 execute the &lt;code&gt;cube()&lt;/code&gt; function four times, each time with a different parameter value, and then write the output of each call to the console.&lt;/p&gt;

&lt;p&gt;Now that we have both the Rust WebAssembly and Deno projects coded and ready to go, we need to create a &lt;code&gt;travis.yml&lt;/code&gt; file that will build the WebAssembly binary, as well as install the Deno runtime environment and run the Deno code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with the &lt;code&gt;.travis.yml&lt;/code&gt; file
&lt;/h2&gt;

&lt;p&gt;One of the nice features of Travis CI is that it will execute a run script in response to an event generated from a webhook installed in a GitHub repository that is bound to Travis CI. Under Travis CI, the run script has a standard name, &lt;code&gt;.travis.yml.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/reselbob/deno-wasm" rel="noopener noreferrer"&gt;deno-wasm&lt;/a&gt; demonstration project for this article stored on GitHub has a webhook installed that sends an event notification to Travis CI whenever code is committed to the &lt;code&gt;deno-wasm&lt;/code&gt; repository. Travis CI receives the event notification and clones the code into a runtime virtual machine created just for the project. Then, it runs the instructions in the expected &lt;code&gt;.travis.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Listing 4 below shows the contents of the &lt;code&gt;.travis.yml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rust&lt;/span&gt;
&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pwd&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rustc --version&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo apt-get update&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo apt-get -y install libssl-dev pkg-config&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rustup target add wasm32-unknown-unknown&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo install wasm-pack&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export PATH="$HOME/.cargo/bin:$PATH"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cd ./rust_for_deno&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;wasm-pack build&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cd ..&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl -fsSL https://deno.land/x/install/install.sh | sh&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ls -l $HOME/.deno&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export DENO_INSTALL="$HOME/.deno"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export PATH="$DENO_INSTALL/bin:$PATH"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deno run https://deno.land/std/examples/welcome.ts&lt;/span&gt;

&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deno run --allow-read main.ts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Listing 4: The travis.yml file for building and running the deployment on Travis CI&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first thing to notice about the &lt;code&gt;.travis.yml&lt;/code&gt; file in listing 4 above is that Travis CI supports the Rust programming language right out of the box. All you need to do is set the &lt;code&gt;language&lt;/code&gt; definition, as shown at line 1.&lt;/p&gt;

&lt;p&gt;The work of creating the WebAssembly binary and installing Deno is done in the &lt;code&gt;before_install&lt;/code&gt; section, starting at line 5.&lt;/p&gt;

&lt;p&gt;Lines 7 and 8 are convenience instructions that report the present working directory &lt;code&gt;(pwd)&lt;/code&gt; and the current version of the Rust compiler installed &lt;code&gt;(rustc --version)&lt;/code&gt;. This is done just to make sure that the &lt;code&gt;.travis.yml&lt;/code&gt; script is talking to the Travis CI runtime in a predictable manner.&lt;/p&gt;

&lt;p&gt;Lines 9 and 10 install some added packages that Ubuntu needs in order to execute the &lt;code&gt;wasm-pack&lt;/code&gt; instruction that will come.&lt;/p&gt;

&lt;p&gt;Lines 11 through 15 do the work of installing the &lt;code&gt;wasm-pack&lt;/code&gt; Rust package and creating the WebAssembly binary using &lt;code&gt;wasm-pack&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Deno is not installed in the Travis CI runtime environment by default. Thus, lines 17 through 20 do the work of installing it and configuring the &lt;code&gt;DENO_INSTALL&lt;/code&gt; environment variable. Also, the &lt;code&gt;PATH&lt;/code&gt; environment variable is updated to accommodate the Deno binaries.&lt;/p&gt;

&lt;p&gt;Line 21 runs a Deno &lt;code&gt;Hello World&lt;/code&gt; program downloaded from the internet, to verify that Deno is up and running.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, the code that uses the &lt;code&gt;cube()&lt;/code&gt; function in the WebAssembly binary is stored in the file &lt;code&gt;main.ts&lt;/code&gt;. &lt;code&gt;main.ts&lt;/code&gt; is called within the script section of the &lt;code&gt;.travis.yml&lt;/code&gt; file at line 24 above.&lt;/p&gt;

&lt;p&gt;The output of the call to the &lt;code&gt;main.ts&lt;/code&gt; file is shown below in figure 2.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Figure 2: The output from the demonstration application running under Travis CI&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So there you have it. We’ve just used the Travis CI runtime environment to create a WebAssembly binary and run it in a Deno program. Granted, this is just a small demonstration program, but it does reveal the critical aspects of using WebAssembly to provide services to interested consumers in an isolated manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;It’s interesting that Solomon Hykes, the co-founder of Docker, &lt;a href="https://conferences.codegram.com/talks/bringing-webassembly-outside-the-web-with-wasi-fsf2019" rel="noopener noreferrer"&gt;said this&lt;/a&gt; about WebAssembly:&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;“If WASM+WASI [WebAssembly and its system interface] existed in 2008, we wouldn’t have needed to create Docker.&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;Server-side WebAssembly has significant potential. Its elegance and power make it an attractive technology for the fast execution of complex algorithms on the server side. Consequently, there are a growing number of projects that are publishing tools for WebAssembly development. You can already create WASM binaries in Go, Rust, C# and C/C++. In addition, there are initiatives to bring support for WebAssembly to a wider array of languages. For example, &lt;a href="https://www.assemblyscript.org/" rel="noopener noreferrer"&gt;AssemblyScript&lt;/a&gt; is intended to allow developers to create WebAssembly binaries from JavaScript code.&lt;/p&gt;

&lt;p&gt;The opportunities at hand are significant. Of course, in order to make WebAssembly a viable addition to your programming toolbox, you will need to take the time to master the details of the technology. But, as current trends reveal, WebAssembly is becoming a mainstay on the server side, and realizing its value will be an investment that will yield dramatic returns.&lt;/p&gt;

&lt;p&gt;WebAssembly is here. The time to take advantage of the opportunities at hand is now.&lt;/p&gt;

</description>
      <category>news</category>
      <category>feature</category>
      <category>infrastructure</category>
      <category>community</category>
    </item>
  </channel>
</rss>
