Create separate steps/jobs for PR/Forks versus branches

It is clear on how to make conditional steps based on the branch of the project. i.e. your workflow article provided. However, is there a way so only certain steps/jobs happen just for pull requests?

For instance, I’d like to do a full build/test for all PRs. Let’s say that passes, I merge the PR to master, then I’d like to automatically do the same exact steps except this time also do a deploy which requires my secrets/credentials. It would be ideal if I could conditionally set steps within a job to know to execute if it is a PR versus a branch.

1 Like

I ended up figuring this out myself via modifying the config.yml as such:

        if [[ ((`echo $CIRCLE_BRANCH | grep -c "pull"` > 0))]]; then 
          echo "Skip doing stuff since it is a PR."
        else
          echo "Not a PR, so now do what I want."
        fi
1 Like

Got a syntax error with that, but tweaked it with help from ShellCheck:

command: |
  if [[ $(echo "$CIRCLE_BRANCH" | grep -c "pull") -gt 0 ]]; then
    echo "Skip doing stuff since it is a PR."
  else
    echo "Not a PR, so now do what I want."
  fi
2 Likes

Another approach, using filters in the workflows config:

jobs:
  - forks_only:
      filters:
        branches:
          # only from forks
          only: /^pull\/.*$/
  - canonical_repo_only:
      filters:
        branches:
          # only from canonical repository
          # https://stackoverflow.com/a/5334825/358804
          only: /^(?!pull\/).*$/

The advantages here (versus @dtzar’s shell conditionals):

  • It’s using native CircleCI config, rather than having to break out to shell conditionals
  • The jobs are segmented, which is good if you want very different steps between builds from forks vs. the canonical repo

The disadvantages:

  • It’s equally non-intuitive
  • The jobs are segmented, so you kinda have to maintain them in two places (assuming you want the steps to be similar)
  • This doesn’t work for required status checks in GitHub, which expect a consistent name for all pull requests
  • Regular expression lookarounds aren’t supported by all regex engines, so while it works on CircleCI now, it may not in the future if they switch to a different language/engine for parsing the config

Example usage. A future approach that splits the difference would be using optional build steps, but that isn’t possible yet.

4 Likes

I’m not sure how only: /^(?!pull\/).*$/ would work, if I make a PR from a master branch in a fork, it shows up as CIRCLECI_BRANCH=master, does filter work differently?

Are you sure? I’m consistently seeing CIRCLE_BRANCH=pull/<number> where I would expect it.

@afeld I was hoping you could help me understand your YAML a bit better.

If I understand canonical repository correctly, this should match against any pushes to my repository that are not coming from forks - so, if I have a branch such as feature/some-new-feature, and push to it, would it trigger the jobs specified in this workflow?

I also presume you’d need to have CircleCI configured to not run only on pull requests? :thinking:

this should match against any pushes to my repository that are not coming from forks

Correct. The ?! in the regular expression is called a negative lookahead, and is basically saying “match branches where CircleCI doesn’t include pull/ at the beginning,” which are pull requests from forks.

if I have a branch such as feature/some-new-feature, and push to it, would it trigger the jobs specified in this workflow?

Yep!

you’d need to have CircleCI configured to not run only on pull requests?

I think it would work work either way. If set to only build on pull requests, it would only build pull requests from branches in the canonical repository.

1 Like

@afeld thanks a bunch!

1 Like

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