package gitw import ( "errors" "fmt" "gitea.yves-biener.de/yves-biener/gitwarrior/internal/gitea" "gitea.yves-biener.de/yves-biener/gitwarrior/internal/taskwarrior" ) type Project struct { server gitea.Gitea repository gitea.Repository issues []Issue milestones []gitea.Milestone } func NewProject(server gitea.Gitea, repository gitea.Repository) Project { return Project{ server: server, repository: repository, } } func (project *Project) Pull() error { if err := project.Fetch(); err != nil { return err } if err := project.merge(); err != nil { return err } return nil } func (project *Project) Fetch() error { comments, err := project.server.GetComments(project.repository) if err != nil { return err } issues, err := project.server.GetIssues(project.repository) if err != nil { return err } project.milestones, err = project.server.GetMilestones(project.repository) if err != nil { return err } for _, issue := range issues { var issue_comments []gitea.Comment for _, comment := range comments { if comment.Issue_url == issue.Html_url { issue_comments = append(issue_comments, comment) } } project.issues = append(project.issues, Issue{ git_issue: issue, comments: issue_comments, }) } return nil } // TODO: tasks should include the corresponding time's of the git related issues and milestones func (project *Project) merge() error { var tasks []taskwarrior.Task var filter taskwarrior.Filter // TODO: merge milestones for _, milestone := range project.milestones { filter.Reset() filter.IncludeGitId(milestone.Id) filter.IncludeGitType(taskwarrior.MILESTONE) git_tasks, err := taskwarrior.GetTasks(filter) if err != nil { return err } var task taskwarrior.Task if len(git_tasks) > 1 { return errors.New("Git milestone id was at least used twice in taskwarrior tasks.") } else if len(git_tasks) == 0 { // NOTE: ignore closed milestones which do not have a taskwarrior task if milestone.State == string(gitea.CLOSED) { continue } // NOTE: this milestone does not yet exist task = taskwarrior.NewTask( milestone.Title, project.repository.Name, milestone.Id, taskwarrior.MILESTONE, ) task.Due = taskwarrior.GoTimeToTaskTime(milestone.Due_on) task.Entry = taskwarrior.GoTimeToTaskTime(milestone.Created_at) task.Modified = taskwarrior.GoTimeToTaskTime(milestone.Updated_at) task.AppendComment(milestone.Description, milestone.Updated_at) fmt.Printf("\tCreated milestone: '%s'\n", task.Description) tasks = append(tasks, task) } else { // NOTE: there is exactly one git_task task = milestone.Merge(git_tasks[0]) fmt.Printf("\tUpdated milestone: '%s'\n", task.Description) tasks = append(tasks, task) } } // NOTE: merge tasks // TODO: link milestones into tasks for _, issue := range project.issues { filter.Reset() filter.IncludeGitId(issue.git_issue.Id) filter.IncludeGitType(taskwarrior.ISSUE) git_tasks, err := taskwarrior.GetTasks(filter) if err != nil { return err } var task taskwarrior.Task if len(git_tasks) > 1 { return errors.New("Git issue id was at least used twice in taskwarrior tasks.") } else if len(git_tasks) == 0 { // NOTE: ignore closed issues which do not have a taskwarrior task if issue.git_issue.State == string(gitea.CLOSED) { continue } // NOTE: this task does not yet exist task = taskwarrior.NewTask( issue.git_issue.Title, project.repository.Name, issue.git_issue.Id, taskwarrior.ISSUE, issue.git_issue.Labels..., ) task.Entry = taskwarrior.GoTimeToTaskTime(issue.git_issue.Created_at) task.Modified = taskwarrior.GoTimeToTaskTime(issue.git_issue.Updated_at) for _, comment := range issue.comments { task.AppendComment(comment.Body, comment.Updated_at) } fmt.Printf("\tCreated task: '%s'\n", task.Description) tasks = append(tasks, task) } else { // NOTE: there is excactly one git_task task = issue.merge(git_tasks[0]) fmt.Printf("\tUpdated task: '%s'\n", task.Description) tasks = append(tasks, task) } } // TODO: dry-run switch if false { return taskwarrior.UpdateTasks(tasks) } return nil } type Issue struct { git_issue gitea.Issue comments []gitea.Comment } func (i *Issue) into() (taskwarrior.Task, error) { // TODO: identify if issue is already an existing task var filter taskwarrior.Filter filter.IncludeGitId(i.git_issue.Id) filter.IncludeGitType(taskwarrior.ISSUE) tasks, err := taskwarrior.GetTasks(filter) if err != nil { // this means that a task for this issue does not exist yet return taskwarrior.NewTask( i.git_issue.Title, i.git_issue.Repository.Name, i.git_issue.Id, taskwarrior.ISSUE, i.git_issue.Labels..., ), nil } else { // this means that a task exists and it needs to be merged if len(tasks) != 1 { return taskwarrior.Task{}, errors.New("Did not find exactly one task for a given issue.Id") } return i.merge(tasks[0]), nil } } // TODO: implement merging of git issue or milestone into a taskwarrior task func (i *Issue) merge(task taskwarrior.Task) taskwarrior.Task { // TODO: issue values into task: // - is the issue more recent than the task? // - apply changes into task // - in case of merge conflicts ask user for corresponding action: // 1. use theirs // 2. use mine // 3. use provided value return task }