<?xml version= "1.0" encoding= "utf-8" standalone= "yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Devops on Spinning Code</title>
    <link>https://spinningcode.org/tags/devops/</link>
    <description>Recent content in Devops on Spinning Code</description> <generator>Hugo -- 0.157.0</generator>
    <language>en-US</language> <lastBuildDate>Fri, 05 Jan 2024 23:07:12 +0000</lastBuildDate> <atom:link href= "https://spinningcode.org/tags/devops/feed.xml" rel= "self" type= "application/rss+xml" /> <item>
      <title>Salesforce Github Actions</title>
      <link>https://spinningcode.org/2024/01/salesforce-github-actions/</link>
      <pubDate>
        Fri, 05 Jan 2024 23:07:12 +0000
      </pubDate> <guid
        isPermaLink="false">https://spinningcode.org/?p=2120</guid>  <description>&lt;p&gt;&lt;em&gt;I started this post back in November, but got &lt;a href=&#34;https://spinningcode.org/2023/12/goodbye-mom/&#34;&gt;rather distracted last month&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I have been wanting to setup a CI pipeline for Salesforce scratch orgs for a long time. The documentation out there isn&amp;rsquo;t great, and it&amp;rsquo;s taken me awhile to get around to powering through the details. For testing that &lt;a href=&#34;https://spinningcode.org/2023/11/salesforce-nonprofit-and-education-scratch-orgs/&#34;&gt;my scratch org configurations for Education Cloud and Nonprofit Cloud&lt;/a&gt; to work properly I finally bit the bullet and setup a Github action.&lt;/p&gt;</description> <content:encoded><![CDATA[<p><em>I started this post back in November, but got <a href="/2023/12/goodbye-mom/">rather distracted last month</a>.</em></p>
<p>I have been wanting to setup a CI pipeline for Salesforce scratch orgs for a long time. The documentation out there isn&rsquo;t great, and it&rsquo;s taken me awhile to get around to powering through the details. For testing that <a href="/2023/11/salesforce-nonprofit-and-education-scratch-orgs/">my scratch org configurations for Education Cloud and Nonprofit Cloud</a> to work properly I finally bit the bullet and setup a Github action.</p>
<h2 id="what-youll-need">What you&rsquo;ll need</h2>
<ol>
<li>An SFDX-style project on Github that you want to setup for automated testing that includes a <a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs.htm">Salesforce scratch org</a>.</li>
<li>An org with Devhub enabled. I recommend using a production org for this, not a developer org because of the <a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_editions_and_allocations.htm">higher scratch org limits.</a> There are <a href="https://www.linkedin.com/posts/jasonlantz_enable-dev-hub-features-in-your-org-activity-7118686134511030272-JOOa?utm_source=share&amp;utm_medium=member_desktop">no good reasons not to enable Devhub</a>.</li>
<li>A working install of <a href="https://developer.salesforce.com/tools/salesforcecli">sf cli</a> with a connection to that devhub-enabled org.</li>
</ol>
<h2 id="setup-github-secret">Setup Github Secret</h2>
<p>For your action to work it will need to use your connection to your Salesforce Devhub. Salesforce CLI stores the needed key on your local machine, which includes tokens to open the org. You will need to put those keys into a <a href="https://docs.github.com/en/rest/actions/secrets">Github secret</a> for proper security.</p>
<p><em>Note: Should that key ever be compromised, they attacker will be able to open the org as the same user. I suggest you consider using a dedicated user with either a <a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/dev_hub_license.htm">Free Limited Access License</a>, or another similarly restrictive set of permissions. These users are designed to avoid exposing data if they are compromised (they are also free, which has some upsides). That said, you can get yourself started with any user that can access to Devhub objects and then switch out to something more restricted later.</em></p>
<p>To get the key from sf cli, run <code>sf org display -o [your devhub alias] --verbose</code> where <code>[your devhub alias]</code> is the name of the connection you selected when setting up the connection. The output of that command will include: &ldquo;Sfdx Auth Url&rdquo;, that is the value you need in your Github secret.</p>
<ol>
<li>In Github, go to your repository&rsquo;s settings, expand Secrets and Variables from the left menu, and select Actions.</li>
<li>Create a new Repository secret.</li>
<li>Name the secret <code>DEVHUB_SFDX_URL</code></li>
<li>Copy and Paste the Sfdx Auth Url value into the Secret field.</li>
</ol>
<h2 id="create-the-github-action">Create the Github Action</h2>
<p>The full details of <a href="https://docs.github.com/en/actions/using-workflows">Github Actions</a> are a deep topic, as are the full capabilities of sf cli for testing. So I&rsquo;m going to focus on setup of an action the creates your scratch org. From there you can expand your workflow as you need.</p>
<p>In your project root create a <code>.github</code> folder, and <code>workflows</code> folder within if you don&rsquo;t already have them. In the workflows folder create a file called <code>buildScratch.yml</code>.</p>
<p>Copy the following code (explained below) into your file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-yml" data-lang="yml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">test run scratch</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Definition when the workflow should run</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># The workflow will run whenever an event happens on a pull request</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">pull_request</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">types</span>: [<span style="color:#ae81ff">opened, synchronize]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">validate_scratch_deploy</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">steps</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Install Salesforce CLI</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Install Salesforce CLI&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">run</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">          npm install @salesforce/cli --location=global
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">          nodeInstallPath=$(npm config get prefix)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">          echo &#34;$nodeInstallPath/bin&#34; &gt;&gt; $GITHUB_PATH
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">          sf --version</span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Checkout the code in the pull request</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Checkout source code&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Load secret for dev hub</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Populate auth file with SFDX_URL secret&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">shell</span>: <span style="color:#ae81ff">bash</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">run</span>: <span style="color:#e6db74">&#34;echo ${{ secrets.DEVHUB_SFDX_URL}} &gt; ./SFDX_URL_STORE.txt&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Authenticate with dev hub&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">run</span>: <span style="color:#ae81ff">sf org login sfdx-url -f ./SFDX_URL_STORE.txt -a devhub -d</span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Create a scratch org</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Create scratch org&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">run</span>: <span style="color:#e6db74">&#34;sf org create scratch -d -f config/project-scratch.json -a our-scratch-org --duration-days 1&#34;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Deploy Project Manifest</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Deploy Metadata&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">run</span>: <span style="color:#e6db74">&#34;sf project deploy start --manifest manifest.xml --target-org our-scratch-org&#34;</span>
</span></span></code></pre></div><h3 id="action-breakdown">Action Breakdown</h3>
<p>The first few lines are common to all actions, it gets a name, then a set of conditions to trigger the workflow. In this case we&rsquo;re calling our workflow &ldquo;test run scratch&rdquo; and it will run when a Pull Request is opened or gets new commits.</p>
<p>The jobs section is the more interesting bit. We tell Github to create a virtual machine using the most recent version of Ubuntu Linux. Next we install Salesforce CLI onto that virtual machine. Once that&rsquo;s done, we tell it to checkout our code from Github onto this virtual machine. With all our tools in place we&rsquo;re ready to start the real work.</p>
<p>The next two steps extract the Github secret we defined earlier into a file on the virtual machine and use that file to authenticate to your Salesforce devhub. All that work gets this temporary virtual machine into the same position as your personal device probably was when we started.</p>
<p>The last two steps create the scratch org based on a hypothetical scratch org configuration file and gives the scratch org a short life of one day. Finally deploy your project&rsquo;s manifest-tracked metadata. This last step could use any version of the <a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_project_commands_unified.htm#cli_reference_project_deploy_start_unified">deploy command</a>. It could also be added by more steps to deploy other metadata, run tests, or anything else you want to have happen.</p>
<h2 id="closing-thoughts">Closing Thoughts</h2>
<p>Building from this point you can do all kinds of things. For example, if you don&rsquo;t need to gain access to the org itself, you can include a step to delete the scratch org when you&rsquo;re done to help avoid the active scratch limit.</p>
<p>You&rsquo;ll want to pay attention to the limits of your org to see if you need to tweak the triggers of your workflow. If you aren&rsquo;t using a production org you scratch limit is only 6 per day, and three at a time; I blew through that testing the steps in this article. Even larger orgs only have 200 per day. So be thoughtful about when your action runs, and how often you clean up.</p>
<p>As always, if you find a flaw in my solution please let me know. I&rsquo;m always interested in making these better.</p>
]]></content:encoded> </item> </channel>
</rss>
