summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/api/server_test.go19
-rw-r--r--internal/storage/db.go19
-rw-r--r--internal/task/validator.go3
-rw-r--r--internal/task/validator_test.go1
4 files changed, 32 insertions, 10 deletions
diff --git a/internal/api/server_test.go b/internal/api/server_test.go
index 4b45f25..67a2fc4 100644
--- a/internal/api/server_test.go
+++ b/internal/api/server_test.go
@@ -217,6 +217,7 @@ func TestGeminiLogs_ParsedCorrectly(t *testing.T) {
tk := createTestTask(t, srv, `{
"name": "Gemini Log Test Task",
"description": "Test Gemini log parsing",
+ "repository_url": "https://github.com/user/repo",
"agent": {
"type": "gemini",
"instructions": "generate some output",
@@ -363,6 +364,7 @@ func TestCreateTask_Success(t *testing.T) {
payload := `{
"name": "API Task",
"description": "Created via API",
+ "repository_url": "https://github.com/user/repo",
"agent": {
"type": "claude",
"instructions": "do the thing",
@@ -422,6 +424,7 @@ func TestProject_RoundTrip(t *testing.T) {
payload := `{
"name": "Project Task",
"project": "test-project",
+ "repository_url": "https://github.com/user/repo",
"agent": {
"type": "claude",
"instructions": "do the thing",
@@ -496,6 +499,7 @@ func TestListTasks_WithTasks(t *testing.T) {
for i := 0; i < 3; i++ {
tk := &task.Task{
ID: fmt.Sprintf("lt-%d", i), Name: fmt.Sprintf("T%d", i),
+ RepositoryURL: "https://github.com/user/repo",
Agent: task.AgentConfig{Type: "claude", Instructions: "x"}, Priority: task.PriorityNormal,
Retry: task.RetryConfig{MaxAttempts: 1, Backoff: "linear"},
Tags: []string{}, DependsOn: []string{}, State: task.StatePending,
@@ -533,6 +537,7 @@ func createTaskWithState(t *testing.T, store *storage.DB, id string, state task.
tk := &task.Task{
ID: id,
Name: "test-task-" + id,
+ RepositoryURL: "https://github.com/user/repo",
Agent: task.AgentConfig{Type: "claude", Instructions: "do something"},
Priority: task.PriorityNormal,
Retry: task.RetryConfig{MaxAttempts: 1, Backoff: "linear"},
@@ -911,6 +916,7 @@ func TestRunTask_ManualRunIgnoresRetryLimit(t *testing.T) {
tk := &task.Task{
ID: "retry-limit-manual",
Name: "Retry Limit Task",
+ RepositoryURL: "https://github.com/user/repo",
Agent: task.AgentConfig{Instructions: "do something"},
Priority: task.PriorityNormal,
Retry: task.RetryConfig{MaxAttempts: 1, Backoff: "linear"},
@@ -948,6 +954,7 @@ func TestRunTask_WithinRetryLimit_Returns202(t *testing.T) {
tk := &task.Task{
ID: "retry-within-1",
Name: "Retry Within Task",
+ RepositoryURL: "https://github.com/user/repo",
Agent: task.AgentConfig{Instructions: "do something"},
Priority: task.PriorityNormal,
Retry: task.RetryConfig{MaxAttempts: 3, Backoff: "linear"},
@@ -995,7 +1002,7 @@ func TestDeleteTask_Success(t *testing.T) {
srv, store := testServer(t)
// Create a task to delete.
- created := createTestTask(t, srv, `{"name":"Delete Me","agent":{"type":"claude","instructions":"x","model":"sonnet"}}`)
+ created := createTestTask(t, srv, `{"name":"Delete Me","repository_url":"https://github.com/user/repo","agent":{"type":"claude","instructions":"x","model":"sonnet"}}`)
req := httptest.NewRequest("DELETE", "/api/tasks/"+created.ID, nil)
w := httptest.NewRecorder()
@@ -1030,6 +1037,7 @@ func TestDeleteTask_RunningTaskRejected(t *testing.T) {
tk := &task.Task{
ID: "running-task-del",
Name: "Running Task",
+ RepositoryURL: "https://github.com/user/repo",
Agent: task.AgentConfig{Instructions: "x", Model: "sonnet"},
Priority: task.PriorityNormal,
Tags: []string{},
@@ -1584,6 +1592,7 @@ func TestRunTask_AgentTimesOut_TaskSetToTimedOut(t *testing.T) {
tk := &task.Task{
ID: "async-timeout-1",
Name: "timeout-test",
+ RepositoryURL: "https://github.com/user/repo",
Agent: task.AgentConfig{Type: "claude", Instructions: "do something"},
Priority: task.PriorityNormal,
Retry: task.RetryConfig{MaxAttempts: 1, Backoff: "linear"},
@@ -2016,7 +2025,13 @@ func TestProjects_CRUD(t *testing.T) {
}
func TestHandleRunTask_CascadesRetryToFailedDeps(t *testing.T) {
- srv, store := testServer(t)
+ // Use a blocking runner so tasks stay QUEUED long enough to assert state.
+ block := make(chan struct{})
+ t.Cleanup(func() { close(block) })
+ srv, store := testServerWithRunner(t, &mockRunner{onRun: func(*task.Task, *storage.Execution) error {
+ <-block
+ return nil
+ }})
now := time.Now().UTC()
diff --git a/internal/storage/db.go b/internal/storage/db.go
index ee5ee77..4ae0ab1 100644
--- a/internal/storage/db.go
+++ b/internal/storage/db.go
@@ -19,6 +19,10 @@ func Open(path string) (*DB, error) {
if err != nil {
return nil, fmt.Errorf("opening database: %w", err)
}
+ // SQLite only allows one concurrent writer. Limiting to one open connection
+ // prevents "database is locked" errors when multiple goroutines write
+ // simultaneously via database/sql's connection pool.
+ db.SetMaxOpenConns(1)
s := &DB{db: db}
if err := s.migrate(); err != nil {
db.Close()
@@ -334,9 +338,10 @@ func (s *DB) RejectTask(id, comment string) error {
// TaskUpdate holds the fields that UpdateTask may change.
type TaskUpdate struct {
- Name string
- Description string
- Config task.AgentConfig
+ Name string
+ Description string
+ RepositoryURL string
+ Config task.AgentConfig
Priority task.Priority
TimeoutNS int64
Retry task.RetryConfig
@@ -375,13 +380,11 @@ func (s *DB) UpdateTask(id string, u TaskUpdate) error {
now := time.Now().UTC()
result, err := s.db.Exec(`
UPDATE tasks
- SET name = ?, description = ?, config_json = ?, priority = ?, timeout_ns = ?,
+ SET name = ?, description = ?, repository_url = ?, config_json = ?, priority = ?, timeout_ns = ?,
retry_json = ?, tags_json = ?, depends_on_json = ?, state = ?, updated_at = ?
WHERE id = ?`,
- u.Name, u.Description, string(configJSON), string(u.Priority), u.TimeoutNS,
- string(retryJSON), string(tagsJSON), string(depsJSON), string(task.StatePending), now,
- id,
- )
+ u.Name, u.Description, u.RepositoryURL, configJSON, string(u.Priority), u.TimeoutNS,
+ retryJSON, tagsJSON, depsJSON, string(task.StatePending), now, id)
if err != nil {
return err
}
diff --git a/internal/task/validator.go b/internal/task/validator.go
index 003fab9..43e482e 100644
--- a/internal/task/validator.go
+++ b/internal/task/validator.go
@@ -29,6 +29,9 @@ func Validate(t *Task) error {
if t.Name == "" {
ve.Add("name is required")
}
+ if t.RepositoryURL == "" {
+ ve.Add("repository_url is required")
+ }
if t.Agent.Instructions == "" {
ve.Add("agent.instructions is required")
}
diff --git a/internal/task/validator_test.go b/internal/task/validator_test.go
index c0ab986..2c6735c 100644
--- a/internal/task/validator_test.go
+++ b/internal/task/validator_test.go
@@ -9,6 +9,7 @@ func validTask() *Task {
return &Task{
ID: "test-id",
Name: "Valid Task",
+ RepositoryURL: "https://github.com/user/repo",
Agent: AgentConfig{
Type: "claude",
Instructions: "do something",