predeploy-doctor 0.1.0__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.
- predeploy_doctor-0.1.0/.gitignore +23 -0
- predeploy_doctor-0.1.0/LICENSE +21 -0
- predeploy_doctor-0.1.0/PKG-INFO +90 -0
- predeploy_doctor-0.1.0/README.md +71 -0
- predeploy_doctor-0.1.0/predeploy/__init__.py +1 -0
- predeploy_doctor-0.1.0/predeploy/checks/__init__.py +0 -0
- predeploy_doctor-0.1.0/predeploy/checks/docker.py +27 -0
- predeploy_doctor-0.1.0/predeploy/checks/env.py +21 -0
- predeploy_doctor-0.1.0/predeploy/checks/files.py +28 -0
- predeploy_doctor-0.1.0/predeploy/checks/k8s.py +38 -0
- predeploy_doctor-0.1.0/predeploy/checks/ports.py +33 -0
- predeploy_doctor-0.1.0/predeploy/cli.py +85 -0
- predeploy_doctor-0.1.0/predeploy/config.py +26 -0
- predeploy_doctor-0.1.0/predeploy.yaml.example +18 -0
- predeploy_doctor-0.1.0/pyproject.toml +33 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.whl
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
venv/
|
|
14
|
+
.venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# Configuration and secrets
|
|
18
|
+
.env
|
|
19
|
+
predeploy.yaml
|
|
20
|
+
|
|
21
|
+
# OS generated files
|
|
22
|
+
.DS_Store
|
|
23
|
+
Thumbs.db
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Pre-Deploy Doctor Contributors
|
|
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,90 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: predeploy-doctor
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A local DevOps readiness checker for safer deployments.
|
|
5
|
+
Author: AyaanB24
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
12
|
+
Classifier: Topic :: System :: Systems Administration
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Requires-Dist: click>=8.0.0
|
|
15
|
+
Requires-Dist: psutil>=5.9.0
|
|
16
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
17
|
+
Requires-Dist: pyyaml>=6.0
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# 🩺 Pre-Deploy Doctor
|
|
21
|
+
|
|
22
|
+
**Pre-Deploy Doctor** is a local DevOps readiness checker that validates whether your environment is safe to deploy BEFORE you run Docker, kubectl, or CI/CD pipelines.
|
|
23
|
+
|
|
24
|
+
It runs 100% locally, requires no cloud accounts or AI, and is designed to catch common "stupid" mistakes before they hit your production infrastructure.
|
|
25
|
+
|
|
26
|
+
## 🚀 Features
|
|
27
|
+
|
|
28
|
+
- **Docker Health**: Checks if Docker is installed and the daemon is actually running.
|
|
29
|
+
- **Environment Validation**: Loads `.env` and validates that your required environment variables are set.
|
|
30
|
+
- **Port Conflicts**: Identifies if required ports are already in use and shows the conflicting process name.
|
|
31
|
+
- **Kubernetes Context Safety**: Warns you if your `kubectl` context isn't in your "allowed" list for the project.
|
|
32
|
+
- **Project Structure**: Ensures critical files like `Dockerfile` are present.
|
|
33
|
+
|
|
34
|
+
## 📦 Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install predeploy-doctor
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 🛠 Usage
|
|
41
|
+
|
|
42
|
+
Run inside any project directory:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
predeploy check
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Configuration (`predeploy.yaml`)
|
|
49
|
+
|
|
50
|
+
Create a `predeploy.yaml` in your project root to customize the checks:
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
required_env:
|
|
54
|
+
- DB_URL
|
|
55
|
+
- SECRET_KEY
|
|
56
|
+
|
|
57
|
+
required_ports:
|
|
58
|
+
- 3000
|
|
59
|
+
- 5432
|
|
60
|
+
|
|
61
|
+
kubernetes:
|
|
62
|
+
allowed_contexts:
|
|
63
|
+
- dev
|
|
64
|
+
- staging
|
|
65
|
+
- minikube
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 📋 Sample Output
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
🩺 Pre-Deploy Doctor Report
|
|
72
|
+
|
|
73
|
+
✔ Docker is running
|
|
74
|
+
✔ Found Dockerfile
|
|
75
|
+
✔ All required environment variables are set
|
|
76
|
+
❌ Port 3000 already in use (Process: node)
|
|
77
|
+
⚠ Kubernetes context 'production' not in allowed list
|
|
78
|
+
|
|
79
|
+
==============================
|
|
80
|
+
Status: ❌ NOT SAFE TO DEPLOY
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 🔢 Exit Codes
|
|
84
|
+
|
|
85
|
+
- `0`: All checks passed (or only warnings). Safe to deploy.
|
|
86
|
+
- `1`: One or more critical checks failed. **Deployment should be blocked.**
|
|
87
|
+
|
|
88
|
+
## 📜 License
|
|
89
|
+
|
|
90
|
+
MIT
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# 🩺 Pre-Deploy Doctor
|
|
2
|
+
|
|
3
|
+
**Pre-Deploy Doctor** is a local DevOps readiness checker that validates whether your environment is safe to deploy BEFORE you run Docker, kubectl, or CI/CD pipelines.
|
|
4
|
+
|
|
5
|
+
It runs 100% locally, requires no cloud accounts or AI, and is designed to catch common "stupid" mistakes before they hit your production infrastructure.
|
|
6
|
+
|
|
7
|
+
## 🚀 Features
|
|
8
|
+
|
|
9
|
+
- **Docker Health**: Checks if Docker is installed and the daemon is actually running.
|
|
10
|
+
- **Environment Validation**: Loads `.env` and validates that your required environment variables are set.
|
|
11
|
+
- **Port Conflicts**: Identifies if required ports are already in use and shows the conflicting process name.
|
|
12
|
+
- **Kubernetes Context Safety**: Warns you if your `kubectl` context isn't in your "allowed" list for the project.
|
|
13
|
+
- **Project Structure**: Ensures critical files like `Dockerfile` are present.
|
|
14
|
+
|
|
15
|
+
## 📦 Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install predeploy-doctor
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 🛠 Usage
|
|
22
|
+
|
|
23
|
+
Run inside any project directory:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
predeploy check
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Configuration (`predeploy.yaml`)
|
|
30
|
+
|
|
31
|
+
Create a `predeploy.yaml` in your project root to customize the checks:
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
required_env:
|
|
35
|
+
- DB_URL
|
|
36
|
+
- SECRET_KEY
|
|
37
|
+
|
|
38
|
+
required_ports:
|
|
39
|
+
- 3000
|
|
40
|
+
- 5432
|
|
41
|
+
|
|
42
|
+
kubernetes:
|
|
43
|
+
allowed_contexts:
|
|
44
|
+
- dev
|
|
45
|
+
- staging
|
|
46
|
+
- minikube
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 📋 Sample Output
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
🩺 Pre-Deploy Doctor Report
|
|
53
|
+
|
|
54
|
+
✔ Docker is running
|
|
55
|
+
✔ Found Dockerfile
|
|
56
|
+
✔ All required environment variables are set
|
|
57
|
+
❌ Port 3000 already in use (Process: node)
|
|
58
|
+
⚠ Kubernetes context 'production' not in allowed list
|
|
59
|
+
|
|
60
|
+
==============================
|
|
61
|
+
Status: ❌ NOT SAFE TO DEPLOY
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 🔢 Exit Codes
|
|
65
|
+
|
|
66
|
+
- `0`: All checks passed (or only warnings). Safe to deploy.
|
|
67
|
+
- `1`: One or more critical checks failed. **Deployment should be blocked.**
|
|
68
|
+
|
|
69
|
+
## 📜 License
|
|
70
|
+
|
|
71
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import shutil
|
|
3
|
+
|
|
4
|
+
def check_docker():
|
|
5
|
+
"""
|
|
6
|
+
Checks if Docker is installed and running.
|
|
7
|
+
Returns: (bool, str) - (Success, Message)
|
|
8
|
+
"""
|
|
9
|
+
if not shutil.which("docker"):
|
|
10
|
+
return False, "Docker is not installed"
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
# 'docker info' returns 0 if daemon is running
|
|
14
|
+
process = subprocess.run(
|
|
15
|
+
["docker", "info"],
|
|
16
|
+
stdout=subprocess.DEVNULL,
|
|
17
|
+
stderr=subprocess.DEVNULL,
|
|
18
|
+
timeout=5
|
|
19
|
+
)
|
|
20
|
+
if process.returncode == 0:
|
|
21
|
+
return True, "Docker is running"
|
|
22
|
+
else:
|
|
23
|
+
return False, "Docker daemon is not running"
|
|
24
|
+
except subprocess.TimeoutExpired:
|
|
25
|
+
return False, "Docker info command timed out (daemon might be unresponsive)"
|
|
26
|
+
except Exception as e:
|
|
27
|
+
return False, f"Error checking Docker: {str(e)}"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
def check_env(config):
|
|
4
|
+
"""
|
|
5
|
+
Validates required environment variables from config.
|
|
6
|
+
Returns: list of (bool, str) - (Success, Message)
|
|
7
|
+
"""
|
|
8
|
+
required_vars = config.get("required_env", [])
|
|
9
|
+
if not required_vars:
|
|
10
|
+
return [(True, "No required environment variables specified")]
|
|
11
|
+
|
|
12
|
+
results = []
|
|
13
|
+
missing_vars = []
|
|
14
|
+
for var in required_vars:
|
|
15
|
+
if not os.environ.get(var):
|
|
16
|
+
missing_vars.append(var)
|
|
17
|
+
|
|
18
|
+
if not missing_vars:
|
|
19
|
+
return [(True, "All required environment variables are set")]
|
|
20
|
+
else:
|
|
21
|
+
return [(False, f"Missing environment variables: {', '.join(missing_vars)}")]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
def check_files():
|
|
4
|
+
"""
|
|
5
|
+
Checks for presence of critical project files.
|
|
6
|
+
Returns: list of (bool, str) - (Success, Message)
|
|
7
|
+
"""
|
|
8
|
+
results = []
|
|
9
|
+
|
|
10
|
+
# Critical files
|
|
11
|
+
critical_files = ["Dockerfile", "docker-compose.yml"]
|
|
12
|
+
found_any = False
|
|
13
|
+
|
|
14
|
+
for filename in critical_files:
|
|
15
|
+
if Path(filename).exists():
|
|
16
|
+
results.append((True, f"Found {filename}"))
|
|
17
|
+
found_any = True
|
|
18
|
+
else:
|
|
19
|
+
# We only fail if NONE of them exist or if they are expected?
|
|
20
|
+
# User said: "Missing critical files -> FAIL"
|
|
21
|
+
# I'll report success for what's found and maybe warning for what's missing
|
|
22
|
+
# but if it's a Docker project, a Dockerfile is usually mandatory.
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
if not found_any:
|
|
26
|
+
return [(False, "No Dockerfile or docker-compose.yml found in current directory")]
|
|
27
|
+
|
|
28
|
+
return results
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import shutil
|
|
3
|
+
|
|
4
|
+
def check_k8s(config):
|
|
5
|
+
"""
|
|
6
|
+
Checks if kubectl is installed and context is allowed.
|
|
7
|
+
Returns: list of (bool, str, str) - (Success, Message, Level)
|
|
8
|
+
Level can be 'fail', 'warning', 'success'
|
|
9
|
+
"""
|
|
10
|
+
if not shutil.which("kubectl"):
|
|
11
|
+
return [(True, "kubectl is not installed", "warning")]
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
result = subprocess.run(
|
|
15
|
+
["kubectl", "config", "current-context"],
|
|
16
|
+
capture_output=True,
|
|
17
|
+
text=True,
|
|
18
|
+
encoding="utf-8",
|
|
19
|
+
errors="ignore",
|
|
20
|
+
timeout=5
|
|
21
|
+
)
|
|
22
|
+
if result.returncode != 0:
|
|
23
|
+
return [(True, "Could not determine kubectl context", "warning")]
|
|
24
|
+
|
|
25
|
+
current_context = result.stdout.strip()
|
|
26
|
+
k8s_config = config.get("kubernetes", {})
|
|
27
|
+
allowed_contexts = k8s_config.get("allowed_contexts", [])
|
|
28
|
+
|
|
29
|
+
if not allowed_contexts:
|
|
30
|
+
return [(True, f"Kubernetes context: {current_context}", "warning")]
|
|
31
|
+
|
|
32
|
+
if current_context in allowed_contexts:
|
|
33
|
+
return [(True, f"Kubernetes context '{current_context}' is allowed", "success")]
|
|
34
|
+
else:
|
|
35
|
+
return [(True, f"Kubernetes context '{current_context}' not in allowed list", "warning")]
|
|
36
|
+
|
|
37
|
+
except Exception as e:
|
|
38
|
+
return [(True, f"Error checking Kubernetes: {str(e)}", "warning")]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import psutil
|
|
2
|
+
|
|
3
|
+
def check_ports(config):
|
|
4
|
+
"""
|
|
5
|
+
Checks if required ports are available.
|
|
6
|
+
Returns: list of (bool, str) - (Success, Message)
|
|
7
|
+
"""
|
|
8
|
+
required_ports = config.get("required_ports", [])
|
|
9
|
+
if not required_ports:
|
|
10
|
+
return [(True, "No required ports specified")]
|
|
11
|
+
|
|
12
|
+
results = []
|
|
13
|
+
# Get all active connections
|
|
14
|
+
connections = psutil.net_connections()
|
|
15
|
+
|
|
16
|
+
in_use = {}
|
|
17
|
+
for conn in connections:
|
|
18
|
+
if conn.laddr.port in required_ports and conn.status == 'LISTEN':
|
|
19
|
+
# Try to find the process name
|
|
20
|
+
try:
|
|
21
|
+
process = psutil.Process(conn.pid)
|
|
22
|
+
name = process.name()
|
|
23
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
24
|
+
name = "Unknown"
|
|
25
|
+
in_use[conn.laddr.port] = name
|
|
26
|
+
|
|
27
|
+
for port in required_ports:
|
|
28
|
+
if port in in_use:
|
|
29
|
+
results.append((False, f"Port {port} already in use (Process: {in_use[port]})"))
|
|
30
|
+
else:
|
|
31
|
+
results.append((True, f"Port {port} is available"))
|
|
32
|
+
|
|
33
|
+
return results
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import click
|
|
3
|
+
from .config import load_config, load_environment
|
|
4
|
+
from .checks.docker import check_docker
|
|
5
|
+
from .checks.env import check_env
|
|
6
|
+
from .checks.ports import check_ports
|
|
7
|
+
from .checks.k8s import check_k8s
|
|
8
|
+
from .checks.files import check_files
|
|
9
|
+
|
|
10
|
+
# Constants for status symbols
|
|
11
|
+
SUCCESS = "✔"
|
|
12
|
+
FAILURE = "❌"
|
|
13
|
+
WARNING = "⚠"
|
|
14
|
+
|
|
15
|
+
@click.group()
|
|
16
|
+
def main():
|
|
17
|
+
"""🩺 Pre-Deploy Doctor: A local DevOps readiness checker."""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@main.command()
|
|
21
|
+
def check():
|
|
22
|
+
"""Run all readiness checks."""
|
|
23
|
+
click.echo("\n🩺 Pre-Deploy Doctor Report\n")
|
|
24
|
+
|
|
25
|
+
config = load_config()
|
|
26
|
+
load_environment()
|
|
27
|
+
|
|
28
|
+
overall_safe = True
|
|
29
|
+
|
|
30
|
+
# 1. Docker Check
|
|
31
|
+
docker_success, docker_msg = check_docker()
|
|
32
|
+
if docker_success:
|
|
33
|
+
click.secho(f"{SUCCESS} {docker_msg}", fg="green")
|
|
34
|
+
else:
|
|
35
|
+
click.secho(f"{FAILURE} {docker_msg}", fg="red")
|
|
36
|
+
overall_safe = False
|
|
37
|
+
|
|
38
|
+
# 2. File Checks
|
|
39
|
+
file_results = check_files()
|
|
40
|
+
for success, msg in file_results:
|
|
41
|
+
if success:
|
|
42
|
+
click.secho(f"{SUCCESS} {msg}", fg="green")
|
|
43
|
+
else:
|
|
44
|
+
click.secho(f"{FAILURE} {msg}", fg="red")
|
|
45
|
+
overall_safe = False
|
|
46
|
+
|
|
47
|
+
# 3. Env Checks
|
|
48
|
+
env_results = check_env(config)
|
|
49
|
+
for success, msg in env_results:
|
|
50
|
+
if success:
|
|
51
|
+
click.secho(f"{SUCCESS} {msg}", fg="green")
|
|
52
|
+
else:
|
|
53
|
+
click.secho(f"{FAILURE} {msg}", fg="red")
|
|
54
|
+
overall_safe = False
|
|
55
|
+
|
|
56
|
+
# 4. Port Checks
|
|
57
|
+
port_results = check_ports(config)
|
|
58
|
+
for success, msg in port_results:
|
|
59
|
+
if success:
|
|
60
|
+
click.secho(f"{SUCCESS} {msg}", fg="green")
|
|
61
|
+
else:
|
|
62
|
+
click.secho(f"{FAILURE} {msg}", fg="red")
|
|
63
|
+
overall_safe = False
|
|
64
|
+
|
|
65
|
+
# 5. K8s Checks (Warnings)
|
|
66
|
+
k8s_results = check_k8s(config)
|
|
67
|
+
for success, msg, level in k8s_results:
|
|
68
|
+
if level == "success":
|
|
69
|
+
click.secho(f"{SUCCESS} {msg}", fg="green")
|
|
70
|
+
elif level == "warning":
|
|
71
|
+
click.secho(f"{WARNING} {msg}", fg="yellow")
|
|
72
|
+
else:
|
|
73
|
+
click.secho(f"{FAILURE} {msg}", fg="red")
|
|
74
|
+
overall_safe = False
|
|
75
|
+
|
|
76
|
+
click.echo("\n" + "="*30)
|
|
77
|
+
if overall_safe:
|
|
78
|
+
click.secho(f"Status: {SUCCESS} SAFE TO DEPLOY", bold=True, fg="green")
|
|
79
|
+
sys.exit(0)
|
|
80
|
+
else:
|
|
81
|
+
click.secho(f"Status: {FAILURE} NOT SAFE TO DEPLOY", bold=True, fg="red")
|
|
82
|
+
sys.exit(1)
|
|
83
|
+
|
|
84
|
+
if __name__ == "__main__":
|
|
85
|
+
main()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import yaml
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from dotenv import load_dotenv
|
|
5
|
+
|
|
6
|
+
def load_config():
|
|
7
|
+
"""
|
|
8
|
+
Loads predeploy.yaml if it exists.
|
|
9
|
+
Returns a dictionary of configuration.
|
|
10
|
+
"""
|
|
11
|
+
config_path = Path("predeploy.yaml")
|
|
12
|
+
if config_path.exists():
|
|
13
|
+
try:
|
|
14
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
15
|
+
return yaml.safe_load(f) or {}
|
|
16
|
+
except Exception:
|
|
17
|
+
return {}
|
|
18
|
+
return {}
|
|
19
|
+
|
|
20
|
+
def load_environment():
|
|
21
|
+
"""
|
|
22
|
+
Loads .env file if present in the current directory.
|
|
23
|
+
"""
|
|
24
|
+
dotenv_path = Path(".env")
|
|
25
|
+
if dotenv_path.exists():
|
|
26
|
+
load_dotenv(dotenv_path)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# 🩺 Pre-Deploy Doctor Configuration Example
|
|
2
|
+
# Copy this to 'predeploy.yaml' and modify it for your project.
|
|
3
|
+
|
|
4
|
+
# Environment variables that MUST be set
|
|
5
|
+
required_env:
|
|
6
|
+
- DB_URL
|
|
7
|
+
- SECRET_KEY
|
|
8
|
+
|
|
9
|
+
# Ports that MUST be available
|
|
10
|
+
required_ports:
|
|
11
|
+
- 3000
|
|
12
|
+
|
|
13
|
+
# Kubernetes Safety
|
|
14
|
+
kubernetes:
|
|
15
|
+
allowed_contexts:
|
|
16
|
+
- dev-cluster
|
|
17
|
+
- docker-desktop
|
|
18
|
+
- minikube
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "predeploy-doctor"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A local DevOps readiness checker for safer deployments."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "AyaanB24" }
|
|
12
|
+
]
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Topic :: Software Development :: Build Tools",
|
|
19
|
+
"Topic :: System :: Systems Administration",
|
|
20
|
+
]
|
|
21
|
+
requires-python = ">=3.8"
|
|
22
|
+
dependencies = [
|
|
23
|
+
"click>=8.0.0",
|
|
24
|
+
"PyYAML>=6.0",
|
|
25
|
+
"psutil>=5.9.0",
|
|
26
|
+
"python-dotenv>=1.0.0",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
predeploy = "predeploy.cli:main"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["predeploy"]
|