Add deployment automation system with build/publish workflow and fix path resolution
This commit introduces a complete deployment automation system for Windows Server deployment: New Features: - Publish-And-Deploy.ps1: Interactive console for building locally and transferring to server * Supports auto-detection of transfer method (Windows Share or SSH) * Configurable via deploy-config.json * Integrated with Build-ROA2WEB.ps1 for consistent builds - Check-And-Deploy.ps1: Server-side auto-deployment script * Monitors transfer directory for new packages * Automatically deploys when new version detected * Integrates with ROA2WEB-Console.ps1 for deployment - Setup-AutoDeploy.ps1: Configures scheduled task for auto-deployment - DEPLOYMENT_AUTOMATION.md: Complete documentation for automation workflow Bug Fixes: - Fix path resolution in Publish-And-Deploy.ps1: Added Resolve-FullPath function to correctly resolve ../deploy-package path - Fix ROA2WEB-Console.ps1 exit codes: Properly return boolean values and exit codes in non-interactive mode - Fix Build-ROA2WEB.ps1 script copying: Added debug output and force deletion to avoid caching issues Enhancements: - ROA2WEB-Console.ps1: Support for ROA2WEB_SOURCE environment variable for flexible source paths - Build-ROA2WEB.ps1: Enhanced debug output for troubleshooting script copying issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
751
deployment/windows/docs/DEPLOYMENT_AUTOMATION.md
Normal file
751
deployment/windows/docs/DEPLOYMENT_AUTOMATION.md
Normal file
@@ -0,0 +1,751 @@
|
||||
# ROA2WEB - Automated Deployment System
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
This document describes the **automated deployment system** for ROA2WEB Windows Server deployment. The system enables:
|
||||
|
||||
- ✅ **Build locally** on dev machine (WSL/Windows)
|
||||
- ✅ **Auto-transfer** via Windows Share (LAN) or SSH (remote)
|
||||
- ✅ **Auto-deploy** on server (no manual intervention needed)
|
||||
- ✅ **Interactive menus** for easy configuration
|
||||
- ✅ **No Remote Desktop required**
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Dev Machine (WSL/Windows) │
|
||||
│ │
|
||||
│ Publish-And-Deploy.ps1 (Interactive Menu) │
|
||||
│ ├─ Load deploy-config.json │
|
||||
│ ├─ Build-ROA2WEB.ps1 (create deploy-package/) │
|
||||
│ └─ Transfer: │
|
||||
│ ├─ Auto: Try Windows Share → fallback SSH │
|
||||
│ ├─ Windows Share: \\10.0.20.36\ROA2WEB-Deploy │
|
||||
│ └─ SSH: scp to 10.0.20.36:22122 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Windows Server │
|
||||
│ │
|
||||
│ C:\Temp\ │
|
||||
│ └─ deploy-20241112-153045\ │
|
||||
│ ├─ backend/ │
|
||||
│ ├─ frontend/ │
|
||||
│ ├─ telegram-bot/ │
|
||||
│ └─ scripts/ROA2WEB-Console.ps1 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Scheduled Task: ROA2WEB-AutoDeploy (every 5 minutes) │
|
||||
│ │
|
||||
│ Check-And-Deploy.ps1 │
|
||||
│ ├─ Scan C:\Temp\ for deploy-* folders │
|
||||
│ ├─ Find newest package (by LastWriteTime) │
|
||||
│ ├─ Compare with last-deploy.json │
|
||||
│ └─ If newer: │
|
||||
│ ├─ Set $env:ROA2WEB_SOURCE = package path │
|
||||
│ ├─ Execute ROA2WEB-Console.ps1 -Action DeployAll │
|
||||
│ └─ Update last-deploy.json │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start Guide
|
||||
|
||||
### Dev Machine Setup (One-Time)
|
||||
|
||||
1. **Edit Configuration** (optional, defaults are provided):
|
||||
```powershell
|
||||
cd deployment/windows/scripts
|
||||
notepad deploy-config.json
|
||||
```
|
||||
|
||||
Default configuration:
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"host": "10.0.20.36",
|
||||
"sshPort": 22122,
|
||||
"sshUser": "Administrator",
|
||||
"sshKeyPath": "~\\.ssh\\id_ed25519",
|
||||
"windowsShare": "\\\\10.0.20.36\\Temp"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Test Connections**:
|
||||
```powershell
|
||||
.\Publish-And-Deploy.ps1
|
||||
# Menu: [2] Test Connections
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Server Setup (One-Time)
|
||||
|
||||
1. **Windows Share** (already exists):
|
||||
```powershell
|
||||
# Share already exists: \\10.0.20.36\Temp
|
||||
# Maps to: C:\Temp on server
|
||||
|
||||
# Create scripts directory (if not exists)
|
||||
New-Item -Path "C:\Temp\ROA2WEB-Scripts" -ItemType Directory -Force
|
||||
```
|
||||
|
||||
2. **Run Setup Wizard**:
|
||||
```powershell
|
||||
# Copy Setup-AutoDeploy.ps1 to server, then:
|
||||
cd C:\path\to\scripts
|
||||
.\Setup-AutoDeploy.ps1
|
||||
```
|
||||
|
||||
The wizard will:
|
||||
- ✅ Create directory structure (`C:\Temp`, `C:\Temp\ROA2WEB-Scripts`)
|
||||
- ✅ Copy `Check-And-Deploy.ps1` to scripts folder
|
||||
- ✅ Create Scheduled Task (`ROA2WEB-AutoDeploy`)
|
||||
- ✅ Configure auto-deploy (every 5 minutes)
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage
|
||||
|
||||
### Interactive Deployment (Dev Machine)
|
||||
|
||||
```powershell
|
||||
cd deployment/windows/scripts
|
||||
.\Publish-And-Deploy.ps1
|
||||
```
|
||||
|
||||
**Main Menu:**
|
||||
```
|
||||
[1] Build & Publish Package
|
||||
→ Select Component (All/Frontend/Backend/TelegramBot)
|
||||
→ Select Transfer Method (Auto/WindowsShare/SSH)
|
||||
→ Build + Transfer automatically
|
||||
|
||||
[2] Test Connections
|
||||
→ Test Windows Share accessibility
|
||||
→ Test SSH connection
|
||||
|
||||
[3] Configure Settings
|
||||
→ Edit server host, SSH port, paths, etc.
|
||||
|
||||
[4] View Current Configuration
|
||||
→ Display active settings
|
||||
|
||||
[Q] Quit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Non-Interactive Deployment (Dev Machine)
|
||||
|
||||
```powershell
|
||||
# Quick deploy (auto-detect transfer method)
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All
|
||||
|
||||
# Force Windows Share (LAN)
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All -TransferMethod WindowsShare
|
||||
|
||||
# Force SSH (remote/WAN)
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component Frontend -TransferMethod SSH
|
||||
|
||||
# Test connections only
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action TestConnections
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Server-Side Management
|
||||
|
||||
#### Manual Check & Deploy (Server)
|
||||
|
||||
```powershell
|
||||
cd C:\ROA2WEB-Scripts
|
||||
|
||||
# Interactive menu
|
||||
.\Check-And-Deploy.ps1 -Interactive
|
||||
|
||||
# Non-interactive check + deploy
|
||||
.\Check-And-Deploy.ps1
|
||||
|
||||
# Check only (no deploy)
|
||||
.\Check-And-Deploy.ps1 -CheckOnly
|
||||
```
|
||||
|
||||
#### Manage Scheduled Task (Server)
|
||||
|
||||
```powershell
|
||||
# View task
|
||||
Get-ScheduledTask -TaskName "ROA2WEB-AutoDeploy"
|
||||
|
||||
# Start task manually (trigger check now)
|
||||
Start-ScheduledTask -TaskName "ROA2WEB-AutoDeploy"
|
||||
|
||||
# Disable auto-deploy temporarily
|
||||
Disable-ScheduledTask -TaskName "ROA2WEB-AutoDeploy"
|
||||
|
||||
# Re-enable auto-deploy
|
||||
Enable-ScheduledTask -TaskName "ROA2WEB-AutoDeploy"
|
||||
|
||||
# View logs
|
||||
Get-Content "C:\ROA2WEB-Scripts\Logs\check-and-deploy.log" -Tail 50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 File Structure
|
||||
|
||||
### Dev Machine
|
||||
```
|
||||
deployment/windows/scripts/
|
||||
├── deploy-config.json # Configuration file (edit server settings)
|
||||
├── Publish-And-Deploy.ps1 # Interactive build & publish script
|
||||
├── Build-ROA2WEB.ps1 # Existing build script (unchanged)
|
||||
├── ROA2WEB-Console.ps1 # Existing deployment script (updated)
|
||||
└── Setup-AutoDeploy.ps1 # Server setup wizard
|
||||
```
|
||||
|
||||
### Server
|
||||
```
|
||||
C:\Temp\ # Monitored folder (Windows Share)
|
||||
├── ROA2WEB-Scripts\ # Scripts and state (permanent)
|
||||
│ ├── Check-And-Deploy.ps1 # Monitoring script (runs via scheduled task)
|
||||
│ ├── Setup-AutoDeploy.ps1 # Setup wizard (optional, for debug)
|
||||
│ ├── last-deploy.json # Tracks last deployed package
|
||||
│ └── Logs\
|
||||
│ └── check-and-deploy.log # Deployment logs
|
||||
│
|
||||
├── deploy-20241112-153045\ # Timestamped deployment packages
|
||||
│ ├── backend/
|
||||
│ ├── frontend/
|
||||
│ ├── telegram-bot/
|
||||
│ └── scripts/
|
||||
│ └── ROA2WEB-Console.ps1
|
||||
│
|
||||
└── deploy-20241111-120000\ # Previous package (kept as backup)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration Reference
|
||||
|
||||
### deploy-config.json
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"host": "10.0.20.36", // Server IP/hostname
|
||||
"sshPort": 22122, // SSH port
|
||||
"sshUser": "Administrator", // SSH username
|
||||
"sshKeyPath": "~\\.ssh\\id_ed25519", // SSH private key path
|
||||
"windowsShare": "\\\\10.0.20.36\\Temp", // Network share path
|
||||
"deployPath": "C:\\Temp" // Server-side deploy path
|
||||
},
|
||||
"build": {
|
||||
"defaultComponent": "All", // Default: All/Frontend/Backend/TelegramBot
|
||||
"outputPath": "./deploy-package" // Local build output
|
||||
},
|
||||
"transfer": {
|
||||
"defaultMethod": "Auto", // Auto/WindowsShare/SSH
|
||||
"scpRemotePath": "C:/Temp", // SCP remote path (Windows format)
|
||||
"retryAttempts": 3, // Transfer retry attempts
|
||||
"timeout": 300 // Transfer timeout (seconds)
|
||||
},
|
||||
"deployment": {
|
||||
"autoDeployEnabled": true, // Auto-deploy when new package found
|
||||
"checkIntervalMinutes": 5 // How often to check (minutes)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Editing Configuration:**
|
||||
|
||||
**Option 1:** Edit JSON file directly:
|
||||
```powershell
|
||||
notepad deployment/windows/scripts/deploy-config.json
|
||||
```
|
||||
|
||||
**Option 2:** Use interactive configuration editor:
|
||||
```powershell
|
||||
.\Publish-And-Deploy.ps1
|
||||
# Menu: [3] Configure Settings
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Transfer Methods
|
||||
|
||||
### Auto-detect (Recommended)
|
||||
```powershell
|
||||
.\Publish-And-Deploy.ps1 -TransferMethod Auto
|
||||
```
|
||||
- **LAN**: Tries Windows Share first (fast, ~30 seconds)
|
||||
- **Remote**: Falls back to SSH if share not accessible
|
||||
- **Smart**: Automatically chooses best method
|
||||
|
||||
### Windows Share (LAN Only)
|
||||
```powershell
|
||||
.\Publish-And-Deploy.ps1 -TransferMethod WindowsShare
|
||||
```
|
||||
- **Speed**: ⚡⚡⚡⚡⚡ Very fast (LAN)
|
||||
- **Requirements**: Dev machine in same network as server
|
||||
- **Protocol**: SMB (port 445)
|
||||
- **Use case**: Office/home network
|
||||
|
||||
### SSH/SCP (LAN or Remote)
|
||||
```powershell
|
||||
.\Publish-And-Deploy.ps1 -TransferMethod SSH
|
||||
```
|
||||
- **Speed**: ⚡⚡⚡ Decent (depends on bandwidth)
|
||||
- **Requirements**: SSH key configured, server accessible
|
||||
- **Protocol**: SSH (port 22122)
|
||||
- **Use case**: Remote work, VPN, internet
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Troubleshooting
|
||||
|
||||
### Dev Machine Issues
|
||||
|
||||
#### Error: "Windows Share is not accessible"
|
||||
```powershell
|
||||
# Test share access
|
||||
Test-Path "\\10.0.20.36\Temp"
|
||||
|
||||
# Check network connectivity
|
||||
Test-NetConnection -ComputerName 10.0.20.36 -Port 445
|
||||
|
||||
# Solution: Use SSH instead
|
||||
.\Publish-And-Deploy.ps1 -TransferMethod SSH
|
||||
```
|
||||
|
||||
#### Error: "SSH connection failed"
|
||||
```powershell
|
||||
# Test SSH manually
|
||||
ssh -i ~\.ssh\id_ed25519 -p 22122 Administrator@10.0.20.36
|
||||
|
||||
# Common issues:
|
||||
# 1. Wrong key path → Edit deploy-config.json
|
||||
# 2. Key permissions → Ensure key file has correct Windows permissions
|
||||
# 3. Server not reachable → Check firewall/VPN
|
||||
```
|
||||
|
||||
#### Error: "Configuration file not found"
|
||||
```powershell
|
||||
# Script will auto-create default config on first run
|
||||
.\Publish-And-Deploy.ps1
|
||||
|
||||
# Or create manually from example:
|
||||
Copy-Item deploy-config.json.example deploy-config.json
|
||||
notepad deploy-config.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Server Issues
|
||||
|
||||
#### Scheduled Task Not Running
|
||||
```powershell
|
||||
# Check task status
|
||||
Get-ScheduledTask -TaskName "ROA2WEB-AutoDeploy" | Select-Object State, LastRunTime, LastTaskResult
|
||||
|
||||
# View task history
|
||||
Get-ScheduledTaskInfo -TaskName "ROA2WEB-AutoDeploy"
|
||||
|
||||
# Check logs
|
||||
Get-Content "C:\ROA2WEB-Scripts\Logs\check-and-deploy.log" -Tail 50
|
||||
|
||||
# Solution: Run setup wizard again
|
||||
.\Setup-AutoDeploy.ps1
|
||||
```
|
||||
|
||||
#### Deployment Not Triggered
|
||||
```powershell
|
||||
# Check if new package exists
|
||||
Get-ChildItem "C:\Temp" -Directory | Where-Object { $_.Name -like "deploy-*" } | Sort-Object LastWriteTime -Descending
|
||||
|
||||
# Check last deployment state
|
||||
Get-Content "C:\Temp\ROA2WEB-Scripts\last-deploy.json" | ConvertFrom-Json
|
||||
|
||||
# Manual trigger
|
||||
cd C:\Temp\ROA2WEB-Scripts
|
||||
.\Check-And-Deploy.ps1 -Interactive
|
||||
# Menu: [2] Check and Deploy Now
|
||||
```
|
||||
|
||||
#### Package Found But Not Deployed
|
||||
```powershell
|
||||
# Check if package is newer than last deployment
|
||||
$state = Get-Content "C:\Temp\ROA2WEB-Scripts\last-deploy.json" | ConvertFrom-Json
|
||||
$latest = Get-ChildItem "C:\Temp\deploy-*" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
||||
Write-Host "Last deployed: $($state.lastDeployment.packageName)"
|
||||
Write-Host "Latest package: $($latest.Name)"
|
||||
|
||||
# Solution: Delete state file to force redeploy
|
||||
Remove-Item "C:\Temp\ROA2WEB-Scripts\last-deploy.json"
|
||||
cd C:\Temp\ROA2WEB-Scripts
|
||||
.\Check-And-Deploy.ps1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitoring & Logs
|
||||
|
||||
### View Deployment Logs (Server)
|
||||
```powershell
|
||||
# Real-time log monitoring
|
||||
Get-Content "C:\ROA2WEB-Scripts\Logs\check-and-deploy.log" -Wait
|
||||
|
||||
# Last 100 lines
|
||||
Get-Content "C:\ROA2WEB-Scripts\Logs\check-and-deploy.log" -Tail 100
|
||||
|
||||
# Search for errors
|
||||
Select-String -Path "C:\ROA2WEB-Scripts\Logs\check-and-deploy.log" -Pattern "ERROR"
|
||||
```
|
||||
|
||||
### View Deployment History (Server)
|
||||
```powershell
|
||||
# Interactive menu
|
||||
.\Check-And-Deploy.ps1 -Interactive
|
||||
# Menu: [3] View Deployment History
|
||||
|
||||
# Or view state file directly
|
||||
Get-Content "C:\ROA2WEB-Scripts\last-deploy.json" | ConvertFrom-Json | Format-List
|
||||
```
|
||||
|
||||
### Check Service Status (Server)
|
||||
```powershell
|
||||
# After deployment, verify services
|
||||
Get-Service -Name "ROA2WEB-Backend", "ROA2WEB-TelegramBot"
|
||||
|
||||
# Or use ROA2WEB-Console.ps1
|
||||
cd C:\inetpub\wwwroot\roa2web\scripts
|
||||
.\ROA2WEB-Console.ps1 -NonInteractive -Action Status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Considerations
|
||||
|
||||
### SSH Key Management
|
||||
- **Never commit SSH private keys** to Git
|
||||
- Store keys in secure location (`~/.ssh/` with `chmod 600`)
|
||||
- Use separate key for deployment (not personal key)
|
||||
- Rotate keys periodically
|
||||
|
||||
### Windows Share Permissions
|
||||
```powershell
|
||||
# Restrict share access to specific users (recommended for production)
|
||||
New-SmbShare -Name "ROA2WEB-Deploy" -Path "C:\ROA2WEB-Deploy" -FullAccess "DOMAIN\DeployUser"
|
||||
|
||||
# Or keep "Everyone" for internal network (development)
|
||||
```
|
||||
|
||||
### Scheduled Task Security
|
||||
- Task runs as **SYSTEM** account (full privileges)
|
||||
- Ensure `C:\ROA2WEB-Deploy` is on local drive (not network share)
|
||||
- Review logs regularly for unauthorized deployments
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Best Practices
|
||||
|
||||
### 1. **Test Before Production**
|
||||
```powershell
|
||||
# Always test connections first
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action TestConnections
|
||||
|
||||
# Then test with small component
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component Backend
|
||||
```
|
||||
|
||||
### 2. **Backup Before Deploy**
|
||||
- ROA2WEB-Console.ps1 automatically creates backups
|
||||
- Backups stored in `C:\inetpub\wwwroot\roa2web\backups\`
|
||||
- Last 10 backups retained
|
||||
|
||||
### 3. **Monitor Deployments**
|
||||
```powershell
|
||||
# Set up email alerts for failed deployments (optional)
|
||||
# Add to Check-And-Deploy.ps1:
|
||||
if (-not $deploySuccess) {
|
||||
Send-MailMessage -To "admin@company.com" -Subject "Deployment Failed" ...
|
||||
}
|
||||
```
|
||||
|
||||
### 4. **Regular Cleanup**
|
||||
```powershell
|
||||
# Clean old deployment packages (keep last 5)
|
||||
Get-ChildItem "C:\ROA2WEB-Deploy\deploy-*" |
|
||||
Sort-Object LastWriteTime -Descending |
|
||||
Select-Object -Skip 5 |
|
||||
Remove-Item -Recurse -Force
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Advanced Configuration
|
||||
|
||||
### Custom Check Interval
|
||||
```powershell
|
||||
# Edit scheduled task interval (e.g., every 10 minutes)
|
||||
$trigger = Get-ScheduledTask -TaskName "ROA2WEB-AutoDeploy" | Get-ScheduledTaskTrigger
|
||||
$trigger.Repetition.Interval = "PT10M"
|
||||
Set-ScheduledTask -TaskName "ROA2WEB-AutoDeploy" -Trigger $trigger
|
||||
```
|
||||
|
||||
### Deploy Specific Components Only
|
||||
```powershell
|
||||
# Backend only
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component Backend
|
||||
|
||||
# Frontend only
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component Frontend
|
||||
|
||||
# Telegram Bot only
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component TelegramBot
|
||||
```
|
||||
|
||||
### Custom SSH Port Forwarding
|
||||
```powershell
|
||||
# If server is behind NAT/firewall, use port forwarding
|
||||
# Router: Forward external port 2222 → 10.0.20.36:22122
|
||||
|
||||
# Edit deploy-config.json:
|
||||
{
|
||||
"server": {
|
||||
"host": "public-ip-or-domain.com",
|
||||
"sshPort": 2222,
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Support
|
||||
|
||||
### Common Commands Reference
|
||||
|
||||
**Dev Machine:**
|
||||
```powershell
|
||||
# Quick deploy
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All
|
||||
|
||||
# Test connections
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action TestConnections
|
||||
|
||||
# View config
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action ViewConfig
|
||||
```
|
||||
|
||||
**Server:**
|
||||
```powershell
|
||||
# Check for updates
|
||||
.\Check-And-Deploy.ps1 -CheckOnly
|
||||
|
||||
# Deploy now
|
||||
.\Check-And-Deploy.ps1
|
||||
|
||||
# Interactive menu
|
||||
.\Check-And-Deploy.ps1 -Interactive
|
||||
|
||||
# View logs
|
||||
Get-Content "C:\ROA2WEB-Scripts\Logs\check-and-deploy.log" -Tail 50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Migration from Manual Deployment
|
||||
|
||||
If you were previously using manual deployment (Build-ROA2WEB.ps1 + manual copy):
|
||||
|
||||
1. **One-time server setup:**
|
||||
```powershell
|
||||
# Copy Setup-AutoDeploy.ps1 to server
|
||||
.\Setup-AutoDeploy.ps1
|
||||
```
|
||||
|
||||
2. **Update workflow:**
|
||||
```powershell
|
||||
# OLD: Manual build + copy + Remote Desktop deploy
|
||||
.\Build-ROA2WEB.ps1
|
||||
# ... manual copy ...
|
||||
# ... Remote Desktop to server ...
|
||||
# ... run ROA2WEB-Console.ps1 ...
|
||||
|
||||
# NEW: One command, fully automated
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All
|
||||
# → Server auto-deploys within 5 minutes
|
||||
```
|
||||
|
||||
3. **Benefits:**
|
||||
- ⏱️ **Time saved**: 15 minutes → 2 minutes
|
||||
- 🎯 **Zero manual steps**: No Remote Desktop needed
|
||||
- 🔄 **Consistent**: Same process every time
|
||||
- 📊 **Audit trail**: Full logs and deployment history
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing the Complete Workflow
|
||||
|
||||
### End-to-End Testing Guide
|
||||
|
||||
After completing the setup, test the entire automated deployment workflow:
|
||||
|
||||
#### Step 1: Server Setup (One-Time)
|
||||
|
||||
```powershell
|
||||
# On Dev Machine: Copy scripts to server via Windows Share
|
||||
Copy-Item -Path ".\Check-And-Deploy.ps1" -Destination "\\10.0.20.36\Temp\ROA2WEB-Scripts\"
|
||||
Copy-Item -Path ".\Setup-AutoDeploy.ps1" -Destination "\\10.0.20.36\Temp\ROA2WEB-Scripts\"
|
||||
```
|
||||
|
||||
```powershell
|
||||
# On Server: Run setup wizard (via Remote Desktop - only once)
|
||||
cd C:\Temp\ROA2WEB-Scripts
|
||||
.\Setup-AutoDeploy.ps1
|
||||
|
||||
# Follow wizard prompts:
|
||||
# - Monitor Path: C:\Temp (default)
|
||||
# - Scripts Path: C:\Temp\ROA2WEB-Scripts (default)
|
||||
# - Check Interval: 5 minutes (default)
|
||||
# - Auto-Deploy: Yes (default)
|
||||
# - Create Scheduled Task: Yes (default)
|
||||
```
|
||||
|
||||
#### Step 2: Test Connections (Dev Machine)
|
||||
|
||||
```powershell
|
||||
cd /mnt/e/proiecte/roa2web/deployment/windows/scripts
|
||||
|
||||
# Run connection tests
|
||||
.\Publish-And-Deploy.ps1
|
||||
# Select: [2] Test Connections
|
||||
|
||||
# Expected output:
|
||||
# ✅ Windows Share accessible: \\10.0.20.36\Temp
|
||||
# ✅ SSH connection successful: Administrator@10.0.20.36:22122
|
||||
```
|
||||
|
||||
#### Step 3: First Deployment Test (Dev Machine)
|
||||
|
||||
```powershell
|
||||
# Build and publish a test package
|
||||
.\Publish-And-Deploy.ps1
|
||||
|
||||
# Menu workflow:
|
||||
# [1] Build & Publish Package
|
||||
# → Component: [1] All (or test with Backend only)
|
||||
# → Transfer Method: [1] Auto (recommended)
|
||||
# → Confirm: Y
|
||||
|
||||
# Expected output:
|
||||
# ✅ Building deployment package...
|
||||
# ✅ Transferring via Windows Share...
|
||||
# ✅ Package copied: \\10.0.20.36\Temp\deploy-20241113-HHMMSS\
|
||||
# ✅ Server will auto-deploy within 5 minutes
|
||||
```
|
||||
|
||||
#### Step 4: Verify Auto-Deploy (Server)
|
||||
|
||||
```powershell
|
||||
# Wait 1-5 minutes, then check deployment logs on server:
|
||||
Get-Content "C:\Temp\ROA2WEB-Scripts\Logs\check-and-deploy.log" -Tail 30
|
||||
|
||||
# Expected log entries:
|
||||
# [2024-11-13 HH:MM:SS] [INFO] === Check and Deploy Started ===
|
||||
# [2024-11-13 HH:MM:SS] [SUCCESS] Found 1 package(s), latest: deploy-20241113-HHMMSS
|
||||
# [2024-11-13 HH:MM:SS] [SUCCESS] New package detected
|
||||
# [2024-11-13 HH:MM:SS] [INFO] Executing deployment via ROA2WEB-Console.ps1...
|
||||
# [2024-11-13 HH:MM:SS] [SUCCESS] Deployment completed successfully
|
||||
```
|
||||
|
||||
```powershell
|
||||
# Verify services are running:
|
||||
Get-Service -Name "ROA2WEB-Backend", "ROA2WEB-TelegramBot"
|
||||
|
||||
# Expected output:
|
||||
# Status Name DisplayName
|
||||
# ------ ---- -----------
|
||||
# Running ROA2WEB-Backend ROA2WEB Backend Service
|
||||
# Running ROA2WEB-TelegramBot ROA2WEB Telegram Bot Service
|
||||
```
|
||||
|
||||
#### Step 5: Verify Web Application
|
||||
|
||||
```
|
||||
# Open browser and test:
|
||||
http://10.0.20.36/ # Frontend should load
|
||||
http://10.0.20.36/api/docs # Backend API docs should be accessible
|
||||
```
|
||||
|
||||
### Manual Testing (Optional)
|
||||
|
||||
If you want to test without waiting for Scheduled Task:
|
||||
|
||||
```powershell
|
||||
# On Server: Manual deployment test
|
||||
cd C:\Temp\ROA2WEB-Scripts
|
||||
.\Check-And-Deploy.ps1 -Interactive
|
||||
|
||||
# Menu workflow:
|
||||
# [1] Check for Updates (No Deploy) - verify package is detected
|
||||
# [2] Check and Deploy Now - force immediate deployment
|
||||
# [3] View Deployment History - see deployment records
|
||||
```
|
||||
|
||||
### Troubleshooting Failed Tests
|
||||
|
||||
**If Windows Share test fails:**
|
||||
```powershell
|
||||
# Verify network connectivity
|
||||
Test-NetConnection -ComputerName 10.0.20.36 -Port 445
|
||||
|
||||
# Try manual access
|
||||
Test-Path "\\10.0.20.36\Temp"
|
||||
|
||||
# Fallback: Use SSH transfer instead
|
||||
.\Publish-And-Deploy.ps1 -TransferMethod SSH
|
||||
```
|
||||
|
||||
**If SSH test fails:**
|
||||
```powershell
|
||||
# Test SSH manually
|
||||
ssh -i ~\.ssh\id_ed25519 -p 22122 Administrator@10.0.20.36
|
||||
|
||||
# If key path is wrong, update config:
|
||||
notepad deploy-config.json
|
||||
# Update: "sshKeyPath": "correct\\path\\to\\key"
|
||||
```
|
||||
|
||||
**If auto-deploy doesn't trigger:**
|
||||
```powershell
|
||||
# Verify scheduled task is running (on server):
|
||||
Get-ScheduledTask -TaskName "ROA2WEB-AutoDeploy" | Select-Object State, LastRunTime
|
||||
|
||||
# Manually trigger task:
|
||||
Start-ScheduledTask -TaskName "ROA2WEB-AutoDeploy"
|
||||
|
||||
# Check for errors in logs:
|
||||
Select-String -Path "C:\Temp\ROA2WEB-Scripts\Logs\check-and-deploy.log" -Pattern "ERROR"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Success!
|
||||
|
||||
You've now set up the automated deployment system for ROA2WEB! Deployments are now as simple as:
|
||||
|
||||
```powershell
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All
|
||||
```
|
||||
|
||||
**Server auto-deploys within 5 minutes** - no Remote Desktop, no manual steps! 🚀
|
||||
@@ -658,6 +658,11 @@ function Copy-DeploymentScripts {
|
||||
$scriptsDir = Join-Path $DestPath "scripts"
|
||||
New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null
|
||||
|
||||
# Debug: Show paths
|
||||
Write-Host " [DEBUG] ScriptsSourcePath: $ScriptsSourcePath" -ForegroundColor Magenta
|
||||
Write-Host " [DEBUG] DestPath: $DestPath" -ForegroundColor Magenta
|
||||
Write-Host " [DEBUG] ScriptsDir: $scriptsDir" -ForegroundColor Magenta
|
||||
|
||||
# Essential scripts for all deployments
|
||||
$scripts = @(
|
||||
"ROA2WEB-Console.ps1", # Unified deployment & management console
|
||||
@@ -684,7 +689,25 @@ function Copy-DeploymentScripts {
|
||||
foreach ($script in $scripts) {
|
||||
$scriptPath = Join-Path $ScriptsSourcePath $script
|
||||
if (Test-Path $scriptPath) {
|
||||
$destScript = Join-Path $scriptsDir $script
|
||||
|
||||
# Debug: Show file info
|
||||
$sourceSize = (Get-Item $scriptPath).Length
|
||||
Write-Host " [DEBUG] Copying $script (size: $sourceSize bytes)" -ForegroundColor Magenta
|
||||
|
||||
# Force delete destination first to avoid caching issues
|
||||
if (Test-Path $destScript) {
|
||||
$oldSize = (Get-Item $destScript).Length
|
||||
Write-Host " [DEBUG] Deleting old $script (was: $oldSize bytes)" -ForegroundColor Magenta
|
||||
Remove-Item -Path $destScript -Force
|
||||
}
|
||||
|
||||
Copy-Item -Path $scriptPath -Destination $scriptsDir -Force
|
||||
|
||||
# Debug: Verify copy
|
||||
$newSize = (Get-Item $destScript).Length
|
||||
Write-Host " [DEBUG] Copied $script (new size: $newSize bytes)" -ForegroundColor Magenta
|
||||
|
||||
$copiedCount++
|
||||
} else {
|
||||
Write-Warning "Script not found: $script"
|
||||
|
||||
542
deployment/windows/scripts/Check-And-Deploy.ps1
Normal file
542
deployment/windows/scripts/Check-And-Deploy.ps1
Normal file
@@ -0,0 +1,542 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
ROA2WEB - Auto-Deploy Monitor (Server-Side)
|
||||
|
||||
.DESCRIPTION
|
||||
Server-side script that monitors C:\Temp\ for new deployment packages
|
||||
and automatically deploys them using ROA2WEB-Console.ps1.
|
||||
|
||||
Can run:
|
||||
- Via Scheduled Task (automated, silent)
|
||||
- Interactive mode (manual execution with menu)
|
||||
- Non-interactive mode (command-line automation)
|
||||
|
||||
.PARAMETER Interactive
|
||||
Run in interactive mode with menu
|
||||
|
||||
.PARAMETER WatchPath
|
||||
Path to monitor for deployment packages (default: C:\Temp)
|
||||
|
||||
.PARAMETER StateFile
|
||||
Path to state file tracking last deployment (default: C:\Temp\ROA2WEB-Scripts\last-deploy.json)
|
||||
|
||||
.PARAMETER ConsoleScriptPath
|
||||
Path to ROA2WEB-Console.ps1 script
|
||||
|
||||
.PARAMETER LogPath
|
||||
Path to log file directory (default: C:\Temp\ROA2WEB-Scripts\Logs)
|
||||
|
||||
.PARAMETER CheckOnly
|
||||
Check for updates without deploying
|
||||
|
||||
.EXAMPLE
|
||||
.\Check-And-Deploy.ps1
|
||||
Check for new packages and deploy automatically (silent)
|
||||
|
||||
.EXAMPLE
|
||||
.\Check-And-Deploy.ps1 -Interactive
|
||||
Show interactive menu with deployment options
|
||||
|
||||
.EXAMPLE
|
||||
.\Check-And-Deploy.ps1 -CheckOnly
|
||||
Check for new packages without deploying
|
||||
|
||||
.NOTES
|
||||
Author: ROA2WEB Team
|
||||
Version: 1.0 (Auto-Deploy Monitor)
|
||||
Requires: Administrator privileges, PowerShell 5.1+
|
||||
|
||||
Designed to run via Scheduled Task for automated deployments.
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$Interactive,
|
||||
[string]$WatchPath = "C:\Temp",
|
||||
[string]$StateFile = "C:\Temp\ROA2WEB-Scripts\last-deploy.json",
|
||||
[string]$ConsoleScriptPath = "",
|
||||
[string]$LogPath = "C:\Temp\ROA2WEB-Scripts\Logs",
|
||||
[switch]$CheckOnly
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# =============================================================================
|
||||
# CONFIGURATION
|
||||
# =============================================================================
|
||||
|
||||
$script:Config = @{
|
||||
WatchPath = $WatchPath
|
||||
StateFile = $StateFile
|
||||
LogPath = $LogPath
|
||||
ConsoleScriptPath = if ($ConsoleScriptPath) {
|
||||
$ConsoleScriptPath
|
||||
} else {
|
||||
# Auto-detect ROA2WEB-Console.ps1
|
||||
$possiblePaths = @(
|
||||
"C:\inetpub\wwwroot\roa2web\scripts\ROA2WEB-Console.ps1",
|
||||
(Join-Path $PSScriptRoot "ROA2WEB-Console.ps1")
|
||||
)
|
||||
$found = $possiblePaths | Where-Object { Test-Path $_ } | Select-Object -First 1
|
||||
if ($found) { $found } else { "" }
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# HELPER FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Write-Log {
|
||||
param(
|
||||
[string]$Message,
|
||||
[ValidateSet("INFO", "SUCCESS", "WARNING", "ERROR")]
|
||||
[string]$Level = "INFO"
|
||||
)
|
||||
|
||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
$logMessage = "[$timestamp] [$Level] $Message"
|
||||
|
||||
# Ensure log directory exists
|
||||
if (-not (Test-Path $script:Config.LogPath)) {
|
||||
New-Item -ItemType Directory -Path $script:Config.LogPath -Force | Out-Null
|
||||
}
|
||||
|
||||
$logFile = Join-Path $script:Config.LogPath "check-and-deploy.log"
|
||||
Add-Content -Path $logFile -Value $logMessage
|
||||
|
||||
# Also write to console if interactive
|
||||
if ($Interactive) {
|
||||
$color = switch ($Level) {
|
||||
"SUCCESS" { "Green" }
|
||||
"WARNING" { "Yellow" }
|
||||
"ERROR" { "Red" }
|
||||
default { "White" }
|
||||
}
|
||||
Write-Host $logMessage -ForegroundColor $color
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Step {
|
||||
param([string]$Message)
|
||||
Write-Host "`n[*] $Message" -ForegroundColor Cyan
|
||||
Write-Log -Message $Message -Level "INFO"
|
||||
}
|
||||
|
||||
function Write-Success {
|
||||
param([string]$Message)
|
||||
Write-Host " [OK] $Message" -ForegroundColor Green
|
||||
Write-Log -Message $Message -Level "SUCCESS"
|
||||
}
|
||||
|
||||
function Write-Error {
|
||||
param([string]$Message)
|
||||
Write-Host " [ERROR] $Message" -ForegroundColor Red
|
||||
Write-Log -Message $Message -Level "ERROR"
|
||||
}
|
||||
|
||||
function Write-Warning {
|
||||
param([string]$Message)
|
||||
Write-Host " [WARN] $Message" -ForegroundColor Yellow
|
||||
Write-Log -Message $Message -Level "WARNING"
|
||||
}
|
||||
|
||||
function Wait-ForKeyPress {
|
||||
Write-Host "`nPress any key to continue..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# STATE MANAGEMENT
|
||||
# =============================================================================
|
||||
|
||||
function Get-DeploymentState {
|
||||
if (Test-Path $script:Config.StateFile) {
|
||||
try {
|
||||
return Get-Content -Path $script:Config.StateFile -Raw | ConvertFrom-Json
|
||||
} catch {
|
||||
Write-Warning "Failed to load state file, starting fresh"
|
||||
return $null
|
||||
}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Save-DeploymentState {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[hashtable]$DeploymentInfo
|
||||
)
|
||||
|
||||
try {
|
||||
# Load existing state
|
||||
$state = Get-DeploymentState
|
||||
|
||||
$newEntry = @{
|
||||
packageName = $DeploymentInfo.PackageName
|
||||
component = $DeploymentInfo.Component
|
||||
timestamp = (Get-Date).ToUniversalTime().ToString("o")
|
||||
status = $DeploymentInfo.Status
|
||||
services = $DeploymentInfo.Services
|
||||
}
|
||||
|
||||
if ($state) {
|
||||
# Add current deployment to history
|
||||
if (-not $state.history) {
|
||||
$state.history = @()
|
||||
}
|
||||
if ($state.lastDeployment) {
|
||||
$state.history = @($state.lastDeployment) + $state.history
|
||||
}
|
||||
|
||||
# Keep only last 10 entries in history
|
||||
if ($state.history.Count -gt 10) {
|
||||
$state.history = $state.history | Select-Object -First 10
|
||||
}
|
||||
|
||||
$state.lastDeployment = $newEntry
|
||||
} else {
|
||||
$state = @{
|
||||
lastDeployment = $newEntry
|
||||
history = @()
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure directory exists
|
||||
$stateDir = Split-Path $script:Config.StateFile -Parent
|
||||
if (-not (Test-Path $stateDir)) {
|
||||
New-Item -ItemType Directory -Path $stateDir -Force | Out-Null
|
||||
}
|
||||
|
||||
# Save state
|
||||
$state | ConvertTo-Json -Depth 10 | Set-Content -Path $script:Config.StateFile
|
||||
Write-Success "Deployment state saved"
|
||||
} catch {
|
||||
Write-Error "Failed to save deployment state: $_"
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# PACKAGE DETECTION
|
||||
# =============================================================================
|
||||
|
||||
function Get-LatestDeploymentPackage {
|
||||
Write-Step "Scanning for deployment packages..."
|
||||
|
||||
if (-not (Test-Path $script:Config.WatchPath)) {
|
||||
Write-Warning "Watch path does not exist: $($script:Config.WatchPath)"
|
||||
return $null
|
||||
}
|
||||
|
||||
# Find all deploy-* folders
|
||||
$packages = Get-ChildItem -Path $script:Config.WatchPath -Directory |
|
||||
Where-Object { $_.Name -match "^deploy-\d{8}-\d{6}$" } |
|
||||
Sort-Object LastWriteTime -Descending
|
||||
|
||||
if ($packages.Count -eq 0) {
|
||||
Write-Warning "No deployment packages found"
|
||||
return $null
|
||||
}
|
||||
|
||||
$latest = $packages | Select-Object -First 1
|
||||
Write-Success "Found $($packages.Count) package(s), latest: $($latest.Name)"
|
||||
|
||||
return $latest
|
||||
}
|
||||
|
||||
function Test-IsNewPackage {
|
||||
param([Parameter(Mandatory)]$Package)
|
||||
|
||||
$state = Get-DeploymentState
|
||||
|
||||
if (-not $state -or -not $state.lastDeployment) {
|
||||
Write-Success "No previous deployment found - this is a new package"
|
||||
return $true
|
||||
}
|
||||
|
||||
$lastDeployed = $state.lastDeployment.packageName
|
||||
|
||||
if ($Package.Name -ne $lastDeployed) {
|
||||
Write-Success "New package detected (last deployed: $lastDeployed)"
|
||||
return $true
|
||||
}
|
||||
|
||||
Write-Log -Message "Package already deployed: $($Package.Name)" -Level "INFO"
|
||||
return $false
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# DEPLOYMENT EXECUTION
|
||||
# =============================================================================
|
||||
|
||||
function Invoke-Deployment {
|
||||
param([Parameter(Mandatory)]$Package)
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " STARTING DEPLOYMENT" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host "`nPackage: $($Package.Name)" -ForegroundColor Yellow
|
||||
Write-Host "Path: $($Package.FullName)" -ForegroundColor Gray
|
||||
|
||||
# Find ROA2WEB-Console.ps1 in package
|
||||
$consoleScript = Join-Path $Package.FullName "scripts\ROA2WEB-Console.ps1"
|
||||
|
||||
if (-not (Test-Path $consoleScript)) {
|
||||
Write-Error "ROA2WEB-Console.ps1 not found in package: $consoleScript"
|
||||
return $false
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Step "Executing deployment via ROA2WEB-Console.ps1..."
|
||||
|
||||
# Set environment variable to tell ROA2WEB-Console where the package is
|
||||
$env:ROA2WEB_SOURCE = $Package.FullName
|
||||
|
||||
# Execute deployment (deploy all components)
|
||||
Push-Location (Split-Path $consoleScript -Parent)
|
||||
|
||||
& $consoleScript -NonInteractive -Action DeployAll
|
||||
|
||||
# Capture exit code IMMEDIATELY (before any other command that might reset it)
|
||||
$exitCode = $LASTEXITCODE
|
||||
|
||||
Pop-Location
|
||||
|
||||
# Check if exit code indicates success (0 = success)
|
||||
$deploySuccess = ($exitCode -eq 0)
|
||||
|
||||
if ($deploySuccess) {
|
||||
Write-Success "Deployment completed successfully (exit code: $exitCode)"
|
||||
|
||||
# Save deployment state
|
||||
Save-DeploymentState -DeploymentInfo @{
|
||||
PackageName = $Package.Name
|
||||
Component = "All"
|
||||
Status = "Success"
|
||||
Services = @{
|
||||
backend = "Running"
|
||||
telegramBot = "Running"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Green
|
||||
Write-Host " DEPLOYMENT SUCCESSFUL" -ForegroundColor Green
|
||||
Write-Host ("=" * 70) -ForegroundColor Green
|
||||
|
||||
return $true
|
||||
} else {
|
||||
Write-Error "Deployment failed (exit code: $exitCode)"
|
||||
|
||||
# Save failure state
|
||||
Save-DeploymentState -DeploymentInfo @{
|
||||
PackageName = $Package.Name
|
||||
Component = "All"
|
||||
Status = "Failed"
|
||||
Services = @{}
|
||||
}
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Red
|
||||
Write-Host " DEPLOYMENT FAILED" -ForegroundColor Red
|
||||
Write-Host ("=" * 70) -ForegroundColor Red
|
||||
|
||||
return $false
|
||||
}
|
||||
} catch {
|
||||
Write-Error "Deployment exception: $_"
|
||||
Write-Log -Message $_.ScriptStackTrace -Level "ERROR"
|
||||
|
||||
# Save failure state
|
||||
Save-DeploymentState -DeploymentInfo @{
|
||||
PackageName = $Package.Name
|
||||
Component = "All"
|
||||
Status = "Failed"
|
||||
Services = @{}
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# INTERACTIVE MENU
|
||||
# =============================================================================
|
||||
|
||||
function Show-MainMenu {
|
||||
Clear-Host
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " ROA2WEB - Auto-Deploy Monitor (Interactive)" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " [1] Check for Updates (No Deploy)" -ForegroundColor White
|
||||
Write-Host " (Scan for new packages without deploying)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [2] Check and Deploy Now" -ForegroundColor White
|
||||
Write-Host " (Find latest package and deploy if new)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [3] View Deployment History" -ForegroundColor White
|
||||
Write-Host " (Show previous deployments)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [4] View Current Configuration" -ForegroundColor White
|
||||
Write-Host " (Display monitor settings)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [Q] Quit" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
do {
|
||||
Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline
|
||||
$choice = Read-Host
|
||||
|
||||
switch ($choice.ToUpper()) {
|
||||
"1" { return "CheckOnly" }
|
||||
"2" { return "CheckAndDeploy" }
|
||||
"3" { return "History" }
|
||||
"4" { return "ViewConfig" }
|
||||
"Q" { return "Quit" }
|
||||
default {
|
||||
Write-Host "Invalid choice. Please select 1-4 or Q." -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
} while ($true)
|
||||
}
|
||||
|
||||
function Show-DeploymentHistory {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Deployment History" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
$state = Get-DeploymentState
|
||||
|
||||
if (-not $state) {
|
||||
Write-Host "`nNo deployment history found" -ForegroundColor Yellow
|
||||
return
|
||||
}
|
||||
|
||||
if ($state.lastDeployment) {
|
||||
Write-Host "`nLast Deployment:" -ForegroundColor Yellow
|
||||
Write-Host " Package: $($state.lastDeployment.packageName)" -ForegroundColor Gray
|
||||
Write-Host " Component: $($state.lastDeployment.component)" -ForegroundColor Gray
|
||||
Write-Host " Timestamp: $($state.lastDeployment.timestamp)" -ForegroundColor Gray
|
||||
Write-Host " Status: $($state.lastDeployment.status)" -ForegroundColor $(if ($state.lastDeployment.status -eq "Success") { "Green" } else { "Red" })
|
||||
}
|
||||
|
||||
if ($state.history -and $state.history.Count -gt 0) {
|
||||
Write-Host "`nPrevious Deployments:" -ForegroundColor Yellow
|
||||
$i = 1
|
||||
foreach ($entry in $state.history) {
|
||||
Write-Host " [$i] $($entry.packageName) - $($entry.timestamp) - $($entry.status)" -ForegroundColor Gray
|
||||
$i++
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Show-Configuration {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Current Configuration" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Watch Path: $($script:Config.WatchPath)" -ForegroundColor Gray
|
||||
Write-Host " State File: $($script:Config.StateFile)" -ForegroundColor Gray
|
||||
Write-Host " Log Path: $($script:Config.LogPath)" -ForegroundColor Gray
|
||||
Write-Host " Console Script: $($script:Config.ConsoleScriptPath)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MAIN CHECK & DEPLOY LOGIC
|
||||
# =============================================================================
|
||||
|
||||
function Invoke-CheckAndDeploy {
|
||||
param([switch]$CheckOnly)
|
||||
|
||||
Write-Log -Message "=== Check and Deploy Started ===" -Level "INFO"
|
||||
|
||||
# Get latest package
|
||||
$latestPackage = Get-LatestDeploymentPackage
|
||||
|
||||
if (-not $latestPackage) {
|
||||
Write-Log -Message "No deployment packages found" -Level "INFO"
|
||||
return $false
|
||||
}
|
||||
|
||||
# Check if it's a new package
|
||||
$isNew = Test-IsNewPackage -Package $latestPackage
|
||||
|
||||
if (-not $isNew) {
|
||||
Write-Log -Message "No new packages to deploy" -Level "INFO"
|
||||
return $false
|
||||
}
|
||||
|
||||
if ($CheckOnly) {
|
||||
Write-Success "New package available: $($latestPackage.Name)"
|
||||
Write-Host "`nRun without -CheckOnly to deploy" -ForegroundColor Yellow
|
||||
return $false
|
||||
}
|
||||
|
||||
# Deploy the package
|
||||
$deploySuccess = Invoke-Deployment -Package $latestPackage
|
||||
|
||||
Write-Log -Message "=== Check and Deploy Completed (Success: $deploySuccess) ===" -Level "INFO"
|
||||
|
||||
return $deploySuccess
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MAIN EXECUTION FLOW
|
||||
# =============================================================================
|
||||
|
||||
function Main {
|
||||
# Check if running as Administrator
|
||||
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
|
||||
$isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
|
||||
if (-not $isAdmin) {
|
||||
Write-Host "`n[ERROR] This script requires Administrator privileges" -ForegroundColor Red
|
||||
Write-Host "Please run PowerShell as Administrator and try again.`n" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Interactive mode
|
||||
if ($Interactive) {
|
||||
do {
|
||||
$mainChoice = Show-MainMenu
|
||||
|
||||
switch ($mainChoice) {
|
||||
"CheckOnly" {
|
||||
Invoke-CheckAndDeploy -CheckOnly
|
||||
Wait-ForKeyPress
|
||||
}
|
||||
|
||||
"CheckAndDeploy" {
|
||||
Invoke-CheckAndDeploy
|
||||
Wait-ForKeyPress
|
||||
}
|
||||
|
||||
"History" {
|
||||
Show-DeploymentHistory
|
||||
Wait-ForKeyPress
|
||||
}
|
||||
|
||||
"ViewConfig" {
|
||||
Show-Configuration
|
||||
Wait-ForKeyPress
|
||||
}
|
||||
|
||||
"Quit" {
|
||||
Write-Host "`nGoodbye!`n" -ForegroundColor Cyan
|
||||
return
|
||||
}
|
||||
}
|
||||
} while ($true)
|
||||
}
|
||||
# Non-interactive mode (for Scheduled Task)
|
||||
else {
|
||||
Invoke-CheckAndDeploy -CheckOnly:$CheckOnly | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
# Run main
|
||||
Main
|
||||
847
deployment/windows/scripts/Publish-And-Deploy.ps1
Normal file
847
deployment/windows/scripts/Publish-And-Deploy.ps1
Normal file
@@ -0,0 +1,847 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
ROA2WEB - Interactive Build & Publish Console
|
||||
|
||||
.DESCRIPTION
|
||||
Build deployment packages locally and transfer to Windows Server:
|
||||
- Build locally (Frontend, Backend, Telegram Bot, or All)
|
||||
- Transfer via Windows Share (LAN) or SSH/SCP (remote)
|
||||
- Auto-detect best transfer method
|
||||
- Interactive menu or command-line operation
|
||||
- Server auto-deploys when new package detected
|
||||
|
||||
.PARAMETER NonInteractive
|
||||
Run in non-interactive mode with specific action
|
||||
|
||||
.PARAMETER Action
|
||||
Action to perform in non-interactive mode:
|
||||
- Build: Build and publish package
|
||||
- TestConnections: Test Windows Share and SSH connectivity
|
||||
- Configure: Edit configuration (interactive only)
|
||||
- ViewConfig: Display current configuration
|
||||
|
||||
.PARAMETER Component
|
||||
Component to build (All, Frontend, Backend, TelegramBot)
|
||||
|
||||
.PARAMETER TransferMethod
|
||||
Transfer method (Auto, WindowsShare, SSH)
|
||||
|
||||
.PARAMETER ConfigFile
|
||||
Path to configuration file (default: deploy-config.json)
|
||||
|
||||
.EXAMPLE
|
||||
.\Publish-And-Deploy.ps1
|
||||
Launch interactive menu
|
||||
|
||||
.EXAMPLE
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All
|
||||
Build all components and publish (auto-detect transfer method)
|
||||
|
||||
.EXAMPLE
|
||||
.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component Frontend -TransferMethod SSH
|
||||
Build frontend and publish via SSH
|
||||
|
||||
.NOTES
|
||||
Author: ROA2WEB Team
|
||||
Version: 1.0 (Interactive Build & Publish)
|
||||
Requires: PowerShell 5.1+, SSH key configured for remote access
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$NonInteractive,
|
||||
|
||||
[ValidateSet("Build", "TestConnections", "ViewConfig")]
|
||||
[string]$Action = "",
|
||||
|
||||
[ValidateSet("All", "Frontend", "Backend", "TelegramBot")]
|
||||
[string]$Component = "",
|
||||
|
||||
[ValidateSet("Auto", "WindowsShare", "SSH")]
|
||||
[string]$TransferMethod = "",
|
||||
|
||||
[string]$ConfigFile = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# =============================================================================
|
||||
# CONFIGURATION LOADING
|
||||
# =============================================================================
|
||||
|
||||
$script:ConfigFilePath = if ($ConfigFile) {
|
||||
$ConfigFile
|
||||
} else {
|
||||
Join-Path $PSScriptRoot "deploy-config.json"
|
||||
}
|
||||
|
||||
function Load-Configuration {
|
||||
Write-Host "`nLoading configuration from: $script:ConfigFilePath" -ForegroundColor Gray
|
||||
|
||||
if (-not (Test-Path $script:ConfigFilePath)) {
|
||||
Write-Host "[ERROR] Configuration file not found: $script:ConfigFilePath" -ForegroundColor Red
|
||||
Write-Host "Creating default configuration..." -ForegroundColor Yellow
|
||||
|
||||
$defaultConfig = @{
|
||||
server = @{
|
||||
host = "10.0.20.36"
|
||||
sshPort = 22122
|
||||
sshUser = "Administrator"
|
||||
sshKeyPath = "~/.ssh/roa2web_deploy"
|
||||
windowsShare = "\\10.0.20.36\ROA2WEB-Deploy"
|
||||
deployPath = "C:\ROA2WEB-Deploy"
|
||||
}
|
||||
build = @{
|
||||
defaultComponent = "All"
|
||||
outputPath = "../deploy-package"
|
||||
}
|
||||
transfer = @{
|
||||
defaultMethod = "Auto"
|
||||
scpRemotePath = "/cygdrive/c/ROA2WEB-Deploy"
|
||||
retryAttempts = 3
|
||||
timeout = 300
|
||||
}
|
||||
deployment = @{
|
||||
autoDeployEnabled = $true
|
||||
checkIntervalMinutes = 5
|
||||
}
|
||||
}
|
||||
|
||||
$defaultConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $script:ConfigFilePath
|
||||
Write-Host "Default configuration created. Please review and edit as needed." -ForegroundColor Green
|
||||
}
|
||||
|
||||
try {
|
||||
$script:Config = Get-Content -Path $script:ConfigFilePath -Raw | ConvertFrom-Json
|
||||
Write-Host "✓ Configuration loaded successfully" -ForegroundColor Green
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host "[ERROR] Failed to load configuration: $_" -ForegroundColor Red
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Save-Configuration {
|
||||
try {
|
||||
$script:Config | ConvertTo-Json -Depth 10 | Set-Content -Path $script:ConfigFilePath
|
||||
Write-Host "✓ Configuration saved successfully" -ForegroundColor Green
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host "[ERROR] Failed to save configuration: $_" -ForegroundColor Red
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# HELPER FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Write-Step {
|
||||
param([string]$Message)
|
||||
Write-Host "`n[*] $Message" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Write-Success {
|
||||
param([string]$Message)
|
||||
Write-Host " [OK] $Message" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Write-Error {
|
||||
param([string]$Message)
|
||||
Write-Host " [ERROR] $Message" -ForegroundColor Red
|
||||
}
|
||||
|
||||
function Write-Warning {
|
||||
param([string]$Message)
|
||||
Write-Host " [WARN] $Message" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
function Write-Info {
|
||||
param([string]$Message)
|
||||
Write-Host " [*] $Message" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
function Resolve-FullPath {
|
||||
param([string]$Path)
|
||||
|
||||
# Resolve relative paths from the parent of the scripts directory
|
||||
# This matches the resolution logic in Build-ROA2WEB.ps1
|
||||
$scriptDir = Split-Path -Parent $PSScriptRoot
|
||||
$fullPath = Join-Path $scriptDir $Path
|
||||
$fullPath = [System.IO.Path]::GetFullPath($fullPath)
|
||||
|
||||
return $fullPath
|
||||
}
|
||||
|
||||
function Wait-ForKeyPress {
|
||||
Write-Host "`nPress any key to continue..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# CONNECTION TESTING
|
||||
# =============================================================================
|
||||
|
||||
function Test-WindowsShare {
|
||||
Write-Step "Testing Windows Share access..."
|
||||
|
||||
$sharePath = $script:Config.server.windowsShare
|
||||
Write-Info "Share: $sharePath"
|
||||
|
||||
try {
|
||||
if (Test-Path $sharePath) {
|
||||
Write-Success "Windows Share is accessible"
|
||||
|
||||
# Try to write test file
|
||||
$testFile = Join-Path $sharePath ".test-$(Get-Date -Format 'yyyyMMddHHmmss')"
|
||||
"test" | Out-File -FilePath $testFile -Force
|
||||
|
||||
if (Test-Path $testFile) {
|
||||
Remove-Item -Path $testFile -Force
|
||||
Write-Success "Write permissions verified"
|
||||
return $true
|
||||
} else {
|
||||
Write-Warning "Share is readable but write test failed"
|
||||
return $false
|
||||
}
|
||||
} else {
|
||||
Write-Error "Windows Share is not accessible"
|
||||
Write-Info "Ensure network share is configured and accessible"
|
||||
return $false
|
||||
}
|
||||
} catch {
|
||||
Write-Error "Failed to access Windows Share: $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Test-SSHConnection {
|
||||
Write-Step "Testing SSH connection..."
|
||||
|
||||
$serverHost = $script:Config.server.host
|
||||
$port = $script:Config.server.sshPort
|
||||
$user = $script:Config.server.sshUser
|
||||
$keyPath = $script:Config.server.sshKeyPath
|
||||
|
||||
Write-Info "Host: ${serverHost}:${port}"
|
||||
Write-Info "User: $user"
|
||||
Write-Info "Key: $keyPath"
|
||||
|
||||
# Expand tilde in key path (support both Unix / and Windows \ styles)
|
||||
if ($keyPath -like "~/*" -or $keyPath -like "~\*") {
|
||||
$keyPath = $keyPath -replace "^~", $env:USERPROFILE
|
||||
}
|
||||
|
||||
if (-not (Test-Path $keyPath)) {
|
||||
Write-Error "SSH key not found: $keyPath"
|
||||
return $false
|
||||
}
|
||||
|
||||
try {
|
||||
# Test SSH connection
|
||||
$sshTest = ssh -i "$keyPath" -p $port -o ConnectTimeout=10 -o StrictHostKeyChecking=no "${user}@${serverHost}" "echo 'Connection successful'" 2>&1
|
||||
|
||||
if ($LASTEXITCODE -eq 0 -and $sshTest -like "*Connection successful*") {
|
||||
Write-Success "SSH connection established"
|
||||
return $true
|
||||
} else {
|
||||
Write-Error "SSH connection failed"
|
||||
Write-Info "Output: $sshTest"
|
||||
return $false
|
||||
}
|
||||
} catch {
|
||||
Write-Error "Failed to test SSH connection: $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Test-AllConnections {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Connection Testing" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
$shareOk = Test-WindowsShare
|
||||
$sshOk = Test-SSHConnection
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Test Results" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host "`n Windows Share: " -NoNewline
|
||||
if ($shareOk) {
|
||||
Write-Host "✓ Available" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "✗ Not Available" -ForegroundColor Red
|
||||
}
|
||||
|
||||
Write-Host " SSH Connection: " -NoNewline
|
||||
if ($sshOk) {
|
||||
Write-Host "✓ Available" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "✗ Not Available" -ForegroundColor Red
|
||||
}
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
return @{
|
||||
WindowsShare = $shareOk
|
||||
SSH = $sshOk
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# BUILD & TRANSFER FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Invoke-Build {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateSet("All", "Frontend", "Backend", "TelegramBot")]
|
||||
[string]$Component
|
||||
)
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Building Component: $Component" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
$buildScript = Join-Path $PSScriptRoot "Build-ROA2WEB.ps1"
|
||||
|
||||
if (-not (Test-Path $buildScript)) {
|
||||
Write-Error "Build script not found: $buildScript"
|
||||
return $false
|
||||
}
|
||||
|
||||
try {
|
||||
$outputPath = $script:Config.build.outputPath
|
||||
|
||||
# Resolve the output path using the same logic as Build-ROA2WEB.ps1
|
||||
$resolvedOutputPath = if ([System.IO.Path]::IsPathRooted($outputPath)) {
|
||||
$outputPath
|
||||
} else {
|
||||
Resolve-FullPath -Path $outputPath
|
||||
}
|
||||
|
||||
Write-Step "Building deployment package..."
|
||||
& $buildScript -Component $Component -OutputPath $outputPath
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Build script returned error code: $LASTEXITCODE"
|
||||
}
|
||||
|
||||
if (-not (Test-Path $resolvedOutputPath)) {
|
||||
throw "Build output not found: $resolvedOutputPath"
|
||||
}
|
||||
|
||||
Write-Success "Build completed successfully"
|
||||
return $true
|
||||
} catch {
|
||||
Write-Error "Build failed: $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Copy-ViaWindowsShare {
|
||||
param([string]$SourcePath)
|
||||
|
||||
Write-Step "Transferring via Windows Share..."
|
||||
|
||||
$sharePath = $script:Config.server.windowsShare
|
||||
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
||||
$deployFolder = "deploy-$timestamp"
|
||||
$destPath = Join-Path $sharePath $deployFolder
|
||||
|
||||
try {
|
||||
Write-Info "Destination: $destPath"
|
||||
|
||||
Copy-Item -Path $SourcePath -Destination $destPath -Recurse -Force
|
||||
|
||||
if (Test-Path $destPath) {
|
||||
Write-Success "Files transferred successfully"
|
||||
Write-Success "Server will auto-deploy within $($script:Config.deployment.checkIntervalMinutes) minutes"
|
||||
return $true
|
||||
} else {
|
||||
Write-Error "Transfer failed - destination folder not found"
|
||||
return $false
|
||||
}
|
||||
} catch {
|
||||
Write-Error "Windows Share transfer failed: $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Copy-ViaSSH {
|
||||
param([string]$SourcePath)
|
||||
|
||||
Write-Step "Transferring via SSH/SCP..."
|
||||
|
||||
$serverHost = $script:Config.server.host
|
||||
$port = $script:Config.server.sshPort
|
||||
$user = $script:Config.server.sshUser
|
||||
$keyPath = $script:Config.server.sshKeyPath
|
||||
$remotePath = $script:Config.transfer.scpRemotePath
|
||||
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
||||
$deployFolder = "deploy-$timestamp"
|
||||
|
||||
# Expand tilde in key path (support both Unix / and Windows \ styles)
|
||||
if ($keyPath -like "~/*" -or $keyPath -like "~\*") {
|
||||
$keyPath = $keyPath -replace "^~", $env:USERPROFILE
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Info "Host: ${serverHost}:${port}"
|
||||
Write-Info "Destination: ${remotePath}/${deployFolder}"
|
||||
|
||||
# Create remote directory
|
||||
Write-Info "Creating remote directory..."
|
||||
$createDir = ssh -i "$keyPath" -p $port "${user}@${serverHost}" "mkdir -p '${remotePath}/${deployFolder}'" 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to create remote directory: $createDir"
|
||||
}
|
||||
|
||||
# Transfer files via SCP
|
||||
Write-Info "Transferring files (this may take a few minutes)..."
|
||||
$scpResult = scp -i "$keyPath" -P $port -r "${SourcePath}/*" "${user}@${serverHost}:${remotePath}/${deployFolder}/" 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "SCP transfer failed: $scpResult"
|
||||
}
|
||||
|
||||
Write-Success "Files transferred successfully"
|
||||
Write-Success "Server will auto-deploy within $($script:Config.deployment.checkIntervalMinutes) minutes"
|
||||
return $true
|
||||
} catch {
|
||||
Write-Error "SSH transfer failed: $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-Transfer {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[ValidateSet("Auto", "WindowsShare", "SSH")]
|
||||
[string]$Method,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string]$SourcePath
|
||||
)
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Transfer Method: $Method" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
if ($Method -eq "Auto") {
|
||||
Write-Info "Auto-detecting best transfer method..."
|
||||
|
||||
# Try Windows Share first (faster for LAN)
|
||||
Write-Info "Checking Windows Share availability..."
|
||||
if (Test-Path $script:Config.server.windowsShare) {
|
||||
Write-Success "Windows Share accessible - using Windows Share"
|
||||
return Copy-ViaWindowsShare -SourcePath $SourcePath
|
||||
} else {
|
||||
Write-Warning "Windows Share not accessible - falling back to SSH"
|
||||
return Copy-ViaSSH -SourcePath $SourcePath
|
||||
}
|
||||
} elseif ($Method -eq "WindowsShare") {
|
||||
return Copy-ViaWindowsShare -SourcePath $SourcePath
|
||||
} else {
|
||||
return Copy-ViaSSH -SourcePath $SourcePath
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# CONFIGURATION MANAGEMENT
|
||||
# =============================================================================
|
||||
|
||||
function Show-CurrentConfig {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Current Configuration" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Server Settings:" -ForegroundColor Yellow
|
||||
Write-Host " Host: $($script:Config.server.host)" -ForegroundColor Gray
|
||||
Write-Host " SSH Port: $($script:Config.server.sshPort)" -ForegroundColor Gray
|
||||
Write-Host " SSH User: $($script:Config.server.sshUser)" -ForegroundColor Gray
|
||||
Write-Host " SSH Key: $($script:Config.server.sshKeyPath)" -ForegroundColor Gray
|
||||
Write-Host " Windows Share: $($script:Config.server.windowsShare)" -ForegroundColor Gray
|
||||
Write-Host " Deploy Path: $($script:Config.server.deployPath)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " Build Settings:" -ForegroundColor Yellow
|
||||
Write-Host " Default Component: $($script:Config.build.defaultComponent)" -ForegroundColor Gray
|
||||
Write-Host " Output Path: $($script:Config.build.outputPath)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " Transfer Settings:" -ForegroundColor Yellow
|
||||
Write-Host " Default Method: $($script:Config.transfer.defaultMethod)" -ForegroundColor Gray
|
||||
Write-Host " SCP Remote Path: $($script:Config.transfer.scpRemotePath)" -ForegroundColor Gray
|
||||
Write-Host " Retry Attempts: $($script:Config.transfer.retryAttempts)" -ForegroundColor Gray
|
||||
Write-Host " Timeout (sec): $($script:Config.transfer.timeout)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " Deployment Settings:" -ForegroundColor Yellow
|
||||
Write-Host " Auto-Deploy: $($script:Config.deployment.autoDeployEnabled)" -ForegroundColor Gray
|
||||
Write-Host " Check Interval: $($script:Config.deployment.checkIntervalMinutes) minutes" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " Config File: $script:ConfigFilePath" -ForegroundColor Gray
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Edit-Configuration {
|
||||
Clear-Host
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Configuration Editor" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Current Settings:" -ForegroundColor Yellow
|
||||
Write-Host " Server Host: $($script:Config.server.host)" -ForegroundColor Gray
|
||||
Write-Host " SSH Port: $($script:Config.server.sshPort)" -ForegroundColor Gray
|
||||
Write-Host " SSH User: $($script:Config.server.sshUser)" -ForegroundColor Gray
|
||||
Write-Host " SSH Key: $($script:Config.server.sshKeyPath)" -ForegroundColor Gray
|
||||
Write-Host " Windows Share: $($script:Config.server.windowsShare)" -ForegroundColor Gray
|
||||
Write-Host " Server Deploy Path: $($script:Config.server.deployPath)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [1] Edit SSH Connection Settings" -ForegroundColor White
|
||||
Write-Host " [2] Edit Windows Share Path" -ForegroundColor White
|
||||
Write-Host " [3] Edit Server Deploy Path" -ForegroundColor White
|
||||
Write-Host " [4] Edit Build Settings" -ForegroundColor White
|
||||
Write-Host " [5] Edit Transfer Settings" -ForegroundColor White
|
||||
Write-Host " [S] Save Configuration" -ForegroundColor Green
|
||||
Write-Host " [R] Reset to Defaults" -ForegroundColor Yellow
|
||||
Write-Host " [B] Back (discard changes)" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
do {
|
||||
Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline
|
||||
$choice = Read-Host
|
||||
|
||||
switch ($choice.ToUpper()) {
|
||||
"1" {
|
||||
Write-Host "`nEdit SSH Connection Settings:" -ForegroundColor Yellow
|
||||
Write-Host "Server Host [current: $($script:Config.server.host)]: " -NoNewline
|
||||
$newHost = Read-Host
|
||||
if ($newHost) { $script:Config.server.host = $newHost }
|
||||
|
||||
Write-Host "SSH Port [current: $($script:Config.server.sshPort)]: " -NoNewline
|
||||
$newPort = Read-Host
|
||||
if ($newPort) { $script:Config.server.sshPort = [int]$newPort }
|
||||
|
||||
Write-Host "SSH User [current: $($script:Config.server.sshUser)]: " -NoNewline
|
||||
$newUser = Read-Host
|
||||
if ($newUser) { $script:Config.server.sshUser = $newUser }
|
||||
|
||||
Write-Host "SSH Key Path [current: $($script:Config.server.sshKeyPath)]: " -NoNewline
|
||||
$newKey = Read-Host
|
||||
if ($newKey) { $script:Config.server.sshKeyPath = $newKey }
|
||||
|
||||
Write-Success "SSH settings updated (not saved yet)"
|
||||
return Edit-Configuration
|
||||
}
|
||||
"2" {
|
||||
Write-Host "`nEdit Windows Share Path:" -ForegroundColor Yellow
|
||||
Write-Host "Windows Share [current: $($script:Config.server.windowsShare)]: " -NoNewline
|
||||
$newShare = Read-Host
|
||||
if ($newShare) { $script:Config.server.windowsShare = $newShare }
|
||||
|
||||
Write-Success "Windows Share updated (not saved yet)"
|
||||
return Edit-Configuration
|
||||
}
|
||||
"3" {
|
||||
Write-Host "`nEdit Server Deploy Path:" -ForegroundColor Yellow
|
||||
Write-Host "Deploy Path [current: $($script:Config.server.deployPath)]: " -NoNewline
|
||||
$newPath = Read-Host
|
||||
if ($newPath) { $script:Config.server.deployPath = $newPath }
|
||||
|
||||
Write-Success "Deploy path updated (not saved yet)"
|
||||
return Edit-Configuration
|
||||
}
|
||||
"4" {
|
||||
Write-Host "`nEdit Build Settings:" -ForegroundColor Yellow
|
||||
Write-Host "Default Component (All/Frontend/Backend/TelegramBot) [current: $($script:Config.build.defaultComponent)]: " -NoNewline
|
||||
$newComp = Read-Host
|
||||
if ($newComp) { $script:Config.build.defaultComponent = $newComp }
|
||||
|
||||
Write-Host "Output Path [current: $($script:Config.build.outputPath)]: " -NoNewline
|
||||
$newOut = Read-Host
|
||||
if ($newOut) { $script:Config.build.outputPath = $newOut }
|
||||
|
||||
Write-Success "Build settings updated (not saved yet)"
|
||||
return Edit-Configuration
|
||||
}
|
||||
"5" {
|
||||
Write-Host "`nEdit Transfer Settings:" -ForegroundColor Yellow
|
||||
Write-Host "Default Method (Auto/WindowsShare/SSH) [current: $($script:Config.transfer.defaultMethod)]: " -NoNewline
|
||||
$newMethod = Read-Host
|
||||
if ($newMethod) { $script:Config.transfer.defaultMethod = $newMethod }
|
||||
|
||||
Write-Host "SCP Remote Path [current: $($script:Config.transfer.scpRemotePath)]: " -NoNewline
|
||||
$newScp = Read-Host
|
||||
if ($newScp) { $script:Config.transfer.scpRemotePath = $newScp }
|
||||
|
||||
Write-Success "Transfer settings updated (not saved yet)"
|
||||
return Edit-Configuration
|
||||
}
|
||||
"S" {
|
||||
if (Save-Configuration) {
|
||||
Write-Host "`nConfiguration saved successfully!" -ForegroundColor Green
|
||||
Wait-ForKeyPress
|
||||
return
|
||||
}
|
||||
}
|
||||
"R" {
|
||||
Write-Host "`nAre you sure you want to reset to defaults? [Y/N]: " -ForegroundColor Yellow -NoNewline
|
||||
$confirm = Read-Host
|
||||
if ($confirm.ToUpper() -eq "Y") {
|
||||
Load-Configuration
|
||||
Write-Success "Configuration reset to defaults"
|
||||
return Edit-Configuration
|
||||
}
|
||||
}
|
||||
"B" {
|
||||
Write-Host "`nChanges discarded" -ForegroundColor Yellow
|
||||
Load-Configuration # Reload from file
|
||||
return
|
||||
}
|
||||
default {
|
||||
Write-Host "Invalid choice. Please select 1-5, S, R, or B." -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
} while ($true)
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MENU FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Show-MainMenu {
|
||||
Clear-Host
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " ROA2WEB - Interactive Build & Publish Console" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Main Menu:" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " [1] Build & Publish Package" -ForegroundColor White
|
||||
Write-Host " (Build locally and transfer to server)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [2] Test Connections" -ForegroundColor White
|
||||
Write-Host " (Verify Windows Share and SSH access)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [3] Configure Settings" -ForegroundColor White
|
||||
Write-Host " (Edit deployment configuration)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [4] View Current Configuration" -ForegroundColor White
|
||||
Write-Host " (Display active settings)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [Q] Quit" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
do {
|
||||
Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline
|
||||
$choice = Read-Host
|
||||
|
||||
switch ($choice.ToUpper()) {
|
||||
"1" { return "BuildPublish" }
|
||||
"2" { return "TestConnections" }
|
||||
"3" { return "Configure" }
|
||||
"4" { return "ViewConfig" }
|
||||
"Q" { return "Quit" }
|
||||
default {
|
||||
Write-Host "Invalid choice. Please select 1-4 or Q." -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
} while ($true)
|
||||
}
|
||||
|
||||
function Show-ComponentMenu {
|
||||
Clear-Host
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Select Component to Build" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " [1] All Components" -ForegroundColor White
|
||||
Write-Host " (Frontend + Backend + Telegram Bot)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [2] Frontend + Backend" -ForegroundColor White
|
||||
Write-Host " (Vue.js build + FastAPI backend)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [3] Backend Only" -ForegroundColor White
|
||||
Write-Host " (FastAPI backend + shared modules)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [4] Telegram Bot Only" -ForegroundColor White
|
||||
Write-Host " (Telegram bot standalone package)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [B] Back to Main Menu" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
do {
|
||||
Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline
|
||||
$choice = Read-Host
|
||||
|
||||
switch ($choice.ToUpper()) {
|
||||
"1" { return "All" }
|
||||
"2" { return "Frontend" }
|
||||
"3" { return "Backend" }
|
||||
"4" { return "TelegramBot" }
|
||||
"B" { return "Back" }
|
||||
default {
|
||||
Write-Host "Invalid choice. Please select 1-4 or B." -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
} while ($true)
|
||||
}
|
||||
|
||||
function Show-TransferMenu {
|
||||
Clear-Host
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Select Transfer Method" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " [1] Auto-detect (Recommended)" -ForegroundColor White
|
||||
Write-Host " Try Windows Share first, fallback to SSH" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [2] Windows Share (LAN)" -ForegroundColor White
|
||||
Write-Host " Fast transfer via network share ($($script:Config.server.windowsShare))" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [3] SSH/SCP (Remote)" -ForegroundColor White
|
||||
Write-Host " Secure transfer via SSH (port $($script:Config.server.sshPort))" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [B] Back" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
do {
|
||||
Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline
|
||||
$choice = Read-Host
|
||||
|
||||
switch ($choice.ToUpper()) {
|
||||
"1" { return "Auto" }
|
||||
"2" { return "WindowsShare" }
|
||||
"3" { return "SSH" }
|
||||
"B" { return "Back" }
|
||||
default {
|
||||
Write-Host "Invalid choice. Please select 1-3 or B." -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
} while ($true)
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# ACTION HANDLERS
|
||||
# =============================================================================
|
||||
|
||||
function Invoke-BuildAndPublish {
|
||||
param(
|
||||
[string]$Component = "",
|
||||
[string]$TransferMethod = ""
|
||||
)
|
||||
|
||||
# Get component if not provided
|
||||
if (-not $Component) {
|
||||
$Component = Show-ComponentMenu
|
||||
if ($Component -eq "Back") { return }
|
||||
}
|
||||
|
||||
# Get transfer method if not provided
|
||||
if (-not $TransferMethod) {
|
||||
$TransferMethod = Show-TransferMenu
|
||||
if ($TransferMethod -eq "Back") { return }
|
||||
}
|
||||
|
||||
# Build
|
||||
$buildSuccess = Invoke-Build -Component $Component
|
||||
|
||||
if (-not $buildSuccess) {
|
||||
Write-Host "`n[BUILD FAILED] Cannot proceed with transfer" -ForegroundColor Red
|
||||
if (-not $NonInteractive) { Wait-ForKeyPress }
|
||||
return
|
||||
}
|
||||
|
||||
# Transfer
|
||||
$outputPath = $script:Config.build.outputPath
|
||||
|
||||
# Resolve the output path for transfer
|
||||
$resolvedOutputPath = if ([System.IO.Path]::IsPathRooted($outputPath)) {
|
||||
$outputPath
|
||||
} else {
|
||||
Resolve-FullPath -Path $outputPath
|
||||
}
|
||||
|
||||
$transferSuccess = Invoke-Transfer -Method $TransferMethod -SourcePath $resolvedOutputPath
|
||||
|
||||
if ($transferSuccess) {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Green
|
||||
Write-Host " BUILD & PUBLISH COMPLETED SUCCESSFULLY" -ForegroundColor Green
|
||||
Write-Host ("=" * 70) -ForegroundColor Green
|
||||
Write-Host "`nPackage published to server: $($script:Config.server.host)" -ForegroundColor Gray
|
||||
Write-Host "Server will auto-deploy within $($script:Config.deployment.checkIntervalMinutes) minutes" -ForegroundColor Gray
|
||||
Write-Host ("=" * 70) -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "`n[TRANSFER FAILED] Package built but transfer failed" -ForegroundColor Red
|
||||
}
|
||||
|
||||
if (-not $NonInteractive) { Wait-ForKeyPress }
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MAIN EXECUTION FLOW
|
||||
# =============================================================================
|
||||
|
||||
function Main {
|
||||
# Load configuration
|
||||
if (-not (Load-Configuration)) {
|
||||
Write-Host "`nPress any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Non-interactive mode
|
||||
if ($NonInteractive -and $Action) {
|
||||
switch ($Action) {
|
||||
"Build" {
|
||||
$comp = if ($Component) { $Component } else { $script:Config.build.defaultComponent }
|
||||
$method = if ($TransferMethod) { $TransferMethod } else { $script:Config.transfer.defaultMethod }
|
||||
Invoke-BuildAndPublish -Component $comp -TransferMethod $method
|
||||
}
|
||||
"TestConnections" {
|
||||
Test-AllConnections | Out-Null
|
||||
}
|
||||
"ViewConfig" {
|
||||
Show-CurrentConfig
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# Interactive mode - main loop
|
||||
do {
|
||||
$mainChoice = Show-MainMenu
|
||||
|
||||
switch ($mainChoice) {
|
||||
"BuildPublish" {
|
||||
Invoke-BuildAndPublish
|
||||
}
|
||||
|
||||
"TestConnections" {
|
||||
Test-AllConnections | Out-Null
|
||||
Wait-ForKeyPress
|
||||
}
|
||||
|
||||
"Configure" {
|
||||
Edit-Configuration
|
||||
}
|
||||
|
||||
"ViewConfig" {
|
||||
Show-CurrentConfig
|
||||
Wait-ForKeyPress
|
||||
}
|
||||
|
||||
"Quit" {
|
||||
Write-Host "`nGoodbye!`n" -ForegroundColor Cyan
|
||||
return
|
||||
}
|
||||
}
|
||||
} while ($true)
|
||||
}
|
||||
|
||||
# Run main
|
||||
Main
|
||||
@@ -53,8 +53,14 @@ $ErrorActionPreference = "Stop"
|
||||
# GLOBAL CONFIGURATION
|
||||
# =============================================================================
|
||||
|
||||
# Auto-detect source path: if running from scripts/ subdirectory, use parent
|
||||
$detectedSourcePath = if ((Split-Path $PSScriptRoot -Leaf) -eq "scripts") {
|
||||
# Auto-detect source path with priority:
|
||||
# 1. Environment variable ROA2WEB_SOURCE (set by Check-And-Deploy.ps1)
|
||||
# 2. If running from scripts/ subdirectory, use parent
|
||||
# 3. Otherwise use script root
|
||||
$detectedSourcePath = if ($env:ROA2WEB_SOURCE) {
|
||||
Write-Host "[INFO] Using source path from environment: $env:ROA2WEB_SOURCE" -ForegroundColor Cyan
|
||||
$env:ROA2WEB_SOURCE
|
||||
} elseif ((Split-Path $PSScriptRoot -Leaf) -eq "scripts") {
|
||||
Split-Path $PSScriptRoot -Parent
|
||||
} else {
|
||||
$PSScriptRoot
|
||||
@@ -1649,16 +1655,27 @@ function Execute-ManageAction {
|
||||
function Execute-DeployAction {
|
||||
param([string]$Component)
|
||||
|
||||
# Execute deployment and capture only the boolean result
|
||||
$success = switch ($Component) {
|
||||
"Backend" { Deploy-Backend }
|
||||
"TelegramBot" { Deploy-TelegramBot }
|
||||
"Backend" {
|
||||
$result = Deploy-Backend
|
||||
$result # Explicitly output the boolean
|
||||
}
|
||||
"TelegramBot" {
|
||||
$result = Deploy-TelegramBot
|
||||
$result # Explicitly output the boolean
|
||||
}
|
||||
"All" {
|
||||
$backendOk = Deploy-Backend
|
||||
$telegramOk = Deploy-TelegramBot
|
||||
$backendOk -and $telegramOk
|
||||
# Return combined result
|
||||
($backendOk -and $telegramOk)
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure $success is boolean
|
||||
$success = [bool]$success
|
||||
|
||||
if ($success) {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " DEPLOYMENT COMPLETED" -ForegroundColor Green
|
||||
@@ -1668,6 +1685,9 @@ function Execute-DeployAction {
|
||||
Write-Host " DEPLOYMENT FAILED" -ForegroundColor Red
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
# Explicitly return boolean value
|
||||
return $success
|
||||
}
|
||||
|
||||
function Show-AllStatus {
|
||||
@@ -1698,16 +1718,37 @@ function Main {
|
||||
|
||||
# Non-interactive mode
|
||||
if ($NonInteractive -and $Action) {
|
||||
switch ($Action) {
|
||||
try {
|
||||
$success = switch ($Action) {
|
||||
"DeployBackend" { Execute-DeployAction -Component "Backend" }
|
||||
"DeployTelegramBot" { Execute-DeployAction -Component "TelegramBot" }
|
||||
"DeployAll" { Execute-DeployAction -Component "All" }
|
||||
"StartAll" { Execute-ManageAction -Action "Start" -Component "All" }
|
||||
"StopAll" { Execute-ManageAction -Action "Stop" -Component "All" }
|
||||
"RestartAll" { Execute-ManageAction -Action "Restart" -Component "All" }
|
||||
"Status" { Show-AllStatus }
|
||||
"StartAll" { Execute-ManageAction -Action "Start" -Component "All"; $true }
|
||||
"StopAll" { Execute-ManageAction -Action "Stop" -Component "All"; $true }
|
||||
"RestartAll" { Execute-ManageAction -Action "Restart" -Component "All"; $true }
|
||||
"Status" { Show-AllStatus; $true }
|
||||
default { $false }
|
||||
}
|
||||
|
||||
# Ensure boolean
|
||||
$success = [bool]$success
|
||||
|
||||
# Debug output
|
||||
Write-Host "`n[DEBUG] Action: $Action, Success: $success, Type: $($success.GetType().Name)" -ForegroundColor Magenta
|
||||
|
||||
if ($success) {
|
||||
Write-Host "[DEBUG] Exiting with code 0 (success)" -ForegroundColor Magenta
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "[DEBUG] Exiting with code 1 (failure)" -ForegroundColor Magenta
|
||||
exit 1
|
||||
}
|
||||
} catch {
|
||||
Write-Host "`n[ERROR] Unhandled exception: $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host "[ERROR] Stack trace: $($_.ScriptStackTrace)" -ForegroundColor Red
|
||||
Write-Host "[DEBUG] Exiting with code 1 (exception)" -ForegroundColor Magenta
|
||||
exit 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# Interactive mode - main loop
|
||||
|
||||
472
deployment/windows/scripts/Setup-AutoDeploy.ps1
Normal file
472
deployment/windows/scripts/Setup-AutoDeploy.ps1
Normal file
@@ -0,0 +1,472 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
ROA2WEB - Auto-Deploy Setup Wizard (Server-Side)
|
||||
|
||||
.DESCRIPTION
|
||||
Interactive wizard to configure automatic deployment monitoring on Windows Server.
|
||||
Creates scheduled task that runs Check-And-Deploy.ps1 at specified intervals.
|
||||
|
||||
.PARAMETER MonitorPath
|
||||
Path to monitor for deployment packages (default: C:\Temp)
|
||||
|
||||
.PARAMETER ScriptsPath
|
||||
Path where Check-And-Deploy.ps1 is located (default: C:\Temp\ROA2WEB-Scripts)
|
||||
|
||||
.PARAMETER CheckIntervalMinutes
|
||||
How often to check for new packages in minutes (default: 5)
|
||||
|
||||
.PARAMETER AutoDeploy
|
||||
Automatically deploy new packages when found (default: true)
|
||||
|
||||
.PARAMETER CreateScheduledTask
|
||||
Create Windows Scheduled Task for automation (default: true)
|
||||
|
||||
.PARAMETER NonInteractive
|
||||
Run in non-interactive mode with provided parameters
|
||||
|
||||
.EXAMPLE
|
||||
.\Setup-AutoDeploy.ps1
|
||||
Launch interactive setup wizard
|
||||
|
||||
.EXAMPLE
|
||||
.\Setup-AutoDeploy.ps1 -NonInteractive -MonitorPath "C:\Temp" -CheckIntervalMinutes 5
|
||||
Non-interactive setup with defaults
|
||||
|
||||
.NOTES
|
||||
Author: ROA2WEB Team
|
||||
Version: 1.0 (Auto-Deploy Setup)
|
||||
Requires: Administrator privileges, PowerShell 5.1+
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$MonitorPath = "C:\Temp",
|
||||
[string]$ScriptsPath = "C:\Temp\ROA2WEB-Scripts",
|
||||
[int]$CheckIntervalMinutes = 5,
|
||||
[bool]$AutoDeploy = $true,
|
||||
[bool]$CreateScheduledTask = $true,
|
||||
[switch]$NonInteractive
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# =============================================================================
|
||||
# HELPER FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Write-Step {
|
||||
param([string]$Message)
|
||||
Write-Host "`n[*] $Message" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Write-Success {
|
||||
param([string]$Message)
|
||||
Write-Host " [OK] $Message" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Write-Error {
|
||||
param([string]$Message)
|
||||
Write-Host " [ERROR] $Message" -ForegroundColor Red
|
||||
}
|
||||
|
||||
function Write-Warning {
|
||||
param([string]$Message)
|
||||
Write-Host " [WARN] $Message" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
function Write-Info {
|
||||
param([string]$Message)
|
||||
Write-Host " [*] $Message" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# WIZARD FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Show-WizardWelcome {
|
||||
Clear-Host
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " ROA2WEB - Auto-Deploy Setup Wizard" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " This wizard will configure automatic deployment monitoring." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " What it does:" -ForegroundColor White
|
||||
Write-Host " • Creates directory structure for auto-deployment" -ForegroundColor Gray
|
||||
Write-Host " • Copies Check-And-Deploy.ps1 to scripts folder" -ForegroundColor Gray
|
||||
Write-Host " • Creates Windows Scheduled Task for monitoring" -ForegroundColor Gray
|
||||
Write-Host " • Configures auto-deploy settings" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to continue or Ctrl+C to cancel..." -ForegroundColor Yellow
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
}
|
||||
|
||||
function Get-WizardInput {
|
||||
param(
|
||||
[string]$Prompt,
|
||||
[string]$Default,
|
||||
[switch]$IsNumber,
|
||||
[switch]$IsYesNo
|
||||
)
|
||||
|
||||
do {
|
||||
Write-Host "`n$Prompt" -ForegroundColor Yellow
|
||||
if ($Default) {
|
||||
Write-Host " Default: $Default" -ForegroundColor Gray
|
||||
}
|
||||
Write-Host " > " -NoNewline -ForegroundColor Cyan
|
||||
$input = Read-Host
|
||||
|
||||
# Use default if empty
|
||||
if ([string]::IsNullOrWhiteSpace($input) -and $Default) {
|
||||
return $Default
|
||||
}
|
||||
|
||||
# Validate number
|
||||
if ($IsNumber) {
|
||||
$num = 0
|
||||
if ([int]::TryParse($input, [ref]$num) -and $num -gt 0) {
|
||||
return $num
|
||||
} else {
|
||||
Write-Host " Invalid number. Please enter a positive integer." -ForegroundColor Red
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
# Validate Yes/No
|
||||
if ($IsYesNo) {
|
||||
$normalized = $input.ToUpper()
|
||||
if ($normalized -eq "Y" -or $normalized -eq "YES") {
|
||||
return $true
|
||||
} elseif ($normalized -eq "N" -or $normalized -eq "NO") {
|
||||
return $false
|
||||
} else {
|
||||
Write-Host " Invalid input. Please enter Y or N." -ForegroundColor Red
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return $input
|
||||
} while ($true)
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# SETUP FUNCTIONS
|
||||
# =============================================================================
|
||||
|
||||
function Test-Prerequisites {
|
||||
Write-Step "Checking prerequisites..."
|
||||
|
||||
# Check Administrator
|
||||
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
|
||||
$isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
|
||||
if (-not $isAdmin) {
|
||||
throw "This script requires Administrator privileges"
|
||||
}
|
||||
Write-Success "Running as Administrator"
|
||||
|
||||
# Check PowerShell version
|
||||
if ($PSVersionTable.PSVersion.Major -lt 5) {
|
||||
throw "PowerShell 5.1 or higher is required"
|
||||
}
|
||||
Write-Success "PowerShell version: $($PSVersionTable.PSVersion)"
|
||||
|
||||
# Check if Check-And-Deploy.ps1 exists
|
||||
$checkDeployScript = Join-Path $PSScriptRoot "Check-And-Deploy.ps1"
|
||||
if (-not (Test-Path $checkDeployScript)) {
|
||||
throw "Check-And-Deploy.ps1 not found in: $PSScriptRoot"
|
||||
}
|
||||
Write-Success "Check-And-Deploy.ps1 found"
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
function New-DirectoryStructure {
|
||||
param(
|
||||
[string]$MonitorPath,
|
||||
[string]$ScriptsPath
|
||||
)
|
||||
|
||||
Write-Step "Creating directory structure..."
|
||||
|
||||
# Create monitor path
|
||||
if (-not (Test-Path $MonitorPath)) {
|
||||
New-Item -ItemType Directory -Path $MonitorPath -Force | Out-Null
|
||||
Write-Success "Created: $MonitorPath"
|
||||
} else {
|
||||
Write-Success "Already exists: $MonitorPath"
|
||||
}
|
||||
|
||||
# Create scripts path
|
||||
if (-not (Test-Path $ScriptsPath)) {
|
||||
New-Item -ItemType Directory -Path $ScriptsPath -Force | Out-Null
|
||||
Write-Success "Created: $ScriptsPath"
|
||||
} else {
|
||||
Write-Success "Already exists: $ScriptsPath"
|
||||
}
|
||||
|
||||
# Create logs directory
|
||||
$logsPath = Join-Path $ScriptsPath "Logs"
|
||||
if (-not (Test-Path $logsPath)) {
|
||||
New-Item -ItemType Directory -Path $logsPath -Force | Out-Null
|
||||
Write-Success "Created: $logsPath"
|
||||
} else {
|
||||
Write-Success "Already exists: $logsPath"
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
function Copy-MonitorScript {
|
||||
param(
|
||||
[string]$SourcePath,
|
||||
[string]$DestPath
|
||||
)
|
||||
|
||||
Write-Step "Copying Check-And-Deploy.ps1 to scripts folder..."
|
||||
|
||||
$sourceScript = Join-Path $SourcePath "Check-And-Deploy.ps1"
|
||||
$destScript = Join-Path $DestPath "Check-And-Deploy.ps1"
|
||||
|
||||
# Check if source and destination are the same file
|
||||
$sourceFull = (Resolve-Path $sourceScript -ErrorAction SilentlyContinue).Path
|
||||
$destFull = (Resolve-Path $destScript -ErrorAction SilentlyContinue).Path
|
||||
|
||||
if ($sourceFull -and $destFull -and ($sourceFull -eq $destFull)) {
|
||||
Write-Success "Script already in target location: $destScript"
|
||||
return $destScript
|
||||
}
|
||||
|
||||
try {
|
||||
Copy-Item -Path $sourceScript -Destination $destScript -Force
|
||||
Write-Success "Script copied to: $destScript"
|
||||
return $destScript
|
||||
} catch {
|
||||
Write-Error "Failed to copy script: $_"
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function New-ScheduledTaskForAutoDeployNew {
|
||||
param(
|
||||
[string]$ScriptPath,
|
||||
[int]$IntervalMinutes,
|
||||
[string]$MonitorPath
|
||||
)
|
||||
|
||||
Write-Step "Creating Windows Scheduled Task..."
|
||||
|
||||
$taskName = "ROA2WEB-AutoDeploy"
|
||||
|
||||
# Remove existing task if present
|
||||
$existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
|
||||
if ($existingTask) {
|
||||
Write-Info "Removing existing task..."
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
|
||||
}
|
||||
|
||||
try {
|
||||
# Create action
|
||||
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" `
|
||||
-Argument "-NoProfile -ExecutionPolicy Bypass -File `"$ScriptPath`" -WatchPath `"$MonitorPath`""
|
||||
|
||||
# Create trigger (repeat indefinitely every X minutes)
|
||||
# Note: When RepetitionDuration is not specified, the task repeats indefinitely
|
||||
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) `
|
||||
-RepetitionInterval (New-TimeSpan -Minutes $IntervalMinutes)
|
||||
|
||||
# Create settings
|
||||
$settings = New-ScheduledTaskSettingsSet `
|
||||
-AllowStartIfOnBatteries `
|
||||
-DontStopIfGoingOnBatteries `
|
||||
-StartWhenAvailable `
|
||||
-RunOnlyIfNetworkAvailable:$false `
|
||||
-DontStopOnIdleEnd `
|
||||
-MultipleInstances IgnoreNew
|
||||
|
||||
# Register task (run as SYSTEM)
|
||||
Register-ScheduledTask -TaskName $taskName `
|
||||
-Action $action `
|
||||
-Trigger $trigger `
|
||||
-Settings $settings `
|
||||
-User "SYSTEM" `
|
||||
-RunLevel Highest `
|
||||
-Description "Monitors $MonitorPath for new deployment packages and auto-deploys them" | Out-Null
|
||||
|
||||
Write-Success "Scheduled task created: $taskName"
|
||||
Write-Success "Interval: Every $IntervalMinutes minutes"
|
||||
Write-Success "User: SYSTEM"
|
||||
Write-Success "Status: Enabled"
|
||||
|
||||
return $true
|
||||
} catch {
|
||||
Write-Error "Failed to create scheduled task: $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Show-SetupSummary {
|
||||
param(
|
||||
[hashtable]$Config
|
||||
)
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Setup Summary" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Monitor Path: $($Config.MonitorPath)" -ForegroundColor Gray
|
||||
Write-Host " Scripts Path: $($Config.ScriptsPath)" -ForegroundColor Gray
|
||||
Write-Host " Check Interval: $($Config.CheckIntervalMinutes) minutes" -ForegroundColor Gray
|
||||
Write-Host " Auto-Deploy: $($Config.AutoDeploy)" -ForegroundColor Gray
|
||||
Write-Host " Scheduled Task: $($Config.CreateScheduledTask)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Proceed with setup? [Y/N]: " -ForegroundColor Yellow -NoNewline
|
||||
$confirm = Read-Host
|
||||
|
||||
return ($confirm.ToUpper() -eq "Y" -or $confirm.ToUpper() -eq "YES")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MAIN SETUP FLOW
|
||||
# =============================================================================
|
||||
|
||||
function Invoke-Setup {
|
||||
param([hashtable]$Config)
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Starting Setup" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
try {
|
||||
# Test prerequisites
|
||||
Test-Prerequisites | Out-Null
|
||||
|
||||
# Create directory structure
|
||||
New-DirectoryStructure -MonitorPath $Config.MonitorPath -ScriptsPath $Config.ScriptsPath | Out-Null
|
||||
|
||||
# Copy monitor script
|
||||
$scriptPath = Copy-MonitorScript -SourcePath $PSScriptRoot -DestPath $Config.ScriptsPath
|
||||
|
||||
if (-not $scriptPath) {
|
||||
throw "Failed to copy monitor script"
|
||||
}
|
||||
|
||||
# Create scheduled task if requested
|
||||
if ($Config.CreateScheduledTask) {
|
||||
$taskSuccess = New-ScheduledTaskForAutoDeployNew `
|
||||
-ScriptPath $scriptPath `
|
||||
-IntervalMinutes $Config.CheckIntervalMinutes `
|
||||
-MonitorPath $Config.MonitorPath
|
||||
|
||||
if (-not $taskSuccess) {
|
||||
throw "Failed to create scheduled task"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Green
|
||||
Write-Host " SETUP COMPLETED SUCCESSFULLY" -ForegroundColor Green
|
||||
Write-Host ("=" * 70) -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host " Next Steps:" -ForegroundColor Yellow
|
||||
Write-Host " 1. Deploy packages will be placed in: $($Config.MonitorPath)" -ForegroundColor Gray
|
||||
Write-Host " 2. Server will check for updates every $($Config.CheckIntervalMinutes) minutes" -ForegroundColor Gray
|
||||
Write-Host " 3. New packages will be deployed automatically" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " Manual Testing:" -ForegroundColor Yellow
|
||||
Write-Host " - Test: cd $($Config.ScriptsPath) && .\\Check-And-Deploy.ps1 -Interactive" -ForegroundColor Gray
|
||||
Write-Host " - View Task: Get-ScheduledTask -TaskName 'ROA2WEB-AutoDeploy'" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Green
|
||||
|
||||
return $true
|
||||
} catch {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Red
|
||||
Write-Host " SETUP FAILED" -ForegroundColor Red
|
||||
Write-Host ("=" * 70) -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Error $_
|
||||
Write-Host ""
|
||||
Write-Host ("=" * 70) -ForegroundColor Red
|
||||
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MAIN EXECUTION FLOW
|
||||
# =============================================================================
|
||||
|
||||
function Main {
|
||||
# Non-interactive mode
|
||||
if ($NonInteractive) {
|
||||
$config = @{
|
||||
MonitorPath = $MonitorPath
|
||||
ScriptsPath = $ScriptsPath
|
||||
CheckIntervalMinutes = $CheckIntervalMinutes
|
||||
AutoDeploy = $AutoDeploy
|
||||
CreateScheduledTask = $CreateScheduledTask
|
||||
}
|
||||
|
||||
Invoke-Setup -Config $config | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
# Interactive mode - Wizard
|
||||
Show-WizardWelcome
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " Configuration Wizard" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
# Step 1: Monitor Path
|
||||
$monitorPath = Get-WizardInput -Prompt "[1/5] Deploy Folder Path`n Path to monitor for new deployment packages:" -Default $MonitorPath
|
||||
|
||||
# Step 2: Scripts Path
|
||||
$scriptsPath = Get-WizardInput -Prompt "[2/5] Scripts Folder Path`n Path to store monitoring scripts:" -Default $ScriptsPath
|
||||
|
||||
# Step 3: Check Interval
|
||||
$checkInterval = Get-WizardInput -Prompt "[3/5] Check Interval`n How often to check for updates (minutes):" -Default $CheckIntervalMinutes -IsNumber
|
||||
|
||||
# Step 4: Auto-Deploy
|
||||
Write-Host "`n[4/5] Auto-Deploy Enabled" -ForegroundColor Yellow
|
||||
Write-Host " Deploy automatically when new package found?" -ForegroundColor Yellow
|
||||
Write-Host " [Y] Yes (recommended) [N] No (manual trigger only)" -ForegroundColor Gray
|
||||
$autoDeploy = Get-WizardInput -Prompt " Your choice:" -Default "Y" -IsYesNo
|
||||
|
||||
# Step 5: Scheduled Task
|
||||
Write-Host "`n[5/5] Create Scheduled Task" -ForegroundColor Yellow
|
||||
Write-Host " Create Windows Scheduled Task for automatic monitoring?" -ForegroundColor Yellow
|
||||
Write-Host " [Y] Yes [N] No" -ForegroundColor Gray
|
||||
$createTask = Get-WizardInput -Prompt " Your choice:" -Default "Y" -IsYesNo
|
||||
|
||||
# Configuration object
|
||||
$config = @{
|
||||
MonitorPath = $monitorPath
|
||||
ScriptsPath = $scriptsPath
|
||||
CheckIntervalMinutes = [int]$checkInterval
|
||||
AutoDeploy = $autoDeploy
|
||||
CreateScheduledTask = $createTask
|
||||
}
|
||||
|
||||
# Show summary and confirm
|
||||
$confirmed = Show-SetupSummary -Config $config
|
||||
|
||||
if ($confirmed) {
|
||||
Invoke-Setup -Config $config
|
||||
} else {
|
||||
Write-Host "`nSetup cancelled by user" -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "`nPress any key to exit..." -ForegroundColor Gray
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
}
|
||||
|
||||
# Run main
|
||||
Main
|
||||
24
deployment/windows/scripts/deploy-config.json
Normal file
24
deployment/windows/scripts/deploy-config.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"server": {
|
||||
"host": "10.0.20.36",
|
||||
"sshPort": 22122,
|
||||
"sshUser": "Administrator",
|
||||
"sshKeyPath": "~\\.ssh\\id_ed25519",
|
||||
"windowsShare": "\\\\10.0.20.36\\Temp",
|
||||
"deployPath": "C:\\Temp"
|
||||
},
|
||||
"build": {
|
||||
"defaultComponent": "All",
|
||||
"outputPath": "../deploy-package"
|
||||
},
|
||||
"transfer": {
|
||||
"defaultMethod": "Auto",
|
||||
"scpRemotePath": "C:/Temp",
|
||||
"retryAttempts": 3,
|
||||
"timeout": 300
|
||||
},
|
||||
"deployment": {
|
||||
"autoDeployEnabled": true,
|
||||
"checkIntervalMinutes": 5
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user