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
18 changes: 9 additions & 9 deletions backend/plugins/jira/tasks/apiv2models/comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ import (
)

type Comment struct {
Self string `json:"self"`
Id string `json:"id"`
Author *Account `json:"author"`
Body string `json:"body"`
UpdateAuthor *Account `json:"updateAuthor"`
Created common.Iso8601Time `json:"created"`
Updated common.Iso8601Time `json:"updated"`
JsdPublic bool `json:"jsdPublic"`
Self string `json:"self"`
Id string `json:"id"`
Author *Account `json:"author"`
Body FlexibleDescription `json:"body"`
UpdateAuthor *Account `json:"updateAuthor"`
Created common.Iso8601Time `json:"created"`
Updated common.Iso8601Time `json:"updated"`
JsdPublic bool `json:"jsdPublic"`
}

func (c Comment) ToToolLayer(connectionId uint64, issueId uint64, issueUpdated *time.Time) *models.JiraIssueComment {
Expand All @@ -41,7 +41,7 @@ func (c Comment) ToToolLayer(connectionId uint64, issueId uint64, issueUpdated *
IssueId: issueId,
ComentId: c.Id,
Self: c.Self,
Body: c.Body,
Body: c.Body.Value,
Created: c.Updated.ToTime(),
Updated: c.Updated.ToTime(),
IssueUpdated: issueUpdated,
Expand Down
135 changes: 132 additions & 3 deletions backend/plugins/jira/tasks/apiv2models/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,142 @@ package apiv2models

import (
"encoding/json"
"strings"
"time"

"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/models/common"
"github.com/apache/incubator-devlake/plugins/jira/models"
)

// FlexibleDescription supports both plain text and ADF (Atlassian Document Format) for Jira description field
Comment thread
GoSimplicity marked this conversation as resolved.
// ADF reference: https://developer.atlassian.com/cloud/jira/platform/apis/document/structure/
type FlexibleDescription struct {
Value string
}

// ADFNode represents a node in Atlassian Document Format
type ADFNode struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
Content []ADFNode `json:"content,omitempty"`
Attrs map[string]interface{} `json:"attrs,omitempty"`
}

// UnmarshalJSON implements custom JSON unmarshaling for FlexibleDescription
func (fd *FlexibleDescription) UnmarshalJSON(data []byte) error {
// Handle null values
if string(data) == "null" {
fd.Value = ""
return nil
}

// Try to unmarshal as string first
var str string
if err := json.Unmarshal(data, &str); err == nil {
fd.Value = str
return nil
}

// Try to unmarshal as ADF document
var adfDoc ADFNode
if err := json.Unmarshal(data, &adfDoc); err == nil {
fd.Value = extractTextFromADF(adfDoc)
return nil
}

// Fallback: keep raw JSON as string for debugging
fd.Value = string(data)
return nil
}

// extractTextFromADF recursively extracts plain text from ADF document
func extractTextFromADF(node ADFNode) string {
var result strings.Builder

switch node.Type {
case "text":
result.WriteString(node.Text)
case "hardBreak":
result.WriteString("\n")
case "paragraph":
for _, child := range node.Content {
result.WriteString(extractTextFromADF(child))
}
result.WriteString("\n")
case "heading":
for _, child := range node.Content {
result.WriteString(extractTextFromADF(child))
}
result.WriteString("\n")
case "listItem":
for _, child := range node.Content {
result.WriteString(extractTextFromADF(child))
}
case "bulletList", "orderedList":
for _, child := range node.Content {
result.WriteString("• ")
result.WriteString(extractTextFromADF(child))
result.WriteString("\n")
}
case "table":
for _, row := range node.Content {
if row.Type == "tableRow" {
for j, cell := range row.Content {
if j > 0 {
result.WriteString(" | ")
}
result.WriteString(extractTextFromADF(cell))
}
result.WriteString("\n")
}
}
case "tableCell", "tableHeader":
for _, child := range node.Content {
result.WriteString(extractTextFromADF(child))
}
case "codeBlock":
result.WriteString("```\n")
for _, child := range node.Content {
result.WriteString(extractTextFromADF(child))
}
result.WriteString("\n```\n")
case "blockquote":
result.WriteString("> ")
for _, child := range node.Content {
result.WriteString(extractTextFromADF(child))
}
result.WriteString("\n")
case "doc":
for _, child := range node.Content {
result.WriteString(extractTextFromADF(child))
}
case "inlineCard", "mention":
// Extract text from attrs or content for links and mentions
if attrs, ok := node.Attrs["text"]; ok {
if text, ok := attrs.(string); ok {
result.WriteString(text)
}
} else {
for _, child := range node.Content {
result.WriteString(extractTextFromADF(child))
}
}
default:
// For unknown types, extract content recursively
for _, child := range node.Content {
result.WriteString(extractTextFromADF(child))
}
}

return result.String()
}

// String returns the string value
func (fd FlexibleDescription) String() string {
return fd.Value
}

type Issue struct {
Expand string `json:"expand"`
ID uint64 `json:"id,string"`
Expand Down Expand Up @@ -121,8 +250,8 @@ type Issue struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"components"`
Timeoriginalestimate *int64 `json:"timeoriginalestimate"`
Description string `json:"description"`
Timeoriginalestimate *int64 `json:"timeoriginalestimate"`
Description FlexibleDescription `json:"description"`
Timetracking *struct {
RemainingEstimate string `json:"remainingEstimate"`
TimeSpent string `json:"timeSpent"`
Expand Down Expand Up @@ -233,7 +362,7 @@ func (i Issue) toToolLayer(connectionId uint64) *models.JiraIssue {
IssueKey: i.Key,
StoryPoint: &workload,
Summary: i.Fields.Summary,
Description: i.Fields.Description,
Description: i.Fields.Description.Value,
Type: i.Fields.Issuetype.ID,
StatusName: i.Fields.Status.Name,
StatusKey: i.Fields.Status.StatusCategory.Key,
Expand Down
22 changes: 11 additions & 11 deletions backend/plugins/jira/tasks/apiv2models/worklog.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ import (
)

type Worklog struct {
Self string `json:"self"`
Author *Account `json:"author"`
UpdateAuthor *Account `json:"updateAuthor"`
Comment string `json:"comment"`
Created string `json:"created"`
Updated common.Iso8601Time `json:"updated"`
Started common.Iso8601Time `json:"started"`
TimeSpent string `json:"timeSpent"`
TimeSpentSeconds int `json:"timeSpentSeconds"`
ID string `json:"id"`
IssueID uint64 `json:"issueId,string"`
Self string `json:"self"`
Author *Account `json:"author"`
UpdateAuthor *Account `json:"updateAuthor"`
Comment FlexibleDescription `json:"comment"`
Created string `json:"created"`
Updated common.Iso8601Time `json:"updated"`
Started common.Iso8601Time `json:"started"`
TimeSpent string `json:"timeSpent"`
TimeSpentSeconds int `json:"timeSpentSeconds"`
ID string `json:"id"`
IssueID uint64 `json:"issueId,string"`
}

func (w Worklog) ToToolLayer(connectionId uint64, issueUpdated *time.Time) *models.JiraWorklog {
Expand Down
Loading