incubator-devlake icon indicating copy to clipboard operation
incubator-devlake copied to clipboard

[Bug][Jira] A issue has been deleted in Jira,but devlake didnot delete it in devlake mysql,so when execute config-ui collect data ,the issue still exist

Open Challen-V opened this issue 1 year ago • 2 comments

Search before asking

  • [X] I had searched in the issues and found no similar issues.

What happened

Devlake seems not sync Jira issue status

What do you expect to happen

devlake sync the deleted issue status

How to reproduce

Delete a issue in Jira,then execute collect in config-ui,see the data in Grafana

Anything else

No response

Version

v0.21.0

Are you willing to submit PR?

  • [X] Yes I am willing to submit a PR!

Code of Conduct

Challen-V avatar May 29 '24 01:05 Challen-V

Hey @Challen-V! I'm here to help you with any bugs, questions, or contributions you have for the project. Looking forward to assisting you!

To address the issue where DevLake is not syncing the status of deleted issues from Jira, you need to ensure that the deletion of issues is properly handled in the extractIssues function. Currently, the provided code does not include logic to handle deleted issues.

You can add a check to see if an issue has been deleted and then mark it accordingly. Here is a modified version of the extractIssues function to include this logic:

func extractIssues(data *JiraTaskData, mappings *typeMappings, row *api.RawData) ([]interface{}, errors.Error) {
    var apiIssue apiv2models.Issue
    err := errors.Convert(json.Unmarshal(row.Data, &apiIssue))
    if err != nil {
        return nil, err
    }
    err = apiIssue.SetAllFields(row.Data)
    if err != nil {
        return nil, err
    }
    var results []interface{}
    // if the field `created` is nil, ignore it
    if apiIssue.Fields.Created == nil {
        return results, nil
    }
    sprints, issue, comments, worklogs, changelogs, changelogItems, users := apiIssue.ExtractEntities(data.Options.ConnectionId)
    for _, sprintId := range sprints {
        sprintIssue := &models.JiraSprintIssue{
            ConnectionId:     data.Options.ConnectionId,
            SprintId:         sprintId,
            IssueId:          issue.IssueId,
            IssueCreatedDate: &issue.Created,
            ResolutionDate:   issue.ResolutionDate,
        }
        results = append(results, sprintIssue)
    }
    if issue.ResolutionDate != nil {
        temp := uint(issue.ResolutionDate.Unix()-issue.Created.Unix()) / 60
        issue.LeadTimeMinutes = &temp
    }
    if data.Options.ScopeConfig != nil && data.Options.ScopeConfig.StoryPointField != "" {
        unknownStoryPoint := apiIssue.Fields.AllFields[data.Options.ScopeConfig.StoryPointField]
        switch sp := unknownStoryPoint.(type) {
        case string:
            // string, try to parse
            temp, _ := strconv.ParseFloat(sp, 32)
            issue.StoryPoint = &temp
        case nil:
        default:
            // not string, convert to float64, ignore it if failed
            temp, _ := unknownStoryPoint.(float64)
            issue.StoryPoint = &temp
        }
    }
    // Check if the issue is deleted
    if apiIssue.Fields.Resolution != nil && strings.ToLower(apiIssue.Fields.Resolution.Name) == "deleted" {
        issue.StdStatus = "DELETED"
    } else {
        // code in next line will set issue.Type to issueType.Name
        issue.Type = mappings.typeIdMappings[issue.Type]
        issue.StdType = mappings.stdTypeMappings[issue.Type]
        if issue.StdType == "" {
            issue.StdType = strings.ToUpper(issue.Type)
        }
        issue.StdStatus = getStdStatus(issue.StatusKey)
        if value, ok := mappings.standardStatusMappings[issue.Type][issue.StatusKey]; ok {
            issue.StdStatus = value.StandardStatus
        }
    }
    // issue comments
    results = append(results, issue)
    for _, comment := range comments {
        results = append(results, comment)
    }
    // worklogs
    for _, worklog := range worklogs {
        results = append(results, worklog)
    }
    var issueUpdated *time.Time
    // likely this issue has more changelogs to be collected
    if len(changelogs) == 100 {
        issueUpdated = nil
    } else {
        issueUpdated = &issue.Updated
    }
    // changelogs
    for _, changelog := range changelogs {
        changelog.IssueUpdated = issueUpdated
        results = append(results, changelog)
    }
    // changelog items
    for _, changelogItem := range changelogItems {
        results = append(results, changelogItem)
    }
    // users
    for _, user := range users {
        if user.AccountId != "" {
            results = append(results, user)
        }
    }
    results = append(results, &models.JiraBoardIssue{
        ConnectionId: data.Options.ConnectionId,
        BoardId:      data.Options.BoardId,
        IssueId:      issue.IssueId,
    })
    // labels
    labels := apiIssue.Fields.Labels
    for _, v := range labels {
        issueLabel := &models.JiraIssueLabel{
            IssueId:      issue.IssueId,
            LabelName:    v,
            ConnectionId: data.Options.ConnectionId,
        }
        results = append(results, issueLabel)
    }
    // components
    components := apiIssue.Fields.Components
    var componentNames []string
    for _, v := range components {
        componentNames = append(componentNames, v.Name)
    }
    issue.Components = strings.Join(componentNames, ",")
    // issuelinks
    issuelinks := apiIssue.Fields.Issuelinks
    for _, v := range issuelinks {
        issueLink := &models.JiraIssueRelationship{
            ConnectionId:    data.Options.ConnectionId,
            IssueId:         issue.IssueId,
            IssueKey:        issue.IssueKey,
            TypeId:          v.Type.ID,
            TypeName:        v.Type.Name,
            Inward:          v.Type.Inward,
            Outward:         v.Type.Outward,
            InwardIssueId:   v.InwardIssue.ID,
            InwardIssueKey:  v.InwardIssue.Key,
            OutwardIssueId:  v.OutwardIssue.ID,
            OutwardIssueKey: v.OutwardIssue.Key,
        }
        results = append(results, issueLink)
    }
    return results, nil
}

This modification checks if the issue's resolution is marked as "deleted" and sets the StdStatus to "DELETED" accordingly. This should help in ensuring that deleted issues are properly marked and can be filtered out in Grafana [1].

Details

About Dosu This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

To continue the conversation, mention @dosu.

dosubot[bot] avatar May 29 '24 01:05 dosubot[bot]

Try this:

image

klesh avatar May 30 '24 09:05 klesh

This issue has been automatically marked as stale because it has been inactive for 60 days. It will be closed in next 7 days if no further activity occurs.

github-actions[bot] avatar Aug 04 '24 00:08 github-actions[bot]

This issue has been closed because it has been inactive for a long time. You can reopen it if you encounter the similar problem in the future.

github-actions[bot] avatar Aug 11 '24 00:08 github-actions[bot]