feat: add branch management for production commands

- Introduced `--branch` flag for specifying Git branches (main or nightly) during installation and upgrade processes.
- Implemented validation for branch input and defaulted to 'main' if not specified.
- Enhanced help output to include examples for using the new branch feature.
- Added functionality to save and read branch preferences for future upgrades, improving user experience and flexibility.
This commit is contained in:
anonpenguin23 2025-11-11 08:45:20 +02:00
parent 19bfaff943
commit 52b3a99bb9
No known key found for this signature in database
GPG Key ID: 1CBB1FE35AFBEE30
5 changed files with 114 additions and 9 deletions

View File

@ -13,6 +13,21 @@ The format is based on [Keep a Changelog][keepachangelog] and adheres to [Semant
### Deprecated ### Deprecated
### Fixed ### Fixed
## [0.67.7] - 2025-11-11
### Added
- Added support for specifying the Git branch (main or nightly) during `prod install` and `prod upgrade`.
- The chosen branch is now saved and automatically used for future upgrades unless explicitly overridden.
### Changed
- Updated help messages and examples for production commands to include branch options.
### Deprecated
### Removed
### Fixed
\n
## [0.67.6] - 2025-11-11 ## [0.67.6] - 2025-11-11
### Added ### Added

View File

@ -19,7 +19,7 @@ test-e2e:
.PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports install-hooks kill .PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports install-hooks kill
VERSION := 0.67.6 VERSION := 0.67.7
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ) DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)' LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)'

View File

@ -53,21 +53,29 @@ func showProdHelp() {
fmt.Printf(" --peers ADDRS - Comma-separated bootstrap peers (for non-bootstrap)\n") fmt.Printf(" --peers ADDRS - Comma-separated bootstrap peers (for non-bootstrap)\n")
fmt.Printf(" --bootstrap-join ADDR - Bootstrap raft join address (for secondary bootstrap)\n") fmt.Printf(" --bootstrap-join ADDR - Bootstrap raft join address (for secondary bootstrap)\n")
fmt.Printf(" --domain DOMAIN - Domain for HTTPS (optional)\n") fmt.Printf(" --domain DOMAIN - Domain for HTTPS (optional)\n")
fmt.Printf(" --branch BRANCH - Git branch to use (main or nightly, default: main)\n")
fmt.Printf(" upgrade - Upgrade existing installation (requires root/sudo)\n") fmt.Printf(" upgrade - Upgrade existing installation (requires root/sudo)\n")
fmt.Printf(" Options:\n") fmt.Printf(" Options:\n")
fmt.Printf(" --restart - Automatically restart services after upgrade\n") fmt.Printf(" --restart - Automatically restart services after upgrade\n")
fmt.Printf(" --branch BRANCH - Git branch to use (main or nightly, uses saved preference if not specified)\n")
fmt.Printf(" status - Show status of production services\n") fmt.Printf(" status - Show status of production services\n")
fmt.Printf(" logs <service> - View production service logs\n") fmt.Printf(" logs <service> - View production service logs\n")
fmt.Printf(" Options:\n") fmt.Printf(" Options:\n")
fmt.Printf(" --follow - Follow logs in real-time\n") fmt.Printf(" --follow - Follow logs in real-time\n")
fmt.Printf(" uninstall - Remove production services (requires root/sudo)\n\n") fmt.Printf(" uninstall - Remove production services (requires root/sudo)\n\n")
fmt.Printf("Examples:\n") fmt.Printf("Examples:\n")
fmt.Printf(" # Bootstrap node\n") fmt.Printf(" # Bootstrap node (main branch)\n")
fmt.Printf(" sudo dbn prod install --bootstrap\n\n") fmt.Printf(" sudo dbn prod install --bootstrap\n\n")
fmt.Printf(" # Bootstrap node (nightly branch)\n")
fmt.Printf(" sudo dbn prod install --bootstrap --branch nightly\n\n")
fmt.Printf(" # Join existing cluster\n") fmt.Printf(" # Join existing cluster\n")
fmt.Printf(" sudo dbn prod install --vps-ip 10.0.0.2 --peers /ip4/10.0.0.1/tcp/4001/p2p/Qm...\n\n") fmt.Printf(" sudo dbn prod install --vps-ip 10.0.0.2 --peers /ip4/10.0.0.1/tcp/4001/p2p/Qm...\n\n")
fmt.Printf(" # Secondary bootstrap joining existing cluster\n") fmt.Printf(" # Secondary bootstrap joining existing cluster\n")
fmt.Printf(" sudo dbn prod install --bootstrap --vps-ip 10.0.0.2 --bootstrap-join 10.0.0.1:7001\n\n") fmt.Printf(" sudo dbn prod install --bootstrap --vps-ip 10.0.0.2 --bootstrap-join 10.0.0.1:7001\n\n")
fmt.Printf(" # Upgrade using saved branch preference\n")
fmt.Printf(" sudo dbn prod upgrade --restart\n\n")
fmt.Printf(" # Upgrade and switch to nightly branch\n")
fmt.Printf(" sudo dbn prod upgrade --restart --branch nightly\n\n")
fmt.Printf(" dbn prod status\n") fmt.Printf(" dbn prod status\n")
fmt.Printf(" dbn prod logs node --follow\n") fmt.Printf(" dbn prod logs node --follow\n")
} }
@ -76,7 +84,7 @@ func handleProdInstall(args []string) {
// Parse arguments // Parse arguments
force := false force := false
isBootstrap := false isBootstrap := false
var vpsIP, domain, peersStr, bootstrapJoin string var vpsIP, domain, peersStr, bootstrapJoin, branch string
for i, arg := range args { for i, arg := range args {
switch arg { switch arg {
@ -100,9 +108,24 @@ func handleProdInstall(args []string) {
if i+1 < len(args) { if i+1 < len(args) {
bootstrapJoin = args[i+1] bootstrapJoin = args[i+1]
} }
case "--branch":
if i+1 < len(args) {
branch = args[i+1]
}
} }
} }
// Validate branch if provided
if branch != "" && branch != "main" && branch != "nightly" {
fmt.Fprintf(os.Stderr, "❌ Invalid branch: %s (must be 'main' or 'nightly')\n", branch)
os.Exit(1)
}
// Default to main if not specified
if branch == "" {
branch = "main"
}
// Parse bootstrap peers if provided // Parse bootstrap peers if provided
var bootstrapPeers []string var bootstrapPeers []string
if peersStr != "" { if peersStr != "" {
@ -123,7 +146,13 @@ func handleProdInstall(args []string) {
} }
debrosHome := "/home/debros" debrosHome := "/home/debros"
setup := production.NewProductionSetup(debrosHome, os.Stdout, force) debrosDir := debrosHome + "/.debros"
setup := production.NewProductionSetup(debrosHome, os.Stdout, force, branch)
// Save branch preference for future upgrades
if err := production.SaveBranchPreference(debrosDir, branch); err != nil {
fmt.Fprintf(os.Stderr, "⚠️ Warning: Failed to save branch preference: %v\n", err)
}
// Phase 1: Check prerequisites // Phase 1: Check prerequisites
fmt.Printf("\n📋 Phase 1: Checking prerequisites...\n") fmt.Printf("\n📋 Phase 1: Checking prerequisites...\n")
@ -191,13 +220,25 @@ func handleProdUpgrade(args []string) {
// Parse arguments // Parse arguments
force := false force := false
restartServices := false restartServices := false
for _, arg := range args { branch := ""
for i, arg := range args {
if arg == "--force" { if arg == "--force" {
force = true force = true
} }
if arg == "--restart" { if arg == "--restart" {
restartServices = true restartServices = true
} }
if arg == "--branch" {
if i+1 < len(args) {
branch = args[i+1]
}
}
}
// Validate branch if provided
if branch != "" && branch != "main" && branch != "nightly" {
fmt.Fprintf(os.Stderr, "❌ Invalid branch: %s (must be 'main' or 'nightly')\n", branch)
os.Exit(1)
} }
if os.Geteuid() != 0 { if os.Geteuid() != 0 {
@ -206,11 +247,25 @@ func handleProdUpgrade(args []string) {
} }
debrosHome := "/home/debros" debrosHome := "/home/debros"
debrosDir := debrosHome + "/.debros"
fmt.Printf("🔄 Upgrading production installation...\n") fmt.Printf("🔄 Upgrading production installation...\n")
fmt.Printf(" This will preserve existing configurations and data\n") fmt.Printf(" This will preserve existing configurations and data\n")
fmt.Printf(" Configurations will be updated to latest format\n\n") fmt.Printf(" Configurations will be updated to latest format\n\n")
setup := production.NewProductionSetup(debrosHome, os.Stdout, force) setup := production.NewProductionSetup(debrosHome, os.Stdout, force, branch)
// If branch was explicitly provided, save it for future upgrades
if branch != "" {
if err := production.SaveBranchPreference(debrosDir, branch); err != nil {
fmt.Fprintf(os.Stderr, "⚠️ Warning: Failed to save branch preference: %v\n", err)
} else {
fmt.Printf(" Using branch: %s (saved for future upgrades)\n", branch)
}
} else {
// Show which branch is being used (read from saved preference)
currentBranch := production.ReadBranchPreference(debrosDir)
fmt.Printf(" Using branch: %s (from saved preference)\n", currentBranch)
}
// Phase 1: Check prerequisites // Phase 1: Check prerequisites
fmt.Printf("\n📋 Phase 1: Checking prerequisites...\n") fmt.Printf("\n📋 Phase 1: Checking prerequisites...\n")

View File

@ -34,18 +34,50 @@ type ProductionSetup struct {
NodePeerID string // Captured during Phase3 for later display NodePeerID string // Captured during Phase3 for later display
} }
// ReadBranchPreference reads the stored branch preference from disk
func ReadBranchPreference(debrosDir string) string {
branchFile := filepath.Join(debrosDir, ".branch")
data, err := os.ReadFile(branchFile)
if err != nil {
return "main" // Default to main if file doesn't exist
}
branch := strings.TrimSpace(string(data))
if branch == "" {
return "main"
}
return branch
}
// SaveBranchPreference saves the branch preference to disk
func SaveBranchPreference(debrosDir, branch string) error {
branchFile := filepath.Join(debrosDir, ".branch")
if err := os.MkdirAll(debrosDir, 0755); err != nil {
return fmt.Errorf("failed to create debros directory: %w", err)
}
if err := os.WriteFile(branchFile, []byte(branch), 0644); err != nil {
return fmt.Errorf("failed to save branch preference: %w", err)
}
exec.Command("chown", "debros:debros", branchFile).Run()
return nil
}
// NewProductionSetup creates a new production setup orchestrator // NewProductionSetup creates a new production setup orchestrator
func NewProductionSetup(debrosHome string, logWriter io.Writer, forceReconfigure bool) *ProductionSetup { func NewProductionSetup(debrosHome string, logWriter io.Writer, forceReconfigure bool, branch string) *ProductionSetup {
debrosDir := debrosHome + "/.debros" debrosDir := debrosHome + "/.debros"
arch, _ := (&ArchitectureDetector{}).Detect() arch, _ := (&ArchitectureDetector{}).Detect()
// If branch is empty, try to read from stored preference, otherwise default to main
if branch == "" {
branch = ReadBranchPreference(debrosDir)
}
return &ProductionSetup{ return &ProductionSetup{
debrosHome: debrosHome, debrosHome: debrosHome,
debrosDir: debrosDir, debrosDir: debrosDir,
logWriter: logWriter, logWriter: logWriter,
forceReconfigure: forceReconfigure, forceReconfigure: forceReconfigure,
arch: arch, arch: arch,
branch: "main", branch: branch,
privChecker: &PrivilegeChecker{}, privChecker: &PrivilegeChecker{},
osDetector: &OSDetector{}, osDetector: &OSDetector{},
archDetector: &ArchitectureDetector{}, archDetector: &ArchitectureDetector{},

View File

@ -193,9 +193,12 @@ echo -e "${GREEN}Installation complete!${NOCOLOR}"
echo "" echo ""
echo -e "${CYAN}Next, run the production setup:${NOCOLOR}" echo -e "${CYAN}Next, run the production setup:${NOCOLOR}"
echo "" echo ""
echo "Bootstrap node (first node):" echo "Bootstrap node (first node, main branch):"
echo -e " ${BLUE}sudo dbn prod install --bootstrap${NOCOLOR}" echo -e " ${BLUE}sudo dbn prod install --bootstrap${NOCOLOR}"
echo "" echo ""
echo "Bootstrap node (nightly branch):"
echo -e " ${BLUE}sudo dbn prod install --bootstrap --branch nightly${NOCOLOR}"
echo ""
echo "Secondary node (join existing cluster):" echo "Secondary node (join existing cluster):"
echo -e " ${BLUE}sudo dbn prod install --vps-ip <bootstrap_ip> --peers <multiaddr>${NOCOLOR}" echo -e " ${BLUE}sudo dbn prod install --vps-ip <bootstrap_ip> --peers <multiaddr>${NOCOLOR}"
echo "" echo ""