Django-style migrations for environment (.env) files
Project description
migrate-env
Django-style migrations for environment files.
Your .env.example is the source of truth (like models.py). When it changes, makemigrations detects what was added and writes a numbered, reviewable migration. Each developer runs migrate against their own .env, which gains the new blocks and variables without ever touching the values they already have.
pip install migrate-env
Quick start
# Detect changes in .env.example and write env_migrations/0001_initial.py
migrate_env makemigrations
# Apply pending migrations to your local .env (creates it if missing)
migrate_env migrate .env
# See what's applied
migrate_env showmigrations .env
Later, someone adds a Postgres section to .env.example:
migrate_env makemigrations --name postgres
# Created env_migrations/0002_postgres.py
# - Create assignment block [WHYHC_POSTGRES_DB, WHYHC_POSTGRES_USER, ...]
Everyone else pulls and runs migrate_env migrate .env. Their custom secret keys, hosts, and passwords are untouched; the new block is appended.
The data model
An env file is a sequence of blocks, and is byte-for-byte reconstructible from them:
CommentBlock— leading blank lines + comment lines.AssignmentBlock— leading blank lines + comment lines + assignments.
An Assignment is (Key, Value, Comment | Blank) — the third element is the inline trailing comment (' # like this') or ''. A commented-out assignment such as # WHYHC_CONN_MAX_AGE=0 is parsed as an assignment with enabled=False, representing an optional variable. Prose comments that merely mention FOO=bar mid-sentence, or use spaces around =, remain comments.
from migrate_env import parse
env = parse(open(".env.example").read())
env.render() == open(".env.example").read() # True, always
Migrations
Migrations are plain Python modules, ordered by numeric prefix with validated dependencies:
# env_migrations/0002_postgres.py
from migrate_env import migrations, ops
class Migration(migrations.Migration):
dependencies = ['0001_initial']
operations = [
ops.CreateAssignmentBlock(
comments=['# PostgreSQL database connection'],
assignments=[
ops.Assignment(key='WHYHC_POSTGRES_DB', value='whyhc'),
ops.Assignment(key='WHYHC_POSTGRES_PORT', value='5432'),
],
),
]
Operations are additive and idempotent:
CreateAssignmentBlock/CreateCommentBlock— append a block (skipped if its content already exists).AddAssignments— append variables to an existing block, located by an anchorkey=orcomment=. Keys the user already has anywhere in their file are skipped, so values are never overwritten.AddComments— append documentation comments to an existing block.
Value changes and removals in .env.example are reported as warnings by makemigrations but never auto-migrated — users own their values, and destructive changes deserve a hand-written migration.
Applied state per target file lives in a sidecar (.env.migrations, the analog of Django's django_migrations table). Add it to .gitignore alongside .env.
Commands
| Command | Description |
|---|---|
makemigrations [--example PATH] [--name N] [--dry-run] [--dir D] |
Diff the example against replayed migration state; write a migration |
migrate TARGET [--plan] [--dir D] |
Apply unapplied migrations to TARGET |
showmigrations TARGET [--dir D] |
List migrations with applied status |
Development
To contribute to this library, first checkout the code. Then create a new virtual environment:
cd migrate-env
python -m venv venv
source venv/bin/activate
Now install the dependencies and test dependencies:
python -m pip install -e '.[dev]'
To run the tests:
python -m pytest
License
Apache 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file migrate_env-0.2.1.tar.gz.
File metadata
- Download URL: migrate_env-0.2.1.tar.gz
- Upload date:
- Size: 21.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d4e3933533ebd7aa5d87386483828046b028a7ecd3987bc9202bd7098d281db9
|
|
| MD5 |
6c2b4cba78d2be9afecd5b02c883a944
|
|
| BLAKE2b-256 |
977fb7839cc23b6a08a997c02b0d244afa08eb1a33e7b9f36e6fea9edc08358d
|
Provenance
The following attestation bundles were made for migrate_env-0.2.1.tar.gz:
Publisher:
publish.yml on player1537-playground/migrate-env
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
migrate_env-0.2.1.tar.gz -
Subject digest:
d4e3933533ebd7aa5d87386483828046b028a7ecd3987bc9202bd7098d281db9 - Sigstore transparency entry: 2195148291
- Sigstore integration time:
-
Permalink:
player1537-playground/migrate-env@94fab9cf62eafa7b5d5cd146d9dbfe9a20d6642c -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/player1537-playground
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@94fab9cf62eafa7b5d5cd146d9dbfe9a20d6642c -
Trigger Event:
release
-
Statement type:
File details
Details for the file migrate_env-0.2.1-py3-none-any.whl.
File metadata
- Download URL: migrate_env-0.2.1-py3-none-any.whl
- Upload date:
- Size: 19.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c248299e337f20d1ff7b43f48b0a9b813d89306f237695f133efe1019ae64199
|
|
| MD5 |
e12f1b1fa11106f6765ca6444b3fed81
|
|
| BLAKE2b-256 |
3387e4fa7bd652f2704dc8ff2f2364d002b00d6d555a5452fc8ddf44e90912a8
|
Provenance
The following attestation bundles were made for migrate_env-0.2.1-py3-none-any.whl:
Publisher:
publish.yml on player1537-playground/migrate-env
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
migrate_env-0.2.1-py3-none-any.whl -
Subject digest:
c248299e337f20d1ff7b43f48b0a9b813d89306f237695f133efe1019ae64199 - Sigstore transparency entry: 2195148295
- Sigstore integration time:
-
Permalink:
player1537-playground/migrate-env@94fab9cf62eafa7b5d5cd146d9dbfe9a20d6642c -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/player1537-playground
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@94fab9cf62eafa7b5d5cd146d9dbfe9a20d6642c -
Trigger Event:
release
-
Statement type: