Skip to content
Open
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
46 changes: 46 additions & 0 deletions container/.air.test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
args_bin = []
bin = "./tmp/catnip-test"
cmd = "go build -buildvcs=false -o ./tmp/catnip-test ./cmd/server"
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "docs", "bin", "dist", "internal/tui"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false

[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"

[log]
main_only = false
time = false

[misc]
clean_on_exit = false

[screen]
clear_on_rebuild = false
keep_scroll = true
3 changes: 2 additions & 1 deletion container/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ build-errors.log

# Test coverage
coverage.txt
*.test
*.test
!Dockerfile.test
52 changes: 52 additions & 0 deletions container/Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Test Dockerfile - builds on the main Dockerfile but adds mock scripts for testing
FROM catnip:latest

# Switch to root for setup
USER root

# Install additional test dependencies
RUN apt-get update && apt-get install -y \
socat \
expect \
&& rm -rf /var/lib/apt/lists/*

# Create test-specific directories
RUN mkdir -p /opt/catnip/test/mocks /opt/catnip/test/bin /opt/catnip/test/data

# Copy container source code for tests
COPY container/ /opt/catnip/test/src/

# Copy mock scripts and data (but not integration tests - we'll mount those)
COPY container/test/mocks/ /opt/catnip/test/mocks/
COPY container/test/data/ /opt/catnip/test/data/

# Make mock scripts executable and create symlinks in PATH
RUN chmod +x /opt/catnip/test/mocks/* && \
# Create a test-specific PATH that prioritizes our mocks
mkdir -p /opt/catnip/test/bin && \
ln -sf /opt/catnip/test/mocks/claude /opt/catnip/test/bin/claude && \
ln -sf /opt/catnip/test/mocks/gh /opt/catnip/test/bin/gh && \
ln -sf /opt/catnip/test/mocks/git /opt/catnip/test/bin/git

# Copy go.mod and go.sum, then install dependencies
COPY container/go.mod container/go.sum /opt/catnip/test/src/
RUN bash --login -c "cd /opt/catnip/test/src && go mod download"

# Set proper ownership for catnip user
RUN chown -R catnip:catnip /opt/catnip/test

# Set up test environment variables
ENV CATNIP_TEST_MODE=1
ENV PATH="/opt/catnip/test/bin:${PATH}"
ENV CATNIP_TEST_DATA_DIR="/opt/catnip/test/data"

# Create a test entrypoint that doesn't switch users
COPY container/test/test-entrypoint.sh /test-entrypoint.sh
RUN chmod +x /test-entrypoint.sh

# Set working directory for tests
WORKDIR /workspace

# Use test entrypoint instead of the main one
ENTRYPOINT ["/test-entrypoint.sh"]
CMD ["bash"]
26 changes: 3 additions & 23 deletions container/cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,29 +127,9 @@ func main() {
// Upload routes
v1.Post("/upload", uploadHandler.UploadFile)

// Git routes
v1.Post("/git/checkout/:org/:repo", gitHandler.CheckoutRepository)
v1.Get("/git/status", gitHandler.GetStatus)
v1.Get("/git/worktrees", gitHandler.ListWorktrees)
v1.Delete("/git/worktrees/:id", gitHandler.DeleteWorktree)
v1.Post("/git/worktrees/cleanup", gitHandler.CleanupMergedWorktrees)
v1.Post("/git/worktrees/:id/sync", gitHandler.SyncWorktree)
v1.Get("/git/worktrees/:id/sync/check", gitHandler.CheckSyncConflicts)
v1.Post("/git/worktrees/:id/merge", gitHandler.MergeWorktreeToMain)
v1.Get("/git/worktrees/:id/merge/check", gitHandler.CheckMergeConflicts)
v1.Get("/git/worktrees/:id/diff", gitHandler.GetWorktreeDiff)
v1.Post("/git/worktrees/:id/preview", gitHandler.CreateWorktreePreview)
v1.Post("/git/worktrees/:id/pr", gitHandler.CreatePullRequest)
v1.Put("/git/worktrees/:id/pr", gitHandler.UpdatePullRequest)
v1.Get("/git/worktrees/:id/pr", gitHandler.GetPullRequestInfo)
v1.Get("/git/github/repos", gitHandler.ListGitHubRepositories)
v1.Get("/git/branches/:repo_id", gitHandler.GetRepositoryBranches)

// Claude routes
v1.Get("/claude/session", claudeHandler.GetWorktreeSessionSummary)
v1.Get("/claude/session/:uuid", claudeHandler.GetSessionByUUID)
v1.Get("/claude/sessions", claudeHandler.GetAllWorktreeSessionSummaries)
v1.Post("/claude/messages", claudeHandler.CreateCompletion)
// Register handler routes
gitHandler.RegisterRoutes(v1)
claudeHandler.RegisterRoutes(v1)

// Session management routes
v1.Get("/sessions/active", sessionHandler.GetActiveSessions)
Expand Down
8 changes: 8 additions & 0 deletions container/internal/handlers/claude.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ func NewClaudeHandler(claudeService *services.ClaudeService) *ClaudeHandler {
}
}

// RegisterRoutes registers all claude-related routes
func (h *ClaudeHandler) RegisterRoutes(v1 fiber.Router) {
v1.Get("/claude/session", h.GetWorktreeSessionSummary)
v1.Get("/claude/session/:uuid", h.GetSessionByUUID)
v1.Get("/claude/sessions", h.GetAllWorktreeSessionSummaries)
v1.Post("/claude/messages", h.CreateCompletion)
}

// GetWorktreeSessionSummary returns Claude session information for a specific worktree
// @Summary Get worktree session summary
// @Description Returns Claude Code session metadata for a specific worktree
Expand Down
27 changes: 27 additions & 0 deletions container/internal/handlers/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,33 @@ func NewGitHandler(gitService *services.GitService, gitHTTPService *services.Git
}
}

// RegisterRoutes registers all git-related routes
func (h *GitHandler) RegisterRoutes(v1 fiber.Router) {
// Repository operations
v1.Post("/git/checkout/:org/:repo", h.CheckoutRepository)
v1.Get("/git/status", h.GetStatus)

// Worktree operations
v1.Get("/git/worktrees", h.ListWorktrees)
v1.Delete("/git/worktrees/:id", h.DeleteWorktree)
v1.Post("/git/worktrees/cleanup", h.CleanupMergedWorktrees)
v1.Post("/git/worktrees/:id/sync", h.SyncWorktree)
v1.Get("/git/worktrees/:id/sync/check", h.CheckSyncConflicts)
v1.Post("/git/worktrees/:id/merge", h.MergeWorktreeToMain)
v1.Get("/git/worktrees/:id/merge/check", h.CheckMergeConflicts)
v1.Get("/git/worktrees/:id/diff", h.GetWorktreeDiff)
v1.Post("/git/worktrees/:id/preview", h.CreateWorktreePreview)

// Pull request operations
v1.Post("/git/worktrees/:id/pr", h.CreatePullRequest)
v1.Put("/git/worktrees/:id/pr", h.UpdatePullRequest)
v1.Get("/git/worktrees/:id/pr", h.GetPullRequestInfo)

// GitHub operations
v1.Get("/git/github/repos", h.ListGitHubRepositories)
v1.Get("/git/branches/:repo_id", h.GetRepositoryBranches)
}

// CheckoutRepository handles repository checkout requests
// @Summary Checkout a GitHub repository
// @Description Clones a GitHub repository as a bare repo and creates initial worktree
Expand Down
5 changes: 5 additions & 0 deletions container/internal/handlers/pty.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ func NewPTYHandler(gitService *services.GitService) *PTYHandler {
}
}

// RegisterRoutes registers all PTY-related routes
func (h *PTYHandler) RegisterRoutes(v1 fiber.Router) {
v1.Get("/pty", h.HandleWebSocket)
}

// HandleWebSocket handles WebSocket connections for PTY
// @Summary Create PTY WebSocket connection
// @Description Establishes a WebSocket connection for terminal access
Expand Down
41 changes: 41 additions & 0 deletions container/test/Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Test Dockerfile based on Dockerfile.dev but configured for testing
FROM catnip:latest

# Pre-create live directory and project directory with correct ownership
RUN mkdir -p /live && chown -R catnip:catnip /live
RUN mkdir -p /live/catnip/node_modules && chown -R catnip:catnip /live/catnip

# Create Go cache directories with correct ownership
RUN mkdir -p /home/catnip/.cache/go-build && \
chown -R catnip:catnip /home/catnip/.cache

# Switch to catnip user for development
USER catnip
WORKDIR /workspace

# Install Air and swag for Go hot reloading with cache mount
RUN --mount=type=cache,target=/home/catnip/.cache/go-build,uid=1000,gid=1000 \
--mount=type=cache,target=/home/catnip/go/pkg/mod,uid=1000,gid=1000 \
bash -c 'source /etc/profile.d/catnip.sh && go install github.com/air-verse/air@latest && go install github.com/swaggo/swag/cmd/swag@latest'

# Copy test-specific scripts
COPY --chown=catnip:catnip container/test/scripts/test-entrypoint.sh ./test-entrypoint.sh
RUN chmod +x ./test-entrypoint.sh

# Copy mock scripts and test data
COPY --chown=catnip:catnip container/test/mocks /opt/catnip/test/bin
COPY --chown=catnip:catnip container/test/data /opt/catnip/test/data
RUN chmod +x /opt/catnip/test/bin/*

# Set test environment variables
ENV CATNIP_TEST_MODE=1
ENV CATNIP_PORT=8181
ENV CATNIP_TEST_DATA_DIR=/opt/catnip/test/data
ENV PATH=/opt/catnip/test/bin:$PATH

# Expose test port
EXPOSE 8181
USER root

# Use test entrypoint
ENTRYPOINT ["/entrypoint.sh", "./test-entrypoint.sh"]
Loading
Loading