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, err := cache.NewRepoCacheNoEvents(repo)
32 require.NoError(t, err)
33
34 defer backend.Close()
35 interrupt.RegisterCleaner(backend.Close)
36
37 author, err := identity.NewIdentity(repo, "Michael Muré", "batolettre@gmail.com")
38 require.NoError(t, err)
39
40 tests := []struct {
41 name string
42 url string
43 bug *bug.Snapshot
44 }{
45 {
46 name: "simple issue",
47 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/1",
48 bug: &bug.Snapshot{
49 Operations: []dag.Operation{
50 bug.NewCreateOp(author, 0, "simple issue", "initial comment", nil),
51 bug.NewAddCommentOp(author, 0, "first comment", nil),
52 bug.NewAddCommentOp(author, 0, "second comment", nil),
53 },
54 },
55 },
56 {
57 name: "empty issue",
58 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/2",
59 bug: &bug.Snapshot{
60 Operations: []dag.Operation{
61 bug.NewCreateOp(author, 0, "empty issue", "", nil),
62 },
63 },
64 },
65 {
66 name: "complex issue",
67 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/3",
68 bug: &bug.Snapshot{
69 Operations: []dag.Operation{
70 bug.NewCreateOp(author, 0, "complex issue", "initial comment", nil),
71 bug.NewLabelChangeOperation(author, 0, []bug.Label{"bug"}, []bug.Label{}),
72 bug.NewLabelChangeOperation(author, 0, []bug.Label{"duplicate"}, []bug.Label{}),
73 bug.NewLabelChangeOperation(author, 0, []bug.Label{}, []bug.Label{"duplicate"}),
74 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),
75 bug.NewSetTitleOp(author, 0, "complex issue edited", "complex issue"),
76 bug.NewSetTitleOp(author, 0, "complex issue", "complex issue edited"),
77 bug.NewSetStatusOp(author, 0, common.ClosedStatus),
78 bug.NewSetStatusOp(author, 0, common.OpenStatus),
79 },
80 },
81 },
82 {
83 name: "editions",
84 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/4",
85 bug: &bug.Snapshot{
86 Operations: []dag.Operation{
87 bug.NewCreateOp(author, 0, "editions", "initial comment edited", nil),
88 bug.NewEditCommentOp(author, 0, "", "erased then edited again", nil),
89 bug.NewAddCommentOp(author, 0, "first comment", nil),
90 bug.NewEditCommentOp(author, 0, "", "first comment edited", nil),
91 },
92 },
93 },
94 {
95 name: "comment deletion",
96 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/5",
97 bug: &bug.Snapshot{
98 Operations: []dag.Operation{
99 bug.NewCreateOp(author, 0, "comment deletion", "", nil),
100 },
101 },
102 },
103 {
104 name: "edition deletion",
105 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/6",
106 bug: &bug.Snapshot{
107 Operations: []dag.Operation{
108 bug.NewCreateOp(author, 0, "edition deletion", "initial comment", nil),
109 bug.NewEditCommentOp(author, 0, "", "initial comment edited again", nil),
110 bug.NewAddCommentOp(author, 0, "first comment", nil),
111 bug.NewEditCommentOp(author, 0, "", "first comment edited again", nil),
112 },
113 },
114 },
115 {
116 name: "hidden comment",
117 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/7",
118 bug: &bug.Snapshot{
119 Operations: []dag.Operation{
120 bug.NewCreateOp(author, 0, "hidden comment", "initial comment", nil),
121 bug.NewAddCommentOp(author, 0, "first comment", nil),
122 },
123 },
124 },
125 {
126 name: "transferred issue",
127 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/8",
128 bug: &bug.Snapshot{
129 Operations: []dag.Operation{
130 bug.NewCreateOp(author, 0, "transferred issue", "", nil),
131 },
132 },
133 },
134 {
135 name: "unicode control characters",
136 url: "https://github.com/MichaelMure/git-bug-test-github-bridge/issues/10",
137 bug: &bug.Snapshot{
138 Operations: []dag.Operation{
139 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),
140 },
141 },
142 },
143 }
144
145 login := "test-identity"
146 author.SetMetadata(metaKeyGithubLogin, login)
147
148 token := auth.NewToken(target, envToken)
149 token.SetMetadata(auth.MetaKeyLogin, login)
150 err = auth.Store(repo, token)
151 require.NoError(t, err)
152
153 ctx := context.Background()
154
155 importer := &githubImporter{}
156 err = importer.Init(ctx, backend, core.Configuration{
157 confKeyOwner: "MichaelMure",
158 confKeyProject: "git-bug-test-github-bridge",
159 confKeyDefaultLogin: login,
160 })
161 require.NoError(t, err)
162
163 start := time.Now()
164
165 events, err := importer.ImportAll(ctx, backend, time.Time{})
166 require.NoError(t, err)
167
168 for result := range events {
169 require.NoError(t, result.Err)
170 }
171
172 fmt.Printf("test repository imported in %f seconds\n", time.Since(start).Seconds())
173
174 require.Len(t, backend.Bugs().AllIds(), len(tests))
175
176 for _, tt := range tests {
177 t.Run(tt.name, func(t *testing.T) {
178 b, err := backend.Bugs().ResolveBugCreateMetadata(metaKeyGithubUrl, tt.url)
179 require.NoError(t, err)
180
181 ops := b.Snapshot().Operations
182 require.Len(t, tt.bug.Operations, len(b.Snapshot().Operations))
183
184 for i, op := range tt.bug.Operations {
185 require.IsType(t, ops[i], op)
186 require.Equal(t, op.Author().Name(), ops[i].Author().Name())
187
188 switch op := op.(type) {
189 case *bug.CreateOperation:
190 require.Equal(t, op.Title, ops[i].(*bug.CreateOperation).Title)
191 require.Equal(t, op.Message, ops[i].(*bug.CreateOperation).Message)
192 case *bug.SetStatusOperation:
193 require.Equal(t, op.Status, ops[i].(*bug.SetStatusOperation).Status)
194 case *bug.SetTitleOperation:
195 require.Equal(t, op.Was, ops[i].(*bug.SetTitleOperation).Was)
196 require.Equal(t, op.Title, ops[i].(*bug.SetTitleOperation).Title)
197 case *bug.LabelChangeOperation:
198 require.ElementsMatch(t, op.Added, ops[i].(*bug.LabelChangeOperation).Added)
199 require.ElementsMatch(t, op.Removed, ops[i].(*bug.LabelChangeOperation).Removed)
200 case *bug.AddCommentOperation:
201 require.Equal(t, op.Message, ops[i].(*bug.AddCommentOperation).Message)
202 case *bug.EditCommentOperation:
203 require.Equal(t, op.Message, ops[i].(*bug.EditCommentOperation).Message)
204
205 default:
206 panic("unknown operation type")
207 }
208 }
209 })
210 }
211}