envdrift 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,79 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # PyInstaller
28
+ *.manifest
29
+ *.spec
30
+
31
+ # Installer logs
32
+ pip-log.txt
33
+ pip-delete-this-directory.txt
34
+
35
+ # Unit test / coverage reports
36
+ htmlcov/
37
+ .tox/
38
+ .nox/
39
+ .coverage
40
+ .coverage.*
41
+ .cache
42
+ nosetests.xml
43
+ coverage.xml
44
+ *.cover
45
+ *.py,cover
46
+ .hypothesis/
47
+ .pytest_cache/
48
+
49
+ # Translations
50
+ *.mo
51
+ *.pot
52
+
53
+ # Environments
54
+ .env
55
+ .env.*
56
+ !.env.example
57
+ .venv
58
+ env/
59
+ venv/
60
+ ENV/
61
+ env.bak/
62
+ venv.bak/
63
+
64
+ # IDE
65
+ .idea/
66
+ .vscode/
67
+ *.swp
68
+ *.swo
69
+ *~
70
+
71
+ # Ruff
72
+ .ruff_cache/
73
+
74
+ # macOS
75
+ .DS_Store
76
+
77
+ # UV
78
+ .uv/
79
+ uv.lock
@@ -0,0 +1,23 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.8.2
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+
9
+ - repo: https://github.com/PyCQA/bandit
10
+ rev: 1.7.10
11
+ hooks:
12
+ - id: bandit
13
+ args: ["-c", "pyproject.toml", "-r", "src"]
14
+ additional_dependencies: ["bandit[toml]"]
15
+
16
+ - repo: https://github.com/pre-commit/pre-commit-hooks
17
+ rev: v5.0.0
18
+ hooks:
19
+ - id: trailing-whitespace
20
+ - id: end-of-file-fixer
21
+ - id: check-yaml
22
+ - id: check-added-large-files
23
+ - id: check-toml
envdrift-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jainal Gosaliya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,77 @@
1
+ .PHONY: install dev lint format typecheck security test build clean publish help
2
+
3
+ # Default target
4
+ help:
5
+ @echo "envdrift - Prevent environment variable drift"
6
+ @echo ""
7
+ @echo "Usage: make [target]"
8
+ @echo ""
9
+ @echo "Targets:"
10
+ @echo " install Install production dependencies"
11
+ @echo " dev Install development dependencies"
12
+ @echo " lint Run linting with ruff"
13
+ @echo " format Format code with ruff"
14
+ @echo " typecheck Run type checking with pyrefly"
15
+ @echo " security Run security checks with bandit"
16
+ @echo " test Run tests with pytest"
17
+ @echo " check Run all checks (lint, typecheck, security, test)"
18
+ @echo " build Build package for distribution"
19
+ @echo " publish Publish to PyPI"
20
+ @echo " clean Remove build artifacts"
21
+
22
+ # Install production dependencies
23
+ install:
24
+ uv sync
25
+
26
+ # Install development dependencies
27
+ dev:
28
+ uv sync --all-extras
29
+
30
+ # Run linting
31
+ lint:
32
+ uv run ruff check src tests
33
+
34
+ # Format code
35
+ format:
36
+ uv run ruff check --fix src tests
37
+ uv run ruff format src tests
38
+
39
+ # Run type checking with pyrefly
40
+ typecheck:
41
+ uv run pyrefly check src
42
+
43
+ # Run security checks with bandit
44
+ security:
45
+ uv run bandit -r src -c pyproject.toml
46
+
47
+ # Run tests
48
+ test:
49
+ uv run pytest
50
+
51
+ # Run all checks
52
+ check: lint typecheck security test
53
+
54
+ # Build package
55
+ build: clean
56
+ uv build
57
+
58
+ # Publish to PyPI
59
+ publish: build
60
+ uv publish
61
+
62
+ # Publish to TestPyPI first (for testing)
63
+ publish-test: build
64
+ uv publish --index-url https://test.pypi.org/simple/
65
+
66
+ # Clean build artifacts
67
+ clean:
68
+ rm -rf dist/
69
+ rm -rf build/
70
+ rm -rf *.egg-info/
71
+ rm -rf src/*.egg-info/
72
+ rm -rf .pytest_cache/
73
+ rm -rf .ruff_cache/
74
+ rm -rf .coverage
75
+ rm -rf htmlcov/
76
+ find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
77
+ find . -type f -name "*.pyc" -delete 2>/dev/null || true
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: envdrift
3
+ Version: 0.0.1
4
+ Summary: Prevent environment variable drift with Pydantic schema validation, pre-commit hooks, and dotenvx encryption
5
+ Project-URL: Homepage, https://github.com/jainal09/envdrift
6
+ Project-URL: Documentation, https://github.com/jainal09/envdrift#readme
7
+ Project-URL: Repository, https://github.com/jainal09/envdrift
8
+ Project-URL: Issues, https://github.com/jainal09/envdrift/issues
9
+ Author-email: Jainal Gosaliya <gosaliya.jainal@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: config,dotenv,drift,environment,pre-commit,pydantic,schema,secrets,validation,variables
13
+ Classifier: Development Status :: 1 - Planning
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Security
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: Software Development :: Quality Assurance
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: pydantic-settings>=2.0
27
+ Requires-Dist: pydantic>=2.0
28
+ Requires-Dist: python-dotenv>=1.0
29
+ Requires-Dist: rich>=13.0
30
+ Requires-Dist: typer>=0.9
31
+ Provides-Extra: dev
32
+ Requires-Dist: bandit>=1.7.0; extra == 'dev'
33
+ Requires-Dist: pre-commit>=3.0; extra == 'dev'
34
+ Requires-Dist: pyrefly>=0.2.0; extra == 'dev'
35
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
36
+ Requires-Dist: pytest>=8.0; extra == 'dev'
37
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
38
+ Description-Content-Type: text/markdown
39
+
40
+ # envdrift
41
+
42
+ [![PyPI version](https://badge.fury.io/py/envdrift.svg)](https://badge.fury.io/py/envdrift)
43
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
44
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
45
+
46
+ **Prevent environment variable drift between dev, staging, and production.**
47
+
48
+ > 🚧 **Under Active Development** - Core features coming in v0.1.0
49
+
50
+ ## The Problem
51
+
52
+ Environment variable drift is a silent killer of deployments:
53
+
54
+ - A missing `DATABASE_URL` in production causes a 3am outage
55
+ - Staging has `NEW_FEATURE_FLAG=true` but production doesn't
56
+ - Someone copies the wrong `.env` file and chaos ensues
57
+ - "It works on my machine!" becomes your team's motto
58
+
59
+ **In 2024 alone, 24 million secrets were leaked on GitHub.** Knight Capital lost **$460 million in 45 minutes** due to a configuration deployment error.
60
+
61
+ ## The Solution
62
+
63
+ `envdrift` treats your environment variables with the same rigor as your code:
64
+
65
+ - **Schema Validation**: Define expected variables with Pydantic, catch mismatches at startup
66
+ - **Drift Detection**: Compare `.env.dev` vs `.env.prod` and see exactly what differs
67
+ - **Pre-commit Hooks**: Block commits if your `.env` doesn't match your schema
68
+ - **CI/CD Integration**: Fail fast in pipelines before bad config reaches production
69
+ - **Encryption Support**: Works with dotenvx for secure, committable `.env` files
70
+
71
+ ## Installation
72
+
73
+ ```bash
74
+ pip install envdrift
75
+ # or
76
+ uv add envdrift
77
+ ```
78
+
79
+ ## Quick Start
80
+
81
+ ### Validate your .env against a schema
82
+
83
+ ```bash
84
+ envdrift validate .env --schema myapp.config:Settings
85
+ ```
86
+
87
+ ### Compare environments
88
+
89
+ ```bash
90
+ envdrift diff .env.dev .env.prod
91
+ ```
92
+
93
+ ### Generate a Settings class from existing .env
94
+
95
+ ```bash
96
+ envdrift init .env --output settings.py
97
+ ```
98
+
99
+ ### Install pre-commit hook
100
+
101
+ ```bash
102
+ envdrift hook --install
103
+ ```
104
+
105
+ ## Planned Features (v0.1.0)
106
+
107
+ - [ ] `envdrift validate` - Validate .env against Pydantic schema
108
+ - [ ] `envdrift diff` - Compare two .env files
109
+ - [ ] `envdrift init` - Generate Settings class from .env
110
+ - [ ] `envdrift hook` - Pre-commit hook integration
111
+ - [ ] Rich terminal output with clear error messages
112
+ - [ ] dotenvx encryption detection and support
113
+ - [ ] CI mode with proper exit codes
114
+
115
+ ## Why envdrift?
116
+
117
+ | Feature | python-dotenv | dynaconf | pydantic-settings | **envdrift** |
118
+ |---------|---------------|----------|-------------------|--------------|
119
+ | Load .env | ✅ | ✅ | ✅ | ✅ |
120
+ | Type validation | ❌ | ⚠️ | ✅ | ✅ |
121
+ | Schema enforcement | ❌ | ⚠️ | ✅ | ✅ |
122
+ | Cross-env diff | ❌ | ❌ | ❌ | ✅ |
123
+ | Pre-commit hook | ❌ | ❌ | ❌ | ✅ |
124
+ | Encryption support | ❌ | ❌ | ❌ | ✅ |
125
+
126
+ ## Development
127
+
128
+ ```bash
129
+ # Clone the repo
130
+ git clone https://github.com/jainal09/envdrift.git
131
+ cd envdrift
132
+
133
+ # Install dev dependencies
134
+ make dev
135
+
136
+ # Run checks
137
+ make check
138
+ ```
139
+
140
+ ## License
141
+
142
+ MIT License - see [LICENSE](LICENSE) for details.
143
+
144
+ ## Author
145
+
146
+ **Jainal Gosaliya** - [gosaliya.jainal@gmail.com](mailto:gosaliya.jainal@gmail.com)
@@ -0,0 +1,107 @@
1
+ # envdrift
2
+
3
+ [![PyPI version](https://badge.fury.io/py/envdrift.svg)](https://badge.fury.io/py/envdrift)
4
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ **Prevent environment variable drift between dev, staging, and production.**
8
+
9
+ > 🚧 **Under Active Development** - Core features coming in v0.1.0
10
+
11
+ ## The Problem
12
+
13
+ Environment variable drift is a silent killer of deployments:
14
+
15
+ - A missing `DATABASE_URL` in production causes a 3am outage
16
+ - Staging has `NEW_FEATURE_FLAG=true` but production doesn't
17
+ - Someone copies the wrong `.env` file and chaos ensues
18
+ - "It works on my machine!" becomes your team's motto
19
+
20
+ **In 2024 alone, 24 million secrets were leaked on GitHub.** Knight Capital lost **$460 million in 45 minutes** due to a configuration deployment error.
21
+
22
+ ## The Solution
23
+
24
+ `envdrift` treats your environment variables with the same rigor as your code:
25
+
26
+ - **Schema Validation**: Define expected variables with Pydantic, catch mismatches at startup
27
+ - **Drift Detection**: Compare `.env.dev` vs `.env.prod` and see exactly what differs
28
+ - **Pre-commit Hooks**: Block commits if your `.env` doesn't match your schema
29
+ - **CI/CD Integration**: Fail fast in pipelines before bad config reaches production
30
+ - **Encryption Support**: Works with dotenvx for secure, committable `.env` files
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install envdrift
36
+ # or
37
+ uv add envdrift
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ### Validate your .env against a schema
43
+
44
+ ```bash
45
+ envdrift validate .env --schema myapp.config:Settings
46
+ ```
47
+
48
+ ### Compare environments
49
+
50
+ ```bash
51
+ envdrift diff .env.dev .env.prod
52
+ ```
53
+
54
+ ### Generate a Settings class from existing .env
55
+
56
+ ```bash
57
+ envdrift init .env --output settings.py
58
+ ```
59
+
60
+ ### Install pre-commit hook
61
+
62
+ ```bash
63
+ envdrift hook --install
64
+ ```
65
+
66
+ ## Planned Features (v0.1.0)
67
+
68
+ - [ ] `envdrift validate` - Validate .env against Pydantic schema
69
+ - [ ] `envdrift diff` - Compare two .env files
70
+ - [ ] `envdrift init` - Generate Settings class from .env
71
+ - [ ] `envdrift hook` - Pre-commit hook integration
72
+ - [ ] Rich terminal output with clear error messages
73
+ - [ ] dotenvx encryption detection and support
74
+ - [ ] CI mode with proper exit codes
75
+
76
+ ## Why envdrift?
77
+
78
+ | Feature | python-dotenv | dynaconf | pydantic-settings | **envdrift** |
79
+ |---------|---------------|----------|-------------------|--------------|
80
+ | Load .env | ✅ | ✅ | ✅ | ✅ |
81
+ | Type validation | ❌ | ⚠️ | ✅ | ✅ |
82
+ | Schema enforcement | ❌ | ⚠️ | ✅ | ✅ |
83
+ | Cross-env diff | ❌ | ❌ | ❌ | ✅ |
84
+ | Pre-commit hook | ❌ | ❌ | ❌ | ✅ |
85
+ | Encryption support | ❌ | ❌ | ❌ | ✅ |
86
+
87
+ ## Development
88
+
89
+ ```bash
90
+ # Clone the repo
91
+ git clone https://github.com/jainal09/envdrift.git
92
+ cd envdrift
93
+
94
+ # Install dev dependencies
95
+ make dev
96
+
97
+ # Run checks
98
+ make check
99
+ ```
100
+
101
+ ## License
102
+
103
+ MIT License - see [LICENSE](LICENSE) for details.
104
+
105
+ ## Author
106
+
107
+ **Jainal Gosaliya** - [gosaliya.jainal@gmail.com](mailto:gosaliya.jainal@gmail.com)
@@ -0,0 +1,124 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "envdrift"
7
+ version = "0.0.1"
8
+ description = "Prevent environment variable drift with Pydantic schema validation, pre-commit hooks, and dotenvx encryption"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ { name = "Jainal Gosaliya", email = "gosaliya.jainal@gmail.com" }
14
+ ]
15
+ keywords = [
16
+ "environment",
17
+ "variables",
18
+ "pydantic",
19
+ "validation",
20
+ "dotenv",
21
+ "config",
22
+ "drift",
23
+ "schema",
24
+ "secrets",
25
+ "pre-commit",
26
+ ]
27
+ classifiers = [
28
+ "Development Status :: 1 - Planning",
29
+ "Intended Audience :: Developers",
30
+ "License :: OSI Approved :: MIT License",
31
+ "Operating System :: OS Independent",
32
+ "Programming Language :: Python :: 3",
33
+ "Programming Language :: Python :: 3.11",
34
+ "Programming Language :: Python :: 3.12",
35
+ "Programming Language :: Python :: 3.13",
36
+ "Topic :: Software Development :: Libraries :: Python Modules",
37
+ "Topic :: Software Development :: Quality Assurance",
38
+ "Topic :: Security",
39
+ "Typing :: Typed",
40
+ ]
41
+ dependencies = [
42
+ "pydantic>=2.0",
43
+ "pydantic-settings>=2.0",
44
+ "rich>=13.0",
45
+ "typer>=0.9",
46
+ "python-dotenv>=1.0",
47
+ ]
48
+
49
+ [project.optional-dependencies]
50
+ dev = [
51
+ "ruff>=0.8.0",
52
+ "pyrefly>=0.2.0",
53
+ "bandit>=1.7.0",
54
+ "pytest>=8.0",
55
+ "pytest-cov>=4.0",
56
+ "pre-commit>=3.0",
57
+ ]
58
+
59
+ [project.scripts]
60
+ envdrift = "envdrift.cli:app"
61
+
62
+ [project.urls]
63
+ Homepage = "https://github.com/jainal09/envdrift"
64
+ Documentation = "https://github.com/jainal09/envdrift#readme"
65
+ Repository = "https://github.com/jainal09/envdrift"
66
+ Issues = "https://github.com/jainal09/envdrift/issues"
67
+
68
+ [tool.hatch.build.targets.wheel]
69
+ packages = ["src/envdrift"]
70
+
71
+ [tool.ruff]
72
+ target-version = "py311"
73
+ line-length = 100
74
+ src = ["src", "tests"]
75
+
76
+ [tool.ruff.lint]
77
+ select = [
78
+ "E", # pycodestyle errors
79
+ "W", # pycodestyle warnings
80
+ "F", # Pyflakes
81
+ "I", # isort
82
+ "N", # pep8-naming
83
+ "UP", # pyupgrade
84
+ "B", # flake8-bugbear
85
+ "C4", # flake8-comprehensions
86
+ "SIM", # flake8-simplify
87
+ "PTH", # flake8-use-pathlib
88
+ "RUF", # Ruff-specific rules
89
+ "S", # flake8-bandit (security)
90
+ ]
91
+ ignore = [
92
+ "S101", # assert allowed in tests
93
+ ]
94
+
95
+ [tool.ruff.lint.per-file-ignores]
96
+ "tests/*" = ["S101"]
97
+
98
+ [tool.ruff.format]
99
+ quote-style = "double"
100
+ indent-style = "space"
101
+
102
+ [tool.pytest.ini_options]
103
+ testpaths = ["tests"]
104
+ pythonpath = ["src"]
105
+ addopts = [
106
+ "--strict-markers",
107
+ "--cov=envdrift",
108
+ "--cov-report=term-missing",
109
+ ]
110
+
111
+ [tool.coverage.run]
112
+ source = ["src/envdrift"]
113
+ branch = true
114
+
115
+ [tool.coverage.report]
116
+ exclude_lines = [
117
+ "pragma: no cover",
118
+ "if TYPE_CHECKING:",
119
+ "raise NotImplementedError",
120
+ ]
121
+
122
+ [tool.bandit]
123
+ exclude_dirs = ["tests", ".venv"]
124
+ skips = ["B101"]
@@ -0,0 +1,16 @@
1
+ """Prevent environment variable drift with Pydantic schema validation.
2
+
3
+ envdrift helps you:
4
+ - Validate .env files against Pydantic schemas
5
+ - Detect drift between environments (dev, staging, prod)
6
+ - Integrate with pre-commit hooks and CI/CD pipelines
7
+ - Support dotenvx encryption for secure .env files
8
+ """
9
+
10
+ __version__ = "0.0.1"
11
+ __author__ = "Jainal Gosaliya"
12
+ __email__ = "gosaliya.jainal@gmail.com"
13
+
14
+ from envdrift.core import validate, diff, init
15
+
16
+ __all__ = ["validate", "diff", "init", "__version__"]
@@ -0,0 +1,107 @@
1
+ """Command-line interface for envdrift."""
2
+
3
+ from pathlib import Path
4
+ from typing import Annotated, Optional
5
+
6
+ import typer
7
+ from rich.console import Console
8
+ from rich.panel import Panel
9
+
10
+ app = typer.Typer(
11
+ name="envdrift",
12
+ help="Prevent environment variable drift with Pydantic schema validation.",
13
+ no_args_is_help=True,
14
+ )
15
+ console = Console()
16
+
17
+
18
+ @app.command()
19
+ def validate(
20
+ env_file: Annotated[
21
+ Path, typer.Argument(help="Path to .env file to validate")
22
+ ] = Path(".env"),
23
+ schema: Annotated[
24
+ Optional[str],
25
+ typer.Option("--schema", "-s", help="Dotted path to Settings class"),
26
+ ] = None,
27
+ ci: Annotated[
28
+ bool, typer.Option("--ci", help="CI mode: exit with code 1 on failure")
29
+ ] = False,
30
+ ) -> None:
31
+ """Validate an .env file against a Pydantic schema."""
32
+ console.print(
33
+ Panel(
34
+ "[yellow]Coming soon in v0.1.0[/yellow]\n\n"
35
+ "This command will validate your .env file against a Pydantic Settings schema.",
36
+ title="envdrift validate",
37
+ )
38
+ )
39
+ if ci:
40
+ raise typer.Exit(code=1)
41
+
42
+
43
+ @app.command()
44
+ def diff(
45
+ env1: Annotated[Path, typer.Argument(help="First .env file (e.g., .env.dev)")],
46
+ env2: Annotated[Path, typer.Argument(help="Second .env file (e.g., .env.prod)")],
47
+ ) -> None:
48
+ """Compare two .env files and show differences."""
49
+ console.print(
50
+ Panel(
51
+ "[yellow]Coming soon in v0.1.0[/yellow]\n\n"
52
+ f"This command will compare [bold]{env1}[/bold] and [bold]{env2}[/bold]\n"
53
+ "and show missing, extra, and differing variables.",
54
+ title="envdrift diff",
55
+ )
56
+ )
57
+
58
+
59
+ @app.command()
60
+ def init(
61
+ env_file: Annotated[
62
+ Path, typer.Argument(help="Path to .env file to generate schema from")
63
+ ] = Path(".env"),
64
+ output: Annotated[
65
+ Path, typer.Option("--output", "-o", help="Output file for Settings class")
66
+ ] = Path("settings.py"),
67
+ ) -> None:
68
+ """Generate a Pydantic Settings class from an existing .env file."""
69
+ console.print(
70
+ Panel(
71
+ "[yellow]Coming soon in v0.1.0[/yellow]\n\n"
72
+ f"This command will generate a Pydantic Settings class\n"
73
+ f"from [bold]{env_file}[/bold] and write it to [bold]{output}[/bold].",
74
+ title="envdrift init",
75
+ )
76
+ )
77
+
78
+
79
+ @app.command()
80
+ def hook(
81
+ install: Annotated[
82
+ bool, typer.Option("--install", "-i", help="Install pre-commit hook")
83
+ ] = False,
84
+ ) -> None:
85
+ """Manage pre-commit hook integration."""
86
+ if install:
87
+ console.print(
88
+ Panel(
89
+ "[yellow]Coming soon in v0.1.0[/yellow]\n\n"
90
+ "This command will add envdrift to your .pre-commit-config.yaml",
91
+ title="envdrift hook",
92
+ )
93
+ )
94
+ else:
95
+ console.print("Use --install to add envdrift pre-commit hook")
96
+
97
+
98
+ @app.command()
99
+ def version() -> None:
100
+ """Show envdrift version."""
101
+ from envdrift import __version__
102
+
103
+ console.print(f"envdrift [bold green]{__version__}[/bold green]")
104
+
105
+
106
+ if __name__ == "__main__":
107
+ app()
@@ -0,0 +1,47 @@
1
+ """Core functionality for envdrift."""
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def validate(env_file: Path | str = ".env", schema: str | None = None) -> bool:
7
+ """Validate an .env file against a Pydantic schema.
8
+
9
+ Args:
10
+ env_file: Path to the .env file to validate
11
+ schema: Dotted path to the Pydantic Settings class (e.g., 'app.config:Settings')
12
+
13
+ Returns:
14
+ True if validation passes, False otherwise
15
+
16
+ Raises:
17
+ NotImplementedError: This feature is coming soon
18
+ """
19
+ raise NotImplementedError("Coming soon in v0.1.0")
20
+
21
+
22
+ def diff(env1: Path | str, env2: Path | str) -> dict[str, tuple[str | None, str | None]]:
23
+ """Compare two .env files and return differences.
24
+
25
+ Args:
26
+ env1: Path to first .env file
27
+ env2: Path to second .env file
28
+
29
+ Returns:
30
+ Dictionary of differences: {key: (value_in_env1, value_in_env2)}
31
+
32
+ Raises:
33
+ NotImplementedError: This feature is coming soon
34
+ """
35
+ raise NotImplementedError("Coming soon in v0.1.0")
36
+
37
+
38
+ def init(output: Path | str = "settings.py") -> None:
39
+ """Generate a Pydantic Settings class from an existing .env file.
40
+
41
+ Args:
42
+ output: Path where to write the generated Settings class
43
+
44
+ Raises:
45
+ NotImplementedError: This feature is coming soon
46
+ """
47
+ raise NotImplementedError("Coming soon in v0.1.0")
File without changes
@@ -0,0 +1 @@
1
+ """Tests for envdrift."""
@@ -0,0 +1,42 @@
1
+ """Tests for CLI commands."""
2
+
3
+ from typer.testing import CliRunner
4
+
5
+ from envdrift.cli import app
6
+
7
+ runner = CliRunner()
8
+
9
+
10
+ def test_version() -> None:
11
+ """Test version command."""
12
+ result = runner.invoke(app, ["version"])
13
+ assert result.exit_code == 0
14
+ assert "0.0.1" in result.stdout
15
+
16
+
17
+ def test_validate_coming_soon() -> None:
18
+ """Test validate command shows coming soon message."""
19
+ result = runner.invoke(app, ["validate"])
20
+ assert result.exit_code == 0
21
+ assert "Coming soon" in result.stdout
22
+
23
+
24
+ def test_diff_coming_soon() -> None:
25
+ """Test diff command shows coming soon message."""
26
+ result = runner.invoke(app, ["diff", ".env.dev", ".env.prod"])
27
+ assert result.exit_code == 0
28
+ assert "Coming soon" in result.stdout
29
+
30
+
31
+ def test_init_coming_soon() -> None:
32
+ """Test init command shows coming soon message."""
33
+ result = runner.invoke(app, ["init"])
34
+ assert result.exit_code == 0
35
+ assert "Coming soon" in result.stdout
36
+
37
+
38
+ def test_hook_without_install() -> None:
39
+ """Test hook command without --install flag."""
40
+ result = runner.invoke(app, ["hook"])
41
+ assert result.exit_code == 0
42
+ assert "--install" in result.stdout