@@ -6,14 +6,14 @@ import (
"fmt"
"os"
"sort"
"strings"
"time"
"unicode"
"dmitri.shuralyov.com/changes"
"github.com/andygrunwald/go-gerrit"
"github.com/shurcooL/issues"
"github.com/shurcooL/users"
)
// NewService creates a Gerrit-backed issues.Service using given Gerrit client.
// client must be non-nil.
@@ -243,48 +243,126 @@ func (s service) GetDiff(ctx context.Context, _ string, id uint64, opt *changes.
}
return []byte(diff), nil
}
}
func (s service) ListComments(ctx context.Context, _ string, id uint64, opt *changes.ListCommentsOptions) ([]issues.Comment, error) {
func (s service) ListTimeline(ctx context.Context, _ string, id uint64, opt *changes.ListTimelineOptions) ([]interface{}, error) {
// TODO: Pagination. Respect opt.Start and opt.Length, if given.
change, _, err := s.cl.Changes.GetChangeDetail(fmt.Sprint(id), nil)
if err != nil {
return nil, err
}
var comments []issues.Comment
var timeline []interface{}
{
timeline = append(timeline, changes.Comment{
ID: 0,
User: s.gerritUser(change.Owner),
CreatedAt: time.Time(change.Created),
Body: "", // THINK: Include commit message or no?
Editable: false,
})
}
for idx, message := range change.Messages {
if strings.HasPrefix(message.Tag, "autogenerated:") {
continue
}
comments = append(comments, issues.Comment{
label, body, ok := parseMessage(message.Message)
if !ok {
continue
}
switch label {
case "Code-Review+2":
timeline = append(timeline, changes.TimelineItem{
Actor: s.gerritUser(message.Author),
CreatedAt: time.Time(message.Date),
Payload: changes.ApprovedEvent{},
})
case "Code-Review-2":
timeline = append(timeline, changes.TimelineItem{
Actor: s.gerritUser(message.Author),
CreatedAt: time.Time(message.Date),
Payload: changes.ChangesRequestedEvent{},
})
}
if body == "" {
continue
}
timeline = append(timeline, changes.Comment{
ID: uint64(idx), // TODO: message.ID is not uint64; e.g., "bfba753d015916303152305cee7152ea7a112fe0".
User: s.gerritUser(message.Author),
CreatedAt: time.Time(message.Date),
Body: message.Message,
Body: body,
Editable: false,
})
}
return comments, nil
return timeline, nil
}
func (s service) ListEvents(ctx context.Context, _ string, id uint64, opt *changes.ListCommentsOptions) ([]issues.Event, error) {
// TODO.
return nil, nil
func parseMessage(m string) (label string, body string, ok bool) {
// "Patch Set ".
if !strings.HasPrefix(m, "Patch Set ") {
return "", "", false
}
m = m[len("Patch Set "):]
// "123".
i := strings.IndexFunc(m, func(c rune) bool { return !unicode.IsNumber(c) })
if i == -1 {
return "", "", false
}
m = m[i:]
// ":".
if len(m) < 1 || m[0] != ':' {
return "", "", false
}
m = m[1:]
switch i = strings.IndexByte(m, '\n'); i {
case -1:
label = m
default:
label = m[:i]
body = m[i+1:]
}
if label != "" {
// " ".
if len(label) < 1 || label[0] != ' ' {
return "", "", false
}
label = label[1:]
}
if body != "" {
// "\n".
if len(body) < 1 || body[0] != '\n' {
return "", "", false
}
body = body[1:]
}
return label, body, true
}
func (s service) gerritUser(user gerrit.AccountInfo) users.User {
var avatarURL string
for _, avatar := range user.Avatars {
if avatar.Height == 100 {
avatarURL = avatar.URL
}
}
return users.User{
UserSpec: users.UserSpec{
ID: uint64(user.AccountID),
Domain: s.domain,
},
Login: user.Name, //user.Username, // TODO.
Name: user.Name,
//Email: user.Email,
AvatarURL: fmt.Sprintf("https://%s/accounts/%d/avatar?s=96", s.domain, user.AccountID),
AvatarURL: avatarURL,
}
}
func project(repo string) string {
if i := strings.IndexByte(repo, '/'); i != -1 {