Diff & patch environment configs across local/remote (.env, YAML, config.py) plus single-key editor.
Project description
envdiff / envset
Powerful CLI tools for comparing and editing environment configurations across local and remote systems
envdiff and envset are command-line tools that help you manage environment configurations across different file formats (.env, YAML, Python config.py) and locations (local files or remote servers via SSH).
โจ Features
envdiff โ Compare & Patch
- ๐ Compare environment configs between source and target files
- ๐ Detect missing, extra, and different keys
- ๐ง Generate patches in multiple formats (export, dotenv, PowerShell)
- โ
CI/CD integration with
--checkflag (exits non-zero on differences) - ๐ฏ Filter keys with regex patterns (
--include/--exclude) - ๐ Apply changes directly to
.envfiles with automatic backups - ๐ Remote support via SSH/SCP for both source and target
- ๐ JSON output for machine-readable reports
envset โ Single Key Editor
- โ๏ธ Edit one key across multiple files simultaneously
- ๐ Multi-format support:
.env, YAML, Pythonconfig.py - ๐ In-place rewriting for existing constants and dict assignments
- ๐ฏ Nested keys support for YAML and Python dicts (dot notation)
- ๐ Remote editing via SSH/SCP
- ๐พ Automatic backups before modifications
- ๐ข JSON values support for typed data
๐ Quick Start
Installation
Option 1: pipx (Recommended for CLI tools)
pipx install envdiff-tool
Option 2: pip
pip install envdiff-tool
Option 3: From source
git clone https://github.com/talaatmagdyx/envdiff_fresh.git
cd envdiff_fresh
pip install -e .
Quick Example
# Compare YAML config with .env file
envdiff --source config.yml --target .env --patch-format export
# Set a key across multiple files
envset --files .env config.yml --key LOG_LEVEL --value warning
๐ Documentation
Table of Contents
- envdiff: Compare & Patch
- envset: Single Key Editor
- Remote Operations
- CI/CD Integration
- Advanced Usage
- Windows Support
- Development
๐ envdiff: Compare & Patch
Compare environment configurations and generate patches to synchronize them.
Basic Usage
# Compare source YAML with target .env
envdiff --source examples/source.yml --target examples/target.env
# Output:
# Missing on target (2):
# - database.host
# - database.port
#
# Extra on target (2):
# - DATABASE_HOST
# - DATABASE_PORT
#
# Different values (2):
# - APP_MODE
# - FEATURE_X
Generate Patches
# Generate export format patch
envdiff --source examples/source.yml --target examples/target.env --patch-format export
# Output:
# # Patch (export) โ apply on target to add/update keys
# export database.host='db.prod'
# export database.port='5432'
# export APP_MODE='production'
# export FEATURE_X='True'
Available patch formats:
exportโ Shell export statements (Bash/Zsh)dotenvโ Standard.envformatpowershellโ PowerShell environment variables
Apply Changes Directly
# Apply changes to target .env (creates backup automatically)
envdiff --source config.yml --target .env --apply
# Dry-run to preview changes
envdiff --source config.yml --target .env --apply --apply-dry-run
Filter Keys with Regex
# Only check keys starting with APP_
envdiff --source config.yml --target .env --include '^APP_'
# Exclude secret keys
envdiff --source config.yml --target .env --exclude 'SECRET|PASSWORD|KEY'
# Combine filters
envdiff --source config.yml --target .env \
--include '^APP_' \
--exclude 'SECRET'
Prefix Filtering
# Only compare keys with specific prefix
envdiff --source config.yml --target .env --only-prefix DATABASE
# Ignore keys with specific prefix
envdiff --source config.yml --target .env --ignore-prefix DEBUG
JSON Output
Get machine-readable output for automation:
envdiff --source config.yml --target .env --format json
# Output:
# {
# "source": "config.yml",
# "target": ".env",
# "summary": {
# "missing": 2,
# "extra": 1,
# "different": 1,
# "same": 5
# },
# "keys": {
# "missing": ["APP_NAME", "API_KEY"],
# "extra": ["OLD_KEY"],
# "different": ["DATABASE_URL"]
# },
# "patch": {
# "format": "export",
# "lines": ["export APP_NAME='myapp'", ...]
# }
# }
Case Sensitivity
# Case-insensitive comparison (default)
envdiff --source config.yml --target .env --case-sensitive false
# Case-sensitive comparison
envdiff --source config.yml --target .env --case-sensitive true
โ๏ธ envset: Single Key Editor
Edit a single key across multiple files in different formats.
Basic Usage
# Set LOG_LEVEL in multiple files
envset --files .env config.yml --key LOG_LEVEL --value warning
Supported File Types
.env Files
envset --files .env --key DATABASE_URL --value postgres://localhost/db
YAML Files (Nested Keys)
# Set nested key using dot notation
envset --files config.yml --key app.database.host --value db.example.com
# Set with JSON value (for typed data)
envset --files config.yml --key app.timeout --value '30' --json
Python config.py Files
UPPERCASE Constants:
# Add or update a constant
envset --files config.py --key RABBITMQ_USER --value admin
# In-place rewrite existing constant
envset --files config.py --key RABBITMQ_USER --value root --rewrite
CONFIG/ENV Dictionaries:
# Set nested dict key
envset --files config.py --key database.host --value db.new
# In-place rewrite existing dict assignment
envset --files config.py --key database.host --value db.new --rewrite
Multiple Files
# Update the same key across multiple files
envset --files .env config.yml config.py \
--key API_KEY \
--value "new-secret-key"
JSON Values
# Set complex JSON values
envset --files config.yml \
--key app.features \
--value '{"feature1": true, "feature2": false}' \
--json
Dry Run
# Preview changes without modifying files
envset --files config.py --key RABBITMQ_USER --value admin --dry-run
๐ Remote Operations
Both tools support remote files via SSH/SCP.
SSH Configuration
# Basic remote path
envdiff --source user@server:/path/to/config.yml --target .env
# With SSH port
envdiff --source user@server:/path/config.yml \
--target .env \
--source-ssh-port 2222
# With SSH identity file
envdiff --source user@server:/path/config.yml \
--target .env \
--source-ssh-identity ~/.ssh/id_rsa
# With SSH options
envdiff --source user@server:/path/config.yml \
--target .env \
--source-ssh-extra "StrictHostKeyChecking=no,UserKnownHostsFile=/dev/null"
Remote Examples
# Compare local YAML with remote .env
envdiff --source config.yml --target user@prod:/srv/app/.env
# Set key on remote config.py
envset --files user@prod:/opt/app/config.py \
--key RABBITMQ_USER \
--value root \
--rewrite
# Apply changes to remote .env
envdiff --source config.yml \
--target user@prod:/srv/app/.env \
--apply
๐ CI/CD Integration
Use --check flag to fail CI builds when configurations don't match.
Basic CI Check
# Exit with code 5 if differences exist
envdiff --source config.yml --target .env --check
# In CI script
if ! envdiff --source config.yml --target .env --check; then
echo "Configuration mismatch detected!"
exit 1
fi
With Filters
# Only check specific keys
envdiff --source config.yml --target .env \
--include '^APP_' \
--check
JSON Output for CI
# Get structured output for CI scripts
envdiff --source config.yml --target .env \
--format json \
--check \
--patch-format export
# Exit code 5 if differences remain after filtering
GitHub Actions Example
- name: Check environment configuration
run: |
envdiff \
--source config/production.yml \
--target .env \
--include '^APP_' \
--exclude 'SECRET' \
--check \
--format json
๐ฏ Advanced Usage
Custom Source/Target Types
# Explicitly specify file types
envdiff --source config.yml \
--target config.py \
--source-type yaml \
--target-type py
Show Same Values
# Include keys with matching values in output
envdiff --source config.yml --target .env --show-same
Keys-Only JSON Output
# Get only the keys JSON (without full report)
envdiff --source examples/source.yml --target examples/target.env --keys-json
# Output (JSON followed by text summary):
# {
# "missing": ["database.host", "database.port"],
# "extra": ["DATABASE_HOST", "DATABASE_PORT"],
# "different": ["APP_MODE", "FEATURE_X"],
# "same": null
# }
JSON-Only Mode
# Output only JSON (no human-readable text)
envdiff --source config.yml --target .env --json-only
Backup Control
# Disable automatic backups
envdiff --source config.yml --target .env --apply --apply-backup none
# Backups are enabled by default (format: .env.bak-20240101120000)
๐ช Windows Support
Installation
# Install with pipx
pipx install envdiff-tool
# If pipx is not on PATH, add it:
$Env:Path += ';' + (python -m site --user-base) + '\Scripts'
PowerShell Patch Format
# Generate PowerShell patch
envdiff --source .\config.yml --target .\.env --patch-format powershell > patch.ps1
# Review and apply
Get-Content patch.ps1
. .\patch.ps1
Remote Operations from Windows
Windows 10+ includes OpenSSH, so remote operations work out of the box:
# Compare with remote file
envdiff --source .\config.yml --target user@server:/srv/app/.env
# Edit remote config
envset --files user@server:/opt/app/config.py --key RABBITMQ_USER --value root
๐ File Format Examples
.env Format
APP_NAME=myapp
DATABASE_URL=postgres://localhost/db
LOG_LEVEL=info
YAML Format
app:
name: myapp
database:
url: postgres://localhost/db
logging:
level: info
Python config.py Format
# Constants
RABBITMQ_USER = 'admin'
API_KEY = 'secret-key'
# Or dictionaries
CONFIG = {
'database': {
'host': 'localhost',
'port': 5432
}
}
๐ ๏ธ Development
Setup
# Clone repository
git clone https://github.com/talaatmagdyx/envdiff_fresh.git
cd envdiff_fresh
# Install in editable mode with dev dependencies
pip install -e .[dev]
Running Tests
# Run all tests with coverage
pytest
# Tests require 100% coverage to pass
Linting
# Check code style
ruff check .
# Format code
ruff format .
# Check formatting without changes
ruff format --check .
Project Structure
envdiff_fresh/
โโโ envdiff.py # Main diff/patch tool
โโโ envset.py # Single key editor
โโโ tests/ # Test suite (100% coverage)
โ โโโ test_cli_integration.py
โ โโโ test_coverage.py
โ โโโ test_envset_configpy.py
โ โโโ test_parsers_and_patch.py
โโโ examples/ # Example files
โ โโโ example.env
โ โโโ example.yaml
โ โโโ source.yml
โ โโโ target.env
โ โโโ target_config.py
โโโ pyproject.toml # Project configuration
โโโ requirements.txt # Runtime dependencies
โโโ README.md # This file
๐ Examples Directory
The examples/ directory contains sample files for testing:
example.envโ Sample.envfileexample.yamlโ Sample YAML configurationsource.ymlโ Source file for diff examplestarget.envโ Target file for diff examplestarget_config.pyโ Python config file example
Try them out:
envdiff --source examples/source.yml --target examples/target.env
envset --files examples/example.env examples/example.yaml --key LOG_LEVEL --value debug
๐ข Release Process
This repository includes GitHub Actions workflows for automated releases.
Standard Release
- Bump version in
pyproject.toml - Commit and tag:
git add pyproject.toml git commit -m "chore: bump version to 0.1.1" git tag v0.1.1 git push --follow-tags
- GitHub Actions will:
- Build
sdistandwheelpackages - Create a GitHub Release
- Upload to PyPI (if
PYPI_API_TOKENsecret is set)
- Build
Release Candidate (RC)
- Bump version to RC format (e.g.,
0.2.0rc1) - Tag with RC pattern:
git commit -am "chore: bump version to 0.2.0rc1" git tag v0.2.0-rc1 git push --follow-tags
- GitHub Actions will:
- Build packages
- Create a GitHub Pre-Release
- Upload to TestPyPI (if
TEST_PYPI_API_TOKENsecret is set)
PyPI Tokens
Add tokens in GitHub repository settings:
- Settings โ Secrets and variables โ Actions โ New repository secret
PYPI_API_TOKENโ For production releasesTEST_PYPI_API_TOKENโ For release candidates
โ FAQ
Why do I need both tools?
- envdiff: Compare configurations and generate patches for synchronization
- envset: Quickly update a single key across multiple files
Can I use these tools with Docker?
Yes! Both tools work inside Docker containers. Mount your config files as volumes and run the commands.
How do I handle secrets?
Use --exclude to filter out secret keys from comparisons:
envdiff --source config.yml --target .env --exclude 'SECRET|PASSWORD|KEY'
Can I compare more than two files?
Currently, envdiff compares one source to one target. For multiple comparisons, run the command multiple times or use a script.
What Python versions are supported?
Python 3.8 and above.
๐ License
MIT License โ see LICENSE file for details.
๐ค Contributing
Contributions are welcome! Please ensure:
- All tests pass (
pytest) - Code coverage remains at 100%
- Code follows style guidelines (
ruff check)
๐ Additional Resources
- Run
envdiff --helporenvset --helpfor full command-line options - Check
examples/directory for sample files - Review test files in
tests/for usage examples
Made with โค๏ธ for developers who care about configuration management
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 envdiff_tool-0.1.2.tar.gz.
File metadata
- Download URL: envdiff_tool-0.1.2.tar.gz
- Upload date:
- Size: 42.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c3968930c581d58693c142950e1c3753ee5aef855b91420fd28334a554eba1e
|
|
| MD5 |
8f8735c2555ac841f61a6bd9b832ea57
|
|
| BLAKE2b-256 |
0c81de3a8bbddb07c370ce9de69404a3614025d3a567a2ff84c35b263be3c8fb
|
File details
Details for the file envdiff_tool-0.1.2-py3-none-any.whl.
File metadata
- Download URL: envdiff_tool-0.1.2-py3-none-any.whl
- Upload date:
- Size: 25.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
651dc89d9af8af6ddac8974a3503ac59c6ce2d72f4e4e4484684b877606b8287
|
|
| MD5 |
0b768b28d37baf91c095a5d8e4faec50
|
|
| BLAKE2b-256 |
7640d95142a33141651f86e5cccc85290cb7731cc346b6ce8f25f196d0dd45f8
|