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
10 changes: 10 additions & 0 deletions internal/infra/github/gh_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ func GetSobaLabels() []CreateLabelRequest {
Color: "e1e4e8",
Description: "New issue awaiting processing",
},
{
Name: "soba:todo:high",
Color: "d73a4a",
Description: "High priority task",
},
{
Name: "soba:todo:low",
Color: "cfd3d7",
Description: "Low priority task",
},
{
Name: "soba:queued",
Color: "fbca04",
Expand Down
74 changes: 74 additions & 0 deletions internal/infra/github/label_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package github

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetSobaLabels(t *testing.T) {
labels := GetSobaLabels()

// 既存のラベルが含まれていることを確認
expectedLabels := map[string]bool{
"soba:todo": false,
"soba:todo:high": false,
"soba:todo:low": false,
"soba:queued": false,
"soba:planning": false,
"soba:ready": false,
"soba:doing": false,
"soba:review-requested": false,
"soba:reviewing": false,
"soba:done": false,
"soba:requires-changes": false,
"soba:revising": false,
"soba:lgtm": false,
}

// 全てのラベルが定義されていることを確認
assert.Equal(t, len(expectedLabels), len(labels), "ラベル数が一致しません")

// 各ラベルが正しく定義されていることを確認
for _, label := range labels {
if _, exists := expectedLabels[label.Name]; exists {
expectedLabels[label.Name] = true
// ラベルの色とdescriptionが設定されていることを確認
assert.NotEmpty(t, label.Color, "ラベル %s の色が設定されていません", label.Name)
assert.NotEmpty(t, label.Description, "ラベル %s の説明が設定されていません", label.Name)
}
}

// 全ての期待されるラベルが見つかったか確認
for name, found := range expectedLabels {
assert.True(t, found, "期待されるラベル %s が見つかりません", name)
}
}

func TestGetSobaLabels_Priority(t *testing.T) {
labels := GetSobaLabels()

// 優先度ラベルが正しく定義されているか確認
priorityLabels := map[string]struct {
expectedColor string
expectedDesc string
}{
"soba:todo:high": {
expectedColor: "d73a4a", // 赤系の色(高優先度)
expectedDesc: "High priority task",
},
"soba:todo:low": {
expectedColor: "cfd3d7", // グレー系の色(低優先度)
expectedDesc: "Low priority task",
},
}

for _, label := range labels {
if expected, ok := priorityLabels[label.Name]; ok {
assert.Equal(t, expected.expectedColor, label.Color,
"ラベル %s の色が期待値と異なります", label.Name)
assert.Equal(t, expected.expectedDesc, label.Description,
"ラベル %s の説明が期待値と異なります", label.Name)
}
}
}
58 changes: 56 additions & 2 deletions internal/service/queue_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package service

import (
"context"
"sort"
"strings"

"github.com/douhashi/soba/internal/infra/github"
Expand Down Expand Up @@ -54,8 +55,8 @@ func (q *QueueManager) EnqueueNextIssue(ctx context.Context, issues []github.Iss
return nil
}

// 3. 最小番号のIssueを選択
targetIssue := q.selectMinimumIssue(todoIssues)
// 3. 優先度順で最適なIssueを選択
targetIssue := q.selectPriorityIssue(todoIssues)

// 4. ラベル変更(soba:todo → soba:queued)
q.logger.Info(ctx, "Enqueueing issue", logging.Field{Key: "issue", Value: targetIssue.Number})
Expand Down Expand Up @@ -196,3 +197,56 @@ func (q *QueueManager) hasSobaLabel(issue github.Issue) bool {
}
return false
}

// getPriority はIssueの優先度を判定する(0:高、1:通常、2:低)
func (q *QueueManager) getPriority(issue github.Issue) int {
hasHigh := false
hasLow := false

for _, label := range issue.Labels {
if label.Name == "soba:todo:high" {
hasHigh = true
} else if label.Name == "soba:todo:low" {
hasLow = true
}
}

// 複数の優先度ラベルがある場合は最高優先度を採用
if hasHigh {
return 0
}
if hasLow {
return 2
}
return 1 // デフォルトは通常優先度
}

// sortByPriority はIssueを優先度順にソートする
func (q *QueueManager) sortByPriority(issues []github.Issue) []github.Issue {
sorted := make([]github.Issue, len(issues))
copy(sorted, issues)

sort.Slice(sorted, func(i, j int) bool {
priorityI := q.getPriority(sorted[i])
priorityJ := q.getPriority(sorted[j])

if priorityI != priorityJ {
return priorityI < priorityJ // 優先度が高いほど値が小さい
}

// 同じ優先度の場合はIssue番号順
return sorted[i].Number < sorted[j].Number
})

return sorted
}

// selectPriorityIssue は優先度を考慮して最適なIssueを選択する
func (q *QueueManager) selectPriorityIssue(issues []github.Issue) *github.Issue {
if len(issues) == 0 {
return nil
}

sorted := q.sortByPriority(issues)
return &sorted[0]
}
Loading
Loading