191 lines
5.3 KiB
Go
191 lines
5.3 KiB
Go
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
|
|
}
|