Environment Variable Repalce

I created my first pipeline yesterday and I wanted to replace a placeholder in my bundle.gradle file with the CIRCLE_BUILD_NUM environment variable. The only method I found find was writing my own ‘sed’ command and executing the regex in a run statement. This worked fine to get up and running, since there was only one variable to replace, however this method obviously won’t scale, down the road. Is there a CircleCI feature/orb or other method to do a more comprehensive placeholder/envar swap throughout my project?

  - run:
      name: Increment build id
      command: sed "s/_buildNum/${CIRCLE_BUILD_NUM}/g" -i build.gradle

I do not know of a CircleCI specific solution, but generally speaking, if you need to replace a term in a Git repo you can combine git grep and sed

- run:
    name: Replace build id
    command: |
      git grep -l '_buildNum' | xargs sed -i "s/_buildNum/${CIRCLE_BUILD_NUM}/g"

That would replace all occurrences of _buildNum in your repository.

You could potentially abstract that out into an Orb or even a command in your config.yml

This has not been tested for things like typos, but to get you started:

commands:
  replace:
    description: Replace a value in a git repository
    parameters:
      target:
        type: string
      replacement:
        type: string
    steps:
      - run: |
          git grep -l '<< parameters.target >>' | xargs sed -i 's/<< parameters.target >>/<< parameters.replacement >>/g'

  replace-environment-variable:
    description: Replace a value with an evironment variable in a git repository
    parameters:
      target:
        type: string
      replacement-env-var-name:
        type: string
    steps:
      - run: |
          git grep -l '<< parameters.target >>' | xargs sed -i "s/<< parameters.target >>/${<< parameters.replacement >>}/g"

Notice that we’ll need to do things a little bit differently for environment variables. This is because parameters are passed in a compile-time. Before the environment variables are available. So in this case, instead of passing in a value to replace, we’ll pass in the name of the environment variable (CIRCLE_BUILD_NUM) as opposed to the value 123.

Also, this is not fault-tolerant to special characters and other edge cases. For example if your replacement value contains a / or other characters that would cause issues with sed.

I was trying to replace all variables based on some type of identifier (i.e. a variable name encapsulated with ${}) similar to this Azure DevOps task. You would have to specify the file, but would prevent you from having to run this command once for each and every variable you want to insert. I’m guessing CircleCI doesn’t have this feature?

https://marketplace.visualstudio.com/items?itemName=qetza.replacetokens

@mike Probably a better question: what is the recommended way to replace environment variables within a CircleCI pipeline?

You’re putting yourself through a lot of work when you could just read in the value. Don’t make risky sed calls when you don’t have to.

def buildNumber = System.getenv("CIRCLE_BUILD_NUM")

buildNumber will be null if the environment variable doesn’t exist, so adjust your build logic accordingly.

1 Like

Returns null for me in build gradle even though the output in the build showing the ENVs has that value set. Is there something else I need to do in my gradle to somehow get ENV vars detectable in gradle build script?

You shouldn’t have to, no. Try it out locally by just printing the variable value from your build.gradle and debugging on your own machine. There’s nothing special about Circle’s bash environment

export CIRCLE_BUILD_NUMBER=1
./gradlew classes
# verify the build number appears with your println
export CIRCLECI_BUILD_NUMBER=2
./gradlew classes
# verify the build number changed