grim/youtrack-import

Parents fab48894ef61
Children f19a2cb91197
Fix timestamps for everything and support fixed versions and subsytems
--- a/bitbucket/converter.go Tue Dec 31 01:08:27 2019 -0600
+++ b/bitbucket/converter.go Tue Jan 14 01:08:46 2020 -0600
@@ -1,6 +1,8 @@
package bitbucket
import (
+ "fmt"
+
"hg.sr.ht/~grim/youtrack-import/youtrack"
)
@@ -33,11 +35,16 @@
)
func (a *Archive) convertIssue(bb Issue, userMap map[string]*youtrack.User) *youtrack.Issue {
- reporter := "guest"
+ reporter := "admin"
if user, found := userMap[bb.Reporter.AccountID]; found {
reporter = user.Login
}
+ assignee := ""
+ if user, found := userMap[bb.Assignee.AccountID]; found {
+ assignee = user.Login
+ }
+
yt := &youtrack.Issue{
Number: bb.ID,
Summary: bb.Title,
@@ -45,10 +52,15 @@
Created: bb.CreatedOn,
Updated: bb.UpdatedOn,
Reporter: reporter,
+ Assignee: assignee,
- Priority: bb.Priority,
- Type: bb.Kind,
- State: bb.Status,
+ Priority: bb.Priority,
+ Type: bb.Kind,
+ State: bb.Status,
+ Version: bb.Version,
+ Subsystem: bb.Component,
+
+ Comments: []youtrack.Comment{},
}
// TODO: check if state is resovled then set the Resolved field to the
@@ -65,9 +77,73 @@
yt.State = replace
}
+ // add the comments
+ yt.Comments = a.convertComments(userMap, bb.ID)
+
return yt
}
+func (a *Archive) convertComments(userMap map[string]*youtrack.User, id int) []youtrack.Comment {
+ comments := []youtrack.Comment{}
+
+ for _, comment := range a.Comments {
+ if comment.Issue != id {
+ continue
+ }
+
+ var ytComment youtrack.Comment
+
+ if comment.Content == "" {
+ // if we don't have a content we need to build it from the log
+ // entries
+ for _, log := range a.Logs {
+ if log.Comment == comment.ID {
+ author := "admin"
+ if user, found := userMap[log.User.AccountID]; found {
+ author = user.Login
+ }
+
+ content := ""
+ if log.Field == "content" {
+ content = "edited description"
+ } else {
+ content = fmt.Sprintf(
+ "%s: %s ⟶ %s",
+ log.Field,
+ log.ChangedFrom,
+ log.ChangedTo,
+ )
+ }
+
+ ytComment = youtrack.Comment{
+ Author: author,
+ Created: log.CreatedOn,
+ Text: content,
+ Markdown: true,
+ }
+ }
+ }
+ } else {
+ author := "admin"
+ if user, found := userMap[comment.User.AccountID]; found {
+ author = user.Login
+ }
+
+ ytComment = youtrack.Comment{
+ Author: author,
+ Text: comment.Content,
+ Created: comment.CreatedOn,
+ Updated: comment.UpdatedOn,
+ Markdown: true,
+ }
+ }
+
+ comments = append(comments, ytComment)
+ }
+
+ return comments
+}
+
func (a *Archive) convert(usersMap *UsersMap) (*youtrack.Project, error) {
users, err := a.ExtractUsers(usersMap)
if err != nil {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/youtrack/comments.go Tue Jan 14 01:08:46 2020 -0600
@@ -0,0 +1,20 @@
+package youtrack
+
+import (
+ "sort"
+ "time"
+)
+
+type Comment struct {
+ Author string
+ Text string
+ Created time.Time
+ Updated time.Time
+ Markdown bool
+}
+
+func sortComments(comments []Comment) {
+ sort.Slice(comments, func(i, j int) bool {
+ return comments[i].Created.Before(comments[j].Created)
+ })
+}
--- a/youtrack/issue.go Tue Dec 31 01:08:27 2019 -0600
+++ b/youtrack/issue.go Tue Jan 14 01:08:46 2020 -0600
@@ -17,9 +17,13 @@
UpdatedBy string `yt:"updaterName"`
Resolved time.Time `yt:"resolved"`
Reporter string `yt:"reporter"`
- Voters []string `yt:"voterName"`
- Watchers []string `yt:"watcherName"`
- PermittedGroup string `yt:"permittedGroup"`
+ Assignee string
+ Voters []string `yt:"voterName"`
+ Watchers []string `yt:"watcherName"`
+ PermittedGroup string `yt:"permittedGroup"`
+ Markdown bool
+ Version string
+ Subsystem string
Priority string `yt:"priority"`
Type string `yt:"type"`
@@ -34,16 +38,27 @@
// required fields
x.AddField("numberInProject", fmt.Sprintf("%d", i.Number))
x.AddField("summary", i.Summary)
- x.AddField("created", fmt.Sprintf("%d", i.Created.Unix()))
x.AddField("reporterName", i.Reporter)
+ x.AddField("Assignee", i.Assignee)
+ x.AddField("Type", i.Type)
+ x.AddField("Priority", i.Priority)
+ x.AddField("State", i.State)
// optional fields
+ if i.Markdown {
+ x.AddField("markdown", "true")
+ }
+
+ if !i.Created.IsZero() {
+ x.AddField("created", formatTimeString(i.Created))
+ }
+
if i.Description != "" {
x.AddField("description", i.Description)
}
if !i.Updated.IsZero() {
- x.AddField("updated", fmt.Sprintf("%d", i.Updated.Unix()))
+ x.AddField("updated", formatTimeString(i.Updated))
}
if i.UpdatedBy != "" {
@@ -66,8 +81,17 @@
x.AddField("permittedGroup", i.PermittedGroup)
}
+ if i.Version != "" {
+ x.AddField("Fix Versions", i.Version)
+ }
+
+ if i.Subsystem != "" {
+ x.AddField("Subsystem", i.Subsystem)
+ }
+
+ sortComments(i.Comments)
for _, c := range i.Comments {
- x.AddComment(c.Author, c.Text, c.Created, c.Updated)
+ x.AddComment(c.Author, c.Text, c.Created, c.Updated, c.Markdown)
}
return x
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/youtrack/time.go Tue Jan 14 01:08:46 2020 -0600
@@ -0,0 +1,18 @@
+package youtrack
+
+import (
+ "fmt"
+ "time"
+)
+
+func formatTime(t time.Time) int64 {
+ if t.IsZero() {
+ return 0
+ }
+
+ return t.Unix() * 1000
+}
+
+func formatTimeString(t time.Time) string {
+ return fmt.Sprintf("%d", formatTime(t))
+}
--- a/youtrack/types.go Tue Dec 31 01:08:27 2019 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-package youtrack
-
-import (
- "time"
-)
-
-type Comment struct {
- Author string
- Text string
- Created time.Time
- Updated time.Time
-}
--- a/youtrack/xml.go Tue Dec 31 01:08:27 2019 -0600
+++ b/youtrack/xml.go Tue Jan 14 01:08:46 2020 -0600
@@ -14,17 +14,17 @@
}
type xmlComment struct {
- XMLName xml.Name `xml:"comment"`
- Author string `xml:"author,attr,omitempty"`
- Text string `xml:"text,attr,omitempty"`
- Created int64 `xml:"created,attr,omitempty"`
- Updated int64 `xml:"updated,attr,omitempty"`
+ Author string `xml:"author,attr,omitempty"`
+ Text string `xml:"text,attr,omitempty"`
+ Created int64 `xml:"created,attr,omitempty"`
+ Updated int64 `xml:"updated,attr,omitempty"`
+ Markdown bool `xml:"markdown,attr,omitempty"`
}
type xmlIssue struct {
XMLName xml.Name `xml:"issue"`
Fields []xmlField
- Comments []xmlComment
+ Comments []xmlComment `xml:"comment,omitempty"`
}
func (x *xmlIssue) AddField(name, value string) {
@@ -35,12 +35,13 @@
x.Fields = append(x.Fields, xmlField{Name: name, Values: values})
}
-func (x *xmlIssue) AddComment(author, text string, created, updated time.Time) {
+func (x *xmlIssue) AddComment(author, text string, created, updated time.Time, markdown bool) {
c := xmlComment{
- Author: author,
- Text: text,
- Created: created.Unix(),
- Updated: updated.Unix(),
+ Author: author,
+ Text: text,
+ Created: formatTime(created),
+ Updated: formatTime(updated),
+ Markdown: markdown,
}
x.Comments = append(x.Comments, c)
@@ -54,7 +55,7 @@
type xmlImportReportItemError struct {
FieldName string `xml:"fieldName,attr"`
Value string `xml:"value,attr"`
- Message string `xml:",cdata"`
+ Message string `xml:",chardata"`
}
type xmlImportReportItem struct {
@@ -95,7 +96,7 @@
type xmlError struct {
XMLName xml.Name `xml:"error"`
- Message string `xml:",cdata"`
+ Message string `xml:",chardata"`
}
type xmlUser struct {