fix(taskwarrior): parsing and convertion of times and contents

This commit is contained in:
2023-10-22 12:32:53 +02:00
parent ce2a4769c9
commit 5764a32f02
5 changed files with 103 additions and 26 deletions

View File

@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"strings"
"time" "time"
) )
@@ -36,6 +37,9 @@ func (gitea *Gitea) GetComments(repo Repository) ([]Comment, error) {
if err = decoder.Decode(&data); err != nil { if err = decoder.Decode(&data); err != nil {
return nil, err return nil, err
} }
for _, comment := range data {
comment.Body = strings.ReplaceAll(comment.Body, "\r\n", "\n")
}
return data, nil return data, nil
} }
@@ -53,6 +57,7 @@ func (gitea *Gitea) GetComment(repo Repository, id uint) (Comment, error) {
if err = decoder.Decode(&comment); err != nil { if err = decoder.Decode(&comment); err != nil {
return comment, err return comment, err
} }
comment.Body = strings.ReplaceAll(comment.Body, "\r\n", "\n")
return comment, err return comment, err
} }

11
internal/gitw/diff.go Normal file
View File

@@ -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
}

View File

@@ -3,6 +3,7 @@ package gitw
import ( import (
"errors" "errors"
"fmt" "fmt"
"strings"
"time" "time"
"gitea.yves-biener.de/yves-biener/gitwarrior/internal/gitea" "gitea.yves-biener.de/yves-biener/gitwarrior/internal/gitea"
@@ -48,6 +49,11 @@ func (project *Project) Fetch() error {
} }
for _, issue := range issues { for _, issue := range issues {
var issue_comments []gitea.Comment 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 { for _, comment := range comments {
if comment.Issue_url == issue.Html_url { if comment.Issue_url == issue.Html_url {
issue_comments = append(issue_comments, comment) issue_comments = append(issue_comments, comment)
@@ -67,6 +73,7 @@ func (project *Project) merge() error {
var tasks []taskwarrior.Task var tasks []taskwarrior.Task
var task taskwarrior.Task var task taskwarrior.Task
var filter taskwarrior.Filter var filter taskwarrior.Filter
// NOTE: merge tasks // NOTE: merge tasks
for _, issue := range project.issues { for _, issue := range project.issues {
filter.Reset() filter.Reset()
@@ -104,9 +111,14 @@ func (project *Project) merge() error {
if err := taskwarrior.UpdateTasks(tasks); err != nil { if err := taskwarrior.UpdateTasks(tasks); err != nil {
return err 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 // TODO: merge milestones
for _, milestone := range project.milestones { for _, milestone := range project.milestones {
filter.Reset() filter.Reset()
@@ -153,6 +165,10 @@ func (project *Project) merge() error {
} }
if !dry_run { if !dry_run {
return taskwarrior.UpdateTasks(tasks) return taskwarrior.UpdateTasks(tasks)
} else {
for _, task := range tasks {
fmt.Printf("\t%#v\n\n", task)
}
} }
return nil return nil
} }
@@ -185,33 +201,65 @@ func (issue *Issue) MergeTask(task taskwarrior.Task) (taskwarrior.Task, error) {
if issue.git_issue.Updated_at.After(last_update) { if issue.git_issue.Updated_at.After(last_update) {
// there are changes we need to merge // there are changes we need to merge
if taskwarrior.TaskTimeToGoTime(task.Modified).After(last_update) { 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 { } 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.Description = issue.git_issue.Title
task.Tags = issue.git_issue.Labels
// NOTE: otherwise do not update the value
if issue.git_issue.State == "closed" { if issue.git_issue.State == "closed" {
// otherwise do not update the value
task.Status = "completed" task.Status = "completed"
task.End = taskwarrior.GoTimeToTaskTime(issue.git_issue.Closed_at) 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) annotations := len(task.Annotations)
for i, comment := range issue.comments { for i, comment := range issue.comments {
if comment.Updated_at.After(last_update) { if comment.Updated_at.After(last_update) {
if i < annotations { if i < annotations {
task.Annotations[i].Description = comment.Body task.Annotations[i].Description = comment.Body
task.Annotations[i].Entry = taskwarrior.GoTimeToTaskTime(comment.Updated_at) task.Annotations[i].Entry = taskwarrior.GoTimeToTaskTime(comment.Updated_at)
task.Last_gitw_update = taskwarrior.GoTimeToTaskTime(time.Now())
} else { } else {
task.AppendComment(comment.Body, comment.Updated_at) task.AppendComment(comment.Body, comment.Updated_at)
} }
} }
} }
}
task.Last_gitw_update = taskwarrior.GoTimeToTaskTime(time.Now().In(time.Local))
}
// TODO: issue values into task: // TODO: issue values into task:
// - is the issue more recent than the task? // - is the issue more recent than the task?
// - apply changes into task // - apply changes into task

View File

@@ -59,7 +59,6 @@ func NewTask(description string, project string, git_id uint, git_type Type, tag
} }
func TaskTimeToGoTime(t string) time.Time { func TaskTimeToGoTime(t string) time.Time {
// TODO: apply required changes to the string for correct parsing
splits := strings.Split(t, "T") splits := strings.Split(t, "T")
if len(t) == 0 { if len(t) == 0 {
return time.UnixMicro(0) return time.UnixMicro(0)
@@ -78,6 +77,7 @@ func TaskTimeToGoTime(t string) time.Time {
second = timestamp[2:4] second = timestamp[2:4]
third = timestamp[4 : len(timestamp)-1] third = timestamp[4 : len(timestamp)-1]
timestamp = strings.Join([]string{first, second, third}, ":") 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) value := fmt.Sprintf("%sT%s+02:00", date, timestamp)
result, err := time.Parse(time.RFC3339, value) result, err := time.Parse(time.RFC3339, value)
if err != nil { if err != nil {
@@ -88,13 +88,9 @@ func TaskTimeToGoTime(t string) time.Time {
} }
func GoTimeToTaskTime(t time.Time) string { func GoTimeToTaskTime(t time.Time) string {
result := t.Format(time.RFC3339) result := t.In(time.UTC).Format(time.RFC3339)
// TODO: apply changes to the result
// go: 2023-10-10T19:57:22+02:00
// task: 20231010T195722Z
result = strings.Replace(result, "-", "", 2) result = strings.Replace(result, "-", "", 2)
result = strings.Replace(result, ":", "", 2) result = strings.Replace(result, ":", "", 2)
result = strings.ReplaceAll(result, "+02:00", "Z")
return result return result
} }

View File

@@ -1 +1,18 @@
package taskwarrior 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())
}
}