@@ -2,10 +2,11 @@ package gerritapi import ( "context" "fmt" "net/http" "os" "sort" "strings" "unicode" @@ -26,32 +27,35 @@ func NewService(client *gerrit.Client) change.Service { type service struct { cl *gerrit.Client domain string } func (s service) List(ctx context.Context, rs string, opt change.ListOptions) ([]change.Change, error) { project := project(rs) func (s service) List(ctx context.Context, repo string, opt change.ListOptions) ([]change.Change, error) { project := project(repo) var query string switch opt.Filter { case change.FilterOpen: query = fmt.Sprintf("project:%s status:open", project) case change.FilterClosedMerged: // "status:closed" is equivalent to "(status:abandoned OR status:merged)". query = fmt.Sprintf("project:%s status:closed", project) case change.FilterAll: query = fmt.Sprintf("project:%s", project) } cs, _, err := s.cl.Changes.QueryChanges(&gerrit.QueryChangeOptions{ cs, resp, err := s.cl.Changes.QueryChanges(&gerrit.QueryChangeOptions{ QueryOptions: gerrit.QueryOptions{ Query: []string{query}, Limit: 25, }, ChangeOptions: gerrit.ChangeOptions{ AdditionalFields: []string{"DETAILED_ACCOUNTS", "MESSAGES"}, }, }) if err != nil { if resp != nil && resp.StatusCode == http.StatusNotFound { return nil, os.ErrNotExist } return nil, err } var is []change.Change for _, chg := range *cs { if chg.Status == "DRAFT" { @@ -76,15 +80,19 @@ func (s service) List(ctx context.Context, rs string, opt change.ListOptions) ([ func (s service) Count(_ context.Context, repo string, opt change.ListOptions) (uint64, error) { // TODO. return 0, nil } func (s service) Get(ctx context.Context, _ string, id uint64) (change.Change, error) { chg, _, err := s.cl.Changes.GetChange(fmt.Sprint(id), &gerrit.ChangeOptions{ func (s service) Get(ctx context.Context, repo string, id uint64) (change.Change, error) { project := project(repo) chg, resp, err := s.cl.Changes.GetChange(fmt.Sprintf("%s~%d", project, id), &gerrit.ChangeOptions{ AdditionalFields: []string{"DETAILED_ACCOUNTS", "MESSAGES", "ALL_REVISIONS"}, }) if err != nil { if resp != nil && resp.StatusCode == http.StatusNotFound { return change.Change{}, os.ErrNotExist } return change.Change{}, err } if chg.Status == "DRAFT" { return change.Change{}, os.ErrNotExist } @@ -113,16 +121,20 @@ func state(status string) change.State { default: panic("unreachable") } } func (s service) ListCommits(ctx context.Context, _ string, id uint64) ([]change.Commit, error) { chg, _, err := s.cl.Changes.GetChange(fmt.Sprint(id), &gerrit.ChangeOptions{ func (s service) ListCommits(ctx context.Context, repo string, id uint64) ([]change.Commit, error) { project := project(repo) chg, resp, err := s.cl.Changes.GetChange(fmt.Sprintf("%s~%d", project, id), &gerrit.ChangeOptions{ AdditionalFields: []string{"DETAILED_ACCOUNTS", "ALL_REVISIONS"}, //AdditionalFields: []string{"ALL_REVISIONS", "ALL_COMMITS"}, // TODO: Consider using git committer/author instead... }) if err != nil { if resp != nil && resp.StatusCode == http.StatusNotFound { return nil, os.ErrNotExist } return nil, err } if chg.Status == "DRAFT" { return nil, os.ErrNotExist } @@ -137,23 +149,30 @@ func (s service) ListCommits(ctx context.Context, _ string, id uint64) ([]change } } return commits, nil } func (s service) GetDiff(ctx context.Context, _ string, id uint64, opt *change.GetDiffOptions) ([]byte, error) { func (s service) GetDiff(ctx context.Context, repo string, id uint64, opt *change.GetDiffOptions) ([]byte, error) { project := project(repo) switch opt { case nil: diff, _, err := s.cl.Changes.GetPatch(fmt.Sprint(id), "current", nil) diff, resp, err := s.cl.Changes.GetPatch(fmt.Sprintf("%s~%d", project, id), "current", nil) if err != nil { if resp != nil && resp.StatusCode == http.StatusNotFound { return nil, os.ErrNotExist } return nil, err } return []byte(*diff), nil default: chg, _, err := s.cl.Changes.GetChange(fmt.Sprint(id), &gerrit.ChangeOptions{ chg, resp, err := s.cl.Changes.GetChange(fmt.Sprintf("%s~%d", project, id), &gerrit.ChangeOptions{ AdditionalFields: []string{"ALL_REVISIONS"}, }) if err != nil { if resp != nil && resp.StatusCode == http.StatusNotFound { return nil, os.ErrNotExist } return nil, err } if chg.Status == "DRAFT" { return nil, os.ErrNotExist } @@ -166,11 +185,11 @@ func (s service) GetDiff(ctx context.Context, _ string, id uint64, opt *change.G case 1: base = "" default: base = fmt.Sprint(r.Number - 1) } files, _, err := s.cl.Changes.ListFiles(fmt.Sprint(id), opt.Commit, &gerrit.FilesOptions{ files, _, err := s.cl.Changes.ListFiles(fmt.Sprintf("%s~%d", project, id), opt.Commit, &gerrit.FilesOptions{ Base: base, }) if err != nil { return nil, err } @@ -179,11 +198,11 @@ func (s service) GetDiff(ctx context.Context, _ string, id uint64, opt *change.G sortedFiles = append(sortedFiles, file) } sort.Strings(sortedFiles) var diff string for _, file := range sortedFiles { diffInfo, _, err := s.cl.Changes.GetDiff(fmt.Sprint(id), opt.Commit, file, &gerrit.DiffOptions{ diffInfo, _, err := s.cl.Changes.GetDiff(fmt.Sprintf("%s~%d", project, id), opt.Commit, file, &gerrit.DiffOptions{ Base: base, Context: "5", }) if err != nil { return nil, err @@ -231,18 +250,22 @@ func (s service) GetDiff(ctx context.Context, _ string, id uint64, opt *change.G } return []byte(diff), nil } } func (s service) ListTimeline(ctx context.Context, _ string, id uint64, opt *change.ListTimelineOptions) ([]interface{}, error) { func (s service) ListTimeline(ctx context.Context, repo string, id uint64, opt *change.ListTimelineOptions) ([]interface{}, error) { // TODO: Pagination. Respect opt.Start and opt.Length, if given. chg, _, err := s.cl.Changes.GetChangeDetail(fmt.Sprint(id), nil) project := project(repo) chg, resp, err := s.cl.Changes.GetChangeDetail(fmt.Sprintf("%s~%d", project, id), nil) if err != nil { if resp != nil && resp.StatusCode == http.StatusNotFound { return nil, os.ErrNotExist } return nil, err } comments, _, err := s.cl.Changes.ListChangeComments(fmt.Sprint(id)) comments, _, err := s.cl.Changes.ListChangeComments(fmt.Sprintf("%s~%d", project, id)) if err != nil { return nil, err } var timeline []interface{} timeline = append(timeline, change.Comment{ // CL description.