# Early success in a build

**URL:** <https://discuss.circleci.com/t/early-success-in-a-build/14461>\
**Category:** Build Environment\
**Created:** [July 18, 2017, 5:55pm UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461 "2017-07-18T17:55:57Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![seveibar](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/seveibar/32/16562_2.png) [@seveibar](https://discuss.circleci.com/u/seveibar)\
**Post date:** [July 18, 2017, 5:55pm UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/1 "2017-07-18T17:55:57Z")

</div>

Hi Everyone!

Loving CircleCI 2.0 so far, but we’re noticing some extra build time when we want to complete tests at an early step and not continue performing steps (an early success).

Scenario: We have a monorepo and we build 10+ dockerfiles in parallel. However, if the directory with the dockerfile isn’t different than the one in master (i.e. `git diff origin/master path/to/service` is empty) we don’t have to test and can complete the test early. See the following `circle.yaml`

```yaml
version: 2
defaultBuild: &defaultBuild
  working_directory: ~/monorepo
  docker:
    - image: circleci/node:7.10.0
machine:
  services:
    - docker
jobs:
  project1:
    <<: *defaultBuild
    steps:
      - checkout
      - run: cd libs/scripts ./check-for-difference project1
      - setup_remote_docker:
          reusable: true
      - run: cd libs/scripts ./test project1
      - run: cd libs/scripts ./build project1
  project2:
    <<: *defaultBuild
    steps:
      - checkout
      - run: cd libs/scripts ./check-for-difference project2
      - setup_remote_docker:
          reusable: true
      - run: cd libs/scripts ./test project2
      - run: cd libs/scripts ./build project2

```

We don’t want to unnecessarily run the three steps after the check-for-difference step. I think we could do this with build dependencies, but we might have to checkout multiple times (maybe not that bad of a cost?). Is there a way to “exit early with success”?

---

<div class="post-metadata">

**Author:** ![trumant](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/trumant/32/16573_2.png) [@trumant](https://discuss.circleci.com/u/trumant)\
**Post date:** [July 18, 2017, 10:13pm UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/2 "2017-07-18T22:13:09Z")

</div>

I have a similar workflow that builds multiple Docker images from a monorepo. The solution I’ve come up with is to wrap that logic in a shell script which exits 0 if either the image is built or its not built because the relevant files did not change based on git diff.

The approach was to create a `logical_changes.sh` which parses the git refs in `CIRCLE_COMPARE_URL` to determine the appropriate `git diff ref1 ref2 --name-only` command to run. Then, for each logical change, which equates to a need to build a Docker image, that script exports values like `CI_IMAGE_A_CHANGED` or `CI_IMAGE_B_CHANGED`.

FInally, I have shell scripts for each docker build which source `logical_changes.sh`, test the value of the relevant `CI_IMAGE_*_CHANGED` then either exit 0 early or run the docker build.

Each Docker build in my workflow ends up looking something like:

```yaml
build_and_push_foo_release:
  working_directory: /root/project
  docker:
    - image: foo/circleci-builder
  steps:
    - attach_workspace:
        at: /root/project
    - setup_remote_docker:
        version: 17.05.0-ce
    - run:
        name: Build Foo Docker Image
        command: |
          cd /root/project/
          TAG=$CIRCLE_BRANCH-$CIRCLE_SHA1
          ci/build_foo_docker_image.sh ecom/ $TAG

```

So, in cases where no build and push is necessary, those builds take about 60-90 seconds to `setup_remote_docker`, then exit when the script recognizes it need not build an image.

However, like you I recognize that ideally we could short-circuit earlier potentially using a `when` condition on the steps in a build that could test the value of an environment variable.

---

<div class="post-metadata">

**Author:** ![seveibar](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/seveibar/32/16562_2.png) [@seveibar](https://discuss.circleci.com/u/seveibar)\
**Post date:** [July 19, 2017, 6:11am UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/3 "2017-07-19T06:11:30Z")

</div>

Thanks for the tip @trumant, that approach makes a lot of sense and would definitely bring down our build time. The downside seems to be we have to run `setup_remote_docker`, and we also don’t get to see/profile the different steps in the circleci ui. That said I think I’ll use it in the mean time-

I wonder if this is a feature the circleci team might consider adding, I like your idea of some kind of `when` query, though I’m not sure how much control logic is appropriate in the config file- or how control logic would best be represented in the config.

Naive example of how a basic early success could be implemented in the config:

```yaml
build_and_push_foo_release:
  working_directory: /root/project
  docker:
    - image: foo/circleci-builder
  steps:
    - attach_workspace:
        at: /root/project
    - when:
        command: /root/project/ci/did_foo_change.sh
        action: early_success
    - setup_remote_docker:
        version: 17.05.0-ce
    - run:
        name: Build Foo Docker Image
        command: |
          cd /root/project/
          TAG=$CIRCLE_BRANCH-$CIRCLE_SHA1
          ci/build_foo_docker_image.sh ecom/ $TAG

```

---

<div class="post-metadata">

**Author:** ![dtzar](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/dtzar/32/7419_2.png) [@dtzar](https://discuss.circleci.com/u/dtzar)\
**Post date:** [July 20, 2017, 2:47pm UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/4 "2017-07-20T14:47:19Z")

</div>

What if you setup conditional logic in the YAML + workflow jobs of something like this?

```auto
if [[((`git diff ref1 ref2...` > 0))]]; then 
        echo "pass the job and build the image in the next job which sets up remote_docker"
      else
        echo "fail the job and skip next step in workflow job"
      fi

```

Here is my actual code I use with conditional logic although it is only for relating to doing steps if the commits are on the master branch:

> <https://github.com/Microsoft/PartsUnlimitedMRPmicro/blob/master/.circleci/config.yml#L29>

  
Plus a conditional job workflow like this:  

> <https://github.com/Microsoft/PartsUnlimitedMRPmicro/blob/master/.circleci/config.yml#L356-L359>

I could use something like this for the linked repo which builds all 6 Docker images every time, so if you get it going I’d like to check out the code.

---

<div class="post-metadata">

**Author:** ![KingScooty](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/kingscooty/32/9606_2.png) [@KingScooty](https://discuss.circleci.com/u/KingScooty)\
**Post date:** [November 19, 2017, 5:27pm UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/5 "2017-11-19T17:27:00Z")

</div>

I’ve just come across this post now, and i’m curious whether we’re any closer to having monorepos working nicely with circle ci?

I can’t seem to find any proper answers regarding building only the projects that change. Early success would be nice.

Or a way to generate dynamic workflows? i.e. if conditions are met (git diff /root /project), create the workflow and run it, else skip over it?

---

<div class="post-metadata">

**Author:** ![timc13](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/timc13/32/9994_2.png) [@timc13](https://discuss.circleci.com/u/timc13)\
**Post date:** [January 28, 2018, 7:44pm UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/6 "2018-01-28T19:44:08Z")

</div>

Another use case for this:

master branch runs only `test` job  
staging & production branches run `test` & `deploy` jobs

staging & production runs should be able to detect that the same commit already produced a successful `test` job run in master and so it should just run `deploy`

---

<div class="post-metadata">

**Author:** ![mqchau](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/mqchau/32/12804_2.png) [@mqchau](https://discuss.circleci.com/u/mqchau)\
**Post date:** [March 28, 2018, 5:58pm UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/7 "2018-03-28T17:58:44Z")

</div>

I would like to see this feature too. My company already has some code to figure out whether to skip a build if current branch has no changes related to this build. I just need a way to tell Circle CI to skip the rest of the build after this step yield a flag or something like that.

---

<div class="post-metadata">

**Author:** ![halfer](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/halfer/32/9083_2.png) [@halfer](https://discuss.circleci.com/u/halfer)\
**Post date:** [March 28, 2018, 9:21pm UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/8 "2018-03-28T21:21:05Z")

</div>

I’m not aware of a native skip feature, but would the `git diff` approach above be OK for you? That doesn’t skip the step from a CircleCI recording perspective, but you can elect not to run your tests based on whether there is a change in a repo sub-branch.

Although build servers cannot store state information, you could use the cache system to record the last known hash of a repo, which will help you determine whether to do tests or to skip them, perhaps in a shell script.

---

<div class="post-metadata">

**Author:** ![mqchau](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/mqchau/32/12804_2.png) [@mqchau](https://discuss.circleci.com/u/mqchau)\
**Post date:** [March 29, 2018, 2:31am UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/9 "2018-03-29T02:31:53Z")

</div>

I think that approach was to:

- Write a \*.sh file with environment variable indicating we need to skip this build or not
- Source that file in the next step so now the environment variables are set
- Check environment variables before running the expensive build step

I agree this approach would work. Well, I still prefer to have a native feature where under certain circumstances, Circle CI just skip the rest of the build and mark this build successful.

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/circleci/original/3X/5/1/511608acda8e85906e15909b57bd0a46c1dbe291.png) [@system](https://discuss.circleci.com/u/system)\
**Post date:** [June 27, 2018, 2:31am UTC](https://discuss.circleci.com/t/early-success-in-a-build/14461/10 "2018-06-27T02:31:58Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
