package steps import ( "strings" "testing" "tangled.org/core/api/tangled" "tangled.org/core/workflow" ) func TestBuildCloneCommands_PushTrigger(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 1, Submodules: false, Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPush), Push: &tangled.Pipeline_PushTriggerData{ NewSha: "abc123", OldSha: "def456", Ref: "refs/heads/main", }, Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, DevMode: false, WorkspaceDir: "/tangled/workspace", } cmds, err := BuildCloneCommands(cfg) if err != nil { t.Fatalf("BuildCloneCommands failed: %v", err) } if cmds.Skip { t.Error("Expected Skip to be false") } if cmds.CommitSHA != "abc123" { t.Errorf("Expected CommitSHA 'abc123', got '%s'", cmds.CommitSHA) } expectedURL := "https://example.com/did:plc:user123/my-repo" if cmds.RepoURL != expectedURL { t.Errorf("Expected RepoURL '%s', got '%s'", expectedURL, cmds.RepoURL) } if !strings.Contains(cmds.Init, "git init") { t.Error("Init command should contain 'git init'") } if !strings.Contains(cmds.Remote, "git remote add origin") { t.Error("Remote command should contain 'git remote add origin'") } if !strings.Contains(cmds.Fetch, "git fetch") { t.Error("Fetch command should contain 'git fetch'") } if !strings.Contains(cmds.Fetch, "abc123") { t.Error("Fetch command should contain commit SHA") } if cmds.Checkout != "git checkout FETCH_HEAD" { t.Errorf("Expected Checkout 'git checkout FETCH_HEAD', got '%s'", cmds.Checkout) } if len(cmds.All) != 5 { t.Errorf("Expected 5 commands, got %d", len(cmds.All)) } } func TestBuildCloneCommands_PullRequestTrigger(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 1, Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPullRequest), PullRequest: &tangled.Pipeline_PullRequestTriggerData{ SourceSha: "pr-sha-789", SourceBranch: "feature-branch", TargetBranch: "main", Action: "opened", }, Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, DevMode: false, WorkspaceDir: "/tangled/workspace", } cmds, err := BuildCloneCommands(cfg) if err != nil { t.Fatalf("BuildCloneCommands failed: %v", err) } if cmds.CommitSHA != "pr-sha-789" { t.Errorf("Expected CommitSHA 'pr-sha-789', got '%s'", cmds.CommitSHA) } if !strings.Contains(cmds.Fetch, "pr-sha-789") { t.Error("Fetch command should contain PR commit SHA") } } func TestBuildCloneCommands_ManualTrigger(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 1, Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindManual), Manual: &tangled.Pipeline_ManualTriggerData{ Inputs: nil, }, Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, DevMode: false, WorkspaceDir: "/tangled/workspace", } cmds, err := BuildCloneCommands(cfg) if err != nil { t.Fatalf("BuildCloneCommands failed: %v", err) } // Manual triggers don't have a SHA yet (TODO) if cmds.CommitSHA != "" { t.Errorf("Expected empty CommitSHA for manual trigger, got '%s'", cmds.CommitSHA) } } func TestBuildCloneCommands_SkipFlag(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Skip: true, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPush), Push: &tangled.Pipeline_PushTriggerData{ NewSha: "abc123", }, Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, } cmds, err := BuildCloneCommands(cfg) if err != nil { t.Fatalf("BuildCloneCommands failed: %v", err) } if !cmds.Skip { t.Error("Expected Skip to be true") } if len(cmds.All) != 0 { t.Errorf("Expected no commands when Skip is true, got %d commands", len(cmds.All)) } } func TestBuildCloneCommands_DevMode(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 1, Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPush), Push: &tangled.Pipeline_PushTriggerData{ NewSha: "abc123", }, Repo: &tangled.Pipeline_TriggerRepo{ Knot: "localhost:3000", Did: "did:plc:user123", Repo: "my-repo", }, }, DevMode: true, WorkspaceDir: "/tangled/workspace", } cmds, err := BuildCloneCommands(cfg) if err != nil { t.Fatalf("BuildCloneCommands failed: %v", err) } // In dev mode, should use http:// and replace localhost with host.docker.internal expectedURL := "http://host.docker.internal:3000/did:plc:user123/my-repo" if cmds.RepoURL != expectedURL { t.Errorf("Expected dev mode URL '%s', got '%s'", expectedURL, cmds.RepoURL) } } func TestBuildCloneCommands_DepthAndSubmodules(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 10, Submodules: true, Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPush), Push: &tangled.Pipeline_PushTriggerData{ NewSha: "abc123", }, Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, DevMode: false, WorkspaceDir: "/tangled/workspace", } cmds, err := BuildCloneCommands(cfg) if err != nil { t.Fatalf("BuildCloneCommands failed: %v", err) } if !strings.Contains(cmds.Fetch, "--depth=10") { t.Error("Fetch command should contain '--depth=10'") } if !strings.Contains(cmds.Fetch, "--recurse-submodules=yes") { t.Error("Fetch command should contain '--recurse-submodules=yes'") } } func TestBuildCloneCommands_DefaultDepth(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 0, // Default should be 1 Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPush), Push: &tangled.Pipeline_PushTriggerData{ NewSha: "abc123", }, Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, WorkspaceDir: "/tangled/workspace", } cmds, err := BuildCloneCommands(cfg) if err != nil { t.Fatalf("BuildCloneCommands failed: %v", err) } if !strings.Contains(cmds.Fetch, "--depth=1") { t.Error("Fetch command should default to '--depth=1'") } } func TestBuildCloneCommands_NilPushData(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 1, Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPush), Push: nil, // Nil push data should return error Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, WorkspaceDir: "/tangled/workspace", } _, err := BuildCloneCommands(cfg) if err == nil { t.Error("Expected error when push data is nil") } if !strings.Contains(err.Error(), "push trigger metadata is nil") { t.Errorf("Expected error about nil push metadata, got: %v", err) } } func TestBuildCloneCommands_NilPRData(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 1, Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPullRequest), PullRequest: nil, // Nil PR data should return error Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, WorkspaceDir: "/tangled/workspace", } _, err := BuildCloneCommands(cfg) if err == nil { t.Error("Expected error when pull request data is nil") } if !strings.Contains(err.Error(), "pull request trigger metadata is nil") { t.Errorf("Expected error about nil PR metadata, got: %v", err) } } func TestBuildCloneCommands_CustomWorkspace(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 1, Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPush), Push: &tangled.Pipeline_PushTriggerData{ NewSha: "abc123", }, Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, DevMode: false, WorkspaceDir: "/custom/path", } cmds, err := BuildCloneCommands(cfg) if err != nil { t.Fatalf("BuildCloneCommands failed: %v", err) } if !strings.Contains(cmds.Init, "/custom/path") { t.Error("Init command should use custom workspace directory") } if !strings.Contains(cmds.All[1], "/custom/path") { t.Error("cd command should use custom workspace directory") } } func TestBuildCloneCommands_DefaultWorkspace(t *testing.T) { cfg := CloneConfig{ Workflow: tangled.Pipeline_Workflow{ Clone: &tangled.Pipeline_CloneOpts{ Depth: 1, Skip: false, }, }, TriggerMetadata: tangled.Pipeline_TriggerMetadata{ Kind: string(workflow.TriggerKindPush), Push: &tangled.Pipeline_PushTriggerData{ NewSha: "abc123", }, Repo: &tangled.Pipeline_TriggerRepo{ Knot: "example.com", Did: "did:plc:user123", Repo: "my-repo", }, }, DevMode: false, WorkspaceDir: "", // Empty should default to /tangled/workspace } cmds, err := BuildCloneCommands(cfg) if err != nil { t.Fatalf("BuildCloneCommands failed: %v", err) } if !strings.Contains(cmds.Init, "/tangled/workspace") { t.Error("Init command should default to /tangled/workspace") } }