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