# Git-based Deployment in BYOP Engine ## Overview The BYOP Engine now supports Git-based deployments using Git hooks for continuous deployment. This allows developers to deploy applications by simply pushing to a Git repository. ## How It Works 1. **Initial Setup**: When a VM is initialized: - Creates a bare Git repository on the VM - Sets up a working directory for the component - Configures Git hooks for automatic deployment 2. **Continuous Deployment**: After initial setup, developers can: - Add the remote repository to their local Git config - Push changes to trigger automatic deployment - Monitor deployment progress through the BYOP dashboard 3. **Component-Specific Deployment**: Different components are handled appropriately: - **Frontend**: Built and served via Nginx - **Backend**: Built and managed via systemd or PM2 - **Database**: Configuration files applied and services restarted ## Usage ### Adding a Remote Repository After a component is deployed, add the remote repository to your Git config: ```bash git remote add production ssh://root@/opt/byop/repos/.git ``` ### Deploying Changes Push to the remote repository to trigger a deployment: ```bash git push production ``` The post-receive hook will automatically: 1. Check out the code to the working directory 2. Install dependencies 3. Build the application 4. Restart or reload services as needed ### Monitoring Deployments You can monitor deployment status through: - The BYOP dashboard - SSH access to the VM to check logs - Component status indicators ## Security Considerations - SSH access is controlled through credentials managed by BYOP - Deploy keys can be configured for secure repository access - All operations use secure SSH connections ## Future Enhancements - Support for deployment rollbacks - Automated testing before deployment - Multi-stage deployment environments (dev, staging, production) - Notification system for deployment status updates ## Post script hooks example ```golang // createFrontendPostReceiveHook generates a Git hook for frontend components func createFrontendPostReceiveHook(component models.Component, deployPath string) string { return fmt.Sprintf(`#!/bin/bash echo "Deploying frontend component: %s" # Get the target branch (usually main or master) TARGET="%s" while read oldrev newrev ref do # Check if the pushed branch is our target branch if [[ $ref = refs/heads/$TARGET ]]; then echo "Deploying $TARGET branch..." # Checkout code to the deployment directory GIT_WORK_TREE=%s git checkout -f $TARGET cd %s # Update environment variables echo '%s' > %s/.env # Install dependencies echo "Installing dependencies..." npm install # Build the application echo "Building application..." %s # Notify about completion echo "Frontend deployment completed successfully" fi done `, component.Name, component.Branch, deployPath, deployPath, component.EnvVariables, deployPath, component.BuildCommand) } // createGoPostReceiveHook generates a Git hook for Go components func createGoPostReceiveHook(component models.Component, deployPath string) string { return fmt.Sprintf(`#!/bin/bash echo "Deploying Go component: %s" # Get the target branch (usually main or master) TARGET="%s" while read oldrev newrev ref do # Check if the pushed branch is our target branch if [[ $ref = refs/heads/$TARGET ]]; then echo "Deploying $TARGET branch..." # Checkout code to the deployment directory GIT_WORK_TREE=%s git checkout -f $TARGET cd %s # Update environment variables echo '%s' > %s/.env # Build the application echo "Building Go application..." go build -o app # Restart the service echo "Restarting service..." systemctl restart byop-%s # Notify about completion echo "Go deployment completed successfully" fi done `, component.Name, component.Branch, deployPath, deployPath, component.EnvVariables, deployPath, component.ID) } // createNodePostReceiveHook generates a Git hook for Node.js components func createNodePostReceiveHook(component models.Component, deployPath string) string { return fmt.Sprintf(`#!/bin/bash echo "Deploying Node.js component: %s" # Get the target branch (usually main or master) TARGET="%s" while read oldrev newrev ref do # Check if the pushed branch is our target branch if [[ $ref = refs/heads/$TARGET ]]; then echo "Deploying $TARGET branch..." # Checkout code to the deployment directory GIT_WORK_TREE=%s git checkout -f $TARGET cd %s # Update environment variables echo '%s' > %s/.env # Install dependencies echo "Installing dependencies..." npm install # Build the application if there's a build command if [[ "%s" != "" ]]; then echo "Building application..." %s || true fi # Restart the PM2 process echo "Restarting PM2 process..." pm2 restart byop-%s || pm2 start npm --name "byop-%s" -- start pm2 save # Notify about completion echo "Node.js deployment completed successfully" fi done `, component.Name, component.Branch, deployPath, deployPath, component.EnvVariables, deployPath, component.BuildCommand, component.BuildCommand, component.ID, component.ID) } // createPythonPostReceiveHook generates a Git hook for Python components func createPythonPostReceiveHook(component models.Component, deployPath string) string { return fmt.Sprintf(`#!/bin/bash echo "Deploying Python component: %s" # Get the target branch (usually main or master) TARGET="%s" while read oldrev newrev ref do # Check if the pushed branch is our target branch if [[ $ref = refs/heads/$TARGET ]]; then echo "Deploying $TARGET branch..." # Checkout code to the deployment directory GIT_WORK_TREE=%s git checkout -f $TARGET cd %s # Update environment variables echo '%s' > %s/.env # Update dependencies echo "Updating Python dependencies..." source venv/bin/activate pip install -r requirements.txt # Restart the service echo "Restarting service..." systemctl restart byop-%s # Notify about completion echo "Python deployment completed successfully" fi done `, component.Name, component.Branch, deployPath, deployPath, component.EnvVariables, deployPath, component.ID) } // createDatabasePostReceiveHook generates a Git hook for database components func createDatabasePostReceiveHook(component models.Component, deployPath string, dbType string) string { var configUpdate, restartCmd string switch dbType { case "postgresql": configUpdate = fmt.Sprintf(` # Apply configuration changes if available if [ -f %s/postgresql.conf ]; then cp %s/postgresql.conf /etc/postgresql/*/main/ echo "Updated PostgreSQL configuration" fi`, deployPath, deployPath) restartCmd = "systemctl restart postgresql" case "mariadb", "mysql": configUpdate = fmt.Sprintf(` # Apply configuration changes if available if [ -f %s/my.cnf ]; then cp %s/my.cnf /etc/mysql/ echo "Updated MariaDB configuration" fi`, deployPath, deployPath) restartCmd = "systemctl restart mariadb" case "mongodb": configUpdate = fmt.Sprintf(` # Apply configuration changes if available if [ -f %s/mongodb.conf ]; then cp %s/mongodb.conf /etc/mongodb.conf echo "Updated MongoDB configuration" fi`, deployPath, deployPath) restartCmd = "systemctl restart mongodb" } return fmt.Sprintf(`#!/bin/bash echo "Deploying database component: %s" # Get the target branch (usually main or master) TARGET="%s" while read oldrev newrev ref do # Check if the pushed branch is our target branch if [[ $ref = refs/heads/$TARGET ]]; then echo "Deploying $TARGET branch..." # Checkout code to the deployment directory GIT_WORK_TREE=%s git checkout -f $TARGET cd %s # Update environment variables echo '%s' > %s/.env %s # Run any database migrations if available if [ -f %s/migrations/run.sh ]; then echo "Running database migrations..." bash %s/migrations/run.sh fi # Restart database service echo "Restarting database service..." %s # Notify about completion echo "Database component deployment completed successfully" fi done `, component.Name, component.Branch, deployPath, deployPath, component.EnvVariables, deployPath, configUpdate, deployPath, deployPath, restartCmd) } // createSystemdServiceCommand creates a systemd service file for the component func createSystemdServiceCommand(component models.Component, deploymentPath string) string { var execStart string var workingDir string workingDir = deploymentPath switch component.Language { case "golang": execStart = fmt.Sprintf("%s/app", deploymentPath) case "python": execStart = fmt.Sprintf("%s/venv/bin/python %s/main.py", deploymentPath, deploymentPath) default: execStart = component.BuildCommand } serviceFile := fmt.Sprintf(`[Unit] Description=BYOP Component %s After=network.target [Service] ExecStart=%s WorkingDirectory=%s Restart=always User=root Group=root Environment=PATH=/usr/bin:/usr/local/bin EnvironmentFile=%s/.env [Install] WantedBy=multi-user.target `, component.Name, execStart, workingDir, deploymentPath) return fmt.Sprintf("echo '%s' > /etc/systemd/system/byop-%s.service", serviceFile, component.ID) } ```