feat: Respect BEADS_SYNC_BRANCH environment variable
Fixes daemon and bd sync to honor BEADS_SYNC_BRANCH environment variable as documented in PROTECTED_BRANCHES.md for CI/CD temporary overrides. Changes: - Updated internal/syncbranch.Get() to prioritize env var over DB config - Both daemon sync and bd sync CLI now use syncbranch.Get() - Added comprehensive tests for env var override behavior - Validates branch names using git-style rules This enables CI/CD workflows to override sync branch per-job without mutating database config. Based on PR #364 by Charles P. Cross <cpdata@users.noreply.github.com> Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/steveyegge/beads/internal/storage/sqlite"
|
||||
"github.com/steveyegge/beads/internal/syncbranch"
|
||||
"github.com/steveyegge/beads/internal/types"
|
||||
)
|
||||
|
||||
@@ -200,6 +201,99 @@ func TestSyncBranchCommitAndPush_Success(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSyncBranchCommitAndPush_EnvOverridesDB verifies that BEADS_SYNC_BRANCH
|
||||
// takes precedence over the sync.branch database config for daemon commits.
|
||||
func TestSyncBranchCommitAndPush_EnvOverridesDB(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
initTestGitRepo(t, tmpDir)
|
||||
|
||||
// Setup test store
|
||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||
if err := os.MkdirAll(beadsDir, 0755); err != nil {
|
||||
t.Fatalf("Failed to create .beads dir: %v", err)
|
||||
}
|
||||
|
||||
dbPath := filepath.Join(beadsDir, "test.db")
|
||||
store, err := sqlite.New(context.Background(), dbPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create store: %v", err)
|
||||
}
|
||||
defer store.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
if err := store.SetConfig(ctx, "issue_prefix", "test"); err != nil {
|
||||
t.Fatalf("Failed to set prefix: %v", err)
|
||||
}
|
||||
|
||||
// Configure DB sync.branch to one value
|
||||
if err := store.SetConfig(ctx, "sync.branch", "db-branch"); err != nil {
|
||||
t.Fatalf("Failed to set sync.branch: %v", err)
|
||||
}
|
||||
|
||||
// Set BEADS_SYNC_BRANCH to a different value and ensure it takes precedence.
|
||||
t.Setenv(syncbranch.EnvVar, "env-branch")
|
||||
|
||||
// Initial commit on main branch
|
||||
oldWd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get working directory: %v", err)
|
||||
}
|
||||
defer os.Chdir(oldWd)
|
||||
|
||||
if err := os.Chdir(tmpDir); err != nil {
|
||||
t.Fatalf("Failed to change directory: %v", err)
|
||||
}
|
||||
|
||||
initMainBranch(t, tmpDir)
|
||||
|
||||
// Create test issue and export JSONL
|
||||
issue := &types.Issue{
|
||||
Title: "Env override issue",
|
||||
Status: types.StatusOpen,
|
||||
Priority: 1,
|
||||
IssueType: types.TypeTask,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
if err := store.CreateIssue(ctx, issue, "test"); err != nil {
|
||||
t.Fatalf("Failed to create issue: %v", err)
|
||||
}
|
||||
|
||||
jsonlPath := filepath.Join(beadsDir, "issues.jsonl")
|
||||
if err := exportToJSONLWithStore(ctx, store, jsonlPath); err != nil {
|
||||
t.Fatalf("Failed to export: %v", err)
|
||||
}
|
||||
|
||||
log, _ := newTestSyncBranchLogger()
|
||||
committed, err := syncBranchCommitAndPush(ctx, store, false, log)
|
||||
if err != nil {
|
||||
t.Fatalf("syncBranchCommitAndPush failed: %v", err)
|
||||
}
|
||||
if !committed {
|
||||
t.Fatal("Expected committed=true with env override")
|
||||
}
|
||||
|
||||
// Verify that the worktree and branch are created using the env branch.
|
||||
worktreePath := filepath.Join(tmpDir, ".git", "beads-worktrees", "env-branch")
|
||||
if _, err := os.Stat(worktreePath); os.IsNotExist(err) {
|
||||
t.Fatalf("Env sync branch worktree not created at %s", worktreePath)
|
||||
}
|
||||
|
||||
cmd := exec.Command("git", "branch", "--list", "env-branch")
|
||||
cmd.Dir = tmpDir
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to list branches: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(output), "env-branch") {
|
||||
t.Errorf("Env sync branch not created, branches: %s", string(output))
|
||||
}
|
||||
}
|
||||
|
||||
// TestSyncBranchCommitAndPush_NoChanges tests behavior when no changes to commit
|
||||
func TestSyncBranchCommitAndPush_NoChanges(t *testing.T) {
|
||||
if testing.Short() {
|
||||
|
||||
Reference in New Issue
Block a user