diff --git a/dependency_updater/dependency_updater.go b/dependency_updater/dependency_updater.go index 56204d77a..d234d9fd0 100644 --- a/dependency_updater/dependency_updater.go +++ b/dependency_updater/dependency_updater.go @@ -407,5 +407,9 @@ func writeToGithubOutput(title string, description string, repoPath string) erro } func generateGithubRepoUrl(dependencies Dependencies, dependencyType string) string { - return "https://github.com/" + dependencies[dependencyType].Owner + "/" + dependencies[dependencyType].Repo + info := dependencies[dependencyType] + if info == nil { + return "" + } + return "https://github.com/" + info.Owner + "/" + info.Repo } diff --git a/dependency_updater/dependency_updater_test.go b/dependency_updater/dependency_updater_test.go new file mode 100644 index 000000000..e67941a09 --- /dev/null +++ b/dependency_updater/dependency_updater_test.go @@ -0,0 +1,389 @@ +package main + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestGenerateGithubRepoUrl(t *testing.T) { + deps := Dependencies{ + "op_node": {Owner: "ethereum-optimism", Repo: "optimism"}, + "base_reth": {Owner: "base", Repo: "base"}, + "nethermind": {Owner: "NethermindEth", Repo: "nethermind"}, + "op_geth": {Owner: "ethereum-optimism", Repo: "op-geth"}, + } + + tests := []struct { + name string + depType string + expected string + }{ + {"op_node", "op_node", "https://github.com/ethereum-optimism/optimism"}, + {"base_reth", "base_reth", "https://github.com/base/base"}, + {"nethermind", "nethermind", "https://github.com/NethermindEth/nethermind"}, + {"op_geth", "op_geth", "https://github.com/ethereum-optimism/op-geth"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := generateGithubRepoUrl(deps, tt.depType) + if got != tt.expected { + t.Errorf("generateGithubRepoUrl() = %q, want %q", got, tt.expected) + } + }) + } +} + +func TestGenerateGithubRepoUrl_UnknownDependency(t *testing.T) { + deps := Dependencies{ + "known": {Owner: "test", Repo: "repo"}, + } + + // Accessing an unknown key returns nil, which should return empty string + result := generateGithubRepoUrl(deps, "unknown") + expected := "" + if result != expected { + t.Errorf("generateGithubRepoUrl() for unknown key = %q, want %q", result, expected) + } +} + +func TestWriteToVersionsJson(t *testing.T) { + tmpDir := t.TempDir() + + deps := Dependencies{ + "test_dep": { + Tag: "v1.0.0", + Commit: "abc123def456", + Owner: "testowner", + Repo: "testrepo", + }, + } + + err := writeToVersionsJson(tmpDir, deps) + if err != nil { + t.Fatalf("writeToVersionsJson() returned error: %v", err) + } + + // Verify the file was created + data, err := os.ReadFile(filepath.Join(tmpDir, "versions.json")) + if err != nil { + t.Fatalf("failed to read versions.json: %v", err) + } + + content := string(data) + if !strings.Contains(content, `"tag": "v1.0.0"`) { + t.Errorf("versions.json missing tag: %s", content) + } + if !strings.Contains(content, `"commit": "abc123def456"`) { + t.Errorf("versions.json missing commit: %s", content) + } + if !strings.Contains(content, `"owner": "testowner"`) { + t.Errorf("versions.json missing owner: %s", content) + } +} + +func TestWriteToVersionsJson_InvalidPath(t *testing.T) { + deps := Dependencies{ + "test": {Tag: "v1.0.0", Commit: "abc", Owner: "o", Repo: "r"}, + } + + err := writeToVersionsJson("/nonexistent/path", deps) + if err == nil { + t.Error("writeToVersionsJson() expected error for invalid path, got nil") + } +} + +func TestCreateVersionsEnv_Basic(t *testing.T) { + tmpDir := t.TempDir() + + deps := Dependencies{ + "base_reth_node": { + Tag: "v0.8.0", + Commit: "3049ce2e3a5132f2ef74b4ba14a1a952ea6abdfb", + Owner: "base", + Repo: "base", + }, + "op_node": { + Tag: "op-node/v1.16.11", + Commit: "cba7aba0c98aae22720b21c3a023990a486cb6e0", + Owner: "ethereum-optimism", + Repo: "optimism", + }, + } + + err := createVersionsEnv(tmpDir, deps) + if err != nil { + t.Fatalf("createVersionsEnv() returned error: %v", err) + } + + data, err := os.ReadFile(filepath.Join(tmpDir, "versions.env")) + if err != nil { + t.Fatalf("failed to read versions.env: %v", err) + } + + content := string(data) + + // Verify all expected variables exist + checks := []string{ + "export BASE_RETH_NODE_TAG=v0.8.0", + "export BASE_RETH_NODE_COMMIT=3049ce2e3a5132f2ef74b4ba14a1a952ea6abdfb", + "export BASE_RETH_NODE_REPO=https://github.com/base/base.git", + "export OP_NODE_TAG=op-node/v1.16.11", + "export OP_NODE_COMMIT=cba7aba0c98aae22720b21c3a023990a486cb6e0", + "export OP_NODE_REPO=https://github.com/ethereum-optimism/optimism.git", + } + + for _, check := range checks { + if !strings.Contains(content, check) { + t.Errorf("versions.env missing expected line: %q", check) + } + } +} + +func TestCreateVersionsEnv_BranchTracking(t *testing.T) { + tmpDir := t.TempDir() + + deps := Dependencies{ + "tracking_branch": { + Tag: "", // Tag should be empty for branch tracking + Commit: "oldcommit123", + Owner: "test", + Repo: "test", + Branch: "main", + Tracking: "branch", + }, + } + + err := createVersionsEnv(tmpDir, deps) + if err != nil { + t.Fatalf("createVersionsEnv() returned error: %v", err) + } + + data, err := os.ReadFile(filepath.Join(tmpDir, "versions.env")) + if err != nil { + t.Fatalf("failed to read versions.env: %v", err) + } + + content := string(data) + + // For branch tracking, Tag should be replaced with Branch name + if !strings.Contains(content, "export TRACKING_BRANCH_TAG=main") { + t.Errorf("branch tracking: expected TAG=main, got: %s", content) + } + if !strings.Contains(content, "export TRACKING_BRANCH_COMMIT=oldcommit123") { + t.Errorf("branch tracking: expected COMMIT=oldcommit123, got: %s", content) + } +} + +func TestCreateVersionsEnv_SortedOutput(t *testing.T) { + tmpDir := t.TempDir() + + deps := Dependencies{ + "zeta": {Tag: "v1.0.0", Commit: "a", Owner: "o", Repo: "r"}, + "alpha": {Tag: "v1.0.0", Commit: "b", Owner: "o", Repo: "r"}, + "beta": {Tag: "v1.0.0", Commit: "c", Owner: "o", Repo: "r"}, + } + + err := createVersionsEnv(tmpDir, deps) + if err != nil { + t.Fatalf("createVersionsEnv() returned error: %v", err) + } + + data, err := os.ReadFile(filepath.Join(tmpDir, "versions.env")) + if err != nil { + t.Fatalf("failed to read versions.env: %v", err) + } + + lines := strings.Split(strings.TrimSpace(string(data)), "\n") + + // Verify alphabetical ordering: ALPHA, BETA, ZETA + if len(lines) < 3 { + t.Fatalf("expected at least 3 lines, got %d", len(lines)) + } + + // Check lines are sorted — first line should start with ALPHA, last with ZETA + if !strings.HasPrefix(lines[0], "export ALPHA_") { + t.Errorf("expected first line to start with ALPHA_, got: %s", lines[0]) + } + if !strings.HasPrefix(lines[len(lines)-1], "export ZETA_") { + t.Errorf("expected last line to start with ZETA_, got: %s", lines[len(lines)-1]) + } +} + +func TestCreateVersionsEnv_InvalidPath(t *testing.T) { + deps := Dependencies{ + "test": {Tag: "v1.0.0", Commit: "abc", Owner: "o", Repo: "r"}, + } + + err := createVersionsEnv("/nonexistent/path", deps) + if err == nil { + t.Error("createVersionsEnv() expected error for invalid path, got nil") + } +} + +func TestWriteToGithubOutput(t *testing.T) { + tmpDir := t.TempDir() + outputFile := filepath.Join(tmpDir, "github_output.txt") + + // Set GITHUB_OUTPUT env var for the test + t.Setenv("GITHUB_OUTPUT", outputFile) + + title := "chore: updated repo1, repo2" + description := "### Dependency Updates\n**repo1** - v1.0.0: [diff](url1)\n**repo2** - v2.0.0: [diff](url2)" + + err := writeToGithubOutput(title, description, tmpDir) + if err != nil { + t.Fatalf("writeToGithubOutput() returned error: %v", err) + } + + data, err := os.ReadFile(outputFile) + if err != nil { + t.Fatalf("failed to read GITHUB_OUTPUT: %v", err) + } + + content := string(data) + + if !strings.Contains(content, "TITLE=chore: updated repo1, repo2") { + t.Errorf("GITHUB_OUTPUT missing TITLE, got: %s", content) + } + if !strings.Contains(content, "DESC<