1package github
2
3import (
4 "context"
5 "fmt"
6 "os"
7 "testing"
8 "time"
9
10 "github.com/stretchr/testify/require"
11
12 "github.com/MichaelMure/git-bug/bridge/core"
13 "github.com/MichaelMure/git-bug/bridge/core/auth"
14 "github.com/MichaelMure/git-bug/cache"
15 "github.com/MichaelMure/git-bug/entities/bug"
16 "github.com/MichaelMure/git-bug/entities/common"
17 "github.com/MichaelMure/git-bug/entities/identity"
18 "github.com/MichaelMure/git-bug/entity/dag"
19 "github.com/MichaelMure/git-bug/repository"
20 "github.com/MichaelMure/git-bug/util/interrupt"
21)
22
23func TestGithubImporter(t *testing.T) {
24 envToken := os.Getenv("GITHUB_TOKEN_PRIVATE")
25 if envToken == "" {
26 t.Skip("Env var GITHUB_TOKEN_PRIVATE missing")
27 }
28
29 repo := repository.CreateGoGitTestRepo(t, false)
30
31 backend, buildEvents, err := cache.NewRepoCache(repo)
32 require.NoError(t, err)
33 for event := range buildEvents {
34 require.NoError(t, event.Err)
35 }
36
37 defer backend.Close()
38 interrupt.RegisterCleaner(backend.Close)
39
40 author, err := identity.NewIdentity(repo, "Michael Muré", "batolettre@gmail.com")
41 require.NoError(t, err)
42
43 tests := []struct {
44 name string
45 url string
46 bug *bug.Snapshot
47 }{
48 {
49 name: "simple issue",
50 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/1",
51 bug: &bug.Snapshot{
52 Operations: []dag.Operation{
53 bug.NewCreateOp(author, 0, "simple issue", "initial comment", nil),
54 bug.NewAddCommentOp(author, 0, "first comment", nil),
55 bug.NewAddCommentOp(author, 0, "second comment", nil),
56 },
57 },
58 },
59 {
60 name: "empty issue",
61 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/2",
62 bug: &bug.Snapshot{
63 Operations: []dag.Operation{
64 bug.NewCreateOp(author, 0, "empty issue", "", nil),
65 },
66 },
67 },
68 {
69 name: "complex issue",
70 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/3",
71 bug: &bug.Snapshot{
72 Operations: []dag.Operation{
73 bug.NewCreateOp(author, 0, "complex issue", "initial comment", nil),
74 bug.NewLabelChangeOperation(author, 0, []bug.Label{"bug"}, []bug.Label{}),
75 bug.NewLabelChangeOperation(author, 0, []bug.Label{"duplicate"}, []bug.Label{}),
76 bug.NewLabelChangeOperation(author, 0, []bug.Label{}, []bug.Label{"duplicate"}),
77 bug.NewAddCommentOp(author, 0, "### header\n\n**bold**\n\n_italic_\n\n> with quote\n\n`inline code`\n\n```\nmultiline code\n```\n\n- bulleted\n- list\n\n1. numbered\n1. list\n\n- [ ] task\n- [x] list\n\n@MichaelMure mention\n\n#2 reference issue\n#3 auto-reference issue\n\n", nil),
78 bug.NewSetTitleOp(author, 0, "complex issue edited", "complex issue"),
79 bug.NewSetTitleOp(author, 0, "complex issue", "complex issue edited"),
80 bug.NewSetStatusOp(author, 0, common.ClosedStatus),
81 bug.NewSetStatusOp(author, 0, common.OpenStatus),
82 },
83 },
84 },
85 {
86 name: "editions",
87 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/4",
88 bug: &bug.Snapshot{
89 Operations: []dag.Operation{
90 bug.NewCreateOp(author, 0, "editions", "initial comment edited", nil),
91 bug.NewEditCommentOp(author, 0, "", "erased then edited again", nil),
92 bug.NewAddCommentOp(author, 0, "first comment", nil),
93 bug.NewEditCommentOp(author, 0, "", "first comment edited", nil),
94 },
95 },
96 },
97 {
98 name: "comment deletion",
99 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/5",
100 bug: &bug.Snapshot{
101 Operations: []dag.Operation{
102 bug.NewCreateOp(author, 0, "comment deletion", "", nil),
103 },
104 },
105 },
106 {
107 name: "edition deletion",
108 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/6",
109 bug: &bug.Snapshot{
110 Operations: []dag.Operation{
111 bug.NewCreateOp(author, 0, "edition deletion", "initial comment", nil),
112 bug.NewEditCommentOp(author, 0, "", "initial comment edited again", nil),
113 bug.NewAddCommentOp(author, 0, "first comment", nil),
114 bug.NewEditCommentOp(author, 0, "", "first comment edited again", nil),
115 },
116 },
117 },
118 {
119 name: "hidden comment",
120 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/7",
121 bug: &bug.Snapshot{
122 Operations: []dag.Operation{
123 bug.NewCreateOp(author, 0, "hidden comment", "initial comment", nil),
124 bug.NewAddCommentOp(author, 0, "first comment", nil),
125 },
126 },
127 },
128 {
129 name: "transfered issue",
130 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/8",
131 bug: &bug.Snapshot{
132 Operations: []dag.Operation{
133 bug.NewCreateOp(author, 0, "transfered issue", "", nil),
134 },
135 },
136 },
137 {
138 name: "unicode control characters",
139 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/10",
140 bug: &bug.Snapshot{
141 Operations: []dag.Operation{
142 bug.NewCreateOp(author, 0, "unicode control characters", "u0000: \nu0001: \nu0002: \nu0003: \nu0004: \nu0005: \nu0006: \nu0007: \nu0008: \nu0009: \t\nu0010: \nu0011: \nu0012: \nu0013: \nu0014: \nu0015: \nu0016: \nu0017: \nu0018: \nu0019:", nil),
143 },
144 },
145 },
146 }
147
148 login := "test-identity"
149 author.SetMetadata(metaKeyGithubLogin, login)
150
151 token := auth.NewToken(target, envToken)
152 token.SetMetadata(auth.MetaKeyLogin, login)
153 err = auth.Store(repo, token)
154 require.NoError(t, err)
155
156 ctx := context.Background()
157
158 importer := &githubImporter{}
159 err = importer.Init(ctx, backend, core.Configuration{
160 confKeyOwner: "MichaelMure",
161 confKeyProject: "git-bug-test-github-bridge",
162 confKeyDefaultLogin: login,
163 })
164 require.NoError(t, err)
165
166 start := time.Now()
167
168 events, err := importer.ImportAll(ctx, backend, time.Time{})
169 require.NoError(t, err)
170
171 for result := range events {
172 require.NoError(t, result.Err)
173 }
174
175 fmt.Printf("test repository imported in %f seconds\n", time.Since(start).Seconds())
176
177 require.Len(t, backend.Bugs().AllIds(), len(tests))
178
179 for _, tt := range tests {
180 t.Run(tt.name, func(t *testing.T) {
181 b, err := backend.Bugs().ResolveBugCreateMetadata(metaKeyGithubUrl, tt.url)
182 require.NoError(t, err)
183
184 ops := b.Snapshot().Operations
185 require.Len(t, tt.bug.Operations, len(b.Snapshot().Operations))
186
187 for i, op := range tt.bug.Operations {
188 require.IsType(t, ops[i], op)
189 require.Equal(t, op.Author().Name(), ops[i].Author().Name())
190
191 switch op := op.(type) {
192 case *bug.CreateOperation:
193 require.Equal(t, op.Title, ops[i].(*bug.CreateOperation).Title)
194 require.Equal(t, op.Message, ops[i].(*bug.CreateOperation).Message)
195 case *bug.SetStatusOperation:
196 require.Equal(t, op.Status, ops[i].(*bug.SetStatusOperation).Status)
197 case *bug.SetTitleOperation:
198 require.Equal(t, op.Was, ops[i].(*bug.SetTitleOperation).Was)
199 require.Equal(t, op.Title, ops[i].(*bug.SetTitleOperation).Title)
200 case *bug.LabelChangeOperation:
201 require.ElementsMatch(t, op.Added, ops[i].(*bug.LabelChangeOperation).Added)
202 require.ElementsMatch(t, op.Removed, ops[i].(*bug.LabelChangeOperation).Removed)
203 case *bug.AddCommentOperation:
204 require.Equal(t, op.Message, ops[i].(*bug.AddCommentOperation).Message)
205 case *bug.EditCommentOperation:
206 require.Equal(t, op.Message, ops[i].(*bug.EditCommentOperation).Message)
207
208 default:
209 panic("unknown operation type")
210 }
211 }
212 })
213 }
214}