Last active
December 31, 2025 16:40
-
-
Save aaryadev/760e3835cf6e0f4f6a1b1638c7e21011 to your computer and use it in GitHub Desktop.
deploy the repo using python ( for raspi with AGro tunnel, Apache peroxided deployment)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import http.server | |
| import socketserver | |
| import json | |
| import subprocess | |
| import os | |
| import shutil | |
| import datetime | |
| import sys | |
| import threading | |
| # ========================================== | |
| # CONFIGURATION | |
| # ========================================== | |
| # 1. Server Configuration | |
| PORT = 10000 | |
| # 2. Git Configuration | |
| # Use the SSH URL for your repository | |
| REPO_URL = "git@yourdomain.com:username/repository.git" | |
| # Path to your private SSH key (e.g., "/home/user/.ssh/id_rsa") | |
| # If your key is already loaded in the ssh-agent, you can leave this as None | |
| SSH_KEY_PATH = "/path/to/your/private_key" | |
| # 3. Directory Configuration | |
| TEMP_DIR = "./temp_repo_clone" # Where the repo will be cloned temporarily | |
| DESTINATION_DIR = "./production_app" # Where the final files should go | |
| # 4. List of Cleanup/Build Commands | |
| # Add or remove commands here. These run inside the TEMP_DIR after cloning. | |
| COMMANDS_TO_RUN = [ | |
| "echo 'Starting build process...'", | |
| # "npm install", # Example: Install node dependencies | |
| # "rm -rf .git", # Example: Remove git history | |
| # "rm .gitignore", # Example: Remove gitignore | |
| "echo 'Cleanup commands completed.'" | |
| ] | |
| # ========================================== | |
| # SCRIPT LOGIC | |
| # ========================================== | |
| class WebhookHandler(http.server.BaseHTTPRequestHandler): | |
| def do_POST(self): | |
| """Handle incoming POST requests.""" | |
| # 1. Capture and Store JSON Data | |
| content_length = int(self.headers['Content-Length']) | |
| post_data = self.rfile.read(content_length) | |
| try: | |
| json_data = json.loads(post_data) | |
| # Save to a file with a timestamp | |
| timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") | |
| filename = f"payload_{timestamp}.json" | |
| with open(filename, "w") as f: | |
| json.dump(json_data, f, indent=4) | |
| print(f"[INFO] Received webhook. JSON saved to {filename}") | |
| # 2. Trigger the Deployment Process in the BACKGROUND | |
| # We create a new thread that targets the run_deployment method | |
| deployment_thread = threading.Thread(target=self.run_deployment) | |
| deployment_thread.start() | |
| # 3. Send Response Immediately | |
| self.send_response(200) | |
| self.send_header('Content-type', 'application/json') | |
| self.end_headers() | |
| # This returns immediately while the thread works in the background | |
| self.wfile.write(b'{"status": "success", "message": "Deployment triggered in background"}') | |
| except json.JSONDecodeError: | |
| print("[ERROR] Failed to decode JSON") | |
| self.send_response(400) | |
| self.end_headers() | |
| self.wfile.write(b'{"status": "error", "message": "Invalid JSON"}') | |
| except Exception as e: | |
| print(f"[ERROR] {str(e)}") | |
| self.send_response(500) | |
| self.end_headers() | |
| self.wfile.write(f'{{"status": "error", "message": "{str(e)}"}}'.encode()) | |
| def run_deployment(self): | |
| """Orchestrates the clone, clean, and copy process.""" | |
| print("--- Starting Deployment ---") | |
| # A. Setup SSH Environment | |
| git_env = os.environ.copy() | |
| if SSH_KEY_PATH and os.path.exists(SSH_KEY_PATH): | |
| # This tells Git to use a specific SSH key and disable strict host checking (optional but helpful for scripts) | |
| git_env["GIT_SSH_COMMAND"] = f"ssh -i {SSH_KEY_PATH} -o StrictHostKeyChecking=no" | |
| # B. Clean previous temp directory if it exists | |
| if os.path.exists(TEMP_DIR): | |
| shutil.rmtree(TEMP_DIR) | |
| # C. Clone the Repository | |
| print(f"[CMD] Cloning {REPO_URL} into {TEMP_DIR}...") | |
| try: | |
| subprocess.run( | |
| ["git", "clone", REPO_URL, TEMP_DIR], | |
| check=True, | |
| env=git_env | |
| ) | |
| except subprocess.CalledProcessError as e: | |
| print(f"[FAIL] Git clone failed: {e}") | |
| return | |
| # D. Run User Defined Commands | |
| print("[CMD] Running cleanup/build commands...") | |
| for cmd in COMMANDS_TO_RUN: | |
| try: | |
| # shell=True allows running complex shell commands strings | |
| subprocess.run(cmd, shell=True, check=True, cwd=TEMP_DIR) | |
| except subprocess.CalledProcessError as e: | |
| print(f"[FAIL] Command '{cmd}' failed. Stopping deployment.") | |
| return | |
| # E. Copy Only Modified Files (using rsync) | |
| # rsync is preferred over python's shutil because it handles 'only modified' logic perfectly. | |
| # -a: archive mode (preserves permissions, times, etc.) | |
| # -v: verbose | |
| # --update: skip files that are newer on the receiver | |
| print(f"[CMD] Syncing files to {DESTINATION_DIR}...") | |
| # Ensure destination exists | |
| if not os.path.exists(DESTINATION_DIR): | |
| os.makedirs(DESTINATION_DIR) | |
| try: | |
| # Note: Putting a slash at the end of source (TEMP_DIR/) is important in rsync | |
| # to copy contents, not the folder itself. | |
| rsync_cmd = ["rsync", "-av", "--update", f"{TEMP_DIR}/", DESTINATION_DIR] | |
| subprocess.run(rsync_cmd, check=True) | |
| print("[SUCCESS] Deployment finished successfully.") | |
| except subprocess.CalledProcessError as e: | |
| print(f"[FAIL] Rsync failed: {e}") | |
| # ========================================== | |
| # MAIN ENTRY POINT | |
| # ========================================== | |
| if __name__ == "__main__": | |
| try: | |
| with socketserver.TCPServer(("", PORT), WebhookHandler) as httpd: | |
| print(f"Serving on port {PORT}...") | |
| print(f"Configured to clone from: {REPO_URL}") | |
| print("Press Ctrl+C to stop.") | |
| httpd.serve_forever() | |
| except KeyboardInterrupt: | |
| print("\nServer stopped.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment