runner icon indicating copy to clipboard operation
runner copied to clipboard

Load `env` from files

Open timharris777 opened this issue 5 years ago • 9 comments

It would be awesome if env could be loaded from a file. Example:

name: Loading env vars from file
on:
  push:
    branches:
      - develop

env-file: dev.env
env:
  other-env-var: env-var-value

jobs:
  build:
    ...

timharris777 avatar Aug 11 '20 17:08 timharris777

A workaround would be to use core.exportVariable or fromJson:

jobs:
  env:
    runs-on: ubuntu-latest
    outputs:
      env: ${{ steps.import-env.outputs.result }}

    steps:
    - uses: actions/checkout@v2

    - name: Import environment variables from a file
      id: import-env
      uses: actions/github-script@v2
      with:
        script: |
          const env = parseEnv(`${process.env.GITHUB_WORKSPACE}/dev.env`);
          Object.entries(env).forEach(x => core.exportVariable(...x)); // current job-level env
          return env;

    - name: Print environment variable
      run: echo $ABC
      env: ${{ fromJson(steps.import-env.outputs.result) }} # step-level env

  build:
    runs-on: ubuntu-latest
    needs: [env]
    env: ${{ fromJson(needs.env.outputs.env) }} # job-level env

    steps:
    - name: Print environment variable
      run: echo $ABC

Note I've used actions/github-script to parse the .env to a JavaScript object. If the file is JSON, it's possible to directly read the file into the output.

ylemkimon avatar Aug 16 '20 07:08 ylemkimon

We wrote an action that loads yaml, json, or env files into the current jobs env. However there is no good way to load into the workflow's env. Seems like that should be a feature.

timharris777 avatar Aug 18 '20 19:08 timharris777

parseEnv is not defined:

Run actions/github-script@v2
ReferenceError: parseEnv is not defined
Error: Unhandled error: ReferenceError: parseEnv is not defined
    at eval (eval at callAsyncFunction (/home/runner/work/_actions/actions/github-script/v2/dist/index.js:7985:56), <anonymous>:3:13)
    at callAsyncFunction (/home/runner/work/_actions/actions/github-script/v2/dist/index.js:7986:12)
    at main (/home/runner/work/_actions/actions/github-script/v2/dist/index.js:8011:26)
    at Module.833 (/home/runner/work/_actions/actions/github-script/v2/dist/index.js:7995:1)
    at __webpack_require__ (/home/runner/work/_actions/actions/github-script/v2/dist/index.js:22:30)
    at startup (/home/runner/work/_actions/actions/github-script/v2/dist/index.js:37:19)
    at /home/runner/work/_actions/actions/github-script/v2/dist/index.js:43:18
    at Object.<anonymous> (/home/runner/work/_actions/actions/github-script/v2/dist/index.js:46:10)
    at Module._compile (internal/modules/cjs/loader.js:959:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)

rgstephens avatar Jan 08 '21 22:01 rgstephens

Ended up doing it with the shell:

      - name: Import environment variables from a file
        id: import-env
        shell: bash
        run: |
          while read line; do
            echo "$line" >> $GITHUB_ENV
          done < ${{ env.ENV_FILE }}

rgstephens avatar Jan 09 '21 03:01 rgstephens

Ended up doing it with the shell:

      - name: Import environment variables from a file
        id: import-env
        shell: bash
        run: |
          while read line; do
            echo "$line" >> $GITHUB_ENV
          done < ${{ env.ENV_FILE }}

Why not just use cat?

run: cat ${{ env.ENV_FILE }} >> $GITHUB_ENV

or

run: < ${{ env.ENV_FILE }} >> $GITHUB_ENV

typebrook avatar Jul 25 '21 04:07 typebrook

Ended up doing it with the shell:

      - name: Import environment variables from a file
        id: import-env
        shell: bash
        run: |
          while read line; do
            echo "$line" >> $GITHUB_ENV
          done < ${{ env.ENV_FILE }}

@rgstephens

Im completely new to powershell scripts.

Can you post a windows runner script? Please

AnnamSai avatar Oct 18 '21 06:10 AnnamSai

I faced with the same question and made a export-env-action that you can use as one of your steps:

constants.env file:

PROTOCOL=https
HOST=example.com
PORT=8080
URI=${PROTOCOL}://${HOST}:${PORT}

a step in your workflow:

- uses: cardinalby/export-env-action@v1
  with:
    envFile: 'constants.env'    
    expand: 'true'

# env.PROTOCOL == 'https'
# env.HOST == 'example.com'
# env.PORT == '8080'
# env.URI == 'https://example.com:8080'

cardinalby avatar Jan 18 '22 12:01 cardinalby

Is there anyway to load from an .env file and use it when defining the credentials of a MySQL service? (e.g. DB_PORT=3307)

services:
  mysql:
    image: mysql:5.7
    ports:
      - $DB_PORT:3306

u01jmg3 avatar Sep 22 '22 12:09 u01jmg3

Is there anyway to load from an .env file and use it when defining the credentials of a MySQL service? (e.g. DB_PORT=3307)

services:
  mysql:
    image: mysql:5.7
    ports:
      - $DB_PORT:3306

First, I would warn you that if you store your creds in .env file in the repo then you probably doing something wrong and you should use GitHub Secrets instead.

You case can make sense if you download env file from outside for example. Then, yes, you can use mentioned cardinalby/export-env-action action to read the creds (use mask parameter to mark values as secrets in the workflow) and use ${{ env.MY_PSW }} expression in the workflow. But be aware that other untrasted steps in your workflow can also have access to env variables

cardinalby avatar Jan 08 '23 16:01 cardinalby

Jumping in here with another solution since some of these didn't exactly do what I needed, which was to load a regular env file like this:

image

Into the env vars of the job itself so I can do other env replacement in subsequent steps without having to enumerate all the vars in the env file.

This did the trick:

      - name: Inject env vars
        run: |
          export $(grep -Ev ^'(#|$)' .env)
          envsubst < ./apps/api/.ebextensions/03_inject_env_vars.config | tee ./apps/api/.ebextensions/03_inject_env_vars.config

export takes in the output from grep which removes empty lines and comments from the file envsubst does env substitution on the targeted file, finds all vars that are wrapped in brackets ${VAR} and replaces it with the actual value from the env file... all without having to enumerate them one by one.

raimille1 avatar Mar 30 '23 12:03 raimille1

Ended up doing it with the shell:

      - name: Import environment variables from a file
        id: import-env
        shell: bash
        run: |
          while read line; do
            echo "$line" >> $GITHUB_ENV
          done < ${{ env.ENV_FILE }}

I have my ENV_FILE stored as a secret because it is quite large and has a few credentials in there.

How could I load in from a secret instead of a file?

Any references for the code above would be handy too.

moleary-gsa avatar Apr 20 '23 08:04 moleary-gsa

I faced with the same question and made a export-env-action that you can use as one of your steps:

constants.env file:

PROTOCOL=https
HOST=example.com
PORT=8080
URI=${PROTOCOL}://${HOST}:${PORT}

a step in your workflow:

- uses: cardinalby/export-env-action@v1
  with:
    envFile: 'constants.env'    
    expand: 'true'

# env.PROTOCOL == 'https'
# env.HOST == 'example.com'
# env.PORT == '8080'
# env.URI == 'https://example.com:8080'

I use a secret in the repo for my env file (we keep an env file for LOCAL, DEV, CI and PRODUCTION) so was able to use this approach by adding the following to the start of my job

- name: Create .env file from Secret
  id: import-env
  run: |
    echo "${{ secrets.ENV_FILE }}" >> .env
- uses: cardinalby/export-env-action@v2
  with:
    mask: true
    envFile: '.env'

I'm not sure what best practice is here and my only concern is that .env file hanging around but it works and the variables are masked in the logging - so thank you @cardinalby !

For posterity, the following is what I was trying which lead me here because the variables were all printed to the console:

- name: Setup environment
  run: |
    echo "${{ secrets.ENV_FILE }}"  >> $GITHUB_ENV

moleary-gsa avatar Apr 20 '23 09:04 moleary-gsa

@moleary-gsa I would comment on your approach:

  1. You can remove env file after cardinalby/export-env-action@v2 step because of the security concerns
  2. Even though secrets are masked in the log, I still don't recommend exporting all secrets in this way for the entire job making them available for all untrusted steps. Instead, you should pass secrets only for the steps where they are actually needed.

You can achieve it by using export: false input for export action:

- uses: cardinalby/export-env-action@v2
  id: readEnvFile 
  with:
    mask: true
    export: false
    envFile: '.env'

And pass the secrets to the steps where they are needed by accessing them as steps.readEnvFile.outputs.YOUR_SECRET_NAME

cardinalby avatar Apr 20 '23 09:04 cardinalby

Thank you for your interest in the runner application and taking the time to provide your valuable feedback. We kindly ask you to redirect this feedback to the GitHub Community Support Forum which our team actively monitors and would be a better place to start a discussion for new feature requests in GitHub Actions. For more information on this policy please read our contribution guidelines. 😃

github-actions[bot] avatar Dec 28 '23 00:12 github-actions[bot]