Set label
This commit is contained in:
parent
210fa4ee2d
commit
7f1e554e40
|
|
@ -5,8 +5,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var fixedTime = time.Date(2025, 1, 15, 10, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
func TestCreateIssue_Success(t *testing.T) {
|
func TestCreateIssue_Success(t *testing.T) {
|
||||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Verify request method and path
|
// Verify request method and path
|
||||||
|
|
@ -165,3 +168,481 @@ func TestCreateComment_ServerError(t *testing.T) {
|
||||||
t.Fatal("expected error for 500 response, got nil")
|
t.Fatal("expected error for 500 response, got nil")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- StripCommentFooter Tests ---
|
||||||
|
|
||||||
|
func TestStripCommentFooter_SubmittedByEmail(t *testing.T) {
|
||||||
|
body, email := StripCommentFooter("Description\n\n---\n*Submitted by: user@example.com*")
|
||||||
|
if body != "Description" {
|
||||||
|
t.Errorf("expected body %q, got %q", "Description", body)
|
||||||
|
}
|
||||||
|
if email != "user@example.com" {
|
||||||
|
t.Errorf("expected email %q, got %q", "user@example.com", email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStripCommentFooter_CustomerCommentByEmail(t *testing.T) {
|
||||||
|
body, email := StripCommentFooter("Reply\n\n---\n*Customer comment by: alice@corp.com*")
|
||||||
|
if body != "Reply" {
|
||||||
|
t.Errorf("expected body %q, got %q", "Reply", body)
|
||||||
|
}
|
||||||
|
if email != "alice@corp.com" {
|
||||||
|
t.Errorf("expected email %q, got %q", "alice@corp.com", email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStripCommentFooter_NoFooter(t *testing.T) {
|
||||||
|
body, email := StripCommentFooter("Plain comment")
|
||||||
|
if body != "Plain comment" {
|
||||||
|
t.Errorf("expected body %q, got %q", "Plain comment", body)
|
||||||
|
}
|
||||||
|
if email != "" {
|
||||||
|
t.Errorf("expected empty email, got %q", email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStripCommentFooter_EmptyBody(t *testing.T) {
|
||||||
|
body, email := StripCommentFooter("")
|
||||||
|
if body != "" {
|
||||||
|
t.Errorf("expected empty body, got %q", body)
|
||||||
|
}
|
||||||
|
if email != "" {
|
||||||
|
t.Errorf("expected empty email, got %q", email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStripCommentFooter_FooterWithoutColon(t *testing.T) {
|
||||||
|
body, email := StripCommentFooter("Body\n\n---\n*NoColonHere*")
|
||||||
|
if body != "Body" {
|
||||||
|
t.Errorf("expected body %q, got %q", "Body", body)
|
||||||
|
}
|
||||||
|
if email != "" {
|
||||||
|
t.Errorf("expected empty email, got %q", email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStripCommentFooter_MultipleFooters(t *testing.T) {
|
||||||
|
input := "First\n\n---\n*Submitted by: first@example.com*\n\nMiddle\n\n---\n*Submitted by: second@example.com*"
|
||||||
|
body, email := StripCommentFooter(input)
|
||||||
|
expectedBody := "First\n\n---\n*Submitted by: first@example.com*\n\nMiddle"
|
||||||
|
if body != expectedBody {
|
||||||
|
t.Errorf("expected body %q, got %q", expectedBody, body)
|
||||||
|
}
|
||||||
|
if email != "second@example.com" {
|
||||||
|
t.Errorf("expected email %q, got %q", "second@example.com", email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStripCommentFooter_MarkdownHorizontalRule(t *testing.T) {
|
||||||
|
input := "Text\n\n---\n\nMore text"
|
||||||
|
body, email := StripCommentFooter(input)
|
||||||
|
if body != input {
|
||||||
|
t.Errorf("expected body unchanged %q, got %q", input, body)
|
||||||
|
}
|
||||||
|
if email != "" {
|
||||||
|
t.Errorf("expected empty email, got %q", email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- BuildTimelineViews Tests: Comment events ---
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_TeamComment(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 501,
|
||||||
|
Type: "comment",
|
||||||
|
Body: "Looks good, merging now.",
|
||||||
|
User: APIUser{Login: "alicedev", FullName: "Alice Dev"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
v := views[0]
|
||||||
|
if v.Type != "comment" {
|
||||||
|
t.Errorf("expected type %q, got %q", "comment", v.Type)
|
||||||
|
}
|
||||||
|
if !v.IsTeam {
|
||||||
|
t.Errorf("expected IsTeam=true")
|
||||||
|
}
|
||||||
|
if v.CommentID != 501 {
|
||||||
|
t.Errorf("expected CommentID 501, got %d", v.CommentID)
|
||||||
|
}
|
||||||
|
if v.AuthorName != "Alice Dev" {
|
||||||
|
t.Errorf("expected AuthorName %q, got %q", "Alice Dev", v.AuthorName)
|
||||||
|
}
|
||||||
|
if v.Body != "Looks good, merging now." {
|
||||||
|
t.Errorf("expected body %q, got %q", "Looks good, merging now.", v.Body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_CustomerCommentWithFooter(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 602,
|
||||||
|
Type: "comment",
|
||||||
|
Body: "Please help\n\n---\n*Submitted by: customer@example.com*",
|
||||||
|
User: APIUser{Login: "ticket-bot", FullName: "Ticket Bot"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
v := views[0]
|
||||||
|
if v.IsTeam {
|
||||||
|
t.Errorf("expected IsTeam=false")
|
||||||
|
}
|
||||||
|
if v.CommentID != 602 {
|
||||||
|
t.Errorf("expected CommentID 602, got %d", v.CommentID)
|
||||||
|
}
|
||||||
|
if v.AuthorName != "customer@example.com" {
|
||||||
|
t.Errorf("expected AuthorName %q, got %q", "customer@example.com", v.AuthorName)
|
||||||
|
}
|
||||||
|
if v.Body != "Please help" {
|
||||||
|
t.Errorf("expected body %q, got %q", "Please help", v.Body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_CustomerCommentBotNoFooter(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 603,
|
||||||
|
Type: "comment",
|
||||||
|
Body: "I need assistance",
|
||||||
|
User: APIUser{Login: "ticket-bot", FullName: "Ticket Bot"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
v := views[0]
|
||||||
|
if v.IsTeam {
|
||||||
|
t.Errorf("expected IsTeam=false")
|
||||||
|
}
|
||||||
|
if v.AuthorName != "Customer" {
|
||||||
|
t.Errorf("expected AuthorName %q, got %q", "Customer", v.AuthorName)
|
||||||
|
}
|
||||||
|
if v.CommentID != 603 {
|
||||||
|
t.Errorf("expected CommentID 603, got %d", v.CommentID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_CommentWithAttachments(t *testing.T) {
|
||||||
|
attachments := []Attachment{
|
||||||
|
{ID: 1, Name: "screenshot.png", Size: 1024},
|
||||||
|
{ID: 2, Name: "log.txt", Size: 512},
|
||||||
|
}
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 700,
|
||||||
|
Type: "comment",
|
||||||
|
Body: "See attached",
|
||||||
|
User: APIUser{Login: "dev1", FullName: "Developer One"},
|
||||||
|
Assets: attachments,
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
v := views[0]
|
||||||
|
if v.CommentID != 700 {
|
||||||
|
t.Errorf("expected CommentID 700, got %d", v.CommentID)
|
||||||
|
}
|
||||||
|
if len(v.Attachments) != 2 {
|
||||||
|
t.Fatalf("expected 2 attachments, got %d", len(v.Attachments))
|
||||||
|
}
|
||||||
|
if v.Attachments[0].Name != "screenshot.png" {
|
||||||
|
t.Errorf("expected first attachment %q, got %q", "screenshot.png", v.Attachments[0].Name)
|
||||||
|
}
|
||||||
|
if v.Attachments[1].Name != "log.txt" {
|
||||||
|
t.Errorf("expected second attachment %q, got %q", "log.txt", v.Attachments[1].Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_CommentIDAlwaysSet(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 9999999,
|
||||||
|
Type: "comment",
|
||||||
|
Body: "Large ID test",
|
||||||
|
User: APIUser{Login: "dev", FullName: "Dev"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
if views[0].CommentID != 9999999 {
|
||||||
|
t.Errorf("expected CommentID 9999999, got %d", views[0].CommentID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- BuildTimelineViews Tests: Status change events ---
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_CloseEvent(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 10,
|
||||||
|
Type: "close",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
v := views[0]
|
||||||
|
if v.Type != "status_change" {
|
||||||
|
t.Errorf("expected type %q, got %q", "status_change", v.Type)
|
||||||
|
}
|
||||||
|
if v.EventText != "closed this ticket" {
|
||||||
|
t.Errorf("expected EventText %q, got %q", "closed this ticket", v.EventText)
|
||||||
|
}
|
||||||
|
if !v.IsTeam {
|
||||||
|
t.Errorf("expected IsTeam=true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_ReopenEvent(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 11,
|
||||||
|
Type: "reopen",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
if views[0].EventText != "reopened this ticket" {
|
||||||
|
t.Errorf("expected EventText %q, got %q", "reopened this ticket", views[0].EventText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- BuildTimelineViews Tests: Admin-gated events ---
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_LabelEvent_AdminVisible(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 20,
|
||||||
|
Type: "label",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
Label: &Label{ID: 5, Name: "priority/high"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", true)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
v := views[0]
|
||||||
|
if v.Type != "label" {
|
||||||
|
t.Errorf("expected type %q, got %q", "label", v.Type)
|
||||||
|
}
|
||||||
|
if v.EventText != "added label priority/high" {
|
||||||
|
t.Errorf("expected EventText %q, got %q", "added label priority/high", v.EventText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_LabelEvent_NonAdminHidden(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 21,
|
||||||
|
Type: "label",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
Label: &Label{ID: 5, Name: "priority/high"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(views) != 0 {
|
||||||
|
t.Errorf("expected 0 views for non-admin label event, got %d", len(views))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_LabelEvent_NilLabel(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 22,
|
||||||
|
Type: "label",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
Label: nil,
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", true)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
if views[0].EventText != "added label " {
|
||||||
|
t.Errorf("expected EventText %q, got %q", "added label ", views[0].EventText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_AssigneeEvent_AdminVisible(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 30,
|
||||||
|
Type: "assignees",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
Assignee: &APIUser{Login: "dev2", FullName: "Developer Two"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", true)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
v := views[0]
|
||||||
|
if v.Type != "assignment" {
|
||||||
|
t.Errorf("expected type %q, got %q", "assignment", v.Type)
|
||||||
|
}
|
||||||
|
if v.EventText != "assigned Developer Two" {
|
||||||
|
t.Errorf("expected EventText %q, got %q", "assigned Developer Two", v.EventText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_AssigneeEvent_NonAdminHidden(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 31,
|
||||||
|
Type: "assignees",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
Assignee: &APIUser{Login: "dev2", FullName: "Developer Two"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(views) != 0 {
|
||||||
|
t.Errorf("expected 0 views for non-admin assignees event, got %d", len(views))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_AssigneeEvent_NilAssignee(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 32,
|
||||||
|
Type: "assignees",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
Assignee: nil,
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", true)
|
||||||
|
if len(views) != 1 {
|
||||||
|
t.Fatalf("expected 1 view, got %d", len(views))
|
||||||
|
}
|
||||||
|
if views[0].EventText != "assigned " {
|
||||||
|
t.Errorf("expected EventText %q, got %q", "assigned ", views[0].EventText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- BuildTimelineViews Tests: Edge cases & integration ---
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_UnknownEventType(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 40,
|
||||||
|
Type: "milestone",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
views := BuildTimelineViews(events, "ticket-bot", true)
|
||||||
|
if len(views) != 0 {
|
||||||
|
t.Errorf("expected 0 views for unknown event type, got %d", len(views))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_EmptyEvents(t *testing.T) {
|
||||||
|
views := BuildTimelineViews([]TimelineEvent{}, "ticket-bot", false)
|
||||||
|
if len(views) != 0 {
|
||||||
|
t.Errorf("expected 0 views for empty events, got %d", len(views))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildTimelineViews_MixedEvents(t *testing.T) {
|
||||||
|
events := []TimelineEvent{
|
||||||
|
{
|
||||||
|
ID: 100,
|
||||||
|
Type: "comment",
|
||||||
|
Body: "Team comment",
|
||||||
|
User: APIUser{Login: "dev1", FullName: "Developer One"},
|
||||||
|
CreatedAt: fixedTime,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 101,
|
||||||
|
Type: "label",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
Label: &Label{ID: 5, Name: "bug"},
|
||||||
|
CreatedAt: fixedTime.Add(1 * time.Minute),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 102,
|
||||||
|
Type: "comment",
|
||||||
|
Body: "Customer reply\n\n---\n*Submitted by: cust@test.com*",
|
||||||
|
User: APIUser{Login: "ticket-bot", FullName: "Ticket Bot"},
|
||||||
|
CreatedAt: fixedTime.Add(2 * time.Minute),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 103,
|
||||||
|
Type: "close",
|
||||||
|
User: APIUser{Login: "dev1", FullName: "Developer One"},
|
||||||
|
CreatedAt: fixedTime.Add(3 * time.Minute),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 104,
|
||||||
|
Type: "assignees",
|
||||||
|
User: APIUser{Login: "admin", FullName: "Admin User"},
|
||||||
|
Assignee: &APIUser{Login: "dev1", FullName: "Developer One"},
|
||||||
|
CreatedAt: fixedTime.Add(4 * time.Minute),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-admin: label and assignees should be filtered
|
||||||
|
nonAdminViews := BuildTimelineViews(events, "ticket-bot", false)
|
||||||
|
if len(nonAdminViews) != 3 {
|
||||||
|
t.Fatalf("non-admin: expected 3 views, got %d", len(nonAdminViews))
|
||||||
|
}
|
||||||
|
if nonAdminViews[0].Type != "comment" || nonAdminViews[0].CommentID != 100 {
|
||||||
|
t.Errorf("non-admin view[0]: expected comment with ID 100, got type=%q id=%d", nonAdminViews[0].Type, nonAdminViews[0].CommentID)
|
||||||
|
}
|
||||||
|
if nonAdminViews[1].Type != "comment" || nonAdminViews[1].CommentID != 102 {
|
||||||
|
t.Errorf("non-admin view[1]: expected comment with ID 102, got type=%q id=%d", nonAdminViews[1].Type, nonAdminViews[1].CommentID)
|
||||||
|
}
|
||||||
|
if nonAdminViews[2].Type != "status_change" {
|
||||||
|
t.Errorf("non-admin view[2]: expected status_change, got %q", nonAdminViews[2].Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Admin: all 5 events should produce views
|
||||||
|
adminViews := BuildTimelineViews(events, "ticket-bot", true)
|
||||||
|
if len(adminViews) != 5 {
|
||||||
|
t.Fatalf("admin: expected 5 views, got %d", len(adminViews))
|
||||||
|
}
|
||||||
|
// Verify order preserved
|
||||||
|
expectedTypes := []string{"comment", "label", "comment", "status_change", "assignment"}
|
||||||
|
for i, et := range expectedTypes {
|
||||||
|
if adminViews[i].Type != et {
|
||||||
|
t.Errorf("admin view[%d]: expected type %q, got %q", i, et, adminViews[i].Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Verify comment IDs
|
||||||
|
if adminViews[0].CommentID != 100 {
|
||||||
|
t.Errorf("admin view[0]: expected CommentID 100, got %d", adminViews[0].CommentID)
|
||||||
|
}
|
||||||
|
if adminViews[2].CommentID != 102 {
|
||||||
|
t.Errorf("admin view[2]: expected CommentID 102, got %d", adminViews[2].CommentID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,13 @@ func (h *TicketHandler) Create(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply customer label after creation (CreateIssue labels field is unreliable)
|
||||||
|
if len(labelIDs) > 0 {
|
||||||
|
if err := h.deps.ForgejoClient.AddLabels(repo.ForgejoOwner, repo.ForgejoRepo, issue.Number, labelIDs); err != nil {
|
||||||
|
log.Error().Err(err).Msg("forgejo add customer label error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Upload attachments if any
|
// Upload attachments if any
|
||||||
if form != nil && form.File["attachments"] != nil {
|
if form != nil && form.File["attachments"] != nil {
|
||||||
for _, fh := range form.File["attachments"] {
|
for _, fh := range form.File["attachments"] {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue