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.
@@ -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"]