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
### 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
### 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
VERSION := 0.67.6
VERSION := 0.67.7
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
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(" --bootstrap-join ADDR - Bootstrap raft join address (for secondary bootstrap)\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(" Options:\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(" logs <service> - View production service logs\n")
fmt.Printf(" Options:\n")
fmt.Printf(" --follow - Follow logs in real-time\n")
fmt.Printf(" uninstall - Remove production services (requires root/sudo)\n\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(" # Bootstrap node (nightly branch)\n")
fmt.Printf(" sudo dbn prod install --bootstrap --branch nightly\n\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(" # 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(" # 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 logs node --follow\n")
}
@ -76,7 +84,7 @@ func handleProdInstall(args []string) {
// Parse arguments
force := false
isBootstrap := false
var vpsIP, domain, peersStr, bootstrapJoin string
var vpsIP, domain, peersStr, bootstrapJoin, branch string
for i, arg := range args {
switch arg {
@ -100,9 +108,24 @@ func handleProdInstall(args []string) {
if i+1 < len(args) {
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
var bootstrapPeers []string
if peersStr != "" {
@ -123,7 +146,13 @@ func handleProdInstall(args []string) {
}
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
fmt.Printf("\n📋 Phase 1: Checking prerequisites...\n")
@ -191,13 +220,25 @@ func handleProdUpgrade(args []string) {
// Parse arguments
force := false
restartServices := false
for _, arg := range args {
branch := ""
for i, arg := range args {
if arg == "--force" {
force = true
}
if arg == "--restart" {
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 {
@ -206,11 +247,25 @@ func handleProdUpgrade(args []string) {
}
debrosHome := "/home/debros"
debrosDir := debrosHome + "/.debros"
fmt.Printf("🔄 Upgrading production installation...\n")
fmt.Printf(" This will preserve existing configurations and data\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
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
}
// 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
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"
arch, _ := (&ArchitectureDetector{}).Detect()
// If branch is empty, try to read from stored preference, otherwise default to main
if branch == "" {
branch = ReadBranchPreference(debrosDir)
}
return &ProductionSetup{
debrosHome: debrosHome,
debrosDir: debrosDir,
logWriter: logWriter,
forceReconfigure: forceReconfigure,
arch: arch,
branch: "main",
branch: branch,
privChecker: &PrivilegeChecker{},
osDetector: &OSDetector{},
archDetector: &ArchitectureDetector{},

View File

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