<?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>Forem: Hara Kang</title>
    <description>The latest articles on Forem by Hara Kang (@coderspinoza).</description>
    <link>https://forem.com/coderspinoza</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%2F323304%2F9df72455-0631-45dd-8a53-93888dfef377.jpeg</url>
      <title>Forem: Hara Kang</title>
      <link>https://forem.com/coderspinoza</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/coderspinoza"/>
    <language>en</language>
    <item>
      <title>Github Actions &amp; Workflows for CI/CD</title>
      <dc:creator>Hara Kang</dc:creator>
      <pubDate>Mon, 25 May 2020 16:05:42 +0000</pubDate>
      <link>https://forem.com/coderspinoza/github-actions-workflows-for-ci-cd-32lj</link>
      <guid>https://forem.com/coderspinoza/github-actions-workflows-for-ci-cd-32lj</guid>
      <description>&lt;p&gt;It's been already three months since I have joined &lt;em&gt;DataHunt&lt;/em&gt;, but to be honest, I haven't been able to work on automating our development workflows due to lack of time. Endless march of demos and actual product delivery in a very short time span left us with untested code and no reliable CI/CD pipeline during code push and deploy.&lt;/p&gt;

&lt;p&gt;Therefore, I decided to spend some time this week rebuilding our test suites and structuring CI/CD so that we could deliver our software in a more stable way from now on. My goal was to integrate &lt;em&gt;integrations tests&lt;/em&gt; to Github CI and deploy to Heroku only when the test suite succeeds.&lt;/p&gt;

&lt;p&gt;There were several options that came to my mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Jenkins CI&lt;/li&gt;
&lt;li&gt;Travis CI&lt;/li&gt;
&lt;li&gt;Heroku CI&lt;/li&gt;
&lt;li&gt;Github Actions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of all these solutions, I am leaning toward &lt;code&gt;Github Actions&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jenkins &amp;amp; Travis CI
&lt;/h3&gt;

&lt;p&gt;I had some experiences with &lt;em&gt;Jenkins CI&lt;/em&gt; at my previous company since our team used it for most of our CI/CD flow. Jenkins is easy to install, use, and quite flexible due to its configurable nature. If your team uses a lot of tech stacks, including mobile, web, backend with various languages, then I think probably this is the best option. However, its ease of use just stretches as far as to a very basic task. If you don't mind using locally installed databases or softwares, then &lt;em&gt;Jenkins&lt;/em&gt; will probably provide you with the fasted setup and build speed, since what you have to do is just installing softwares on a machine and running scripts (probably little bit of permission settings). But if you want to use containers for your build environment for providing a consistent and isolated build environments, then things become a little more complicated in Jenkins (at least this is true for my personal experience). You have to manually install docker plugins and set up a containerized build system, which felt like pain in the ass when I tried to set up one for Kakao Android SDK project.&lt;/p&gt;

&lt;p&gt;On the other hand, Travis CI, Heroku CI, and Github CI all offer solutions based on containers that provide isolated build environments. It is true that build speed might slow down because containers must provision necessary services in pre-test stage, but there is a larger benefit in switching because you don't have to upgrade local databases or other environments yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Travis CI
&lt;/h3&gt;

&lt;p&gt;Travis CI is quite good when you host an open source project on Github, since you get the service for free. However, our project was private and the pricing seemed a little expensive at our stage. I am currently using it for &lt;a href="https://github.com/kakao/kakao_flutter_sdk"&gt;kakao_flutter_sdk&lt;/a&gt; open source project that I am maintaining for Kakao organization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Heroku CI
&lt;/h3&gt;

&lt;p&gt;Heroku CI also seemed a good option since we were on the PaaS and clicked well with the Heroku pipeline feature (dev, staging, and production env setup, deploy, etc...) we were using.&lt;/p&gt;

&lt;p&gt;Below screenshot shows automated tests running on pushing to specific branches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7aAZmpPa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www0.assets.heroku.com/assets/continuous-delivery/feature-ci-c84039d23ea6c0724dff85d3bd64868b55eb9678a2dec2c5fb55ad31e802db5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7aAZmpPa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www0.assets.heroku.com/assets/continuous-delivery/feature-ci-c84039d23ea6c0724dff85d3bd64868b55eb9678a2dec2c5fb55ad31e802db5b.png" alt="pipeline-tests"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k1SUy04s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devcenter0.assets.heroku.com/article-images/1495098686-DC-Settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k1SUy04s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devcenter0.assets.heroku.com/article-images/1495098686-DC-Settings.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, there were several downsides.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Builds seemed slower than other alternatives.&lt;/li&gt;
&lt;li&gt;Databases could be provisioned in-dyno but there is no guarantee that every add-on that we use will be available. It would be impossible to run whole integration tests if just one add-on isn't available in Heroku CI env.&lt;/li&gt;
&lt;li&gt;CI/CD will be stuck with infra. If we migrate to AWS in the future, redundant work must be done to setup CI/CD again with other alternative.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Therefore, I decided to try the last option, GitHub Actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Github Actions &amp;amp; Workflows
&lt;/h3&gt;

&lt;p&gt;I have tried Github Actions after just testing with Heroku CI. Just putting a yaml file that specifies your build at &lt;em&gt;.github/workflows/&lt;/em&gt; directory and you are all set. Below are requirements for my automated testing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Should be run on every push/pr to master&lt;/li&gt;
&lt;li&gt;Should connect to Postgres and redis for integration tests&lt;/li&gt;
&lt;li&gt;Tests should be run after dependencies are installed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One specific setting would be like below:&lt;br&gt;
&lt;em&gt;.github/workflows/test.yml&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Integration Tests CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;master&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;master&lt;/span&gt; &lt;span class="pi"&gt;]&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;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&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;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
          &lt;span class="s"&gt;--health-cmd pg_isready&lt;/span&gt;
          &lt;span class="s"&gt;--health-interval 10s&lt;/span&gt;
          &lt;span class="s"&gt;--health-timeout 5s&lt;/span&gt;
          &lt;span class="s"&gt;--health-retries 5&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5432:5432&lt;/span&gt;
      &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;6379:6379&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--entrypoint redis-server&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&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;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;12.x&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Downloads a copy of the code in your repository before running CI tests&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check out repository code&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="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;Use Node.js ${{ matrix.node-version }}&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
    &lt;span class="c1"&gt;# Performs a clean installation of all dependencies in the `package.json` file&lt;/span&gt;
    &lt;span class="c1"&gt;# For more information, see https://docs.npmjs.com/cli/ci.html&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;Install dependencies&lt;/span&gt; 
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&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;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres://postgres:postgres@localhost:5432/postgres&lt;/span&gt;
        &lt;span class="na"&gt;REDIS_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis://localhost:6379&lt;/span&gt;
        &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;

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



&lt;p&gt;Of course, this is my first basic experience with &lt;code&gt;Github Actions&lt;/code&gt; but I will delve more into Github based solutions because this is the only platform that I am pretty sure that will not be replaced by other platforms among stuff that our team is using (with least alternative, I suppose). Familiarizing myself with GitHub Actions could definitely benefit me in other projects!&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/creating-postgresql-service-containers#testing-the-postgresql-service-container"&gt;https://help.github.com/en/actions/configuring-and-managing-workflows/creating-postgresql-service-containers#testing-the-postgresql-service-container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devcenter.heroku.com/articles/heroku-ci"&gt;https://devcenter.heroku.com/articles/heroku-ci&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>github</category>
      <category>heroku</category>
      <category>testing</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
