38

So I have a react/typescript app in my repo that I'm working on and in my repo I have a .env file that I'm ignoring so that my secrets don't get exposed and a .env-example file of important environment variables to configure. My problem is, since I'm not pushing the .env file to my repo, when I deploy my app through the google app engine(this is done in the deployment stage in my gitlab-ci.yml file), these environment variables will not be present in production and I need them for my app to work as I do something like this in my webpack.config.js file.

const dotenv = require('dotenv').config({ path: __dirname + '/.env' });

and then

new webpack.DefinePlugin({
  'process.env': dotenv.parsed
})

Here is my .gitlab-ci file for reference in case anyone here wants to see.

cache:
  paths:
    - node_modules/

stages:
  - build
  - test
  - deploy

Build_Site:
  image: node:8-alpine
  stage: build
  script:
    - npm install --progress=false
    - npm run-script build
  artifacts:
    expire_in: 1 week
    paths:
      - build

Run_Tests:
  image: node:8-alpine
  stage: test
  script:
    - npm install --progress=false
    - npm run-script test

Deploy_Production:
  image: google/cloud-sdk:latest
  stage: deploy
  environment: Production
  only:
    - master
  script:
    - echo $DEPLOY_KEY_FILE_PRODUCTION > /tmp/$CI_PIPELINE_ID.json
    - gcloud auth activate-service-account --key-file /tmp/$CI_PIPELINE_ID.json
    - gcloud config set project $PROJECT_ID_PRODUCTION
    - gcloud info
    - gcloud --quiet app deploy
  after_script:
    - rm /tmp/$CI_PIPELINE_ID.json

Also, feel free to critique my gitlab-ci.yml file so I can make it better.

Luis Averhoff
  • 707
  • 2
  • 9
  • 22
  • Have you found a solution to this? I'm also looking for a way to do this. – IMB Jan 07 '19 at 14:49
  • 1
    @IMB One solution was to create a bash script that creates a temporary .env from the environment variables setup through gitlab duing the build phase(put this in the before scipt), builds the project through npm run build and then deletes the .env file so that it doesn't remain as an artifact(put this in the after script). – Luis Averhoff Jan 07 '19 at 18:02
  • @LuisAverhoff do you have an example of this solution to share? – graffitiMSX May 03 '21 at 17:11

2 Answers2

61

I don't know if you still need this, but this is how I achieved, what you wanted to.

  1. Create your environment variables in your gitlab repo config

  2. Create setup_env.sh:

#!/bin/bash

echo API_URL=$API_URL >> .env
echo NODE_ENV=$NODE_ENV >> .env
  1. Modify your .gitlab-ci.yml. Upsert below to your before_script: section
  - chmod +x ./setup_env.sh
  - ./setup_env.sh
  1. In webpack.config.js make use of https://www.npmjs.com/package/dotenv
require('dotenv').config();

This passes your .env variables available in webpack.config.js file.

Add this to your plugins array (add those variables you need):

    new webpack.DefinePlugin({
      'process.env.API_URL': JSON.stringify(process.env.API_URL),
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
      ...
    })

Now your deployment should use your environment variables specified in you gitlab settings.

Michiel Roos
  • 833
  • 11
  • 13
Mike Czarnota
  • 719
  • 8
  • 9
  • 1
    committing .env files to the repo is a bad practice – Francis Manoj Fernnado Aug 05 '19 at 06:17
  • 9
    @FrancisManojFernnado yup. That's why there is such procedure – Mike Czarnota Aug 06 '19 at 09:00
  • 4
    @MichałCzarnota, would you consider copying the all .env content inside a giltab CI environment variable as a bad practice? As advised here we need to set as much variables as we define entries in the .dotenv file (in the worst case at least). Then we reconstruct the .env file in the prescript instruction. Seems overkill to me. let put the entire .env content in the Gitlab CI environement variable. – chaiyachaiya Jun 29 '20 at 08:36
  • 1
    @chaiyachaiya I think you are right. In the next project I omitted this overhead. But, unfortunately, I didn't find a way to avoid setting env variables in gitlab repo config. – Mike Czarnota Jul 15 '20 at 20:20
  • thanks for this. This was my solution for dotenv in Flutter using CodeMagic CI – Karl Anthony Baluyot Dec 21 '21 at 01:07
2

Committing .env files isn't a bad practice if you don't push any sensitive information in it like:

# App Configuration
PORT=3000
NODE_ENV=production
APP_ENV=APP_ENV
TZ=utc
COMMIT_SHA=COMMIT_SHA

# Rabbitmq configuration
RABBITMQ_HOST=RABBITMQ_HOST
RABBITMQ_USER=RABBITMQ_USER
RABBITMQ_PASS=RABBITMQ_PASS
RABBITMQ_PORT=RABBITMQ_PORT
...

(assuming variables like RABBITMQ_HOST are safely set in your GitLab CI environment variables)

So in the .gitlab-ci.yml job, you can just duplicate the needed .env file and it will automatically be interpreted:

...
test:e2e:
  image: node:lts
  services:
    - postgres:13-alpine
    - rabbitmq:3.9-management
  stage: test
  before_script:
    - cp .env.test .env      # <--- env vars will be applied
    - npm install pm2 -g
    - npm run install:ci
    - npm run db:drop
    - npm run db:migrate
    - npm run db:fixture
    - pm2 start npm -- start --name "myapp"
  script:
    - npm run test:e2e
  after_script:
    - pm2 delete "myapp"
  variables:                 # <---- override any env var you want here
    POSTGRES_DB: test
    POSTGRES_USER: test
    POSTGRES_PASSWORD: testPwd!
    POSTGRES_HOST_AUTH_METHOD: trust
  cache:
    key:
      files:
        - package-lock.json
    paths:
      - .npm/
    policy: pull
  except:
    - /^release.*$/i
    - tags
...

No tricky stuff needed.

Maxime Lafarie
  • 1,924
  • 1
  • 18
  • 36