From 5764a32f02ecb92bc885ee5406dc50446e07c9e2 Mon Sep 17 00:00:00 2001 From: Yves Biener Date: Sun, 22 Oct 2023 12:32:53 +0200 Subject: [PATCH] fix(taskwarrior): parsing and convertion of times and contents --- internal/gitea/comment.go | 5 ++ internal/gitw/diff.go | 11 ++++ internal/gitw/project.go | 88 ++++++++++++++++++++++++------- internal/taskwarrior/task.go | 8 +-- internal/taskwarrior/task_test.go | 17 ++++++ 5 files changed, 103 insertions(+), 26 deletions(-) create mode 100644 internal/gitw/diff.go diff --git a/internal/gitea/comment.go b/internal/gitea/comment.go index d367666..4f05244 100644 --- a/internal/gitea/comment.go +++ b/internal/gitea/comment.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "time" ) @@ -36,6 +37,9 @@ func (gitea *Gitea) GetComments(repo Repository) ([]Comment, error) { if err = decoder.Decode(&data); err != nil { return nil, err } + for _, comment := range data { + comment.Body = strings.ReplaceAll(comment.Body, "\r\n", "\n") + } return data, nil } @@ -53,6 +57,7 @@ func (gitea *Gitea) GetComment(repo Repository, id uint) (Comment, error) { if err = decoder.Decode(&comment); err != nil { return comment, err } + comment.Body = strings.ReplaceAll(comment.Body, "\r\n", "\n") return comment, err } diff --git a/internal/gitw/diff.go b/internal/gitw/diff.go new file mode 100644 index 0000000..ebb5e64 --- /dev/null +++ b/internal/gitw/diff.go @@ -0,0 +1,11 @@ +package gitw + +import "fmt" + +func prompt(value, theirs, mine string) string { + // TODO: create tmp file with the corresponding contents + // open tmp file using the $EDITOR environment variable + // parse and return output of tmp file after $EDITOR execution has been completed + fmt.Printf("\tPrompting for value: '%s'\n", value) + return value +} diff --git a/internal/gitw/project.go b/internal/gitw/project.go index cd6bf99..5245966 100644 --- a/internal/gitw/project.go +++ b/internal/gitw/project.go @@ -3,6 +3,7 @@ package gitw import ( "errors" "fmt" + "strings" "time" "gitea.yves-biener.de/yves-biener/gitwarrior/internal/gitea" @@ -48,6 +49,11 @@ func (project *Project) Fetch() error { } for _, issue := range issues { var issue_comments []gitea.Comment + issue_comments = append(issue_comments, gitea.Comment{ + Body: strings.ReplaceAll(issue.Body, "\r\n", "\n"), + Created_at: issue.Created_at, + Updated_at: issue.Updated_at, + }) for _, comment := range comments { if comment.Issue_url == issue.Html_url { issue_comments = append(issue_comments, comment) @@ -67,6 +73,7 @@ func (project *Project) merge() error { var tasks []taskwarrior.Task var task taskwarrior.Task var filter taskwarrior.Filter + // NOTE: merge tasks for _, issue := range project.issues { filter.Reset() @@ -104,9 +111,14 @@ func (project *Project) merge() error { if err := taskwarrior.UpdateTasks(tasks); err != nil { return err } + } else { + for _, task := range tasks { + fmt.Printf("\t%#v\n\n", task) + } } - // TODO: reset tasks after successfully updating the issues - tasks = nil + + tasks = nil // NOTE: reset tasks after successfully updating the issues + // TODO: merge milestones for _, milestone := range project.milestones { filter.Reset() @@ -153,6 +165,10 @@ func (project *Project) merge() error { } if !dry_run { return taskwarrior.UpdateTasks(tasks) + } else { + for _, task := range tasks { + fmt.Printf("\t%#v\n\n", task) + } } return nil } @@ -185,32 +201,64 @@ func (issue *Issue) MergeTask(task taskwarrior.Task) (taskwarrior.Task, error) { if issue.git_issue.Updated_at.After(last_update) { // there are changes we need to merge if taskwarrior.TaskTimeToGoTime(task.Modified).After(last_update) { - // TODO: this means that there are local modifications which are not yet pushed + // NOTE: this means that there are local modifications which are not yet pushed + if task.Description != issue.git_issue.Title { + task.Description = prompt(task.Description, issue.git_issue.Title, task.Description) + } + if task.Status == "completed" || issue.git_issue.State == "closed" { + if !(task.Status == "completed" && issue.git_issue.State == "closed" || task.Status != "completed" && issue.git_issue.State != "closed") { + task.Status = prompt(task.Status, issue.git_issue.State, task.Status) + } + } + if len(task.Annotations) != len(issue.comments)+1 { + var annotations []string + annotations = append(annotations, issue.git_issue.Body) + for _, annotation := range task.Annotations { + annotations = append(annotations, annotation.Description) + } + var comments []string + for _, comment := range issue.comments { + comments = append(comments, comment.Body) + } + // TODO: how should the user manually enter the values? + // TODO: provide options for theirs, mine and manual edit of the task annotations + // annotation_joined := prompt(strings.Join(annotations, "\n\n"), strings.Join(comments, "\n\n"), strings.Join(annotations, "\n\n")) + } else { + for i := range issue.comments { + // check the modification times? + annotation := task.Annotations[i] + comment := issue.comments[i] + modification_time := taskwarrior.TaskTimeToGoTime(annotation.Entry) + if comment.Updated_at.After(modification_time) { + annotation.Description = comment.Body + annotation.Entry = taskwarrior.GoTimeToTaskTime(comment.Updated_at) + } else { + annotation.Description = prompt(annotation.Description, comment.Body, annotation.Description) + } + task.Annotations[i] = annotation + } + } } else { + // NOTE: there are no modifications between the last received update and the current version, hence we just accept theirs fully task.Description = issue.git_issue.Title - task.Tags = issue.git_issue.Labels - // NOTE: otherwise do not update the value if issue.git_issue.State == "closed" { + // otherwise do not update the value task.Status = "completed" task.End = taskwarrior.GoTimeToTaskTime(issue.git_issue.Closed_at) } - } - task.Last_gitw_update = taskwarrior.GoTimeToTaskTime(time.Now()) - } else { - // there are changes after the previous update here may be merge conflicts - // TODO: implement merge conflict resolution - } - annotations := len(task.Annotations) - for i, comment := range issue.comments { - if comment.Updated_at.After(last_update) { - if i < annotations { - task.Annotations[i].Description = comment.Body - task.Annotations[i].Entry = taskwarrior.GoTimeToTaskTime(comment.Updated_at) - task.Last_gitw_update = taskwarrior.GoTimeToTaskTime(time.Now()) - } else { - task.AppendComment(comment.Body, comment.Updated_at) + annotations := len(task.Annotations) + for i, comment := range issue.comments { + if comment.Updated_at.After(last_update) { + if i < annotations { + task.Annotations[i].Description = comment.Body + task.Annotations[i].Entry = taskwarrior.GoTimeToTaskTime(comment.Updated_at) + } else { + task.AppendComment(comment.Body, comment.Updated_at) + } + } } } + task.Last_gitw_update = taskwarrior.GoTimeToTaskTime(time.Now().In(time.Local)) } // TODO: issue values into task: // - is the issue more recent than the task? diff --git a/internal/taskwarrior/task.go b/internal/taskwarrior/task.go index 96d6616..b613e47 100644 --- a/internal/taskwarrior/task.go +++ b/internal/taskwarrior/task.go @@ -59,7 +59,6 @@ func NewTask(description string, project string, git_id uint, git_type Type, tag } func TaskTimeToGoTime(t string) time.Time { - // TODO: apply required changes to the string for correct parsing splits := strings.Split(t, "T") if len(t) == 0 { return time.UnixMicro(0) @@ -78,6 +77,7 @@ func TaskTimeToGoTime(t string) time.Time { second = timestamp[2:4] third = timestamp[4 : len(timestamp)-1] timestamp = strings.Join([]string{first, second, third}, ":") + // TODO: identify current timezone and use correct format string (works for Europe/Berlin) value := fmt.Sprintf("%sT%s+02:00", date, timestamp) result, err := time.Parse(time.RFC3339, value) if err != nil { @@ -88,13 +88,9 @@ func TaskTimeToGoTime(t string) time.Time { } func GoTimeToTaskTime(t time.Time) string { - result := t.Format(time.RFC3339) - // TODO: apply changes to the result - // go: 2023-10-10T19:57:22+02:00 - // task: 20231010T195722Z + result := t.In(time.UTC).Format(time.RFC3339) result = strings.Replace(result, "-", "", 2) result = strings.Replace(result, ":", "", 2) - result = strings.ReplaceAll(result, "+02:00", "Z") return result } diff --git a/internal/taskwarrior/task_test.go b/internal/taskwarrior/task_test.go index e5968e7..a710d2f 100644 --- a/internal/taskwarrior/task_test.go +++ b/internal/taskwarrior/task_test.go @@ -1 +1,18 @@ package taskwarrior + +import ( + "testing" + "time" +) + +func TestTimeCoversions(t *testing.T) { + current_time := time.Now() + task_current_time := GoTimeToTaskTime(current_time) + go_current_time := TaskTimeToGoTime(task_current_time) + task_current_time = GoTimeToTaskTime(go_current_time) + current_time = TaskTimeToGoTime(task_current_time) + + if current_time.Compare(go_current_time) != 0 { + t.Fatalf("conversion failed: Expected: `%s` but got: `%s`", current_time.String(), go_current_time.String()) + } +}