<?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: Zan Markan</title>
    <description>The latest articles on DEV Community by Zan Markan (@zmarkan).</description>
    <link>https://dev.to/zmarkan</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%2F47268%2F144c7444-820a-40f4-8c28-98a0a29537e3.jpg</url>
      <title>DEV Community: Zan Markan</title>
      <link>https://dev.to/zmarkan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zmarkan"/>
    <language>en</language>
    <item>
      <title>Setting up continuous integration with CircleCI and GitLab</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Wed, 07 Jun 2023 23:12:45 +0000</pubDate>
      <link>https://dev.to/circleci/setting-up-continuous-integration-with-circleci-and-gitlab-1mdp</link>
      <guid>https://dev.to/circleci/setting-up-continuous-integration-with-circleci-and-gitlab-1mdp</guid>
      <description>&lt;p&gt;CircleCI supports &lt;a href="https://circleci.com/blog/announcing-gitlab-support/"&gt;GitLab&lt;/a&gt; as a version control system (VCS). In this tutorial you will learn how to set up your first CircleCI CI/CD pipeline for a project hosted on GitLab. As GitLab can be used either as a SaaS tool, as well as self-managed on-premise installation, I will cover the steps to connect it with CircleCI for both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites and application basics
&lt;/h2&gt;

&lt;p&gt;To follow along with this tutorial, you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge of Git commands&lt;/li&gt;
&lt;li&gt;Git installed and accessible on your machine&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://gitlab.com/users/sign_up"&gt;GitLab account&lt;/a&gt; — either self-managed or SaaS&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://circleci.com/signup/"&gt;CircleCI account&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Starter app
&lt;/h3&gt;

&lt;p&gt;Our starter application is a minimal Python Flask app with a single ‘hello world’ web page, which specifies required dependencies and includes a test. You can access a &lt;a href="https://gitlab.com/cci-devrel-demos/python-app-base"&gt;publicly hosted version of the starter app&lt;/a&gt; on GitLab.com.&lt;/p&gt;

&lt;p&gt;You can get the application by downloading it straight from the GitLab web interface or cloning it via Git.&lt;/p&gt;

&lt;p&gt;For the purposes of this tutorial, you don’t need to write the application from scratch, but if you are interested in complete development instruction, you can read through the beginning of [this blog post](&lt;a href="https://circleci.com/blog/setting-up-continuous-integration-with-github/"&gt;https://circleci.com/blog/setting-up-continuous-integration-with-github/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitLab SaaS vs self-managed
&lt;/h2&gt;

&lt;p&gt;As mentioned above, this tutorial will teach you how to configure and run your CircleCI pipeline for a project hosted either on a self-managed or hosted version of GitLab. You can learn more about the differences between the hosted and self-managed versions in the &lt;a href="https://docs.gitlab.com/ee/install/migrate/compare_sm_to_saas.html"&gt;GitLab docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Setting up GitLab SaaS requires you only to sign up at gitlab.com. You will also need to make sure you can push to GitLab repositories, either by setting up your &lt;a href="https://docs.gitlab.com/ee/user/ssh.html"&gt;SSH key&lt;/a&gt; or &lt;a href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#personal-access-tokens"&gt;personal access token&lt;/a&gt; for using GitLab with either SSH or HTTPS, respectively.&lt;/p&gt;

&lt;p&gt;If you use GitLab self-managed, you will connect to it via your installation URL. This is specific to you, so for the purposes of this tutorial, use the URL &lt;code&gt;yourgitlabinstance.com&lt;/code&gt; as a placeholder.&lt;/p&gt;

&lt;p&gt;Create a new project with the starter app source code. You can use the new project wizard, either at &lt;code&gt;gitlab.com/projects/new&lt;/code&gt; or &lt;code&gt;yourgitlabinstance.com/projects/new&lt;/code&gt;, for SaaS or self-managed respectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a CircleCI config file
&lt;/h2&gt;

&lt;p&gt;Before you set up CircleCI, you can tell it what to eventually start building.&lt;/p&gt;

&lt;p&gt;Create a new directory &lt;code&gt;.circleci&lt;/code&gt; in the top level of the project.&lt;/p&gt;

&lt;p&gt;Now, create a new file &lt;code&gt;config.yml&lt;/code&gt; in that directory (&lt;code&gt;.circleci/config.yml&lt;/code&gt;) — this is your main configuration file for CircleCI.&lt;/p&gt;

&lt;p&gt;Paste the following in the 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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&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;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&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;cimg/python:3.10.11&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deps1-{{ .Branch }}-{{ checksum "requirements.txt" }}&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="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;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;python3 -m venv venv&lt;/span&gt;
            &lt;span class="s"&gt;. venv/bin/activate&lt;/span&gt;
            &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;save_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deps1-{{ .Branch }}-{{ checksum "requirements.txt" }}&lt;/span&gt;
          &lt;span class="na"&gt;paths&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;venv"&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Running tests&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;. venv/bin/activate&lt;/span&gt;
            &lt;span class="s"&gt;python3 tests.py&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-reports/&lt;/span&gt;
          &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python_app&lt;/span&gt;

&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;run-tests&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="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;In the CircleCI config file, you define everything you need CircleCI to do. In this case, you have added a single job (&lt;code&gt;test&lt;/code&gt;) and a workflow (&lt;code&gt;run-tests&lt;/code&gt;) containing that job.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;test&lt;/code&gt; job runs in a &lt;a href="https://circleci.com/blog/docker-image-vs-container/"&gt;Docker container&lt;/a&gt; with Python installed, checks out the code at that specific commit, downloads the dependencies required for the app (Flask, in this case), sets up a Python venv, and runs the tests in &lt;code&gt;tests.py&lt;/code&gt;. It also caches the dependencies to make subsequent pipeline runs faster and stores the test artifacts for easy access from CircleCI. To read more about CircleCI configuration, consult the &lt;a href="https://circleci.com/docs/configuration-reference/"&gt;configuration reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Save, make a new commit, and push to your GitLab repository. Now it’s time to configure your CircleCI integration with GitLab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring CircleCI with GitLab SaaS (GitLab.com)
&lt;/h2&gt;

&lt;p&gt;If you don’t have a CircleCI account yet, create one now. Head to &lt;a href="https://circleci.com/signup/"&gt;https://circleci.com/signup/&lt;/a&gt; and follow the instructions to sign up using your preferred method. If you choose GitLab, you will also be prompted to select your GitLab instance. Press &lt;strong&gt;Connect&lt;/strong&gt; next to GitLab.com.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aUUQejhe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/34Js8TAdWkl0nANRkvODxw/cdef5ce2194a0331bed75a31ed986889/2023-05-08-ci-gitlab-18.48.16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aUUQejhe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/34Js8TAdWkl0nANRkvODxw/cdef5ce2194a0331bed75a31ed986889/2023-05-08-ci-gitlab-18.48.16.png" alt="Connect to your code" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This should now prompt you to authorize CircleCI with your GitLab account, giving CircleCI access to your repositories.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eH5w1lRZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/2VSZ1kg5MI1I1R9S9tYpVJ/3683095bd43b7f67dcbd4822452c8b4d/2023-05-08-ci-gitlab-19.09.38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eH5w1lRZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/2VSZ1kg5MI1I1R9S9tYpVJ/3683095bd43b7f67dcbd4822452c8b4d/2023-05-08-ci-gitlab-19.09.38.png" alt="Authorize CircleCI" width="601" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Authorizing CircleCI will take you to the project creation wizard. You should see your repository on the list, and it should detect the CircleCI config you committed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PWHYDJf7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/55pwGMRJZ5arUonK1Ru7fG/914d779cd5a35492652aac7c8e57b806/2023-05-08-ci-gitlab-19.16.46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PWHYDJf7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/55pwGMRJZ5arUonK1Ru7fG/914d779cd5a35492652aac7c8e57b806/2023-05-08-ci-gitlab-19.16.46.png" alt="Create new project" width="718" height="713"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Create Project&lt;/strong&gt; to start building. This has created the project in CircleCI, and what’s left is to commit and push a change to trigger your first CircleCI pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hpm4hIBj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/4pjBH6grcr53Qs9Z3RpsvH/e2c5618dce322633f4739831674859fe/2023-05-09-ci-gitlab-01.27.40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hpm4hIBj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/4pjBH6grcr53Qs9Z3RpsvH/e2c5618dce322633f4739831674859fe/2023-05-09-ci-gitlab-01.27.40.png" alt="Make a change" width="800" height="673"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make any change, such as an update to your README file, then commit and push. This will create your first pipeline and start building and running your test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f2EPxIAF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/7FKLZa07roF52X4xpiLd3t/225b6190675a9adf76e6ceac52e647ea/2023-05-09-ci-gitlab-01.29.14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f2EPxIAF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/7FKLZa07roF52X4xpiLd3t/225b6190675a9adf76e6ceac52e647ea/2023-05-09-ci-gitlab-01.29.14.png" alt="Build status" width="800" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seconds later it should be marked as successful. The status of your CircleCI pipeline will be automatically updated in your GitLab UI as well. Navigate to Build/Pipelines (on the left-hand side in GitLab) and the pipeline should show up there as well. You can see an example based on this tutorial in this &lt;a href="https://gitlab.com/cci-devrel-demos/cci-python-app/-/pipelines"&gt;public project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--co-axm1d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/5hodZ8zxiaNFW7TM7pNLTa/403fe6d9b33bcd1c25840c1f42534f59/2023-05-09-ci-gitlab-01.32.03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--co-axm1d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/5hodZ8zxiaNFW7TM7pNLTa/403fe6d9b33bcd1c25840c1f42534f59/2023-05-09-ci-gitlab-01.32.03.png" alt="Build/Pipelines" width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking it will show you further details of the pipeline. Clicking the button under external - button &lt;strong&gt;CircleCI: Workflow run tests&lt;/strong&gt; will take you back full circle into your workflow inside CircleCI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c9RZSdbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/WGuoPZr3wfwmwPLDhcL7o/bf8ae751b53e7a6e9728d6b385243e77/2023-05-09-ci-gitlab-01.32.41.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c9RZSdbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/WGuoPZr3wfwmwPLDhcL7o/bf8ae751b53e7a6e9728d6b385243e77/2023-05-09-ci-gitlab-01.32.41.png" alt="Pipeline details" width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting CircleCI to a self-managed GitLab instance
&lt;/h2&gt;

&lt;p&gt;Self-managed installations, unlike the hosted SaaS versions, run on infrastructure you control. They will of course also have a different URL to access them. In this tutorial, use &lt;code&gt;yourgitlabinstance.com&lt;/code&gt; as a placeholder for your actual instance URL. This section closely follows the &lt;a href="https://circleci.com/docs/gitlab-integration"&gt;GitLab integration instructions in the CircleCI docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Assuming you have followed the steps to get the project into GitLab and committed your first CircleCI config file, you can proceed with connecting to GitLab.&lt;/p&gt;

&lt;p&gt;If you don’t have a CircleCI account yet, create one now. Head to &lt;a href="https://circleci.com/signup/"&gt;https://circleci.com/signup/&lt;/a&gt; and follow the instructions to sign up with your preferred method.&lt;/p&gt;

&lt;p&gt;If you choose to sign up with GitLab, you will be prompted to select your GitLab instance. Press &lt;strong&gt;Connect&lt;/strong&gt; next to GitLab self-managed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aUUQejhe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/34Js8TAdWkl0nANRkvODxw/cdef5ce2194a0331bed75a31ed986889/2023-05-08-ci-gitlab-18.48.16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aUUQejhe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/34Js8TAdWkl0nANRkvODxw/cdef5ce2194a0331bed75a31ed986889/2023-05-08-ci-gitlab-18.48.16.png" alt="Connect self-managed" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  GitLab self-managed project setup
&lt;/h3&gt;

&lt;p&gt;The wizard guides you through the setup process step by step.&lt;/p&gt;

&lt;p&gt;First enter the URL of your GitLab instance and click &lt;strong&gt;Verify&lt;/strong&gt;. It will suffix it with &lt;code&gt;/api/v4&lt;/code&gt; to complete your instance’s API endpoint.&lt;/p&gt;

&lt;p&gt;Create your &lt;a href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html"&gt;personal GitLab access token&lt;/a&gt; with an API scope, paste it in the Personal Access Token field and click &lt;strong&gt;Verify&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next, pass in the &lt;code&gt;known_hosts&lt;/code&gt; value and click &lt;strong&gt;Verify&lt;/strong&gt;. You can get this by running &lt;code&gt;ssh-keyscan yourgitlabinstance.com&lt;/code&gt; in the terminal and pasting the entire output in the &lt;code&gt;known_hosts field&lt;/code&gt;. This allows CircleCI to &lt;a href="https://circleci.com/docs/gitlab-integration/#establish-the-authenticity-of-an-ssh-host"&gt;verify the authenticity&lt;/a&gt; of your GitLab instance.&lt;/p&gt;

&lt;p&gt;Finally, select your project in the dropdown. This will likely be &lt;code&gt;cci-python-app&lt;/code&gt;. You can also give it a different name. This will set your GitLab self-managed project up for building on CircleCI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yF8X0WyE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/3uHYOJan5yJSACrQlvHYCH/29d1adf431472cfa84bc2d9cf6a6a7be/2023-05-08-ci-gitlab-20.11.21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yF8X0WyE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/3uHYOJan5yJSACrQlvHYCH/29d1adf431472cfa84bc2d9cf6a6a7be/2023-05-08-ci-gitlab-20.11.21.png" alt="New self-managed project" width="773" height="1084"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Trigger a pipeline by committing a change and pushing it to your GitLab repo. This will start your workflow and show it in the next few seconds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wmuGpcxn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/vKnYtN1PPmy4QUmF5XH3m/b07d56d8985838bd4e56941c8e1c9402/2023-05-09-ci-gitlab-01.37.59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wmuGpcxn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/vKnYtN1PPmy4QUmF5XH3m/b07d56d8985838bd4e56941c8e1c9402/2023-05-09-ci-gitlab-01.37.59.png" alt="Project workflows" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also see your pipeline in the GitLab UI by navigating to CI/CD &amp;gt; Pipelines on the left-hand side. Note that this might look different, depending on what version of GitLab you are using.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GaQ7fczI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/3yPlK18ZvGO75M2hc8dUsC/381d03ef962ea74f903ae24ad6512845/2023-05-09-ci-gitlab-01.33.49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GaQ7fczI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/3yPlK18ZvGO75M2hc8dUsC/381d03ef962ea74f903ae24ad6512845/2023-05-09-ci-gitlab-01.33.49.png" alt="GitLab pipelines view" width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on its status it will take you to the pipeline details, from where you can navigate back to the CircleCI UI to give you a 360 degree view of your project and your CI/CD pipeline’s workflows and jobs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Jhb7py_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/68JW7CkbSe8OZsdCnYjI19/a9bff076e54e4f84dff3054f38295f0e/2023-05-09-ci-gitlab-01.34.42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Jhb7py_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ctf-cci-com.imgix.net/68JW7CkbSe8OZsdCnYjI19/a9bff076e54e4f84dff3054f38295f0e/2023-05-09-ci-gitlab-01.34.42.png" alt="Workflow and jobs" width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You have successfully configured CircleCI to start building your project on a self-managed GitLab instance.&lt;/p&gt;

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

&lt;p&gt;In this tutorial you have learned how to begin building projects hosted on GitLab with CircleCI. We have covered both on-premise self-managed GitLab as well as the hosted SaaS version on GitLab.com.&lt;/p&gt;

&lt;p&gt;Wishing you successful building!&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>gitlab</category>
      <category>cicd</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>CI/CD for interdepartmental teams</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Thu, 02 Feb 2023 18:00:00 +0000</pubDate>
      <link>https://dev.to/circleci/cicd-for-interdepartmental-teams-4h8</link>
      <guid>https://dev.to/circleci/cicd-for-interdepartmental-teams-4h8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The topic of CI/CD is often considered the domain of DevOps, infrastructure, and development teams. I would argue this thinking misses the great opportunity that is including the entire organisation in the conversation around software delivery lifecycle (SDLC). From QA, to product managers, to of course operators, security, all the way through to the top of engineering and technology leadership. Especially as organisations increasingly rely on software, not only in tech industry but in most other industries as well, it makes sense to spread the DevOps thinking and the use of tools such as CI/CD to more folks, more teams, and more departments.&lt;/p&gt;

&lt;p&gt;Incidentally, that’s what the DevOps movement is all about, and its natural evolution. Bringing the principles of early and continuous collaboration across departments to their entire organisations.&lt;/p&gt;

&lt;p&gt;This article argues for the use of CI/CD across various company departments - to anyone involved in - or adjacent to - the software delivery process, and covers the principles and tools that will benefit them, and points you to how to implement this using CircleCI in your organisation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this article is for
&lt;/h2&gt;

&lt;p&gt;People who will benefit the most from this article are the ones implementing pipelines themselves - be it DevOps and Software engineers. While this article is not a tutorial, yet it contains ideas and snippets for implementing the topics discussed within.&lt;/p&gt;

&lt;p&gt;As we’re talking about how CI/CD can benefit most of the organisations, this article will be approachable to people with many different backgrounds. From developers to operations teams, all the way to folks dealing with delivery and governance - delivery managers, security teams, engineering leadership.&lt;/p&gt;

&lt;h2&gt;
  
  
  The software delivery lifecycle from the CI/CD perspective
&lt;/h2&gt;

&lt;p&gt;Software delivery lifecycle, from the perspective of the CI/CD processes works kind of like this - the developers on the team write and push code changes, have them reviewed, and then automatically tested or otherwise validated, built, and ultimately deployed to a target environment using the CI/CD system, at which point the running software begins to be monitored by the operations teams.&lt;/p&gt;

&lt;p&gt;What technologies are used, where it is deployed, how it is monitored, and by whom, will all depend on the organisation; From Go microservices running on Kubernetes, to static websites with lambda functions, to iOS applications on the App Store, and everything in between.&lt;/p&gt;

&lt;p&gt;But of course there are many more things we do. Software doesn’t begin in an editor, it more often begins as a story somewhere on a backlog or a ticket in a bug tracker. That’s when we actually start thinking about what needs to be built, and how it should work, and for whom (and whether it ultimately does work or not), so why not use CI/CD to do more than just build, validate, and deploy?&lt;/p&gt;

&lt;h2&gt;
  
  
  Expanding the SDLC for the entire organisation
&lt;/h2&gt;

&lt;p&gt;A modern CI/CD platform can work beyond just building testing and deploying code, and instead it can tie together many more people and teams.&lt;/p&gt;

&lt;p&gt;In this section we will look at some of these capabilities, and how connecting to external tools can make us focus more on the software we're building and ultimately build better software.&lt;/p&gt;

&lt;h3&gt;
  
  
  QA, Product, and before work gets made
&lt;/h3&gt;

&lt;p&gt;QA engineers work best with constant access to latest builds to run tests on, as well as run and automate their their own tests. They are often also existing CI/CD users, who write test code and commit to the codebase.&lt;br&gt;
&lt;a href="https://circleci.com/docs/collect-test-data"&gt;We can create build outputs either directly in CircleCI&lt;/a&gt; with &lt;code&gt;store_artifacts&lt;/code&gt; and &lt;code&gt;store_test_results&lt;/code&gt; as in the example below, as well as of course through third party tools such as AppStore Connect, and deploying to test environments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  jobs:
    integration-test:
      docker:
        - image: ...
      steps:
        - checkout
        ...
        - run-test ...
        - store_artifacts:
            path: tested_app_binary
        - store_test_results:
            path: test-results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beyond the CI/CD platform itself, QA engineers also work a lot with product management and ticketing software - be it validating the requirements, logging defects, or confirming that updated products do not indeed have the defects anymore.&lt;br&gt;
&lt;a href="https://circleci.com/docs/jira-plugin"&gt;A CI/CD tool can integrate with a PM tool such as Jira&lt;/a&gt;, so that all your builds and deploys are automatically available and referenceable in it. This of course doesn’t only apply to QA engineers but also for product managers.&lt;/p&gt;

&lt;p&gt;You do so by first connecting CircleCI with Jira, and then making sure that you label each commit with the right ticket name - like &lt;code&gt;AB-234&lt;/code&gt;. Finally, as the last step of your deployment or build job - you can invoke the &lt;a href="https://circleci.com/developer/orbs/orb/circleci/jira"&gt;Jira orb&lt;/a&gt;'s notify command, with which you can mark deployments and builds, as in this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;orbs:
    jira: circleci/jira@1.3.1
workflows:
  build:
    jobs:
      - build:
          post-steps:
            - jira/notify 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notifications
&lt;/h3&gt;

&lt;p&gt;You can also notify your QA engineers and product managers of new releases waiting for their verification through the tools the teams already use - like Slack. &lt;br&gt;
&lt;a href="https://circleci.com/docs/slack-orb-tutorial"&gt;You can install a CI/CD tool as an application in your Slack workspace&lt;/a&gt;, which will also let it to post on your behalf. There are many ways to use it, frpm informing you when certain workflows and jobs are like deployments completed, tests are failing, and also when your workflow is waiting on an action - such as an approval or review by a QA engineer, product manager, and also security engineer, or a delivery manager. Below is an example of a generic deployment notification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  deploy:
    docker:
      ...
    steps:  
      - perform_deployment
      - slack/notify:
            event: pass
            template: success_tagged_deploy_1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides Slack there are of course numerous other tools organisations might use, from other instant messaging products to more conventional text messages and e-mails. All of these tend to have APIs which enable similar integrations to be built.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security, Delivery management, and approvals
&lt;/h3&gt;

&lt;p&gt;We have mentioned a few new roles; Security engineers are crucial for all companies to include in their SDLC processes. In an automated CI/CD pipeline, if a security team member doesn’t approve of a deployment after reviewing all necessary documentation and performing the checks, then the deployment should not complete. &lt;/p&gt;

&lt;p&gt;CircleCI offers two very powerful concepts for ensuring access control - approval jobs and contexts. &lt;br&gt;
Approval jobs introduce a manual step in your otherwise automated pipeline, which must be confirmed by an authenticated user in order for the pipeline to proceed. This is very useful for deployments for example.&lt;br&gt;
Contexts in CircleCI can be applied to individual jobs, and can be restricted to specific user groups when for example connected to GitHub. &lt;br&gt;
When using both of them, we can apply contexts to the subsequent job in the workflow after the approval job, in addition to adding user groups to the context itself.&lt;br&gt;
This means that if a non-authenticated person tries to approve this step, the subsequent step will fail with an unauthorized message. I have written a whole blog post on the topic of implementing access control: &lt;a href="https://circleci.com/blog/access-control-cicd/"&gt;https://circleci.com/blog/access-control-cicd/&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You can of course combine both with what we covered previously - Jira and Slack, to flag and notify the folks required to act on a deployment when it happens.&lt;/p&gt;

&lt;p&gt;Going a few steps further even, once the relevant team member is notified and sent a link to the relevant pipeline or job, why not give them everything they need to make a decision? We expect this it as part of reviewing pull and merge requests after all.&lt;br&gt;
For every testing job, security scan, and other checks we execute these tools can usually gather reports - why not make all reports available in a single report job. That’s possible by passing reports between jobs using a &lt;a href="https://circleci.com/docs/workspaces"&gt;workspace&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  security_scan:
    ...
    steps:
      - ...
      - perform-security-scan
      - persist_to_workspace:
          root: workspace
          paths:
            - security-output
  generate_reports:
    ...
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - store_artifacts:
          path: /tmp/workspace/security-output
      - store_artifacts:
          path: /tmp/workspace/some_other_report_output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this way you can leverage the power of a workspace to create a single point where all the relevant reports are collated. This can be a lightweight job which can save a busy team a lot of time and effort. Besides security engineers the same steps can be taken to inform delivery managers for example, and the manual approval jobs can be chained one after another, so the review steps are taken in order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ops, deployment reporting, and going beyond the individual dev team
&lt;/h3&gt;

&lt;p&gt;Now the software is approved and being deployed, we can notify the operations teams of a new deployment.&lt;br&gt;
That means that if any defects have been published, we can trace that back to the problematic deployment, revert that feature, and understand the root cause of breakage. Depending on what tools your operations teams use to monitor the software in production, you can call that API using either an orb or directly, which lets you tie a CircleCI pipeline with a deployment event.&lt;/p&gt;

&lt;p&gt;Finally let’s take a few steps back and realise that we’ve only been talking about a single team and the relevant stakeholders. Apart from very small companies (whose engineers are too busy to read this article anyway) that single team doesn't exist in a vacuum, but works with adjacent teams working on different parts of software, sometimes even integrating one another. So not only is there a single software development cycle, there are many.&lt;/p&gt;

&lt;p&gt;This means that implementing the above steps for a single team helps just that - the single team, but far from the wider organisation. People responsible for working across teams, should take on that work to ensure best practices are followed throughout the organisation. This could be the DevOps team that implement the integrations with security, PM, or ops processes, or the head of engineering looking to find way for their teams of engineers to learn and adopt approaches that work from each other. Looking at insights across multiple teams you could consider the pipeline throughput, mean time to recovery, and other metrics covered in our &lt;a href="https://circleci.com/resources/2022-state-of-software-delivery/"&gt;2022 State of Software Delivery report&lt;/a&gt; to understand and identify the best practices within your own organisation, and areas where you can apply these relatively small improvements for the greatest impact in most teams.&lt;/p&gt;

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

&lt;p&gt;We’re not in the world anymore where CI/CD is the sole domain of the development teams.&lt;br&gt;
The role of DevOps teams is to not only work across the Dev organisations but with the wider teams, promoting the virtues of automation and how it benefits other parts of the business. The DevOps and CI/CD engineers are in fact uniquely positioned to bring that automation to more and more people and roles within the org. &lt;/p&gt;

&lt;p&gt;In this article we have looked at a few ways CI/CD can be used to reach more parts of the company, from sending a slack message to your security engineers telling them of a required review, to letting your QA team know that a new bug fix has been deployed and is ready for testing in their ticketing application, to helping your ops team know that a new deployment has indeed started and could potentially have an impact on the users they are seeing.&lt;/p&gt;

&lt;p&gt;If this article has helped you in a way, I would love to know, also if you have any questions or suggestions about it, or ideas for future articles and guides, reach out to me on &lt;a href="https://twitter.com/zmarkan"&gt;Twitter - @zmarkan&lt;/a&gt; or &lt;a href="//mailto:zan@circleci.com"&gt;email me&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cicd</category>
      <category>circleci</category>
    </item>
    <item>
      <title>Continuous integration for Android projects</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Fri, 26 Aug 2022 19:00:00 +0000</pubDate>
      <link>https://dev.to/circleci/continuous-integration-for-android-projects-51l7</link>
      <guid>https://dev.to/circleci/continuous-integration-for-android-projects-51l7</guid>
      <description>&lt;p&gt;CircleCI is popular among Android developers for several reasons: it’s quick to get started, fast to execute your builds with high parallelism, (whether native, cross- or multi-platform), and even supports running Android emulators right from CircleCI with our Android machine images.&lt;/p&gt;

&lt;p&gt;This article will show you how to build and test Android applications for an example project on the CircleCI platform. The full source code is available &lt;a href="https://github.com/CircleCI-Public/android-testing-circleci-examples"&gt;on GitHub - CircleCI-Public/android-testing-circleci-examples&lt;/a&gt;, and you can find the working pipelines &lt;a href="https://app.circleci.com/pipelines/github/CircleCI-Public/android-testing-circleci-examples"&gt;in the corresponding CircleCI project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To get the most out of this article you should have&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Working knowledge of Android development&lt;/li&gt;
&lt;li&gt;Familiarity with Android tooling and testing frameworks&lt;/li&gt;
&lt;li&gt;Ability to use the Gradle build system&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s available in CircleCI for Android
&lt;/h2&gt;

&lt;p&gt;We have made a few tools available for you for building Android:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker image&lt;/li&gt;
&lt;li&gt;Android machine image&lt;/li&gt;
&lt;li&gt;Android orb&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Docker image
&lt;/h3&gt;

&lt;p&gt;The Docker image is the main executor teams use. It runs in a Docker container and so is very fast to start, and contains everything you might need to get started building Android projects. The full list of preinstalled tools can be found &lt;a href="https://circleci.com/developer/images/image/cimg/android"&gt;in the documentation&lt;/a&gt;. The images also ship with variants that have Node.js, the Android NDK, and browser tools preinstalled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Machine image
&lt;/h3&gt;

&lt;p&gt;The biggest change is the &lt;a href="https://circleci.com/developer/machine/image/android"&gt;new Android machine image&lt;/a&gt;. This is a virtual machine image, so takes a bit more time than the Docker image mentioned above, but it contains all the tools you may need to build your Android applications, including the SDK, Google Cloud tools for Firebase, &lt;a href="https://dev.to/features/python/"&gt;Python&lt;/a&gt;, Node.JS, and Fastlane. The biggest change however is the support for nested virtualisation, which allows you to run Android emulators from within this machine image.&lt;/p&gt;

&lt;p&gt;Android machine images support nested virtualization, which allow running the x86 emulators in CircleCI jobs. If you have been developing for Android since the early years of the platform, you may remember that emulators were very slow. Then x86 emulators started supporting Intel’s Hyper-V hypervisors, which lets the emulator use the resources of the host computer directly. Using resource directly like this makes the emulators able to run much, much more smoothly and quickly.&lt;/p&gt;

&lt;p&gt;For a long time, support was confined to our local hardware. Limited support on CircleCI slowed down emulators and made it difficult to run UI tests. Nested virtualization solves this problem by adding support for fast emulation to a massively reproducible CI/CD environment, making all the benefits of that available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android Orb
&lt;/h3&gt;

&lt;p&gt;Finally there is the CircleCI Android orb which provides easy access to both images as executors, as well as handy jobs and commands for installing SDKs, running emulators, caching, testing, and more. You can read more about what the orb offers in the orb docs &lt;a href="https://circleci.com/developer/orbs/orb/circleci/android"&gt;at this link&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the Android CI demo project
&lt;/h2&gt;

&lt;p&gt;I have created a &lt;a href="https://github.com/zmarkan/android-testing-circleci-examples"&gt;demo project&lt;/a&gt;, which is a fork of Google’s own Android Testing Codelab sources. The Codelab is a simple TO-DO list manager application and contains a combination of unit tests and instrumentation tests, with and without the UI. The project is also available to view &lt;a href="https://app.circleci.com/pipelines/github/zmarkan/android-testing-circleci-examples"&gt;on CircleCI&lt;/a&gt;. If you open it in Android Studio, make sure to switch to the &lt;code&gt;Project&lt;/code&gt; view. Project view lets you view the &lt;code&gt;.circleci/config.yml&lt;/code&gt; file we will be reviewing.&lt;/p&gt;

&lt;p&gt;The project has a single &lt;code&gt;app&lt;/code&gt; module, with the default &lt;code&gt;debug&lt;/code&gt; and &lt;code&gt;release&lt;/code&gt; variants. The &lt;code&gt;test&lt;/code&gt; directory contains unit tests, while the &lt;code&gt;androidTest&lt;/code&gt; directory contains instrumentation tests. The full CircleCI configuration is included, and I will be referring to it in this article. The configuration is located in &lt;code&gt;.circleci/config.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building and testing CI for the sample Android app
&lt;/h2&gt;

&lt;p&gt;Our CI process must do three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run unit tests inside a virtual machine&lt;/li&gt;
&lt;li&gt;Run instrumentation tests on the emulator&lt;/li&gt;
&lt;li&gt;Build a release version of the app&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will run unit tests and instrumentation tests side by side. If both types of tests are successful, we can assemble the release build. We will also add a condition to continue on to the release build &lt;em&gt;only&lt;/em&gt; if new work has been commited to the “main” branch, and only following successful emulator tests on every Android version from 23 to 30. When our build meets this condition, we will have solid assurance that our application will work on many different Android devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;As I mentioned before, everything from this point on will refer to the CircleCI configuration file in &lt;code&gt;.circleci/config.yml&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the CircleCI Android orb
&lt;/h3&gt;

&lt;p&gt;The first step for creating our &lt;a href="https://dev.to/ronpowelljr/what-is-a-ci-cd-pipeline-4lc5-temp-slug-7512512"&gt;CI pipeline&lt;/a&gt; is to use the Android orb, which contains many of the steps already pre-written for you. The latest version is available in the &lt;a href="https://circleci.com/developer/orbs/orb/circleci/android"&gt;orb docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After the orb is defined, the script specifies these jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;unit-test&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;android-test&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;release-build&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One workflow, &lt;code&gt;test-and-build&lt;/code&gt;, is also included.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: 2.1

orbs:
  android: "2.1.2"

jobs:
  unit-test:
    ...
  android-test:
    ...
  release-build:
    ...
    # We'll get to this later

workflows:
  test-and-build:
    ...
  # We'll get to this later

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running unit tests
&lt;/h3&gt;

&lt;p&gt;Our &lt;code&gt;unit-test&lt;/code&gt; job contains an executor from the Android orb: &lt;code&gt;android/android-docker&lt;/code&gt;. As mentioned this runs it in a Docker container which is extremely fast to start up.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;steps&lt;/code&gt; stanza, there are a few things to note. First, we run &lt;code&gt;android/restore-gradle-cache&lt;/code&gt; Gradle cache helps store our dependencies and build artifacts. After running the test command, we also run &lt;code&gt;android/save-gradle-cache&lt;/code&gt; and &lt;code&gt;android/save-build-cache&lt;/code&gt; to make sure subsequent builds run faster by using the cache. These all come from the Android orb, as indicated by the prefix &lt;code&gt;android/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We could also modify what gets cached by passing the &lt;code&gt;find-args&lt;/code&gt; parameter to &lt;code&gt;restore-gradle-cache&lt;/code&gt;. A great advanced example can be found &lt;a href="https://github.com/owntracks/android/blob/59f13afa93a27904e739493d96af64ab36f783eb/.circleci/continue-config.yml#L17-L44"&gt;in this open source project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main build step happens in the &lt;code&gt;android/run-tests&lt;/code&gt; command, where we call &lt;code&gt;./gradlew testDebug&lt;/code&gt; within a &lt;code&gt;test-command&lt;/code&gt; parameter. This command runs all unit tests for the &lt;code&gt;debug&lt;/code&gt; build variant. As a bonus, this command comes with a default retry value to help you avoid test flakiness.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  unit-test:
    executor:
      name: android/android-docker
      tag: 2022.08.1
    steps:
      - checkout
      - android/restore-gradle-cache
      - android/run-tests:
          test-command: ./gradlew testDebug
      - android/save-gradle-cache
      ...

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running Android tests on the emulator
&lt;/h3&gt;

&lt;p&gt;Our &lt;code&gt;android-test&lt;/code&gt; job is the one that uses the new Android emulator capability. The job uses the same Android machine executor as the &lt;code&gt;build&lt;/code&gt; job. All subsequent jobs will use the same executor, and the cache restoration steps are also the same.&lt;/p&gt;

&lt;p&gt;Emulator requires us to run on a machine image, so we specified &lt;code&gt;android/android-machine&lt;/code&gt; as the executor. To improve build times, we specify the &lt;code&gt;resource-class&lt;/code&gt; as xlarge. You can also run it on a &lt;code&gt;large&lt;/code&gt; executor, but I have found that the lack of resources causes slower build times. I recommend that you do some experimentation on your own to find the right size executor for your project.&lt;/p&gt;

&lt;p&gt;The next step is even shorter; we need just the &lt;code&gt;android/start-emulator-and-run-tests&lt;/code&gt; command. This command does exactly what it says: it starts the specified emulator and runs the tests. We pass in the &lt;code&gt;test-command&lt;/code&gt; again as the parameter (it uses the &lt;code&gt;android/run-tests&lt;/code&gt; command). The &lt;code&gt;system-image&lt;/code&gt; is the fully qualified Android emulator system image. We currently bundle our Android machine images back to SDK version 23. You could install more by using the &lt;code&gt;sdkmanager&lt;/code&gt; tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  android-test:
    executor:
      name: android/android-machine
      resource-class: xlarge
    steps:
      - checkout
      - android/start-emulator-and-run-tests:
          test-command: ./gradlew connectedDebugAndroidTest
          system-image: system-images;android-30;google_apis;x86
      ...

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

&lt;/div&gt;



&lt;p&gt;You could code all the emulator setup steps manually using the commands specified in the Android orb: &lt;code&gt;create-avd&lt;/code&gt;, &lt;code&gt;start-emulator&lt;/code&gt;, &lt;code&gt;wait-for-emulator&lt;/code&gt;, and &lt;code&gt;run-tests&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storing the test results
&lt;/h3&gt;

&lt;p&gt;There is more to testing than just running the tests, as we can get a lot of value from seeing exactly what has failed from right inside the CircleCI dashboard. For that we can use &lt;code&gt;store_test_results&lt;/code&gt; functions built into the CircleCI platform, which will show our passing (or failing) builds.&lt;/p&gt;

&lt;p&gt;The steps differ slightly between unit tests and instrumentation tests, as each of their respective Gradle tasks stores the tests in a different place. For unit tests the tests will be in &lt;code&gt;app/build/test-results&lt;/code&gt;, and for instrumentation tests they will be in &lt;code&gt;app/build/outputs/androidTest-results&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We suggest you create a new &lt;code&gt;Save test results&lt;/code&gt; step, which uses the &lt;code&gt;find&lt;/code&gt; utility and copies all test results files into a common location - like &lt;code&gt;test-results/junit&lt;/code&gt;, and then store it from there. Also make sure to add the &lt;code&gt;when: always&lt;/code&gt; parameter to the step, so the step runs regardless of whether the tests above succeed or fail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storing unit tests
&lt;/h3&gt;

&lt;p&gt;For this project, we want the XML based results. Calling &lt;code&gt;store_artifacts&lt;/code&gt; makes those results parseable on the CircleCI platform. You can also store the HTML output if you prefer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
- android/run-tests:
  test-command: ./gradlew testDebug
- run:
    name: Save test results
    command: |
        mkdir -p ~/test-results/junit/
        find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/junit/ \;
    when: always
- store_test_results:
    path: ~/test-results
- store_artifacts:
    path: ~/test-results/junit

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Storing instrumentation tests
&lt;/h3&gt;

&lt;p&gt;There are different regex command for different test types. The rest of the steps to store test results are identical to the unit tests example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- android/start-emulator-and-run-tests:
        test-command: ./gradlew connectedDebugAndroidTest
        system-image: &amp;lt;&amp;lt; parameters.system-image &amp;gt;&amp;gt;
    - run:
        name: Save test results
        command: |
          mkdir -p ~/test-results/junit/
          find . -type f -regex ".*/build/outputs/androidTest-results/.*xml" -exec cp {} ~/test-results/junit/ \;
        when: always
    - store_test_results:
        path: ~/test-results
    - store_artifacts:
        path: ~/test-results/junit

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Making a release build and storing the artifacts
&lt;/h3&gt;

&lt;p&gt;For this project, we need to store the application we are building. To complete this part of the process, we use the &lt;code&gt;release-build&lt;/code&gt; job, which has two parts of note. A &lt;code&gt;run&lt;/code&gt; step calls &lt;code&gt;./gradlew assembleRelease&lt;/code&gt;. Then, &lt;code&gt;store_artifacts&lt;/code&gt; points to where the built APK is. For a full CI/CD project, you could sign and upload that APK to a beta distribution service. You could even create a release on Play Store with Fastlane. Both of those activties are out of scope for this article, though.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  ...
  release-build:
    executor:
      name: android/android-machine
      resource-class: xlarge
    steps:
      - checkout
      - android/restore-gradle-cache
      - android/restore-build-cache
      - run:
          name: Assemble release build
          command: |
            ./gradlew assembleRelease
      - store_artifacts:
          path: app/build/outputs/apk/release

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running tests on multiple Android versions simultaneously
&lt;/h3&gt;

&lt;p&gt;The Android platform evolves all the time, and each version has its own bugs and pecularities. I am sure you have encountered some of them. A good way to avoid undefined behaviour across different versions of Android is to test on as many of them as you can. The CircleCI job matrix feature makes it easier to run jobs on multiple versions.&lt;/p&gt;

&lt;p&gt;To use the job matrix, add a parameter to the job you want to test on multiple versions. Our &lt;code&gt;android-test&lt;/code&gt; job does that using the &lt;code&gt;system-image&lt;/code&gt; parameter. We have also specified a default value for the parameter, so you can run the job without it.&lt;/p&gt;

&lt;p&gt;To use the parameter, specify where you need its value by placing it within pairs of angle brackets - &lt;code&gt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; android-test:
    parameters: # this is a parameter
      system-image:
        type: string
        default: system-images;android-30;google_apis;x86
    executor:
      name: android/android-machine
      resource-class: xlarge
    steps:
      - checkout
      - android/start-emulator-and-run-tests:
          test-command: ./gradlew connectedDebugAndroidTest
          system-image: &amp;lt;&amp;lt; parameters.system-image &amp;gt;&amp;gt; # parameter being used

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

&lt;/div&gt;



&lt;p&gt;To pass values to the parameter in the workflows, use the &lt;code&gt;matrix&lt;/code&gt; parameter of the job we are calling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;workflows:
  jobs:
  ...
  - android-test:
      matrix:
        alias: android-test-all
        parameters:
          system-image:
            - system-images;android-30;google_apis;x86
            - system-images;android-29;google_apis;x86
            - system-images;android-28;google_apis;x86
            - system-images;android-27;google_apis;x86
            - system-images;android-26;google_apis;x86
            - system-images;android-26;google_apis;x86
            - system-images;android-26;google_apis;x86
            - system-images;android-26;google_apis;x86
      name: android-test-&amp;lt;&amp;lt;matrix.system-image&amp;gt;&amp;gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Making each run faster by caching
&lt;/h3&gt;

&lt;p&gt;Alongside building our application, installing dependencies, and running tests, we often want to leverage cache as well. This allows us to do repeated tasks less often. Android and especially Gradle provides an excellent mechanism for this - &lt;a href="https://docs.gradle.org/current/userguide/build_cache.html"&gt;the Gradle Build cache&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This lets you skip pre-built parts of the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing what runs when
&lt;/h3&gt;

&lt;p&gt;During development, we create many commits, and developers should be encouraged to push them to a remote repository as often as possible. Each one of these committs creates a new CI/CD build, though, and we might not need every test run on all possible devices for a single commit. On the other hand, if the &lt;code&gt;main&lt;/code&gt; branch is our primary source of truth, we want to run as many tests on that as possible, to ensure it is always working as intended. We might want to initate the release deployment only on &lt;code&gt;main&lt;/code&gt;, and not on any other branch.&lt;/p&gt;

&lt;p&gt;We can use CircleCI’s &lt;code&gt;requires&lt;/code&gt; and &lt;code&gt;filters&lt;/code&gt; stanzas to define workflows that fit our process. Our &lt;code&gt;release-build&lt;/code&gt; job &lt;code&gt;requires&lt;/code&gt; the &lt;code&gt;unit-test&lt;/code&gt; jobs. That means the &lt;code&gt;release-build&lt;/code&gt; is put in the queue until all the &lt;code&gt;unit-test&lt;/code&gt; jobs have passed. Only then is the &lt;code&gt;release-build&lt;/code&gt; job run.&lt;/p&gt;

&lt;p&gt;We can use &lt;code&gt;filters&lt;/code&gt; to set up logical rules for running a particular job only on a specific branch or git tag. For example, we have a filter for our &lt;code&gt;main&lt;/code&gt; branch that runs the &lt;code&gt;android-test&lt;/code&gt; with a full matrix of emulators. In another example, the &lt;code&gt;release&lt;/code&gt; build triggers only on &lt;code&gt;main&lt;/code&gt;, and only when its two required jobs have run successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;workflows:
  test-and-build:
    jobs:
      - unit-test
      - android-test: # Commits to any branch - skip matrix of devices
          filters:
            branches:
              ignore: main
      - android-test: # Commits to main branch only - run full matrix
          matrix:
            alias: android-test-all
            parameters:
              system-image:
                - system-images;android-30;google_apis;x86
                - system-images;android-29;google_apis;x86
                - system-images;android-28;google_apis;x86
                - system-images;android-27;google_apis;x86
                - system-images;android-26;google_apis;x86
                - system-images;android-25;google_apis;x86
                - system-images;android-24;google_apis;x86
                - system-images;android-23;google_apis;x86
          name: android-test-&amp;lt;&amp;lt;matrix.system-image&amp;gt;&amp;gt;
          filters:
            branches:
              only: main 
      - release-build:
          requires:
            - unit-test
            - android-test-all
          filters:
            branches:
              only: main # Commits to main branch

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Improving your Android application CI process
&lt;/h2&gt;

&lt;p&gt;The steps I have described in this article are only a beginning. There are many ways you can improve the flow. Here are just a handful of ideas:&lt;/p&gt;

&lt;h3&gt;
  
  
  Build once, run many times
&lt;/h3&gt;

&lt;p&gt;If you are an experienced Android developer you know that the &lt;code&gt;connectedAndroidTest&lt;/code&gt; will always run the entire build process from the start. Using CircleCI, we could build the entire application and tests once, pass the artifacts down to following jobs, and simply run the tests on the emulators. This process could potentially save several build minutes per job run.&lt;/p&gt;

&lt;p&gt;To make this happen, add three commandline steps in each emulator run: install the app, install the instrumentation app, and run the instrumentation tests. For our application, we would enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adb install app/build/outputs/apk/debug/app-debug.apk  
adb install app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk  
adb shell am instrument -w com.example.android.architecture.blueprints.reactive.test/androidx.test.runner.AndroidJUnitRunner 

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

&lt;/div&gt;



&lt;p&gt;It is true that this code sends output to the the command line. That is not the tidy test output that Gradle provides. If you are motivated to make the output look better, &lt;a href="https://stackoverflow.com/questions/33896315/how-to-retrieve-test-results-when-using-adb-shell-am-instrument"&gt;this StackOverflow topic&lt;/a&gt; might help you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running on real devices
&lt;/h3&gt;

&lt;p&gt;Emulators are one tool, but real world devices are often (sadly) much different. There is nothing that can replace a real-world device test. For that you can use a solution offering real devices in the cloud, like Sauce Labs or Firebase Test Lab.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying to beta testers, and releasing the application
&lt;/h3&gt;

&lt;p&gt;This build and test example project is just one part of a wider CI/CD story. You can take your CI/CD process much further. For example, you can automatically release new versions of your applications right to the Play Store. CircleCI has a handful of guides to help you. &lt;a href="https://dev.to/ronpowelljr/continuous-integration-and-deployment-for-android-apps-with-fastlane-36j7-temp-slug-5167162"&gt;This tutorial&lt;/a&gt; is a great place to start. The &lt;a href="https://docs.fastlane.tools/getting-started/android/release-deployment/"&gt;official Fastlane documentation&lt;/a&gt; is another helpful resource.&lt;/p&gt;

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

&lt;p&gt;In this article, I described building an Android application with CircleCI, and testing it. For our sample project, we used unit tests and a matrix of Android platform emulators, using the new CircleCI Android orb and machine images. We also touched on how to store and display test results, and how to orchestrate workflows to run tests will not give us the tidy test output that Gradle provides, and all output is on a portion of devices.&lt;/p&gt;

&lt;p&gt;Do let me know if there is another Android topic you might want me to explore, either in an article or a live stream. Contact me on &lt;a href="https://twitter.com/zmarkan/"&gt;Twitter - @zmarkan&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>android</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Implementing access control policies in CI/CD pipelines</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Fri, 29 Apr 2022 12:00:00 +0000</pubDate>
      <link>https://dev.to/circleci/implementing-access-control-policies-in-cicd-pipelines-1mc5</link>
      <guid>https://dev.to/circleci/implementing-access-control-policies-in-cicd-pipelines-1mc5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This tutorial covers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Protected branches and security groups in GitHub&lt;/li&gt;
&lt;li&gt;Using contexts in CircleCI&lt;/li&gt;
&lt;li&gt;Setting up approval jobs in CircleCI&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine yourself in this situation: You are a motivated and skilled DevOps or DevEx engineer. You have a plan to implement automated, complete &lt;a href="https://dev.to/ronpowelljr/what-is-a-ci-cd-pipeline-4lc5-temp-slug-7512512"&gt;CI/CD pipelines&lt;/a&gt;. You know how to do it, and you know how the extra productivity and automation will benefit your team and the whole company. But the project is never approved, because of security concerns.&lt;/p&gt;

&lt;p&gt;Many organizations, especially those in regulated industries, have strict requirements for releasing their software, and rightfully so. Who can trigger a release, and when, under what conditions, and what specific checks are required before release can go ahead must be tightly controlled, auditable, and reversible.&lt;/p&gt;

&lt;p&gt;These kinds of complicated processes often require a dedicated delivery manager to collect and present all relevant feature briefs, test data, security assessment, and rollback plans to a committee of decision makers in the company. That group can give the delivery manager the green light to deploy, often also on a specific schedule.&lt;/p&gt;

&lt;p&gt;There is another approach. You can set up effective and fully automated CI/CD pipelines that include all the checks a human delivery manager and approval committee can complete. This tutorial will show you ways to create fine grained access control for your pipelines. You can use these methods for strictly regulated internal company projects for the enterprise, as well as for popular open source projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This tutorial assumes you have experience with CI/CD pipelines, and ideally with CircleCI. To implement the steps covered you will also need admin access to your GitHub and CircleCI organizations (and accounts for both services).&lt;/p&gt;

&lt;p&gt;If you do not have administrator access to a GitHub organization, you can create a free one in GitHub and use it with a free CircleCI account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Access control in CI/CD pipelines in enterprise projects
&lt;/h2&gt;

&lt;p&gt;For an enterprise organization it is vital that existing checks are followed and communicated well. The process often includes manual checks of supporting documentation and the potential impact to business before a release can continue. I will guide you through implementing a pipeline that executes a number of verification steps automatically, and continues with deployment to production &lt;em&gt;only&lt;/em&gt; after the dedicated delivery manager manually approves the process.&lt;/p&gt;

&lt;p&gt;To implement access control you will need to set up a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protected branches in GitHub&lt;/li&gt;
&lt;li&gt;Security groups in GitHub&lt;/li&gt;
&lt;li&gt;Contexts in CircleCI&lt;/li&gt;
&lt;li&gt;Approval jobs in CircleCI&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Protected branches
&lt;/h3&gt;

&lt;p&gt;Setting up a protected branch is the first step to setting up access control. A protected branch prohibits team members from pushing code directly to that branch, and instead forces all changes to go through the pull request (PR) process. Commonly you would protect the branch you use to create releases from; &lt;code&gt;main&lt;/code&gt; for example. You can toggle protected branches in the settings for your repo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8974eWIQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-04-20-access-control-protected-branch.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8974eWIQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-04-20-access-control-protected-branch.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" alt="Setting up protected branches in GitHub" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also specify rules and exceptions, such as review requirements, checks that need to pass before merging, history rules, and much more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lCR8yJa7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-04-20-access-control-protected-branch-rules.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lCR8yJa7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-04-20-access-control-protected-branch-rules.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" alt="Branch protection rules" width="800" height="923"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my example I set up my &lt;code&gt;main&lt;/code&gt; branch as a protected branch that requires a review and PR to pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up security groups
&lt;/h3&gt;

&lt;p&gt;If a user without the correct context privileges triggers a CircleCI pipeline (for example, with a commit), then the job that requires that context will be marked as 403 (unauthorized).&lt;/p&gt;

&lt;p&gt;In our organization we will set up two security groups: &lt;code&gt;development-leads&lt;/code&gt; and &lt;code&gt;delivery-managers&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;All developers in your organization can push to their own branches and issue pull requests, but only team leaders should be required to review any new pull requests. Only when the team leader approves can changes be merged into the protected &lt;code&gt;main&lt;/code&gt; branch. Then, when delivery managers get the green light to ship, they are the ones to trigger releases of software. In this tutorial, we will create a separate security group for them.&lt;/p&gt;

&lt;p&gt;CircleCI will use these security groups with contexts to limit which jobs can be executed by whom, so that only the delivery managers can trigger them manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using CircleCI contexts
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://circleci.com/docs/2.0/contexts/"&gt;Contexts&lt;/a&gt; in CircleCI serve a double role. One role limits the scope of secrets shared with a job while the other controls access.&lt;/p&gt;

&lt;p&gt;Only a job that has a context specified to it in a workflow is able to use the context’s secrets as environment variables. Contexts are shared across the entire organization in CircleCI, so they can be reused in multiple projects. You can set them up using the organization settings menu on the left hand side of the CircleCI dashboard.&lt;/p&gt;

&lt;p&gt;For access control, you can specify security groups to any context. For this tutorial,&lt;br&gt;&lt;br&gt;
we will create a context called &lt;code&gt;release&lt;/code&gt; and specify the &lt;code&gt;delivery-mgrs&lt;/code&gt; security group to it.&lt;/p&gt;

&lt;p&gt;Now you can set up your pipeline. The sample project uses the following flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tests&lt;/li&gt;
&lt;li&gt;Security scans&lt;/li&gt;
&lt;li&gt;Dev environment deployment&lt;/li&gt;
&lt;li&gt;Approval job for the delivery manager&lt;/li&gt;
&lt;li&gt;Production deployment
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;workflows:
 build-test-deploy:
   jobs:
     - test
     - security-scan:
         context: security
     - deploy-app:
         name: deploy-app-dev
         env: dev
         context: deployment-dev
         requires:
           - test
           - security-scan
         filters:
           branches:
             only:
               - main
     - approve-for-prod:
         type: approval
         requires:
           - deploy-app-dev
     - deploy-app:
         name: deploy-app-prod
         env: prod
         requires:
           - approve-for-prod
         context: release-prod


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

&lt;/div&gt;



&lt;p&gt;The pipeline uses contexts for environment variables like our API keys, but also uses the &lt;code&gt;release-prod&lt;/code&gt; context. The &lt;code&gt;release-prod&lt;/code&gt; context is gated so it can only be used by a delivery manager.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up approval jobs
&lt;/h3&gt;

&lt;p&gt;The final piece of the puzzle is the approval job: &lt;code&gt;approve-for-prod&lt;/code&gt;. Technically, anyone can log in and approve this job. However, the &lt;code&gt;deploy-app-prod&lt;/code&gt; job following it uses the &lt;code&gt;release-prod&lt;/code&gt; context, which only accepts delivery managers’ credentials. If someone without those credentials approves it, the release job will fail with an &lt;code&gt;unauthorized&lt;/code&gt; error, and the whole pipeline will terminate unsuccessfully.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other helpful bits and pieces
&lt;/h3&gt;

&lt;p&gt;One additional control we have set up in our workflow is the branch filter. The development deployment will occur only on the &lt;code&gt;main&lt;/code&gt; branch because of that filter. The &lt;code&gt;main&lt;/code&gt; branch is labelled as protected so the only way to get the code onto the &lt;code&gt;main&lt;/code&gt; branch is by passing the automated checks and code review, potentially by a lead engineer.&lt;/p&gt;

&lt;p&gt;You could also use dedicated QA or Security review steps that require manual approval. Build them the same way as part of the chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerations for open source projects
&lt;/h2&gt;

&lt;p&gt;So far we covered the enterprise use case for access control. Most OSS projects do not have the same strict compliance requirements as enterprises. In contrast these projects need to have their contributions opened to a much wider group of people. That means allowing many more people to trigger pipelines.&lt;/p&gt;

&lt;p&gt;Often the company that initiated and owns a popular OSS project continues to employ the core contributors. They will probably be joined by other regular contributors and maintainers that are not part of that company. And then there is everyone else - anyone who occasionally might contribute a fix or a feature.&lt;/p&gt;

&lt;p&gt;For that scenario, you can set up three flows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Company internal flow&lt;/strong&gt;. Members contribute and also administer everything. Company employees are likely the only people allowed to release new versions of software. We can call them “inner core contributors”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semi-internal flow&lt;/strong&gt;. These members are part of the organization and will be able to push directly to the main OSS repository. They will be able to use CircleCI for everything, including debugging jobs with SSH and triggering pipelines. Call them “outer core contributors”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard flow&lt;/strong&gt;. The rest of the contributors in the community who can issue PRs, otherwise work on their own. We will call them “community contributors”.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For community contributors. the flow is standard: make a fork, then open a pull request. You can toggle CircleCI to build pull requests that will automatically verify their changes.&lt;/p&gt;

&lt;p&gt;You should still have a protected branch, and required checks.&lt;/p&gt;

&lt;p&gt;For the groups of core contributors, you may want to include some secrets as well. Secrets require some more work. Also, passing secrets via forks is inherently insecure. Anyone could extract any secrets you allow to pass by modifying the pipeline in their PR. This could include API keys to certain services, or credentials to where your project is distributed.&lt;/p&gt;

&lt;p&gt;One option is to avoid passing secrets to forks altogether. You will have to push any code after reviewing it into your own org, where it can be executed, and then merged into your default branch. There is a helpful article that &lt;a href="https://dev.to/circleci/triggering-trusted-ci-jobs-on-untrusted-forks-o84-temp-slug-4362685"&gt;explains the process&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The other option is to &lt;em&gt;allow&lt;/em&gt; passing secrets to forks, but to prevent these secrets from being shared unless the code has been thoroughly reviewed and approved by a team member. You can set that up in the CircleCI project settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sIWkq49a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-04-20-access-control-circleci-settings.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sIWkq49a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-04-20-access-control-circleci-settings.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" alt="CircleCI sharing secrets across forks" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you toggle secrets you will need to set up an approval job. Put any secrets in a context that will be accessed only by people who belong to that context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;If you use this method, make sure that &lt;strong&gt;all&lt;/strong&gt; contexts in your organization specify the security group. If you do not, a malicious actor could guess your context name in a PR that gets executed and extract environment variables from it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With your inner and outer core of contributors, you can set up access controls in very much the same way. Maybe only the inner core can release new versions, but anyone in the outer core can merge any pull requests. Or maybe you just have one set of core maintainers who can do everything. The details are up to you!&lt;/p&gt;

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

&lt;p&gt;In this article we have looked at ways to protect your CI/CD pipelines further by setting up access controls to cordon off parts of pipelines (and the associated credentials) to a limited scope of people. This is a versatile approach and works for both enterprise organizations as well as OSS projects.&lt;/p&gt;

&lt;p&gt;We used security groups, protected branches, contexts, and approval jobs in CircleCI to achieve that effect, for both OSS and proprietary projects. Experiment with the best configuration for your organization and release your applications safely and securely.&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>pipelines</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Advanced pipeline orchestration with the circleback pattern</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Fri, 25 Feb 2022 10:00:00 +0000</pubDate>
      <link>https://dev.to/circleci/advanced-pipeline-orchestration-with-the-circleback-pattern-4ee8</link>
      <guid>https://dev.to/circleci/advanced-pipeline-orchestration-with-the-circleback-pattern-4ee8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This tutorial covers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Orchestrating triggers for a dependent pipeline&lt;/li&gt;
&lt;li&gt;Intro to the circleback pattern&lt;/li&gt;
&lt;li&gt;Creating the config for a circleback pipeline&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;With multiple teams working on many projects, having a single pipeline for your software is just not enough. These projects need to be built and integrated before they can be tested and released. So how do dev teams handle this situation? Many teams approach the problem by breaking down software into smaller parts that do less, and are easier to maintain and build. This approach has resulted in the microservices architectures that are increasingly common in our industry.&lt;/p&gt;

&lt;p&gt;The downside is that breaking software into smaller parts increases complexity. The combination of more parts and higher complexity makes it more difficult to test applications and operate them in production.&lt;/p&gt;

&lt;p&gt;CI/CD pipelines are not an exception here. In &lt;a href="https://dev.to/blog/triggering-pipelines-from-pipelines/"&gt;my previous article in this series&lt;/a&gt;, we looked at triggering pipelines from other pipelines. That post described how to link multiple projects together in CircleCI, so that one deployment kicks off another.&lt;/p&gt;

&lt;p&gt;In this article we will go a few steps further. I will provide an example of pipeline orchestration where the first pipeline not only triggers the other, but also waits on another pipeline to complete, before continuing. I call this the circleback pattern because it “circles back” to the second pipeline to signal when it has completed the work. Using this pattern allows for better integration testing and more complex deployment and release scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This tutorial covers advanced pipeline orchestration techniques, so experience with CircleCI and DevOps is a must.&lt;/li&gt;
&lt;li&gt;The tutorial also builds on a previous tutorial: &lt;a href="https://dev.to/blog/triggering-pipelines-from-pipelines/"&gt;Triggering pipelines from other pipelines&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources and sample code
&lt;/h2&gt;

&lt;p&gt;The source code for this example is located in two repositories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/CircleCI-Public/circleback-cicd-project-a"&gt;Pipeline A - does the triggering&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/CircleCI-Public/circleback-cicd-project-a"&gt;Pipeline B - gets triggered and circles back&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introducing the circleback pattern
&lt;/h2&gt;

&lt;p&gt;There are three steps in the circleback orchestration of these multiple pipelines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first pipeline waits&lt;/li&gt;
&lt;li&gt;The second pipeline terminates&lt;/li&gt;
&lt;li&gt;Results are retrieved from the first pipeline Another way of describing it is that the second pipeline calls or “circles back” to the first, while the first one is suspended and waiting for the signal to continue.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An alternative approach would be to keep the first pipeline running, checking periodically whether the second pipeline has finished. The main drawback of this approach is the increased cost for the running job’s continuous polling.&lt;/p&gt;

&lt;p&gt;Depending on the status of the second pipeline, the first continues executing until it either terminates successfully or fails.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6hWCJei5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-02-14-circleback-pattern-diagram.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6hWCJei5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-02-14-circleback-pattern-diagram.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" alt="Circle back pattern diagram" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why have pipelines wait for other projects to complete?
&lt;/h2&gt;

&lt;p&gt;As mentioned in the introduction, this is an advanced technique aimed at taming the complexity that stems from working with multiple projects. It can be used by teams working on multiple interdependent projects that they do not want to put in a single repository like a monorepo. Another use would be to have a centralized repository for tests, for example in a hardware company. This technique could also be useful for integration testing of a microservices application, or for orchestrating complex deployment scenarios. There are many possibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing pipeline triggers
&lt;/h2&gt;

&lt;p&gt;We have 2 pipelines we want to orchestrate&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pipeline A, which does the triggering&lt;/li&gt;
&lt;li&gt;Pipeline B is triggered, and circles back to pipeline A&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pipeline B is dependent on A, and can be used to validate A.&lt;/p&gt;

&lt;p&gt;Both pipelines need to have API keys set up and available. You can use the API key set as an environment variable (&lt;code&gt;CIRCLECI_API_KEY&lt;/code&gt;) in the job in pipeline A, and also in pipeline B when it calls back. You can either set it in both projects, or at the organization level as a context. For this tutorial, I set it at the organization level as the &lt;code&gt;circleci_api&lt;/code&gt; context, so that both projects can use the same API key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trigger the pipeline
&lt;/h3&gt;

&lt;p&gt;The triggering process is explained in depth in the first part of this tutorial, &lt;a href="https://dev.to/blog/triggering-pipelines-from-pipelines/"&gt;Triggering pipelines from other pipelines&lt;/a&gt;. In this follow-up tutorial, I will cover just the important differences.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To circle back from the pipeline, pass the original pipeline’s ID to it. Then it can be retrieved and reached with the API.&lt;/li&gt;
&lt;li&gt;You also need to store the triggered pipeline’s ID. You will need to get its result later on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the sample code, the parameter is called &lt;code&gt;triggering-pipeline-id&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --request POST \
                --url https://circleci.com/api/v2/project/gh/zmarkan-demos/circleback-cicd-project-b/pipeline \
                --header "Circle-Token: $CIRCLECI_API_KEY" \
                --header "content-type: application/json" \
                --data '{"branch":"main","parameters":{"triggering-pipeline-id":"&amp;lt;&amp;lt; pipeline.id &amp;gt;&amp;gt;"}}'

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

&lt;/div&gt;



&lt;p&gt;To store the pipeline ID, wrap your &lt;code&gt;curl&lt;/code&gt; call in &lt;code&gt;$()&lt;/code&gt; and assign it to the variable &lt;code&gt;CREATED_PIPELINE&lt;/code&gt;. To extract the ID from the response body, use the &lt;code&gt;jq&lt;/code&gt; tool, and write it to the file &lt;code&gt;pipeline.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATED_PIPELINE=$(curl --request POST \
                --url https://circleci.com/api/v2/project/gh/zmarkan-demos/semaphore_demo_project_b/pipeline \
                --header "Circle-Token: $CIRCLECI_API_KEY" \
                --header "content-type: application/json" \
                --data '{"branch":"main","parameters":{"triggering-pipeline-id":"&amp;lt;&amp;lt; pipeline.id &amp;gt;&amp;gt;"}}' \
              | jq -r '.id'
              )
              echo "my created pipeline"
              echo $CREATED_PIPELINE
              mkdir ~/workspace
              echo $CREATED_PIPELINE &amp;gt; pipeline.txt

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

&lt;/div&gt;



&lt;p&gt;Now that you have the file &lt;code&gt;pipeline.txt&lt;/code&gt; created, use &lt;code&gt;persist_to_workspace&lt;/code&gt; to store it and use it in a subsequent job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- persist_to_workspace:
            root: .
            paths: 
              - pipeline.txt  

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

&lt;/div&gt;



&lt;p&gt;The whole job configuration is here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
jobs:
  trigger-project-b-pipeline:
      docker: 
        - image: cimg/base:2021.11
      resource_class: small
      steps:
        - run:
            name: Ping another pipeline
            command: |
              CREATED_PIPELINE=$(curl --request POST \
                --url https://circleci.com/api/v2/project/gh/zmarkan-demos/semaphore_demo_project_b/pipeline \
                --header "Circle-Token: $CIRCLECI_API_KEY" \
                --header "content-type: application/json" \
                --data '{"branch":"main","parameters":{"triggering-pipeline-id":"&amp;lt;&amp;lt; pipeline.id &amp;gt;&amp;gt;"}}' \
              | jq -r '.id'
              )
              echo "my created pipeline"
              echo $CREATED_PIPELINE
              mkdir ~/workspace
              echo $CREATED_PIPELINE &amp;gt; pipeline.txt
        - persist_to_workspace:
            root: .
            paths: 
              - pipeline.txt  
...

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Orchestrating the waits
&lt;/h3&gt;

&lt;p&gt;The previous job will trigger a pipeline B, which needs to complete before it can circle back to pipeline A. You can use the &lt;code&gt;approval&lt;/code&gt; job in CircleCI like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
workflows:
  node-test-and-deploy:
    jobs:
      ...
      - trigger-project-b-pipeline:
          context: 
            - circleci-api
          requires:
            - build-and-test
          filters:
            branches:
              only: main
      - wait-for-triggered-pipeline:
          type: approval
          requires: 
            - trigger-project-b-pipeline
      - check-status-of-triggered-pipeline:
          requires:
            - wait-for-triggered-pipeline
          context:
            - circleci-api
      ...

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

&lt;/div&gt;



&lt;p&gt;After the job &lt;code&gt;trigger-project-b-pipeline&lt;/code&gt;, enter the &lt;code&gt;wait-for-triggered-pipeline&lt;/code&gt;. Because that job type is &lt;code&gt;approval&lt;/code&gt; it will wait until someone (in this case, the API) manually approves it. (More details in the next section.) After it is approved, add a &lt;code&gt;requires&lt;/code&gt; stanza so it continues to a subsequent job.&lt;/p&gt;

&lt;p&gt;Both jobs that use the CircleCI API have the &lt;code&gt;context&lt;/code&gt; specified, so the API token is available to both as an environment variable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Circle back to pipeline A
&lt;/h3&gt;

&lt;p&gt;For now we are done with pipeline A, and it is pipeline B’s time to shine. CircleCI’s &lt;code&gt;approval&lt;/code&gt; job is a special kind of job that waits until accepted. It is commonly used to hold a pipeline in a pending state until it is approved by a human delivery lead or infosec engineer.&lt;/p&gt;

&lt;p&gt;At this point, pipeline B knows the ID of pipeline A, so you can use the approval API to get it. You only have the ID of the pipeline being run, but not the actual job that needs approval, so you will need more than one API call:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get all jobs in the pipeline&lt;/li&gt;
&lt;li&gt;Find the approval job by name&lt;/li&gt;
&lt;li&gt;Send a request to approve the job&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Approving the job allows pipeline A to continue.&lt;/p&gt;

&lt;p&gt;If the tests fail in pipeline B, then that job automatically fails. A workflow with required jobs will not continue in this case. You can get around by using &lt;code&gt;post-steps&lt;/code&gt; in the pipeline, which always executes. The whole workflow is shown in the next sample code block.&lt;/p&gt;

&lt;p&gt;Parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;parameters:
  triggering-pipeline-id:
    type: string
    default: ""

...

workflows:
  node-test-and-deploy:
    jobs:
      - build-and-test:
          post-steps:
            - approve-job-in-triggering-pipeline
          context: 
            - circleci-api       

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

&lt;/div&gt;



&lt;p&gt;Script to perform the approval API call can be implemented like this. For this tutorial, I used a &lt;code&gt;command&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
commands:
  approve-job-in-triggering-pipeline:
    steps:
      - run:
          name: Ping CircleCI API and approve the pending job
          command: |
            echo &amp;lt;&amp;lt; pipeline.parameters.triggering-pipeline-id &amp;gt;&amp;gt;
            if ! [-z "&amp;lt;&amp;lt; pipeline.parameters.triggering-pipeline-id &amp;gt;&amp;gt;"] 
            then
              workflow_id=$(curl --request GET \
                --url https://circleci.com/api/v2/pipeline/&amp;lt;&amp;lt; pipeline.parameters.triggering-pipeline-id &amp;gt;&amp;gt;/workflow \
                --header "Circle-Token: $CIRCLECI_API_KEY" \
                --header "content-type: application/json" \
              | jq -r '.items[0].id')

              echo $workflow_id

              waiting_job_id=$(curl --request GET \
                --url https://circleci.com/api/v2/workflow/$workflow_id/job \
                --header "Circle-Token: $CIRCLECI_API_KEY" \
                --header "content-type: application/json" \
              | jq -r '.items[] | select(.name == "wait-for-triggered-pipeline").id')

              echo $waiting_job_id

              curl --request POST \
                --url https://circleci.com/api/v2/workflow/$workflow_id/approve/$waiting_job_id \
                --header "Circle-Token: $CIRCLECI_API_KEY" \
                --header "content-type: application/json"

            fi
          when: always       
...

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

&lt;/div&gt;



&lt;p&gt;The script first checks for the existence of the &lt;code&gt;triggering-pipeline-id&lt;/code&gt; pipeline parameter. It proceeds only if that parameter exists. The &lt;code&gt;when: always&lt;/code&gt; line in the command makes sure that this executes regardless of termination status.&lt;/p&gt;

&lt;p&gt;Then it makes 3 API calls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get workflow ID in a pipeline. There is just one workflow in that pipeline for this sample project.&lt;/li&gt;
&lt;li&gt;Get jobs in that workflow, use &lt;code&gt;jq&lt;/code&gt; to select the one that matches the approval job name (&lt;code&gt;wait-for-triggered-pipeline&lt;/code&gt;), and extract the approval job’s ID.&lt;/li&gt;
&lt;li&gt;Make the request to the approval endpoint with the waiting job ID.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For this tutorial, we are storing results like workflow ID and job ID in local bash variables, and using them in subsequent calls to the API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : &lt;em&gt;If you have more jobs than can be sent in a single response, you might have to handle pagination as well.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that you have made the approval request, pipeline B is complete, and pipeline A should be running again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update pipeline A with the result of B
&lt;/h3&gt;

&lt;p&gt;After pipeline A has been approved, the next job in the workflow will begin. If your workflow graph requires it, pipeline A can trigger multiple jobs.&lt;/p&gt;

&lt;p&gt;We still do not have any indication of the result of the previous workflow. To get that information, you can use the API again to get B’s status from pipeline A. An example job could look like that: &lt;code&gt;check-status-of-triggered-pipeline&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, you need to retrieve the ID of the triggered pipeline, which is pipeline B. This is the same ID that was persisted in a workspace in an earlier step. Retrieve it using &lt;code&gt;cat&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; - attach_workspace:
          at: workspace
      - run:
          name: Check triggered workflow status
          command: |
            triggered_pipeline_id=$(cat workspace/pipeline.txt)

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

&lt;/div&gt;



&lt;p&gt;Then use the API to retrieve the workflow. Use &lt;code&gt;jq&lt;/code&gt; to get just the status of the first item in the returned array of workflows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;created_workflow_status=$(curl --request GET \
                --url "https://circleci.com/api/v2/pipeline/${triggered_pipeline_id}/workflow" \
                --header "Circle-Token: $CIRCLECI_API_KEY" \
                --header "content-type: application/json" \
              | jq -r '.items[0].status'
            )

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

&lt;/div&gt;



&lt;p&gt;Check that status is not &lt;code&gt;success&lt;/code&gt;. If it is not, use &lt;code&gt;exit&lt;/code&gt; to terminate the job with exit code -1. If the workflow is successful, it will terminate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [["$created_workflow_status" != "success"]]; then
              echo "Workflow not successful - ${created_workflow_status}"
              (exit -1) 
            fi

            echo "Created workflow successful"

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

&lt;/div&gt;



&lt;p&gt;Here is the full config for the job &lt;code&gt;check-status-of-triggered-pipeline&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; check-status-of-triggered-pipeline:
    docker: 
      - image: cimg/base:2021.11
    resource_class: small 
    steps:
      - attach_workspace:
          at: workspace
      - run:
          name: Check triggered workflow status
          command: |
            triggered_pipeline_id=$(cat workspace/pipeline.txt)
            created_workflow_status=$(curl --request GET \
                --url "https://circleci.com/api/v2/pipeline/${triggered_pipeline_id}/workflow" \
                --header "Circle-Token: $CIRCLECI_API_KEY" \
                --header "content-type: application/json" \
              | jq -r '.items[0].status'
            )
            echo $created_workflow_status
            if [["$created_workflow_status" != "success"]]; then
              echo "Workflow not successful - ${created_workflow_status}"
              (exit -1) 
            fi

            echo "Created workflow successful"

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

&lt;/div&gt;



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

&lt;p&gt;In this article we have reviewed an example of a complex pipeline orchestration pattern that I have named “circleback”. The circleback pattern creates a dependent pipeline and allows you to wait for it to terminate before completing. It involves making several API keys from both projects, the use of an approval job, and the workspace feature of CircleCI to store and pass values such as pipeline ID across jobs in a workflow. The sample projects are located in separate repositories: &lt;a href="https://github.com/CircleCI-Public/circleback-cicd-project-a"&gt;project A&lt;/a&gt;, and &lt;a href="https://github.com/CircleCI-Public/circleback-cicd-project-B"&gt;project B&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If this article has helped you in a way, I would love to know, also if you have any questions or suggestions about it, or ideas for future articles and guides, reach out to me on &lt;a href="https://twitter.com/zmarkan"&gt;Twitter - @zmarkan&lt;/a&gt; or &lt;a href="//mailto:zan@circleci.com"&gt;email me&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>pipelines</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Testing locally with CircleCI runners</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Tue, 18 Jan 2022 10:00:00 +0000</pubDate>
      <link>https://dev.to/circleci/testing-locally-with-circleci-runners-mg6</link>
      <guid>https://dev.to/circleci/testing-locally-with-circleci-runners-mg6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;In this article you will learn how to set up the CircleCI runner agent on your local machine to run tests. You will also learn how to configure your CircleCI pipeline so that the runner is invoked correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many development teams start their CI/CD journey with a local build box (or six) that run their tests. In several mobile teams I worked on, for example, we had a few Mac Mini boxes with physical devices plugged in that we used for running local UI and unit tests. Eventually we migrated to a cloud-based solution, which brought us much greater stability and many new features. But moving to the cloud also meant our local hardware was obsolete. We had to rely on emulation, or opt for another cloud-based device farm for that.&lt;/p&gt;

&lt;p&gt;With CircleCI’s runners, you can keep using your own devices to run tests on, while benefiting from everything else available in the CircleCI cloud. You can also use runners for tests that &lt;em&gt;need&lt;/em&gt; to run on your own infrastructure, for security-critical scenarios, or when you are developing your own hardware.&lt;/p&gt;

&lt;p&gt;With the launch of the &lt;a href="https://dev.to/blog/new-cicd-free-plan-what-devs-get/"&gt;CircleCI Free plan&lt;/a&gt;, features like runners are now available to everyone. In this article you will learn how to set up the CircleCI runner agent on your local machine to run tests. You will also learn how to configure your CircleCI pipeline so that the runner is invoked correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This tutorial assumes some experience with CircleCI and an understanding of how pipelines are configured to build and test software projects.&lt;/p&gt;

&lt;p&gt;I have created a &lt;a href="https://github.com/zmarkan-demos/android-testing-runner-example"&gt;sample project&lt;/a&gt; that shows the runner configuration.&lt;/p&gt;

&lt;p&gt;You can also find its builds &lt;a href="https://app.circleci.com/pipelines/github/zmarkan-demos/android-testing-runner-example/7/workflows/8feabfe4-c942-4949-bf88-cfed8aca7615/jobs/30"&gt;in the CircleCI dashboard for the sample project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : &lt;em&gt;This example shows an Android application and tests, using the runner on macOS. The principles behind it can be universally applied, though: to iOS apps, custom hardware, or for runner on different infrastructure, like Docker containers, Windows, Linux machines, and more.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How runners work
&lt;/h2&gt;

&lt;p&gt;A runner is a process installed on your infrastructure that communicates with CircleCI. Runners function as their own resource class. Your &lt;code&gt;config.yml&lt;/code&gt; still defines the pipeline, jobs, and workflows, but instead of using CircleCI’s cloud-based resources like containers and virtual machines, you execute it on your own.&lt;/p&gt;

&lt;p&gt;First, install the runner agent locally. This is a daemon process that runs in the background, checking for prompts from CircleCI. When CircleCI signals that a job must be triggered on the runner, the agent executes the workload. It also has access to the same credentials as the cloud version of CircleCI, so it runs seamlessly and can fetch the code from your repositories.&lt;/p&gt;

&lt;p&gt;Once the job is complete, the results and any artifacts are sent back to the cloud service. Only the actual job execution is done on your infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Implementation consists of these processes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up the runner agent locally&lt;/li&gt;
&lt;li&gt;Invoking the runner from your CircleCI &lt;code&gt;config.yml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setting up the runner agent
&lt;/h3&gt;

&lt;p&gt;Installing the runner agent depends on which platform you are using. Refer to the setup instructions in the &lt;a href="https://circleci.com/docs/2.0/runner-installation"&gt;CircleCI docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For my sample application, I installed the runner agent on a Mac computer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : &lt;em&gt;These steps are just a brief overview and not a complete guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The main steps to set up the runner are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Register a new runner in your organization&lt;/li&gt;
&lt;li&gt;Install the runner agent, following the instructions for your platform&lt;/li&gt;
&lt;li&gt;Start the runner daemon, and make sure it runs on system startup&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use the &lt;code&gt;circleci&lt;/code&gt; CLI tool too register a new runner in your organization. If it is your first runner, you may need to create a namespace in that organization. You will be referring to that specific runner from the CircleCI config using that fully qualified name. In my case, that was &lt;code&gt;zan_demos_namespace/mac_runner&lt;/code&gt;; &lt;code&gt;mac_runner&lt;/code&gt; is the name of the runner, and &lt;code&gt;zan_demos_namespace&lt;/code&gt; is the namespace I used.&lt;/p&gt;

&lt;p&gt;Here is a sample command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ circleci runner resource-class create zmarkan-demos-namespace/local-mac-runner "Local Mac OS Runner" --generate-token

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

&lt;/div&gt;



&lt;p&gt;This command will also set up a new API token for this runner to use with CircleCI API in the organization. That is made possible because of the &lt;code&gt;--generate-token&lt;/code&gt; flag. Be sure to store that token for later.&lt;/p&gt;

&lt;p&gt;After registering the runner with CircleCI, install the runner agent following the instructions &lt;a href="https://circleci.com/docs/2.0/runner-installation"&gt;in the docs&lt;/a&gt;. The setup requires software like &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;sha256sum&lt;/code&gt;, &lt;code&gt;tar&lt;/code&gt;, and &lt;code&gt;gzip&lt;/code&gt; preinstalled. There may be other software required.&lt;/p&gt;

&lt;p&gt;Set up some daemon scripts, and pass in these values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The API token created in the previous step&lt;/li&gt;
&lt;li&gt;The runner namespace&lt;/li&gt;
&lt;li&gt;The name you specified&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The particulars of these items vary based on the platform you are using. For example, on Mac you need to create a &lt;code&gt;launchd.plist&lt;/code&gt; and start it with &lt;code&gt;launchctl&lt;/code&gt;. On Linux it will be a new service that starts with &lt;code&gt;systemctl&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invoking the runner from a pipeline
&lt;/h2&gt;

&lt;p&gt;Once the runner agent is in motion, you can invoke it from a job in the &lt;code&gt;.circleci/config.yml&lt;/code&gt; file. Make sure to specify the &lt;code&gt;machine&lt;/code&gt; executor type and the resource class with your runner’s namespace and runner name. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; runner-test:
    machine: true
    resource_class: zmarkan-demos-namespace/local-mac-runner
    environment:
      JAVA_HOME: /Users/zmarkan/libs/jdk-11.0.2.jdk/Contents/Home
      ANDROID_SDK_ROOT: /Users/zmarkan/Library/Android/sdk
    steps:
      - checkout
      - run:
          name: Run connected check on local runner
          command: |
            ./gradlew connectedDebugAndroidTest

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

&lt;/div&gt;



&lt;p&gt;In my example, I had some Android devices connected to my Mac, so the runner could access that local hardware to run tests on them.&lt;/p&gt;

&lt;p&gt;I also needed to pass in some specific values that come out of the box when using CircleCI’s own infrastructure, like &lt;code&gt;JAVA_HOME&lt;/code&gt; and &lt;code&gt;ANDROID_SDK_ROOT&lt;/code&gt;. This is because they were not readily accessible in the specific shell that CircleCI runner uses. On most modern Macs the shell used is Zsh; CircleCI runs Bash by default.&lt;/p&gt;

&lt;p&gt;The rest of the steps are straightforward and will depend on your application and what you want to execute. In my case that was checking out the code from the repo and running the tests. You could also use &lt;code&gt;store_artifacts&lt;/code&gt; and &lt;code&gt;store_test_results&lt;/code&gt; to process the tests and save outputs. The outputs would then be available in your CircleCI cloud dashboard.&lt;/p&gt;

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

&lt;p&gt;In this article you have learned how to set up a local CircleCI runner for executing CircleCI cloud workloads on your local infrastructure. Runner has many use cases, from security to execution on bespoke hardware, all with the same CI/CD experience that cloud based CircleCI offers.&lt;/p&gt;

&lt;p&gt;If you have any feedback or suggestions about topics I should cover next, reach out to me on &lt;a href="https://twitter.com/zmarkan/"&gt;Twitter - @zmarkan&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>cicd</category>
      <category>testing</category>
      <category>runners</category>
    </item>
    <item>
      <title>Build private CircleCI orbs on any organization</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Thu, 13 Jan 2022 10:00:00 +0000</pubDate>
      <link>https://dev.to/circleci/build-private-circleci-orbs-on-any-organization-14fc</link>
      <guid>https://dev.to/circleci/build-private-circleci-orbs-on-any-organization-14fc</guid>
      <description>&lt;p&gt;Using CircleCI’s orbs is a great way to share CI/CD configuration across projects. Public orbs work well for wide adoption, but private orbs have been helpful for organizations needing to share common internal configuration in a secure, non-public way. Private orbs work only within the organization that publishes them.&lt;/p&gt;

&lt;p&gt;We recently opened up private orbs access to all CircleCI customers, including those on the &lt;a href="https://dev.to/blog/new-cicd-free-plan-what-devs-get/"&gt;Free plan&lt;/a&gt;. This new access opens up a number of new possibilities for your pipelines.&lt;/p&gt;

&lt;p&gt;In this article you will learn about private orbs and how to use them for your own organization. We will be using the sample orb I built, which contains a command and a job that lets you trigger CircleCI pipelines in other projects using cURL. You can find the source code of the project in &lt;a href="https://github.com/zmarkan-demos/api-requester-orb-sample"&gt;this repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This article assumes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Working knowledge of &lt;a href="https://circleci.com/docs/2.0"&gt;CircleCI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Understanding of how pipelines work&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://circleci.com/docs/2.0/local-cli"&gt;CircleCI CLI&lt;/a&gt; installed and configured locally on your machine&lt;/li&gt;
&lt;li&gt;You are using either a project organization or your personal organization on GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use cases for private orbs
&lt;/h2&gt;

&lt;p&gt;Like orbs in general, private orbs are useful for sharing steps and tasks that are common to multiple projects.&lt;/p&gt;

&lt;p&gt;Many organizations have their own frameworks and internal tools used across many teams. With private orbs they can share those tools easily, without opening it up to the wider world. Some use cases for private orbs include deployment to your proprietary Kubernetes clusters or other infrastructure, dealing with custom hardware, all the way to logging or common admin tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial setup
&lt;/h2&gt;

&lt;p&gt;We will use the CircleCI CLI for this task. With the CLI you will create a new orb, and register it with CircleCI so it can be referenced by other CircleCI pipelines. The CLI allows you to release new versions of your orb.&lt;/p&gt;

&lt;p&gt;The whole orb creation process is &lt;a href="https://circleci.com/docs/2.0/local-cli/"&gt;documented in the CircleCI docs&lt;/a&gt;. This article will serve as a quick recap of it and explanation of the steps involved.&lt;/p&gt;

&lt;p&gt;Create an empty git repository and note its path. I created mine under my &lt;code&gt;zmarkan-demos&lt;/code&gt; organization, and named it &lt;code&gt;api-requester-orb-sample&lt;/code&gt;, so the path is: &lt;code&gt;git@github.com:zmarkan-demos/api-requester-orb-sample.git&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, create the actual orb with the CLI’s &lt;code&gt;circleci orb init&lt;/code&gt; command, passing in a local path where you want the orb source to be located. This directory must be new; do not use one that already exists. In my case, this was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;circleci orb init ~/github/api-requester-orb-sample --private

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

&lt;/div&gt;



&lt;p&gt;The main difference between public and private orbs is the &lt;code&gt;--private&lt;/code&gt; flag at the end.&lt;/p&gt;

&lt;p&gt;The CLI asks you to either follow the guided setup, which is what I did, or to do it yourself. I recommend using the automated process is recommended as it will set up everything in the directory with an empty orb template, as well as link it to your repository, create a namespace for your orb, and create a CircleCI project for the new orb, just make sure to copy the git URL from the repository you created earlier.&lt;/p&gt;

&lt;p&gt;Finally you need to push the local code to the remote repository -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/github/api-requester-orb-sample
git push origin master

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

&lt;/div&gt;



&lt;p&gt;Note: All orbs exist in a namespace within your organization. This is the same for any runner agents you have registered already.&lt;/p&gt;

&lt;p&gt;You can also review your new private orbs in your organization settings, where they are clearly labeled as private under the &lt;code&gt;type&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HDutLjqp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-01-06-private-orb-list-ui.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HDutLjqp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-01-06-private-orb-list-ui.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" alt="List of orbs in the UI" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Developing an orb
&lt;/h2&gt;

&lt;p&gt;The orb development process depends on whether you opt for the automated guided process or follow your own. As with the setup section, the CircleCI docs cover both scenarios.&lt;/p&gt;

&lt;p&gt;If you have followed the quick setup route, then the CLI will have generated the whole project for you from template. It has samples for a command, job, executor, and a test for it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SAHp2P-Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-01-06-private-orb-generated-ui.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SAHp2P-Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://production-cci-com.imgix.net/blog/media/2022-01-06-private-orb-generated-ui.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" alt="Orb project view" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can remove any part of the orb that you do not need. In my case I removed the scripts and executors, and kept the commands and jobs. Orbs are just a collection of CircleCI configuration scripts that get resolved and bundled when you run a pipeline.&lt;/p&gt;

&lt;p&gt;We created 2 scripts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;commands/trigger-pipeline.yml&lt;/code&gt; command&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;jobs/trigger-circleci-pipeline.yml&lt;/code&gt; job&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The job wraps the command and executes in the base Docker executor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the trigger-pipeline command
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;trigger-pipeline&lt;/code&gt; command has 4 parameters, and a single step, as shown in this code sample:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;description: &amp;gt;
  This command triggers CircleCI pipeline specified.
  The job execution environment must have cURL utility available

parameters:
  repo-name:
    type: string
    description: "Repo name to trigger pipeline for"

  branch-name:
    type: string
    default: main
    description: "Branch name to trigger"

  trigger-params-json:
    type: string
    default: "{}"
    description: Pipeline trigger parameters in JSON format

  circle-token-env-var:
    type: env_var_name
    default: CIRCLE_TOKEN
    description: Environment variable containing your CircleCI API Key. Default is $CIRCLECI_API_KEY

steps:
  - run:
      name: Run cURL request
      command: |
        curl --request POST \
            --url "https://circleci.com/api/v2/project/gh/${CIRCLE_PROJECT_USERNAME}/&amp;lt;&amp;lt; parameters.repo-name &amp;gt;&amp;gt;/pipeline" \
            --header "Circle-Token: ${&amp;lt;&amp;lt; parameters.circle-token-env-var &amp;gt;&amp;gt;}" \
            --header "content-type: application/json" \
            --data '{"branch":"&amp;lt;&amp;lt; parameters.branch-name &amp;gt;&amp;gt;","parameters":&amp;lt;&amp;lt; parameters.trigger-params-json &amp;gt;&amp;gt;}"'

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

&lt;/div&gt;



&lt;p&gt;Unlike a full CircleCI pipeline config, this one does not require a &lt;code&gt;version&lt;/code&gt; stanza. With only a single command source, it doesn’t have &lt;code&gt;jobs&lt;/code&gt; or &lt;code&gt;workflows&lt;/code&gt; either. All 4 parameters are also specific to this command, unlike the pipeline parameters available in the full CircleCI config.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;curl&lt;/code&gt; command in the run step hits the CircleCI API to trigger another pipeline. It is &lt;a href="https://dev.to/blog/triggering-pipelines-from-pipelines/"&gt;described in detail in this blog post&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the trigger-circleci-pipeline job
&lt;/h3&gt;

&lt;p&gt;Writing a job that consumes the command we just created is straightforward. Within the same orb, you can use that command as if it were a local command you had defined in the config. In our example in &lt;code&gt;jobs/trigger-circleci-pipeline.yml&lt;/code&gt; it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;description: &amp;gt;
  Job that trigger CircleCI pipeline in another project with the payload specified

docker:
  - image: cimg/base:2021.12

parameters:
  repo-name:
    type: string
    description: "Repo name to trigger pipeline for"
  branch-name:
    type: string
    default: main
    description: "Branch name to trigger"

  trigger-params-json:
    type: string
    default: "{}"
    description: Pipeline trigger parameters in JSON format

  circle-token-env-var:
    type: env_var_name
    default: CIRCLE_TOKEN
    description: Environment variable containing your CircleCI API Key. Default is $CIRCLECI_API_KEY

steps:
  - trigger-pipeline:
      repo-name: &amp;lt;&amp;lt; parameters.repo-name &amp;gt;&amp;gt;
      branch-name: &amp;lt;&amp;lt; parameters.branch-name &amp;gt;&amp;gt;
      trigger-params-json: &amp;lt;&amp;lt; parameters.trigger-params-json &amp;gt;&amp;gt;
      circle-token-env-var: &amp;lt;&amp;lt; parameters.circle-token-env-var &amp;gt;&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;This command has the parameters, and as with all other jobs in CircleCI we need the executor: &lt;code&gt;docker&lt;/code&gt; in our case. The &lt;code&gt;steps&lt;/code&gt; stanza contains a single step, invoking our &lt;code&gt;trigger-pipeline&lt;/code&gt; command from before, with any parameters we set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing and deploying the orb
&lt;/h2&gt;

&lt;p&gt;To build, test, and deploy our orb, the orb template project uses CircleCI itself. Within the config in &lt;code&gt;.circleci/config.yml&lt;/code&gt; most everything is pre-made for you. All you need to do is to write tests for it. By default, it contains a job named &lt;code&gt;integration-test-1&lt;/code&gt;, which you can modify to use your own orb. Here is a snippet that invokes the &lt;code&gt;trigger-pipeline&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  integration-test-1:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - api-requester-orb-sample/trigger-pipeline:
          repo-name: pinging-me-softly
          branch-name: main
          trigger-params-json: '{"image-name": "cimg/base:2021.12"}'

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

&lt;/div&gt;



&lt;p&gt;To publish a release version you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change from the default &lt;code&gt;alpha&lt;/code&gt; branch to either the &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;main&lt;/code&gt; branch&lt;/li&gt;
&lt;li&gt;Include a &lt;code&gt;[semver:patch|minor|major]&lt;/code&gt; message in the commit&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this article you have learned about building private orbs for CircleCI, which are now available to all CircleCI customers. Private orbs allow you to have shared CI/CD pipeline configuration across multiple projects. These private orbs can be used by any team member in your organization, without the risk of exposing your config to the public.&lt;/p&gt;

&lt;p&gt;The process as a whole is almost identical for publishing public orbs. Just add the &lt;code&gt;--private&lt;/code&gt; flag in the &lt;code&gt;circleci orb init&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;To read more about orb development check out &lt;a href="https://circleci.com/docs/2.0/orb-author/"&gt;the docs pages on authoring orbs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To read about testing and verifying bash scripts in your orbs using BATS and ShellCheck, &lt;a href="https://circleci.com/docs/2.0/testing-orbs/"&gt;check out this docs page on orb testing methodologies&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions about this article, or ideas for future articles and guides, reach out to me on &lt;a href="https://twitter.com/zmarkan"&gt;Twitter - @zmarkan&lt;/a&gt; or &lt;a href="//mailto:zan@circleci.com"&gt;email me&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>orbs</category>
      <category>cicd</category>
      <category>config</category>
    </item>
    <item>
      <title>Getting started with scheduled pipelines</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Tue, 14 Dec 2021 14:00:00 +0000</pubDate>
      <link>https://dev.to/circleci/getting-started-with-scheduled-pipelines-38f</link>
      <guid>https://dev.to/circleci/getting-started-with-scheduled-pipelines-38f</guid>
      <description>&lt;p&gt;CircleCI’s scheduled pipelines let you run &lt;a href="https://dev.to/blog/what-is-a-ci-cd-pipeline/"&gt;pipelines&lt;/a&gt; at regular intervals; hourly, daily, or weekly. If you have used &lt;a href="https://dev.to/blog/manual-job-approval-and-scheduled-workflow-runs/"&gt;scheduled workflows&lt;/a&gt;, you will find that replacing them with scheduled pipelines gives you much more power, control, and flexibility. In this tutorial, I will guide you through how scheduled pipelines work, describe some of their cool use cases, and show you how to get started setting up scheduled pipelines for your team. I will demonstrate using both the API and the UI and how you can set up scheduled pipelines from scratch or migrate to them from scheduled workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Here is what you will need to follow the tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://circleci.com/signup/" rel="noopener noreferrer"&gt;CircleCI account&lt;/a&gt; with a project configured&lt;/li&gt;
&lt;li&gt;Some Node.JS knowledge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use the &lt;a href="https://github.com/zmarkan/android-espresso-scrollablescroll" rel="noopener noreferrer"&gt;sample project&lt;/a&gt; as you go through the steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling regular builds and tests
&lt;/h2&gt;

&lt;p&gt;There are many reasons to schedule CI/CD work instead of just executing when you push code to a repository. The first and most obvious reason to schedule is to have regular builds of software. Often folks outside of the development team (product managers, QA engineers, and other stakeholders) need access to the latest build of software you and your team are working on. Of course, you can always trigger a build manually on demand, but that can be distracting for you and other developers on the team. It is so much easier to automate this process and point all the stakeholders to where they can find the newest build. This applies to everything from web apps and mobile apps, to backend services, libraries, and anything in between.&lt;/p&gt;

&lt;p&gt;Scheduled builds automatically build software at night or off-hours when there is no development going on. These nightly builds (as they are sometimes called) take the latest revision off your main branch and produce a staging or beta build of the software.&lt;/p&gt;

&lt;p&gt;You can use scheduled pipelines to run the entire test suite so the nightly build also verifies that your software works and is ready and waiting when you start your next working day. Scheduling allows you to run those expensive and time-consuming functional or integration tests you do not want to run on every commit. The build does not need to be run nightly. You can run it at a cadence that suits your team, every few hours, or even several times per hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling other kinds of work
&lt;/h2&gt;

&lt;p&gt;But why stop at builds? You might also schedule work that is not necessarily a build but needs to happen regularly, like a batch process, database backups, or restarting services. If it can be added to a script on a machine that has access to your environments, it can be done in a CI/CD system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Legacy way of scheduling — scheduled workflows
&lt;/h2&gt;

&lt;p&gt;The ability to schedule work isn’t exactly new to CircleCI. Development teams have been able to include scheduling as part of the configuration, with schedules defined using cron syntax on the workflow level. There are a few downsides to this approach, though:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It requires development work to make any changes to the schedule, or even to review schedules already in place.&lt;/li&gt;
&lt;li&gt;In CircleCI, pipelines are triggered, not workflows.&lt;/li&gt;
&lt;li&gt;Fine-tuning permissions was difficult because it was not always clear who scheduled the work that was triggered.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How scheduled pipelines improve developer experience
&lt;/h2&gt;

&lt;p&gt;Here are some of the benefits of scheduled pipelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can schedule entire pipelines, including any pipeline parameters you want to pass.&lt;/li&gt;
&lt;li&gt;With scheduling handled outside the configuration file, you can query and set schedules using both the API and the UI. This ability provides more flexibility with who manages scheduling and execution.&lt;/li&gt;
&lt;li&gt;Scheduled pipelines work with &lt;a href="https://circleci.com/docs/2.0/contexts/" rel="noopener noreferrer"&gt;contexts&lt;/a&gt;. Contexts give you fine-grained control of who has access to perform and schedule certain jobs. You can gate your deployment credentials to only the engineers with sufficient permissions, so no one else can set up those schedules. Contexts can also be used with dynamic configuration to unlock even more flexibility for your CI/CD setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have covered some basic facts about scheduled pipelines, we can implement one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing a scheduled pipeline
&lt;/h2&gt;

&lt;p&gt;First, we need a pipeline to schedule. Luckily, I have a &lt;a href="https://github.com/zmarkan/android-espresso-scrollablescroll" rel="noopener noreferrer"&gt;project that had used scheduled workflows&lt;/a&gt;. It is an open source Android library project that runs nightly deployments, so it is ideal for scheduling use cases. I recommend that you fork the project on GitHub and set it up as a project on CircleCI.&lt;/p&gt;

&lt;p&gt;For our example schedule, we want to run a build every night and deploy it to the Sonatype snapshots repository. This build makes the repository available for anyone to use and get the freshest code.&lt;/p&gt;

&lt;p&gt;There is a workflow already defined for it in our &lt;code&gt;.circleci/config.yml&lt;/code&gt; - &lt;code&gt;nightly-snapshot&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  parameters:
    run-schedule:
        type: boolean
        default: false

  nightly-snapshot:
    when: &amp;lt;&amp;lt; pipeline.parameters.run-schedule &amp;gt;&amp;gt;
    jobs:
      - android/run-ui-tests:
          name: build-and-test
          system-image: system-images;android-23;google_apis;x86
          test-command: ./gradlew assemble sample:connectedDebugAndroidTest
      - deploy-to-sonatype:
          name: Deploy Snapshot to Sonatype
          requires:
            - build-and-test

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

&lt;/div&gt;



&lt;p&gt;The workflow has two jobs: one to run the tests and another to deploy the snapshot. There is no scheduling logic in the pipeline itself, apart from a &lt;code&gt;when&lt;/code&gt; statement that checks for the &lt;code&gt;run-schedule&lt;/code&gt; pipeline parameter. Our scheduler will set the parameter when triggering the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the API to schedule pipelines
&lt;/h2&gt;

&lt;p&gt;To get started with scheduling using the API, you need the API token. To get the token, log in to CircleCI and click your avatar in the bottom left corner. Clicking your avatar opens User Settings. Navigate to Personal API Tokens, create a new token, and save it somewhere safe. In the sample project there is a &lt;code&gt;build-scheduling&lt;/code&gt; directory, with a file called &lt;code&gt;.env.sample&lt;/code&gt;. You can copy that file to &lt;code&gt;.env&lt;/code&gt; and replace the placeholder token with yours. You should do the same with other parts of the &lt;code&gt;.env&lt;/code&gt; file: &lt;code&gt;PROJECT_ID&lt;/code&gt; and &lt;code&gt;ORG_NAME&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CIRCLECI_TOKEN=YOUR_CIRCLECI_TOKEN
PROJECT_ID=YOUR_PROJECT_ID
ORG_NAME=YOUR_VCS_USERNAME
VCS_TYPE=github

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

&lt;/div&gt;



&lt;p&gt;With environment variables set, we can make the API calls. Scheduled pipelines use the &lt;a href="https://dev.to/blog/introducing-circleci-api-v2/"&gt;CircleCI API v2&lt;/a&gt;. To post a new schedule, you need to make a POST request to the endpoint. The endpoint consists of your CircleCI project, your username, and your VCS provider. Here is an example: &lt;code&gt;https://circleci.com/api/v2/project/github/zmarkan/android-espresso-scrollablescroll/schedule&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This example POST call from the &lt;code&gt;setup_nightly_build.js&lt;/code&gt; script uses Axios JavaScript library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const token = process.env.CIRCLECI_TOKEN

axios.post("https://circleci.com/api/v2/project/github/zmarkan/android-espresso-scrollablescroll/schedule", {
    name: "Nightly build",
    description: "Builds and pushes a new build to Sonatype snapshots every night. Like clockwork.",
        "attribution-actor": "system",
        parameters: {
          branch: "main",
          "run-schedule": true
        },
        timetable: {
            per_hour: 1,
            hours_of_day: [1],
            days_of_week: ["TUE", "WED", "THU", "FRI", "SAT"]
        }
    },{
        headers: { 'circle-token': token }
    }
)

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

&lt;/div&gt;



&lt;p&gt;The body payload contains the schedule name, which must be unique, and an optional description. It includes an attribution actor, which can be either &lt;code&gt;system&lt;/code&gt; for a neutral actor or &lt;code&gt;current&lt;/code&gt;, which takes your current user’s permissions (as per the token you use). The payload also includes parameters like which branch to use when triggering the pipeline and any other parameters you have set up. This tutorial uses &lt;code&gt;run-schedule&lt;/code&gt; in the config file. The last part of the body is the &lt;code&gt;timetable&lt;/code&gt;, which is where we define when and how frequently to run our scheduled pipelines. The fields to use here are &lt;code&gt;per_hour&lt;/code&gt;, &lt;code&gt;hours_of_day&lt;/code&gt;, and &lt;code&gt;days_of_week&lt;/code&gt;. Note that this does not take a cron expression, which makes it more easily parsable by humans reasoning with the API.&lt;/p&gt;

&lt;p&gt;In the headers, we will pass a &lt;code&gt;circle-token&lt;/code&gt; using the token we generated earlier in the CircleCI UI.&lt;/p&gt;

&lt;p&gt;In the timetable, we set everything to run at 1:00 am (UTC), on Tuesday to Saturday, the night after the work has finished. We do not need to run on Sunday and Monday, because in our example project, there is no one working over the weekend. The codebase will not change on those days.&lt;/p&gt;

&lt;p&gt;In addition to the POST method, the API takes exposes other methods such as GET, DELETE, and PUT for retrieving, deleting, and updating schedules. There are samples for &lt;code&gt;get_schedules.js&lt;/code&gt; and &lt;code&gt;delete_schedule.js&lt;/code&gt; in the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the GUI
&lt;/h2&gt;

&lt;p&gt;Instead of using the API, you can set up scheduled pipelines from right in the CircleCI dashboard. From your project in CircleCI, go to Project Settings, and select &lt;strong&gt;Triggers&lt;/strong&gt; from the menu on the left.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Add Scheduled Trigger&lt;/strong&gt; to open the page where you can set up a new scheduled pipeline. The form has the same options as the API: trigger name, days of the week, start time, parameters, attributed user, and the others.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Save Trigger&lt;/strong&gt; to activate it. The trigger will be ready to start scheduling your pipelines at the dates and times you specified.&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%2Fproduction-cci-com.imgix.net%2Fblog%2Fmedia%2F2021-12-02-scheduled-pipeline-triggers.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" 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%2Fproduction-cci-com.imgix.net%2Fblog%2Fmedia%2F2021-12-02-scheduled-pipeline-triggers.png%3Fixlib%3Drb-3.2.1%26w%3D2000%26auto%3Dformat%26fit%3Dmax%26q%3D60%26ch%3DDPR%252CWidth%252CViewport-Width%252CSave-Data" alt="Trigger set up in the GUI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating from scheduled workflows
&lt;/h2&gt;

&lt;p&gt;So far, we have explored setting up the pipelines and reviewing them using both the API and the GUI. Now we can focus on migrating your existing scheduled workflows to the more advantageous scheduled pipelines.&lt;/p&gt;

&lt;p&gt;This example shows a scheduled workflow where everything is defined in the config file. It includes the trigger configuration to the workflow definition, passing in the schedule with the cron expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nightly-snapshot:
    triggers: #use the triggers key to indicate a scheduled build
      - schedule:
          cron: "0 0 * * *" # use cron syntax to set the schedule
          filters:
            branches:
              only:
                - main
    jobs:
      - android/run-ui-tests:
          name: build-and-test
          system-image: system-images;android-23;google_apis;x86
          test-command: ./gradlew assemble sample:connectedDebugAndroidTest
      - deploy-to-sonatype:
          name: Deploy Snapshot to Sonatype
          requires:
            - build-and-test

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

&lt;/div&gt;



&lt;p&gt;In our case, this is run at midnight every day, and we want to trigger it only on the main branch.&lt;/p&gt;

&lt;p&gt;To migrate there are a few steps to complete:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Trigger the existing &lt;code&gt;nightly-snapshot&lt;/code&gt; workflow in the scheduled pipeline.&lt;/li&gt;
&lt;li&gt;Introduce a new pipeline variable called &lt;code&gt;run-schedule&lt;/code&gt;, as we did in the first example.&lt;/li&gt;
&lt;li&gt;For all workflows, add &lt;code&gt;when&lt;/code&gt; expressions that indicate to run them when &lt;code&gt;run-schedule&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt; and not to run other workflows unless &lt;code&gt;run-schedule&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;parameters:
  run-schedule:
    type: boolean
    default: false

workflows:
  build-test-deploy:
    when:
      not: &amp;lt;&amp;lt; pipeline.parameters.run-schedule &amp;gt;&amp;gt;
    jobs:
      ...

  nightly-snapshot:
    when: &amp;lt;&amp;lt; pipeline.parameters.run-schedule &amp;gt;&amp;gt;
    jobs:
      ...

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

&lt;/div&gt;



&lt;p&gt;The rest of the process is the same as when setting up from scratch:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resolve the cron expression; you can use an &lt;a href="https://crontab.guru/#0_0_*_*_*" rel="noopener noreferrer"&gt;online tool like this&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set up the schedule using either the API or the GUI with the new timetable configuration, and the &lt;code&gt;run-schedule&lt;/code&gt; pipeline parameter.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Scheduled pipelines are a versatile component of your CI/CD toolkit, allowing you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger your builds on a recurring basis&lt;/li&gt;
&lt;li&gt;Utilize pipeline parameters&lt;/li&gt;
&lt;li&gt;Fine-tune control of who can set up pipelines&lt;/li&gt;
&lt;li&gt;Clearly define the permissions needed when they run using CircleCI contexts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this tutorial, you have learned about how scheduled pipelines work in CircleCI and how to set them up, either from scratch or porting from scheduled workflows. We also covered how to use the API and the web UI, and reviewed some use cases for them to get you started.&lt;/p&gt;

&lt;p&gt;Let us know how you and your team fare with scheduled pipelines, porting your scheduled workflows, or if you would like to see any additions to the UI or API features.&lt;/p&gt;

&lt;p&gt;If you have any feedback or suggestions about topics I should cover next, reach out to me on &lt;a href="https://twitter.com/zmarkan/" rel="noopener noreferrer"&gt;Twitter - @zmarkan&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>pipelines</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Manage complex development projects by triggering pipelines from other pipelines</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Fri, 10 Dec 2021 10:00:00 +0000</pubDate>
      <link>https://dev.to/circleci/manage-complex-development-projects-by-triggering-pipelines-from-other-pipelines-ak5</link>
      <guid>https://dev.to/circleci/manage-complex-development-projects-by-triggering-pipelines-from-other-pipelines-ak5</guid>
      <description>&lt;p&gt;It is no secret that software development is becoming an increasingly complex process. The individual elements of software like apps, libraries, and services are interconnected and dependent on many other elements. Development teams deal with a whole ecosystem of services that they develop, maintain, or depend on, which in turn are dependent on other software ecosystems, maintained by separate teams. Maintaining this ecosystem is as complex as you might imagine. Making sure the whole system works, and keeps working as intended, is a hugely challenging effort.&lt;/p&gt;

&lt;p&gt;Triggering pipelines from other pipelines is one of many techniques that can help you manage complex connected and interdependent development projects. In this tutorial, I will cover some use cases for using this techniques and why it can be helpful. You can follow along as I present an example of how to implement a pipeline-to-pipeline trigger using CURL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This intermediate to advanced tutorial requires some understanding of CircleCI and its pipelines. It will be especially useful if you use CircleCI and have some projects that have already been configured. Everything covered in this article will work on all &lt;a href="https://circleci.com/pricing/"&gt;CircleCI plans&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use cases for pipeline-to-pipeline triggers
&lt;/h2&gt;

&lt;p&gt;There are several reasons to consider triggering new pipelines from existing pipelines. Microservices orchestration is a prime example. It is a common pattern to have microservices in each respective version control repository, each of which requires a separate CircleCI pipeline configuration. As one service gets deployed, you could redeploy others that depend on this new version. Or you could trigger an expansive suite of &lt;a href="https://dev.to/blog/unit-testing-vs-integration-testing/"&gt;integration tests&lt;/a&gt; that run independently of the wider test and deployment flow.&lt;/p&gt;

&lt;p&gt;If you are not using microservices, you can use pipeline-to-pipeline triggers to publish and test libraries that are integrated with downstream consumers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing pipeline triggers
&lt;/h2&gt;

&lt;p&gt;One workflow for triggering pipelines follows these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first pipeline is executed, makes a build, runs some tests, and triggers a deployment.&lt;/li&gt;
&lt;li&gt;After that process completes successfully, the first pipeline makes an API call to CircleCI to trigger another pipeline in a different project.&lt;/li&gt;
&lt;li&gt;The second pipeline executes a build, runs tests, and triggers a deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this scenario, the first pipeline can also pass some pipeline parameters like the name and version of what was deployed, so that the newly triggered pipeline has some context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coordinating separate services using pipeline triggers
&lt;/h2&gt;

&lt;p&gt;To orchestrate two separate services, you can invoke the CircleCI API from a single job. You will need to know the name of the project with the pipeline you want to trigger from that job. To address a pipeline with an API, you will need the organization name (&lt;code&gt;zmarkan&lt;/code&gt; in my case) and the project name (&lt;code&gt;pinging-me-softly&lt;/code&gt; because I have an odd sense of humor).&lt;/p&gt;

&lt;p&gt;Next, get a personal API token. You must have push access to both projects for this to work. You can store that API token in this project’s environment variable. For increased security, store it in a &lt;a href="https://circleci.com/docs/2.0/contexts/"&gt;context&lt;/a&gt;. In my example, I used a context called &lt;code&gt;circleci-api&lt;/code&gt;, with a &lt;code&gt;CIRCLE_API_TOKEN&lt;/code&gt; name for that environment variable.&lt;/p&gt;

&lt;p&gt;To trigger a pipeline, you will need to send a POST request to the pipeline’s endpoint of the project. This is the URL I used for this tutorial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://circleci.com/api/v2/project/gh/zmarkan/pinging-me-softly/pipeline

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

&lt;/div&gt;



&lt;p&gt;The payload must contain details of the branch or tag you want to trigger the pipeline with, along with any pipeline parameters you want to pass to it.&lt;/p&gt;

&lt;p&gt;Here is an example job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  trigger-new-pipeline:
      docker: 
        - image: cimg/base:2021.11
      resource_class: small
      steps:
        - run:
            name: Ping another pipeline
            command: |
              curl --request POST \
                --url https://circleci.com/api/v2/project/gh/zmarkan/pinging-me-softly/pipeline \
                --header "Circle-Token: $CIRCLECI_API_KEY" \
                --header "content-type: application/json" \
                --data '{"branch":"main","parameters":{"image-name":"'$DOCKER_LOGIN"/"$CIRCLE_PROJECT_REPONAME":"0.1.&amp;lt;&amp;lt; pipeline.number &amp;gt;&amp;gt;'"}}'

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

&lt;/div&gt;



&lt;p&gt;The job uses the &lt;code&gt;cimg/base&lt;/code&gt; image and the &lt;code&gt;small&lt;/code&gt; resource class, which is more than sufficient for sending a single HTTP request. The only dependency is on the CURL tool which ships with all CircleCI images, including &lt;code&gt;cimg/base&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To trigger the pipeline, there is a single command to run: &lt;code&gt;curl&lt;/code&gt;. The API key is passed in the &lt;code&gt;Circle-Token&lt;/code&gt; header, passing in the environment variable that contains the token. The payload body is a JSON object, which contains a &lt;code&gt;branch&lt;/code&gt; and parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  { 
    "branch":"main",
    "parameters": {
        "image-name":"'$DOCKER_LOGIN"/"$CIRCLE_PROJECT_REPONAME":"0.1.&amp;lt;&amp;lt; pipeline/ number&amp;gt;&amp;gt;'"
    }
  }

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

&lt;/div&gt;



&lt;p&gt;The value of the &lt;code&gt;image-name&lt;/code&gt; parameter is a string constructed of three variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$DOCKER_LOGIN&lt;/code&gt; is an environment variable set in this project or in context.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$CIRCLE_PROJECT_REPONAME&lt;/code&gt; is a built-in environment variable that specifies this project in CircleCI.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pipeline.number&lt;/code&gt; is another built-in environment variable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a whole, this value provides the name of the Docker image we built in the previous step. I used &lt;code&gt;zmarkan/demo-full:0.1.119&lt;/code&gt; in &lt;a href="https://app.circleci.com/pipelines/github/zmarkan/pinging-me-softly/9/workflows/b17cb199-cc43-4275-967c-686b47d5824a/jobs/9"&gt;this example&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling the pipeline trigger
&lt;/h2&gt;

&lt;p&gt;The pipeline trigger is handled for you automatically by CircleCI, the same way it handles a new git commit in your repository. By default, all your workflows will run, and it will take the last commit of a branch or tag that you specified in the API call. For this tutorial, I specified &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can handle any parameters you pass (&lt;code&gt;image-name&lt;/code&gt; in my case) in your jobs and workflows. Just make sure to declare them in the &lt;code&gt;parameters&lt;/code&gt; section of the config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  version: 2.1

  parameters:
    image-name:
      type: string
      default: "Not a real image name"

  jobs:
    print-image-name:
      docker: 
        - image: cimg/base:2021.11
      steps:
        - checkout
        - run:
            name: Echo Image name
            command: echo &amp;lt;&amp;lt; pipeline.parameters.image-name &amp;gt;&amp;gt;

  workflows:
    run-workflow:
      jobs:
        - print-image-name

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

&lt;/div&gt;



&lt;p&gt;This pipeline example has a single workflow. It prints out the name of the image we built in the previous pipeline and passed via the API to this pipeline.&lt;/p&gt;

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

&lt;p&gt;In this article I have demonstrated how to use the CircleCI API to trigger another pipeline when the first project’s pipeline is complete. It is a straightforward process that requires a single API call from a running job, and is available to all CircleCI users and organizations.&lt;/p&gt;

&lt;p&gt;This technique opens up new possibilities for orchestrating complex workflows, including microservices architecture, and decoupling expensive integration testing work from build and deploy scenarios. There are many, many more possibilities for you and your team to experiment with.&lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions about this article, or ideas for future articles and guides, reach out to me on &lt;a href="https://twitter.com/zmarkan"&gt;Twitter - @zmarkan&lt;/a&gt; or &lt;a href="//mailto:zan@circleci.com"&gt;email me&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>pipelines</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Building Kotlin Multiplatform projects in a CI/CD pipeline</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Wed, 06 Oct 2021 12:00:00 +0000</pubDate>
      <link>https://dev.to/circleci/building-kotlin-multiplatform-projects-in-a-cicd-pipeline-142e</link>
      <guid>https://dev.to/circleci/building-kotlin-multiplatform-projects-in-a-cicd-pipeline-142e</guid>
      <description>&lt;p&gt;&lt;a href="https://kotlinlang.org/"&gt;Kotlin&lt;/a&gt; is one of the most versatile programming languages available, in large part because of the Kotlin team’s focus on bringing it to as many platforms as possible. It is the primary language for developing Android applications and is popular for JVM backends. Kotlin also features targets for native binary compilation with Kotlin/Native, and for web through Kotlin/JS. One of its most promising features is the ability to target multiple platforms it compiles to.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://kotlinlang.org/docs/mobile/getting-started.html"&gt;Kotlin Multiplatform Mobile (KMM)&lt;/a&gt; comes in: it lets you write and reuse the same Kotlin code across Android and iOS applications. As mobile clients often aim for feature parity, this is a clever approach to avoid duplicating work, and we all know how developers love avoiding duplicate work. Trust me, I’m a developer and I know how true this is.&lt;/p&gt;

&lt;p&gt;Anyway, back to Kotlin Multiplatform. This is a different approach from cross-platform tools such as Flutter and React Native, which provide unified UI on top of everything. KMM lets you write common business logic while keeping the user interface and experience firmly in the domain of their native platforms. In many cases, that approach is preferable to application users, and therefore your customers.&lt;/p&gt;

&lt;p&gt;This article will show you how to get started building KMM projects in a &lt;a href="https://circleci.com/blog/what-is-a-ci-cd-pipeline/"&gt;CI/CD pipeline&lt;/a&gt;, and include that in your team's development workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes for following along
&lt;/h2&gt;

&lt;p&gt;This article assumes understanding of Kotlin, as well as familiarity with at least one of Android or iOS, ideally both platforms. This article does not teach you KMM. For that, review one of existing tutorials on the Kotlin’s site, or the Readme from the sample application.&lt;/p&gt;

&lt;p&gt;Also note: KMM is currently in Alpha version. The technology and the APIs are constantly changing and evolving and we are doing our best to keep the samples working and up to date, yet it should come with no guarantees beyond the API versions in the samples. &lt;/p&gt;

&lt;h1&gt;
  
  
  Building multiplatform projects in a CI/CD pipeline
&lt;/h1&gt;

&lt;p&gt;To build a multiplatform project in the context of CI/CD think of it as building distinct projects for each individual target platform.&lt;br&gt;
&lt;a href="https://github.com/CircleCI-Public/kmm-production-sample"&gt;Our project&lt;/a&gt; is based on &lt;a href="https://github.com/Kotlin/kmm-production-sample"&gt;Kotlin's own Multiplatform sample - a RSS reader application&lt;/a&gt;. It contains 2 apps, as well as a shared Kotlin codebase in the form of a Kotlin library. The shared library stays in Kotlin for compilation on Android, and compiles down to native code to run on ARM64 for iOS targets.&lt;/p&gt;

&lt;p&gt;Android app code is located in &lt;code&gt;androidApp&lt;/code&gt;, and written in a familiar Kotlin codebase. The iOS app is written in Swift, and located in &lt;code&gt;iosApp&lt;/code&gt;. To understand how KMM makes everything work, check out the official KMM documentation &lt;a href="https://kotlinlang.org/docs/mobile/home.html"&gt;documentation&lt;/a&gt; and the &lt;a href="https://github.com/Kotlin/kmm-production-sample"&gt;sample project&lt;/a&gt; on Kotlin's GitHub repo that this project is based off.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building a basic pipeline
&lt;/h2&gt;

&lt;p&gt;The simplest CI/CD pipeline for KMM projects contains 2 jobs in a single workflow, that execute the build for each respective platform. Jobs in CircleCI are a succession of commands or steps, which execute in a predetermined environment. This environment is the key to building the app for different platforms. For iOS, we need to build it on Mac hardware, passing in &lt;code&gt;macos&lt;/code&gt; for executor. Android is more permissive, but we can still pick a pre-built environment that contains all the SDKs and everything else built in. For this tutorial, we will use the &lt;code&gt;android&lt;/code&gt; Docker image as provided by the &lt;code&gt;android&lt;/code&gt; orb.&lt;/p&gt;

&lt;p&gt;The jobs themselves are straightforward and not really relevant for this tutorial: check out the code, compile, maybe run some tests, build, maybe even deploy. As part of this guide we will not focus on the jobs. Instead we will spend some time setting up the environment and workflows for the build. If you want to learn more about setting up the build and test job for Android you can read about it in &lt;a href="https://circleci.com/blog/building-android-on-circleci/"&gt;this post&lt;/a&gt;. If you want to learn more about setting up the build and tests on iOS, you can read more in &lt;a href="https://circleci.com/docs/2.0/ios-tutorial/"&gt;this tutorial in the CircleCI documentation&lt;/a&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;orbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/android@1.0.3&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-android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;android/android&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/restore-build-cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/restore-gradle-cache&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;./gradlew androidApp:assembleDebug&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/save-gradle-cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/save-build-cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;androidApp/build/outputs/apk/debug&lt;/span&gt;
  &lt;span class="na"&gt;build-ios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;macos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;xcode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;12.4.0&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow proper XCode dependency resolution&lt;/span&gt;
          &lt;span class="na"&gt;command&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 defaults write com.apple.dt.Xcode IDEPackageSupportUseBuiltinSCM YES&lt;/span&gt;
            &lt;span class="s"&gt;rm ~/.ssh/id_rsa || true&lt;/span&gt;
            &lt;span class="s"&gt;for ip in $(dig @8.8.8.8 bitbucket.org +short); do ssh-keyscan bitbucket.org,$ip; ssh-keyscan $ip; done 2&amp;gt;/dev/null &amp;gt;&amp;gt; ~/.ssh/known_hosts || true&lt;/span&gt;
            &lt;span class="s"&gt;for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan github.com,$ip; ssh-keyscan $ip; done 2&amp;gt;/dev/null &amp;gt;&amp;gt; ~/.ssh/known_hosts || true&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Gem dependencies&lt;/span&gt;
          &lt;span class="na"&gt;command&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 iosApp&lt;/span&gt;
            &lt;span class="s"&gt;bundle install&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fastlane Tests&lt;/span&gt;
          &lt;span class="na"&gt;command&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 iosApp&lt;/span&gt;
            &lt;span class="s"&gt;fastlane scan&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iosApp/fastlane/test_output&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_test_results&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iosApp/fastlane/test_output/report.junit&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-all&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="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build-android&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build-ios&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Building the Android app
&lt;/h3&gt;

&lt;p&gt;The best way to start building Android apps is by using the Android orb. This gives you a few built-in jobs and commands that make it easier to build. For this exercize, we are installing Gradle dependencies, and running a Gradle command to run the unit tests.&lt;/p&gt;

&lt;p&gt;The main difference Kotlin Multiplatform brings is that the app is not the top level project. Instead, it is located in the &lt;code&gt;androidApp&lt;/code&gt; module. This module has a dependency on &lt;code&gt;shared&lt;/code&gt;, so we need to invoke Gradle commands with the &lt;code&gt;androidApp:&lt;/code&gt; prefix.&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;orbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/android@1.0.3&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-android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;android/android&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/restore-build-cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/restore-gradle-cache&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;./gradlew androidApp:assembleDebug&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/save-gradle-cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/save-build-cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;androidApp/build/outputs/apk/debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Building the iOS app
&lt;/h3&gt;

&lt;p&gt;As we mentioned above, building iOS apps requires Mac hardware with XCode installed. For the &lt;code&gt;build-ios&lt;/code&gt; job, we will use &lt;code&gt;macos&lt;/code&gt; executor where we pass the xcode version as parameter. In our case it is: &lt;code&gt;xcode: 12.4.0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The rest of the steps are common, regardless of whether you use CocoaPods or Swift Package Manager. You will usually install some dependencies, and then you can build the app and run the tests using Fastlane. For this tutorial, we will just run some tests.&lt;/p&gt;

&lt;p&gt;The shared Kotlin code is automatically built as a framework when we initiate a build with Fastlane, so there is nothing left to do here.&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
 &lt;span class="s"&gt;build-ios&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;macos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;xcode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;12.4.0&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow proper XCode dependency resolution&lt;/span&gt;
          &lt;span class="na"&gt;command&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 defaults write com.apple.dt.Xcode IDEPackageSupportUseBuiltinSCM YES&lt;/span&gt;
            &lt;span class="s"&gt;rm ~/.ssh/id_rsa || true&lt;/span&gt;
            &lt;span class="s"&gt;for ip in $(dig @8.8.8.8 bitbucket.org +short); do ssh-keyscan bitbucket.org,$ip; ssh-keyscan $ip; done 2&amp;gt;/dev/null &amp;gt;&amp;gt; ~/.ssh/known_hosts || true&lt;/span&gt;
            &lt;span class="s"&gt;for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan github.com,$ip; ssh-keyscan $ip; done 2&amp;gt;/dev/null &amp;gt;&amp;gt; ~/.ssh/known_hosts || true&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Gem dependencies&lt;/span&gt;
          &lt;span class="na"&gt;command&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 iosApp&lt;/span&gt;
            &lt;span class="s"&gt;bundle install&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fastlane Tests&lt;/span&gt;
          &lt;span class="na"&gt;command&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 iosApp&lt;/span&gt;
            &lt;span class="s"&gt;fastlane scan&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iosApp/fastlane/test_output&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_test_results&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iosApp/fastlane/test_output/report.junit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating an advanced pipeline with dynamic config
&lt;/h2&gt;

&lt;p&gt;This sample pipeline works well to build and test both target platforms of your KMM app every time someone commits to the repository. But we can do better. The reality of mobile development is that we have specialists focusing their work on their respective platforms. There are the folks who like and use Android, love crafting great UX and experiences for Android, and know the platform inside and out. On the other hand, there are developers who focus on iOS in the same way. There is always some cross over working on the common codebase. There will still be individuals who specialize on either one or the other platform on most teams. &lt;/p&gt;

&lt;p&gt;Development progress usually takes shape in one of these configurations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android frontend codebase only&lt;/li&gt;
&lt;li&gt;iOS frontend codebase only&lt;/li&gt;
&lt;li&gt;Shared KMM codebase that is consumed by both frontend codebases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the first two scenarios, building only for the platform being worked on makes much more sense, and saves time, credits, and efficiency.&lt;/p&gt;

&lt;p&gt;To optimize this flow we can use CircleCI’s dynamic config feature, which helps us orchestrate projects like this much more efficiently. Dynamic config lets you build only the parts of the app that you have changed.&lt;/p&gt;

&lt;p&gt;Dynamic config works through a setup workflow, which in the first step evaluates the codebase, detects what has changed (more on this a bit later), and only then runs the &lt;strong&gt;&lt;em&gt;real&lt;/em&gt;&lt;/strong&gt; workflow, the one that is building the portion of the app that is relevant.&lt;/p&gt;

&lt;p&gt;The setup workflow still uses the &lt;code&gt;config.yml&lt;/code&gt; that CircleCI users are probably familiar with. The workflow that gets executed uses a path filtering orb, which detects the changes compared to a specified branch. Here is the full config.&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;setup&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;orbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# the path-filtering orb is required to continue a pipeline based on&lt;/span&gt;
  &lt;span class="c1"&gt;# the path of an updated fileset&lt;/span&gt;
  &lt;span class="na"&gt;path-filtering&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/path-filtering@0.0.2&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;select-for-build&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="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path-filtering/filter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;base-revision&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;config-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.circleci/continue-config.yml&lt;/span&gt;
          &lt;span class="na"&gt;mapping&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;shared/.*|^(?!shared/.*|iosApp/.*|androidApp/.*).*  build-all     true&lt;/span&gt;
            &lt;span class="s"&gt;androidApp/.*                                       build-android true&lt;/span&gt;
            &lt;span class="s"&gt;iosApp/.*                                           build-ios     true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a break down of this config:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;setup:true&lt;/code&gt; indicates to CircleCI that we are using dynamic configuration, and that this is the first part of the pipeline to run. The setup workflow is this configuration’s only workflow. It has a single job, &lt;code&gt;path-filtering/filter&lt;/code&gt;, which is from the &lt;code&gt;path-filtering&lt;/code&gt; orb. The job takes a few parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;base-revision&lt;/code&gt; indicates the branch to compare against&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mapping&lt;/code&gt; determines which paths to compare (more about this later)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;config-path&lt;/code&gt; points to &lt;code&gt;continue-config.yml&lt;/code&gt;, which is the next config to evaluate after this setup workflow. In our case we are pointing to a static file, but we could also construct this new configuration file programmatically beforehand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To use &lt;code&gt;mapping&lt;/code&gt;, you define the paths of the project to compare against the codebase in the base revision. There is one path per line. Then, set a pipeline parameter to pass to the subsequent pipeline, and its value. All these are separated by whitespace.&lt;/p&gt;

&lt;p&gt;Lines 2 and 3 are fairly straightforward:&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="s"&gt;androidApp/.* build-android  &lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the path we are interested in is all files and subdirectories in &lt;code&gt;androidApp/&lt;/code&gt; directory. That is where the codebase for the Android-specific frontend is. The pipeline parameter, &lt;code&gt;build-android&lt;/code&gt;, is set to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first matching line however is more complex because of the much longer regex matcher:&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="s"&gt;shared/.*|^(?!shared/.*|iosApp/.*|androidApp/.*).*  build-all  &lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It matches paths in both &lt;code&gt;shared/&lt;/code&gt; directory, which is where our Kotlin multiplatform code is located, as well as anything that is not in &lt;code&gt;shared/&lt;/code&gt;, &lt;code&gt;iosApp/&lt;/code&gt;, or &lt;code&gt;androidApp/&lt;/code&gt; directories, which includes any other top level files. We have set the pipeline parameter &lt;code&gt;build-all&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;, which will trigger builds of the apps for both platform.&lt;/p&gt;

&lt;p&gt;As specified in &lt;code&gt;continue-config.yml&lt;/code&gt;, after the mapping has evaluated all changes and set all relevant pipeline parameters, CircleCI stops this job, and kicks off the second part of this dynamic workflow. Here is the complete 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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;orbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/android@1.0.3&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boolean&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;build-android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boolean&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;build-ios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boolean&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&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-android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;android/android&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/restore-build-cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/restore-gradle-cache&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Android app&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;./gradlew androidApp:assembleDebug&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/save-gradle-cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;android/save-build-cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;androidApp/build/outputs/apk/debug&lt;/span&gt;
  &lt;span class="na"&gt;build-ios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;macos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;xcode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;12.4.0&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow proper XCode dependency resolution&lt;/span&gt;
          &lt;span class="na"&gt;command&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 defaults write com.apple.dt.Xcode IDEPackageSupportUseBuiltinSCM YES&lt;/span&gt;
            &lt;span class="s"&gt;rm ~/.ssh/id_rsa || true&lt;/span&gt;
            &lt;span class="s"&gt;for ip in $(dig @8.8.8.8 bitbucket.org +short); do ssh-keyscan bitbucket.org,$ip; ssh-keyscan $ip; done 2&amp;gt;/dev/null &amp;gt;&amp;gt; ~/.ssh/known_hosts || true&lt;/span&gt;
            &lt;span class="s"&gt;for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan github.com,$ip; ssh-keyscan $ip; done 2&amp;gt;/dev/null &amp;gt;&amp;gt; ~/.ssh/known_hosts || true&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Gem dependencies&lt;/span&gt;
          &lt;span class="na"&gt;command&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 iosApp&lt;/span&gt;
            &lt;span class="s"&gt;bundle install&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fastlane Tests&lt;/span&gt;
          &lt;span class="na"&gt;command&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 iosApp&lt;/span&gt;
            &lt;span class="s"&gt;fastlane scan&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iosApp/fastlane/test_output&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_test_results&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iosApp/fastlane/test_output/report.junit&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;run-android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;or&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt; pipeline.parameters.build-android &amp;gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt; pipeline.parameters.build-all &amp;gt;&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build-android&lt;/span&gt;
  &lt;span class="na"&gt;run-ios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;or&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt; pipeline.parameters.build-ios &amp;gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt; pipeline.parameters.build-all &amp;gt;&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build-ios&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;setup:true&lt;/code&gt; line is not included here, which indicates that this is a ‘standard’ CircleCI configuration file. It does contain the &lt;code&gt;parameters&lt;/code&gt; section with the pipeline parameters we defined in the previous stage.&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;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boolean&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;build-android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boolean&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;build-ios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boolean&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use pipeline parameters we first need to define them in the pipeline. We used them earlier. Now you specify their types and default values: all &lt;code&gt;boolean&lt;/code&gt; and set to &lt;code&gt;false&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;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;run-android&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;or&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt; pipeline.parameters.build-android &amp;gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt; pipeline.parameters.build-all &amp;gt;&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build-android&lt;/span&gt;
  &lt;span class="na"&gt;run-ios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;or&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt; pipeline.parameters.build-ios &amp;gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt; pipeline.parameters.build-all &amp;gt;&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build-ios&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the parameters are defined, we can use them when filtering workflows. Unlike the much simpler config shown the previous section, we need to split the jobs across 2 workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The job for Android is named &lt;code&gt;run-android&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The job for iOS is named &lt;code&gt;run-ios&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can use the &lt;code&gt;when&lt;/code&gt; stanza combined with logical operators to specify filters for when to run a particular workflow. For Android, it is either a &lt;code&gt;build-all&lt;/code&gt; or &lt;code&gt;build-android&lt;/code&gt; pipeline parameter. For iOS, it is a &lt;code&gt;build-ios&lt;/code&gt; or &lt;code&gt;build-all&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This workflow runs selectively based on the changed files that run the jobs relevant to the workflow. This set up lets your team operate faster and more efficiently, while still leveraging all the multiplatform capabilities of KMM.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In this tutorial, you have learned how to set up a pipeline that builds Kotlin Multiplatform Mobile projects on CircleCI. It is similar to building any other project, except for knowing which platform to build for first. Mobile platforms are often developed separately, so we have used the CircleCI dynamic configuration feature to build just the portion of the app developers are currently working on.&lt;/p&gt;

&lt;p&gt;If you have any questions or suggestions about this article, or ideas for future articles and guides, reach out to me on  &lt;a href="https://twitter.com/zmarkan"&gt;Twitter - @zmarkan&lt;/a&gt; or &lt;a href="//mailto:zan@circleci.com"&gt;email me&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>kotlin</category>
      <category>mobile</category>
      <category>circleci</category>
    </item>
    <item>
      <title>What I learned in 6 months at an AI company</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Thu, 21 May 2020 17:04:39 +0000</pubDate>
      <link>https://dev.to/zmarkan/what-i-learned-in-6-months-at-an-ai-company-459k</link>
      <guid>https://dev.to/zmarkan/what-i-learned-in-6-months-at-an-ai-company-459k</guid>
      <description>&lt;p&gt;Back in January I joined a company called &lt;a href="https://datarobot.com" rel="noopener noreferrer"&gt;DataRobot&lt;/a&gt; as a Developer Advocate. My job is to inspire, enable, and represent developers using our machine learning (ML) products. &lt;br&gt;
If you're not familiar with DataRobot, we provide artificial intelligence (AI) products and solutions to some of the world's largest and well known enterprises and governmental organizations. &lt;/p&gt;

&lt;p&gt;Before joining, I had no meaningful experience in ML, data science, or AI. The farthest I got to ML was building an AI powered chatbot for a product I used to work with. I just knew that ML was &lt;em&gt;hard&lt;/em&gt; 😅. &lt;br&gt;
Since then I have built a few AI powered apps of my own, so I feel like I can talk a bit more about it. This article describes some of the things I learned in my first half year in the AI and ML industry - going from complete newbie to someone who can leverage ML in apps.&lt;/p&gt;

&lt;h1&gt;
  
  
  AI is everywhere! 🗺
&lt;/h1&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%2Fphc3j2dzlfhxxbb4txv5.jpg" 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%2Fphc3j2dzlfhxxbb4txv5.jpg" alt="hong kong city Photo by Alexandre .L on Unsplash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used to dismiss ML as &lt;em&gt;just another hype&lt;/em&gt;, in the same bucket as blockchain or virtual reality. I thought it was mostly confined to Big Tech, academia, and hobbyists, definitely not something you'd interact with on a daily basis.&lt;/p&gt;

&lt;p&gt;This was mostly true... &lt;strong&gt;about a decade ago&lt;/strong&gt;. Boy, was I wrong.&lt;/p&gt;

&lt;p&gt;The reality is, many organizations you interact with on a daily basis use ML in some way in their business, without you even realising. Your bank might use ML for fraud detection, your supermarket to forecast how much flour to stock, or a factory might use it to detect defects in the products they produce before they get to you. &lt;/p&gt;

&lt;p&gt;Where ML especially shines is with economies of scale. When you have huge amounts of data to run through - imagine the number of transactions a bank or a large retailer might process, and even savings in the low single digit percentages compound dramatically. &lt;br&gt;
These are only a few examples, but ML is often good fit in many areas where you want to automate and augment tasks that would otherwise be hard, or tedious for human workers... Now where have I heard this one before? 🤔 &lt;/p&gt;

&lt;p&gt;There's a reason why we call the current rise and rise of AI &lt;strong&gt;the Fourth Industrial Revolution&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Machine Learning is super hard... 😱
&lt;/h1&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%2Fkh216otassrzd8qalp5r.jpg" 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%2Fkh216otassrzd8qalp5r.jpg" alt="bicycle race Photo by Florian Schmaezz on Unsplash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As an industry, ML is evolving rapidly&lt;/strong&gt;. It's a moving target on all fronts - algorithms, frameworks, hardware, to use cases ranging from academic projects like AlphaGo, to self driving cars, to medical and health research. There's lots of hard science at work pushing the boundaries of what's possible. All of this progress is incredibly difficult to keep track of, and ensure you're really following the best practices.&lt;/p&gt;

&lt;p&gt;Beyond all the technical difficulties of the bleeding edge, you have some great &lt;strong&gt;operational challenges&lt;/strong&gt; as well. For example, once you've trained a model, how do you ensure that your model &lt;em&gt;remains&lt;/em&gt; accurate over time. This is crucial, especially when data you're using starts to change in ways you haven't foreseen, and your models aren't reflective of the real world. &lt;/p&gt;

&lt;p&gt;Last but not least, there are also &lt;strong&gt;challenges with governance and AI bias&lt;/strong&gt;. Most AIs are seen as black boxes where you can't know why a certain answer was given. If a laboratory wants to use AI to help produce a diagnosis, they can't risk relying on a black box when human lives are at stake.&lt;/p&gt;

&lt;h1&gt;
  
  
  ...but using ML doesn't have to be a struggle 🦸‍♀️
&lt;/h1&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%2Foxa2je9zu5zc7mf1ayah.jpg" 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%2Foxa2je9zu5zc7mf1ayah.jpg" alt="View over the mountains Photo by Simon Berger on Unsplash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luckily, &lt;strong&gt;today's bleeding edge is more accessible than ever&lt;/strong&gt;. We've solved many hard things. &lt;br&gt;
You don't need a degree in electronics to use a computer, or a networking degree to be a web developer, you don't need a data science degree anymore to build and deploy AI. The whole AI industry is moving towards democratization, and enabling everyone to work with, and benefit from AI.&lt;br&gt;
There are awesome tools out there that let you build and leverage leverage models, and you don't even need to touch the frameworks like Tensorflow or Pytorch yourself.&lt;/p&gt;

&lt;p&gt;Take &lt;strong&gt;Automated Machine Learning (AutoML)&lt;/strong&gt; for example. AutoML is DataRobot's product and an associated technique that lets you train dozens of ML models using a variety of algorithms on a single dataset, pitting them against each other in order to determine which model is the best for your data. What used to take days can now be accomplished in mere minutes. New and refined algorithms are constantly being added to AutoML tools, making the models they produce ever better and better. All you need to do is to press a button. &lt;/p&gt;

&lt;p&gt;We have also made some serious progress towards overcoming operational and governance challenges I mentioned earlier. We have tools available that let you &lt;strong&gt;monitor your ML models&lt;/strong&gt; in the wild and that let you know if a model is at risk of becoming inaccurate due to changes in underlying data (we call that data drift). &lt;br&gt;
Our models are also not black boxes anymore, and we can explain with increasing confidence why a given model has returned a certain prediction. Unsurprisingly, this field is called &lt;strong&gt;Explainable AI&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Difficulties with Data Dealing 🐘
&lt;/h1&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%2Fs4c1ip7zf3qo3w4lqqr0.jpg" 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%2Fs4c1ip7zf3qo3w4lqqr0.jpg" alt="Playing cards Photo by Amanda Jones on Unsplash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For all the problems we've solved already, one thing remains clear - we need data for machine learning, and obtaining that data for ML is difficult. &lt;/p&gt;

&lt;p&gt;Datasets need to be representative of your problem domain. In very few cases are you able to apply a dataset from the web that works well for your own use-case. Face and object detection is a good example of where that works - that's why many companies are in the business of providing AI-powered image and speech recognition software and services. &lt;/p&gt;

&lt;p&gt;Often you will also need to combine multiple data sources from various sections of the business into a single learning dataset (unless you're lucky and have a data warehouse at hand already).&lt;br&gt;
For this, SQL rules the world. Sometimes you need to revisit your SQL knowledge because you have obviously forgotten everything apart from the most basic commands in the last 8-ish years. Speaking for a friend, of course. 😇&lt;/p&gt;

&lt;p&gt;Finally, and this might be pretty shocking for developers, but sometimes constructing a good training dataset also requires lots of human effort at some point in the process. Whether you're manually classifying a dataset you're preparing, or validating the output of a script - it's eyes before AI. 👀&lt;/p&gt;

&lt;h1&gt;
  
  
  The Pervasive Popularity of Python 🐍
&lt;/h1&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%2Fua8x1rm4km9wgqzgbtqn.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%2Fua8x1rm4km9wgqzgbtqn.png" alt="A man teaching snakes programming - meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://python.org" rel="noopener noreferrer"&gt;Python&lt;/a&gt; is one of the most popular programming languages. I knew that, yet it still surprised me. This shouldn't be strange as it's the one language that caters to both data scientists as well as developers (as opposed to say Java, R, or Matlab). Python lets you build both apps, and manipulate large sets of data with the same syntax.&lt;/p&gt;

&lt;p&gt;One of Python's strongest suits is it's readability. Python reads like English - it's probably the most English-like out of all programming languages. This makes it incredibly accessible for learning. It also has a mature set of libraries for a wide range of use-cases, from web development to scientific computing, giving it a broad appeal.&lt;br&gt;
Yet, not everything about Python is perfect. The language is almost 30 years old, some 5 years senior to Java, JavaScript, and PHP, and this age shows. One of my pet peeves is the situation with dependency management. Sure, it comes with a package manager with PyPI, but the only way to ensure you're isolating your environment properly is by using an archaic combination of console commands to create and initialise Virtualenv. I find Virtualenv so confusing &lt;a href="https://gist.github.com/zmarkan/50844676b14aebafa15f212361863db9" rel="noopener noreferrer"&gt;that I have a gist I can refer to each time I deal with a new project&lt;/a&gt; 🙈.&lt;/p&gt;

&lt;p&gt;Finally, the ways developer and data scientists might use Python are &lt;em&gt;vastly&lt;/em&gt; different. Sure, the syntax is the same, but the ecosystems vary wildly. From the libraries and frameworks you might use for either development or data science, all the way to tools used and best practices followed.&lt;/p&gt;

&lt;p&gt;For example, data scientists love their &lt;a href="https://jupyter.org/" rel="noopener noreferrer"&gt;Jupyter notebooks&lt;/a&gt; 📓. They are a sort of dynamic, executable documentation, where you write part markdown and part code, and then execute it alongside the documentation - rendering spreadsheets and graphs side by side! They are the preferred way to interact with &lt;a href="https://kaggle.com" rel="noopener noreferrer"&gt;Kaggle&lt;/a&gt; competitions and datasets. This concept is great for experimentation and therefore ideal for data scientists, yet not at all suited for building and maintaining production software - something I cherish more as a developer. What's more - all that fancy dynamic approach generates some extremely hard to review JSON code, if you ever decide to host that on GitHub 😬.&lt;/p&gt;

&lt;h1&gt;
  
  
  What about the Rise of the Robots? 🤖
&lt;/h1&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%2Fl4uaj7oepbrt2grm7f8i.jpg" 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%2Fl4uaj7oepbrt2grm7f8i.jpg" alt="Humanoid robot Photo by Franck V. on Unsplash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You've probably encountered film, books, or games talking about the rise and revolt of intelligent machines - the Matrix, Terminator, 2001: A Space Odyssey, and many others. It's easy for media to paint a bleak picture.&lt;/p&gt;

&lt;p&gt;Yet, from what I've seen so far, we have little to fear from the AI that we currently possess. Indeed, AI is developing at a rapid pace - some of the brightest people I know are working hard on pushing the boundaries. &lt;/p&gt;

&lt;p&gt;At the same time, it's become more and more accessible for you and me to build - and benefit from - AI, and we have some amazing tools available that make it easy to approach.&lt;/p&gt;

&lt;p&gt;So, if you'd like to see what the bleeding edge looks like and what it can do, we recently opened a trial for DataRobot for developers. If you'd like to try out the latest and greatest of ML tools, please reach out to me for access to DataRobot trial - at &lt;a href="mailto:zan@datarobot.com"&gt;zan@datarobot.com&lt;/a&gt;, quoting dev.to in the subject.&lt;/p&gt;

&lt;p&gt;That's just a few thoughts on my perspective after 6 months in the AI industry. There has been a lot of learning, and a lot of surprises, and I'm more enthusiastic about the future than ever, and how dramatically our lives will change because of it. &lt;br&gt;
What about you? What are your thoughts and perspectives on AI and the tools that are available? Let me know in the comments!&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>ai</category>
      <category>development</category>
      <category>career</category>
    </item>
    <item>
      <title>Why I believe in the brave new world of serverless</title>
      <dc:creator>Zan Markan</dc:creator>
      <pubDate>Thu, 30 May 2019 15:02:49 +0000</pubDate>
      <link>https://dev.to/pusher/why-i-believe-in-the-brave-new-world-of-serverless-42n7</link>
      <guid>https://dev.to/pusher/why-i-believe-in-the-brave-new-world-of-serverless-42n7</guid>
      <description>&lt;p&gt;A few days ago I took part in a lunch &amp;amp; learn session at work, where we discussed the paper &lt;a href="https://arxiv.org/pdf/1812.03651.pdf"&gt;Serverless Computing - One step forward, two steps back&lt;/a&gt;. It was an excellent discussion, and if there weren't any time constraints I'm sure we could have talked about it for the rest of the week, not just our lunch hour.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; In my eyes, serverless is not just AWS Lambda functions. Or Azure, Google, or IBM/Apache Openwhisk. It's all the other technologies that work well alongside it - databases, queues, event-driven computation, and technologies that make it super easy to configure and deploy new services in code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What made it such a great discussion is the fact that while most technologies are polarizing, only a few are as deeply polarizing as serverless. &lt;/p&gt;

&lt;p&gt;The Serverless Hater's greatest hits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;serverless has servers&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;I can't use it for machine learning or [insert obscure academic research topic here]&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;&lt;em&gt;It's more expensive than renting your own EC2 instances and running your own servers!&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Vendor lock-in!&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;It's slow!&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;I can't run it on custom hardware!&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these… are true in their sense. Not all use cases are well supported by serverless technologies (or at all). &lt;br&gt;
My argument is just that… it doesn't really matter. There are two main reasons for it.&lt;/p&gt;
&lt;h1&gt;
  
  
  Reason 1: The new liberal computing 🗽
&lt;/h1&gt;

&lt;p&gt;Most profoundly, serverless is just a marketing name (yet a pretty good one - it certainly has &lt;a href="https://www.marketingweek.com/2014/10/22/marmite-the-marketing-story-even-the-haters-love/"&gt;that Marmite quality…&lt;/a&gt;) for a new computing paradigm - an idea. &lt;/p&gt;

&lt;p&gt;It's the idea of writing some code and letting the vendor deploy it anywhere without worrying too much about the where, how, or how much maintaining it is going to cost you, as you only pay per invocation. Serverless is about making it simple and fun to experiment. It's what Heroku was, but more. &lt;/p&gt;

&lt;p&gt;The &lt;a href="https://serverless.com"&gt;Serverless framework&lt;/a&gt; (with a capital S) makes most of your configurations portable between vendors, and opinionated frameworks like &lt;a href="https://arc.codes"&gt;Architect&lt;/a&gt; make it great for quick productivity.&lt;/p&gt;

&lt;p&gt;Tools like &lt;a href="https://glitch.com"&gt;Glitch&lt;/a&gt;, in addition to being beautifully weird, lets you tinker with deployed code from users of the whole platform, directly in your web browser, like GitHub without any of the git.&lt;/p&gt;

&lt;p&gt;To paraphrase &lt;a href="https://twitter.com/pawel_ledwon"&gt;Paweł Ledwoń&lt;/a&gt;, our CTO at Pusher - &lt;em&gt;"Serverless might be this generation's PHP"&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;That's awesome. PHP made a whole generation build things. &lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1132826772976701440-819" src="https://platform.twitter.com/embed/Tweet.html?id=1132826772976701440"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1132826772976701440-819');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1132826772976701440&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Just like PHP did back in the day, serverless is opening doors to programming to the new generation of app developers (also known as "&lt;em&gt;kids these days&lt;/em&gt;"). &lt;br&gt;
Returning to my earlier point, as of why the arguments against serverless (mostly) don't matter? As long as serverless (or any technology, or computing paradigm) is able to lower the barrier to entry to, the playing field has expanded enough, so that it has free rein to take up a bunch of new market share. As the market grows, the earlier arguments merely become fringe or niche concerns.&lt;/p&gt;

&lt;p&gt;And the kids? They are the ones who are going to build the future - &lt;em&gt;The kids are alright&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
   Reason 2: Birth of an ecosystem (of ecosystems), and mash it like it's 2005 🕺
&lt;/h1&gt;

&lt;p&gt;The idea of "just" liberalizing computing was mostly true for the first generation of serverless, way back when Lambda was new. In 2019, serverless is also liberalizing how easy it is for services to interact with one another. It's increasingly being used to extend the functionality of existing services with whatever you really wish to create - flows, extended logic, you name it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pusher.com/docs/chatkit/webhooks"&gt;Webhooks&lt;/a&gt; &lt;a href="https://pusher.com/docs/beams/concepts/webhooks"&gt;are&lt;/a&gt; &lt;a href="https://pusher.com/docs/channels/server_api/webhooks"&gt;everywhere&lt;/a&gt;, and let you integrate and glue services together, with ease. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://zeit.co/now"&gt;Zeit Now&lt;/a&gt; lets you make any app serverless, and deploy it in seconds, with one command. They have also launched an integration marketplace, that lets developers connect other services, and manage them from Zeit. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;The good people at Zeit are also running &lt;a href="https://zeit.co/hackathon"&gt;a global hackathon&lt;/a&gt; with some cool prizes &lt;strong&gt;between 1 and 2 June 2019&lt;/strong&gt;, and &lt;a href="https://pusher.com"&gt;Pusher&lt;/a&gt; is one of the sponsors. If you're building something with Pusher APIs, please come &lt;a href="https://twitter.com/zmarkamn"&gt;talk to me&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We also we have &lt;a href="https://www.netlify.com/products/functions/"&gt;Netlify Functions&lt;/a&gt; -they let you add dynamic components to otherwise static sites that deploy in seconds. &lt;/p&gt;

&lt;p&gt;Or &lt;a href="https://github.com/features/actions"&gt;Github Actions&lt;/a&gt;, to create complex flows based on what's going on in GitHub, taking ops to the next level. &lt;/p&gt;

&lt;p&gt;Or &lt;a href="https://auth0.com/docs/rules"&gt;Auth0 has their rules&lt;/a&gt; that extend the log in functionality of their services. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://workers.dev/"&gt;Cloudflare workers&lt;/a&gt; deploy and execute anywhere in the world - and execute nearest to your request. &lt;/p&gt;

&lt;p&gt;We're seeing an ecosystem of ecosystems emerge. Want to handle a webhook? &lt;a href="https://github.com/zmarkan/chatkit-greeter-bot"&gt;Build a chatbot, even&lt;/a&gt;? Serverless makes that really, really easy. Just add JavaScript ✨.&lt;/p&gt;

&lt;p&gt;What the new generation of serverless reminds me of is actually fulfilling the promise of API mash-ups.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For the younger generation, API mash-ups were the idea from circa 2005 (or when Twitter wasn't a thing yet) - of making dynamic and fully-featured websites by calling on different APIs and connecting their results on your own site.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;API mash-ups never really took off in the mid noughties, because the tech just wasn't there at the time. The ecosystem wasn't there. But now, I believe it is here, and serverless is the glue. The JAMstack (JavaScript, APIs, Markdown) is a prime example of where we currently are, and it's amazing.&lt;/p&gt;




&lt;p&gt;To summarize, I am a huge fan of Serverless. I believe serverless is  a paradigm that greatly lowers the barriers for getting into software programming, and will see serious adoption and development in the next few years. &lt;br&gt;
It's also showing itself as a great "glue" technology, connecting various service ecosystems, and making them work well together. These two benefits greatly outweigh any naysayer arguments.&lt;br&gt;
More, and together - that's progress, and I'm sure that amazing things will happen. 🚀&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>development</category>
      <category>lambda</category>
      <category>functions</category>
    </item>
  </channel>
</rss>
