Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ A tiny Go program that shows git diffs in the current directory and all git repo
# Build
go build -o diff-server .

# Run (default port 8080, current directory)
# Run (default port 3844, current directory)
./diff-server

# Run on custom port
./diff-server -port 9000
./diff-server -p 9000

# Scan a different directory
./diff-server -C /path/to/workspace
```

Then open http://localhost:8080 (or your custom port) in a browser to view the diffs.
Then open http://localhost:3844 (or your custom port) in a browser to view the diffs.
10 changes: 5 additions & 5 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,21 @@ func serveDiffsHTML(w http.ResponseWriter, _ *http.Request) {

func findGitRepos(root string) ([]string, error) {
var repos []string

err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return nil
}

if info.IsDir() && info.Name() == ".git" {
repoPath := filepath.Dir(path)
repos = append(repos, repoPath)
return filepath.SkipDir
}

return nil
})

return repos, err
}

Expand All @@ -75,7 +75,7 @@ func serveDiffsText(w http.ResponseWriter, r *http.Request) {
if relPath == "." {
relPath = ""
}

repoName := relPath
if repoName == "" {
repoName = filepath.Base(repoPath)
Expand Down
94 changes: 47 additions & 47 deletions handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ import (

func setupTestGitRepo(t *testing.T, dir string) {
t.Helper()

cmd := exec.Command("git", "init")
cmd.Dir = dir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to init git repo: %v", err)
}

cmd = exec.Command("git", "config", "user.email", "test@example.com")
cmd.Dir = dir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to set git email: %v", err)
}

cmd = exec.Command("git", "config", "user.name", "Test User")
cmd.Dir = dir
if err := cmd.Run(); err != nil {
Expand All @@ -35,20 +35,20 @@ func setupTestGitRepo(t *testing.T, dir string) {
func TestServeDiffsHTML(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("Accept", "text/html")

w := httptest.NewRecorder()
diffsHandler(w, req)

resp := w.Result()
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200, got %d", resp.StatusCode)
}

contentType := resp.Header.Get("Content-Type")
if !strings.Contains(contentType, "text/html") {
t.Errorf("expected content-type text/html, got %s", contentType)
}

body := w.Body.String()
if !strings.Contains(body, "<!DOCTYPE html>") {
t.Errorf("expected HTML document")
Expand All @@ -57,53 +57,53 @@ func TestServeDiffsHTML(t *testing.T) {

func TestServeDiffsText_PWDIsGitRepo(t *testing.T) {
tmpDir := t.TempDir()

setupTestGitRepo(t, tmpDir)

testFile := filepath.Join(tmpDir, "test.txt")
if err := os.WriteFile(testFile, []byte("initial content\n"), 0644); err != nil {
t.Fatalf("failed to write test file: %v", err)
}

cmd := exec.Command("git", "add", "test.txt")
cmd.Dir = tmpDir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to git add: %v", err)
}

cmd = exec.Command("git", "commit", "-m", "initial commit")
cmd.Dir = tmpDir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to commit: %v", err)
}

if err := os.WriteFile(testFile, []byte("modified content\n"), 0644); err != nil {
t.Fatalf("failed to modify test file: %v", err)
}

oldDir, _ := os.Getwd()
defer os.Chdir(oldDir)

if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("failed to chdir: %v", err)
}

req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("Accept", "text/x-diff")

w := httptest.NewRecorder()
diffsHandler(w, req)

resp := w.Result()
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200, got %d", resp.StatusCode)
}

contentType := resp.Header.Get("Content-Type")
if !strings.Contains(contentType, "text/x-diff") {
t.Errorf("expected content-type text/x-diff, got %s", contentType)
}

body := w.Body.String()
if !strings.Contains(body, "diff --git") {
t.Errorf("expected diff output, got: %s", body)
Expand All @@ -115,53 +115,53 @@ func TestServeDiffsText_PWDIsGitRepo(t *testing.T) {

func TestServeDiffsText_GitSubdirectory(t *testing.T) {
tmpDir := t.TempDir()

subDir := filepath.Join(tmpDir, "subproject")
if err := os.MkdirAll(subDir, 0755); err != nil {
t.Fatalf("failed to create subdir: %v", err)
}

setupTestGitRepo(t, subDir)

testFile := filepath.Join(subDir, "sub.txt")
if err := os.WriteFile(testFile, []byte("sub content\n"), 0644); err != nil {
t.Fatalf("failed to write test file: %v", err)
}

cmd := exec.Command("git", "add", "sub.txt")
cmd.Dir = subDir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to git add: %v", err)
}

cmd = exec.Command("git", "commit", "-m", "sub commit")
cmd.Dir = subDir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to commit: %v", err)
}

if err := os.WriteFile(testFile, []byte("modified sub\n"), 0644); err != nil {
t.Fatalf("failed to modify test file: %v", err)
}

oldDir, _ := os.Getwd()
defer os.Chdir(oldDir)

if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("failed to chdir: %v", err)
}

req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("Accept", "text/x-diff")

w := httptest.NewRecorder()
diffsHandler(w, req)

resp := w.Result()
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200, got %d", resp.StatusCode)
}

body := w.Body.String()
if !strings.Contains(body, "diff --git") {
t.Errorf("expected diff output, got: %s", body)
Expand All @@ -176,78 +176,78 @@ func TestServeDiffsText_GitSubdirectory(t *testing.T) {

func TestServeDiffsText_LargeDiffTruncation(t *testing.T) {
tmpDir := t.TempDir()

setupTestGitRepo(t, tmpDir)

testFile := filepath.Join(tmpDir, "large.txt")
largeContent := strings.Repeat("x", 1024*1024)
if err := os.WriteFile(testFile, []byte(largeContent), 0644); err != nil {
t.Fatalf("failed to write test file: %v", err)
}

cmd := exec.Command("git", "add", "large.txt")
cmd.Dir = tmpDir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to git add: %v", err)
}

cmd = exec.Command("git", "commit", "-m", "large commit")
cmd.Dir = tmpDir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to commit: %v", err)
}

modifiedContent := strings.Repeat("y", 1024*1024)
if err := os.WriteFile(testFile, []byte(modifiedContent), 0644); err != nil {
t.Fatalf("failed to modify test file: %v", err)
}

anotherFile := filepath.Join(tmpDir, "another.txt")
moreContent := strings.Repeat("z", 5*1024*1024)
if err := os.WriteFile(anotherFile, []byte(moreContent), 0644); err != nil {
t.Fatalf("failed to write another file: %v", err)
}

cmd = exec.Command("git", "add", "another.txt")
cmd.Dir = tmpDir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to git add: %v", err)
}

cmd = exec.Command("git", "commit", "-m", "another commit")
cmd.Dir = tmpDir
if err := cmd.Run(); err != nil {
t.Fatalf("failed to commit: %v", err)
}

yetAnotherContent := strings.Repeat("w", 5*1024*1024)
if err := os.WriteFile(anotherFile, []byte(yetAnotherContent), 0644); err != nil {
t.Fatalf("failed to modify another file: %v", err)
}

oldDir, _ := os.Getwd()
defer os.Chdir(oldDir)

if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("failed to chdir: %v", err)
}

req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("Accept", "text/x-diff")

w := httptest.NewRecorder()
diffsHandler(w, req)

resp := w.Result()
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200, got %d", resp.StatusCode)
}

body := w.Body.String()
if len(body) > 5*1024*1024 {
t.Errorf("expected diff to be truncated to 5MB, got %d bytes", len(body))
}

if len(body) == 0 {
t.Error("expected some diff output")
}
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

func main() {
port := flag.String("port", "8080", "Port to listen on")
port := flag.String("p", "3844", "Port to listen on")
workspaceDir := flag.String("C", ".", "Directory to scan for git repositories")
flag.Parse()

Expand Down
Loading