Skip to content

Commit

Permalink
Allow different configs for different machines
Browse files Browse the repository at this point in the history
Introduces environment variables template file and tasks related to the
environment variables files. You're supposed to create a `.env.local`
and a `.env.prod` based on `.env.template`. There's a task that ensures
the keys in `.env.template` are also present in the other files. There's
another task that sets the environment variables in production.

For:
#12
  • Loading branch information
liammulh committed Mar 28, 2024
1 parent bd92f85 commit 6efc7bf
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .ebignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Environment variables:
.env.local
.env.prod

# Python stuff:
.coverage
.mypy_cache
.pytest_cache
Expand Down
1 change: 1 addition & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export SOME_VAR="Test"
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# Elastic Beanstalk stuff:
!.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml
.elasticbeanstalk/*

# Environment variable files:
.env.local
.env.prod

# Python stuff:
.coverage
.mypy_cache
.pytest_cache
Expand Down
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mypy = "*"
pytest = "*"
invoke = "*"
coverage = "*"
python-dotenv = "*"

[requires]
python_version = "3.12"
11 changes: 10 additions & 1 deletion Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ For all other command line tasks, the affils project uses [Invoke](https://docs.
We have diagrams for our current and desired affiliations workflow in
the [diagrams directory](./doc/diagrams).

## Environment variables

We use environment variables files (commonly referred to as `.env`
files) to configure the affiliations service. For more info on how we
use `.env` files, see the [doc on environment variables](./doc/envars.md).

## Deployment

Read the [doc](./doc/deploy.md) on deploying to production.
12 changes: 12 additions & 0 deletions doc/envars.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Environment variables

There's a `.env.template` file that is the source of truth for
environment variable keys. You're supposed to create a `.env.local` file
and a `.env.prod` file based on `.env.template`. The keys in each
environment variable file should stay the same at all times. This is
enforced programmatically using Invoke tasks. (See the `tasks.py` file
for more details on this.) The values of the keys can differ between
files, of course.

When you deploy to production, the production environment variables are
automatically uploaded to production.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ platformdirs==4.2.0
pluggy==1.4.0
pylint==3.1.0
pytest==8.1.1
python-dotenv==1.0.1
tomlkit==0.12.4
typing_extensions==4.10.0
Werkzeug==3.0.1
7 changes: 7 additions & 0 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""

# Built-in libraries:
import os
import subprocess

# Third-party dependencies:
Expand All @@ -28,3 +29,9 @@ def current_git_sha():
# Strip newline character from the end of the string.
sha = output[0 : len(output) - 1]
return sha


@app.route("/env")
def display_env_var():
"""Displays environment variable for testing purposes."""
return os.environ.get("SOME_VAR")
40 changes: 36 additions & 4 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,20 @@
"""

# Third-party dependencies:
from dotenv import dotenv_values
from invoke import task

# Environment variable files:
ENV_TRUTH = ".env.template" # The source of truth for all .env files.
ENV_LOCAL = ".env.local"
ENV_PROD = ".env.prod"

# Configs:
TRUTH_CONFIG = dotenv_values(ENV_TRUTH)
LOCAL_CONFIG = dotenv_values(ENV_LOCAL)
PROD_CONFIG = dotenv_values(ENV_PROD)
CONFIGS = [LOCAL_CONFIG, PROD_CONFIG]


@task
def fmt(c):
Expand All @@ -32,18 +44,29 @@ def test(c):
c.run("coverage run -m pytest && coverage report")


@task(pre=[fmt, lint, types, test])
@task
def envsame(c):
"""Ensure environment variable keys match in each .env file."""
for config in CONFIGS:
if config.keys() != TRUTH_CONFIG.keys():
print(".env keys do not match. Check your .env files.")
exit(1)


@task(pre=[fmt, lint, types, test, envsame])
def check(c):
"""Run all code checks."""


@task
def reqs(c):
"""Generate requirements.txt file for use in GitHub Actions.
"""Generate requirements.txt file.
The GitHub Actions workflow runners don't seem to play nicely with
Pipenv. We generate a requirements.txt file and use it to install
dependencies in GitHub Actions.
We also use the requirements.txt file on Elastic Beanstalk.
"""
add_warning = (
"echo '# Do not edit directly. This file is generated.\n' > requirements.txt"
Expand All @@ -61,10 +84,19 @@ def dev(c):
Assumes you've activated the virtual environment.
"""
c.run("cd src && flask run")
c.run(f"source {ENV_LOCAL} && cd src && flask run")


@task
@task(pre=[envsame])
def envprod(c):
"""Set production environment variables."""
vars = " ".join([f"{key}={val}" for key, val in PROD_CONFIG.items()])
c.run(f"eb setenv {vars}")


# Make sure our requirements.txt is up-to-date before we deploy.
# Set environment variables before we deploy.
@task(pre=[reqs, envprod])
def deploy(c):
"""Deploy the affils service.
Expand Down

0 comments on commit 6efc7bf

Please sign in to comment.