+4
-1
appview/db/db.go
+4
-1
appview/db/db.go
···
109
109
repo_at text not null,
110
110
pull_id integer not null,
111
111
title text not null,
112
+
body text not null,
112
113
patch text,
113
-
patch_at text not null,
114
+
pull_at text,
115
+
rkey text not null,
116
+
target_branch text not null,
114
117
open integer not null default 1,
115
118
created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
116
119
unique(repo_at, pull_id),
+46
-43
appview/db/pulls.go
+46
-43
appview/db/pulls.go
···
7
7
"github.com/bluesky-social/indigo/atproto/syntax"
8
8
)
9
9
10
-
type Pulls struct {
11
-
ID int `json:"id"`
12
-
OwnerDid string `json:"owner_did"`
13
-
RepoAt string `json:"repo_at"`
14
-
PullId int `json:"pull_id"`
15
-
Title string `json:"title"`
16
-
Patch string `json:"patch,omitempty"`
17
-
PatchAt string `json:"patch_at"`
18
-
Open int `json:"open"`
19
-
Created time.Time `json:"created"`
10
+
type Pull struct {
11
+
ID int
12
+
OwnerDid string
13
+
RepoAt syntax.ATURI
14
+
PullAt syntax.ATURI
15
+
TargetBranch string
16
+
Patch string
17
+
PullId int
18
+
Title string
19
+
Body string
20
+
Open int
21
+
Created time.Time
22
+
Rkey string
20
23
}
21
24
22
-
type PullComments struct {
23
-
ID int `json:"id"`
24
-
OwnerDid string `json:"owner_did"`
25
-
PullId int `json:"pull_id"`
26
-
RepoAt string `json:"repo_at"`
27
-
CommentId int `json:"comment_id"`
28
-
CommentAt string `json:"comment_at"`
29
-
Body string `json:"body"`
30
-
Created time.Time `json:"created"`
25
+
type PullComment struct {
26
+
ID int
27
+
OwnerDid string
28
+
PullId int
29
+
RepoAt string
30
+
CommentId int
31
+
CommentAt string
32
+
Body string
33
+
Created time.Time
31
34
}
32
35
33
-
func NewPull(tx *sql.Tx, pull *Pulls) error {
36
+
func NewPull(tx *sql.Tx, pull *Pull) error {
34
37
defer tx.Rollback()
35
38
36
39
_, err := tx.Exec(`
···
55
58
pull.PullId = nextId
56
59
57
60
_, err = tx.Exec(`
58
-
insert into pulls (repo_at, owner_did, pull_id, title, patch)
59
-
values (?, ?, ?, ?, ?)
60
-
`, pull.RepoAt, pull.OwnerDid, pull.PullId, pull.Title, pull.Patch)
61
+
insert into pulls (repo_at, owner_did, pull_id, title, target_branch, body, patch, rkey)
62
+
values (?, ?, ?, ?, ?, ?, ?, ?)
63
+
`, pull.RepoAt, pull.OwnerDid, pull.PullId, pull.Title, pull.TargetBranch, pull.Body, pull.Patch, pull.Rkey)
61
64
if err != nil {
62
65
return err
63
66
}
···
70
73
}
71
74
72
75
func SetPullAt(e Execer, repoAt syntax.ATURI, pullId int, pullAt string) error {
73
-
_, err := e.Exec(`update pulls set patch_at = ? where repo_at = ? and pull_id = ?`, pullAt, repoAt, pullId)
76
+
_, err := e.Exec(`update pulls set pull_at = ? where repo_at = ? and pull_id = ?`, pullAt, repoAt, pullId)
74
77
return err
75
78
}
76
79
77
80
func GetPullAt(e Execer, repoAt syntax.ATURI, pullId int) (string, error) {
78
81
var pullAt string
79
-
err := e.QueryRow(`select patch_at from pulls where repo_at = ? and pull_id = ?`, repoAt, pullId).Scan(&pullAt)
82
+
err := e.QueryRow(`select pull_at from pulls where repo_at = ? and pull_id = ?`, repoAt, pullId).Scan(&pullAt)
80
83
return pullAt, err
81
84
}
82
85
···
92
95
return ownerDid, err
93
96
}
94
97
95
-
func GetPulls(e Execer, repoAt syntax.ATURI) ([]Pulls, error) {
96
-
var pulls []Pulls
98
+
func GetPulls(e Execer, repoAt syntax.ATURI) ([]Pull, error) {
99
+
var pulls []Pull
97
100
98
-
rows, err := e.Query(`select owner_did, pull_id, created, title, patch, open from pulls where repo_at = ? order by created desc`, repoAt)
101
+
rows, err := e.Query(`select owner_did, pull_id, created, title, open, target_branch, pull_at, body, patch, rkey from pulls where repo_at = ? order by created desc`, repoAt)
99
102
if err != nil {
100
103
return nil, err
101
104
}
102
105
defer rows.Close()
103
106
104
107
for rows.Next() {
105
-
var pull Pulls
108
+
var pull Pull
106
109
var createdAt string
107
-
err := rows.Scan(&pull.OwnerDid, &pull.PullId, &createdAt, &pull.Title, &pull.Patch, &pull.Open)
110
+
err := rows.Scan(&pull.OwnerDid, &pull.PullId, &createdAt, &pull.Title, &pull.Open, &pull.TargetBranch, &pull.PullAt, &pull.Body, &pull.Patch, &pull.Rkey)
108
111
if err != nil {
109
112
return nil, err
110
113
}
···
125
128
return pulls, nil
126
129
}
127
130
128
-
func GetPull(e Execer, repoAt syntax.ATURI, pullId int) (*Pulls, error) {
129
-
query := `select owner_did, created, title, patch, open from pulls where repo_at = ? and pull_id = ?`
131
+
func GetPull(e Execer, repoAt syntax.ATURI, pullId int) (*Pull, error) {
132
+
query := `select owner_did, created, title, open, target_branch, pull_at, body, patch, rkey from pulls where repo_at = ? and pull_id = ?`
130
133
row := e.QueryRow(query, repoAt, pullId)
131
134
132
-
var pull Pulls
135
+
var pull Pull
133
136
var createdAt string
134
-
err := row.Scan(&pull.OwnerDid, &createdAt, &pull.Title, &pull.Patch, &pull.Open)
137
+
err := row.Scan(&pull.OwnerDid, &createdAt, &pull.Title, &pull.Open, &pull.TargetBranch, &pull.PullAt, &pull.Body, &pull.Patch, &pull.Rkey)
135
138
if err != nil {
136
139
return nil, err
137
140
}
···
145
148
return &pull, nil
146
149
}
147
150
148
-
func GetPullWithComments(e Execer, repoAt syntax.ATURI, pullId int) (*Pulls, []PullComments, error) {
149
-
query := `select owner_did, pull_id, created, title, patch, open from pulls where repo_at = ? and pull_id = ?`
151
+
func GetPullWithComments(e Execer, repoAt syntax.ATURI, pullId int) (*Pull, []PullComment, error) {
152
+
query := `select owner_did, pull_id, created, title, open, target_branch, pull_at, body, patch, rkey from pulls where repo_at = ? and pull_id = ?`
150
153
row := e.QueryRow(query, repoAt, pullId)
151
154
152
-
var pull Pulls
155
+
var pull Pull
153
156
var createdAt string
154
-
err := row.Scan(&pull.OwnerDid, &pull.PullId, &createdAt, &pull.Title, &pull.Patch, &pull.Open)
157
+
err := row.Scan(&pull.OwnerDid, &pull.PullId, &createdAt, &pull.Title, &pull.Open, &pull.TargetBranch, &pull.PullAt, &pull.Body, &pull.Patch, &pull.Rkey)
155
158
if err != nil {
156
159
return nil, nil, err
157
160
}
···
170
173
return &pull, comments, nil
171
174
}
172
175
173
-
func NewPullComment(e Execer, comment *PullComments) error {
176
+
func NewPullComment(e Execer, comment *PullComment) error {
174
177
query := `insert into pull_comments (owner_did, repo_at, comment_at, pull_id, comment_id, body) values (?, ?, ?, ?, ?, ?)`
175
178
_, err := e.Exec(
176
179
query,
···
184
187
return err
185
188
}
186
189
187
-
func GetPullComments(e Execer, repoAt syntax.ATURI, pullId int) ([]PullComments, error) {
188
-
var comments []PullComments
190
+
func GetPullComments(e Execer, repoAt syntax.ATURI, pullId int) ([]PullComment, error) {
191
+
var comments []PullComment
189
192
190
193
rows, err := e.Query(`select owner_did, pull_id, comment_id, comment_at, body, created from pull_comments where repo_at = ? and pull_id = ? order by created asc`, repoAt, pullId)
191
194
if err == sql.ErrNoRows {
192
-
return []PullComments{}, nil
195
+
return []PullComment{}, nil
193
196
}
194
197
if err != nil {
195
198
return nil, err
···
197
200
defer rows.Close()
198
201
199
202
for rows.Next() {
200
-
var comment PullComments
203
+
var comment PullComment
201
204
var createdAt string
202
205
err := rows.Scan(&comment.OwnerDid, &comment.PullId, &comment.CommentId, &comment.CommentAt, &comment.Body, &createdAt)
203
206
if err != nil {
+27
appview/pages/pages.go
+27
appview/pages/pages.go
···
506
506
return p.executeRepo("repo/issues/new", w, params)
507
507
}
508
508
509
+
type RepoNewPullParams struct {
510
+
LoggedInUser *auth.User
511
+
RepoInfo RepoInfo
512
+
Active string
513
+
}
514
+
515
+
func (p *Pages) RepoNewPull(w io.Writer, params RepoNewPullParams) error {
516
+
params.Active = "pulls"
517
+
return p.executeRepo("repo/pulls/new", w, params)
518
+
}
519
+
509
520
type RepoPullsParams struct {
510
521
LoggedInUser *auth.User
511
522
RepoInfo RepoInfo
523
+
Pulls []db.Pull
512
524
Active string
525
+
DidHandleMap map[string]string
513
526
}
514
527
515
528
func (p *Pages) RepoPulls(w io.Writer, params RepoPullsParams) error {
516
529
params.Active = "pulls"
517
530
return p.executeRepo("repo/pulls/pulls", w, params)
531
+
}
532
+
533
+
type RepoSinglePullParams struct {
534
+
LoggedInUser *auth.User
535
+
RepoInfo RepoInfo
536
+
DidHandleMap map[string]string
537
+
Pull db.Pull
538
+
Comments []db.PullComment
539
+
Active string
540
+
}
541
+
542
+
func (p *Pages) RepoSinglePull(w io.Writer, params RepoSinglePullParams) error {
543
+
params.Active = "pulls"
544
+
return p.executeRepo("repo/pulls/pull", w, params)
518
545
}
519
546
520
547
func (p *Pages) Static() http.Handler {
+38
appview/pages/templates/repo/pulls/new.html
+38
appview/pages/templates/repo/pulls/new.html
···
1
+
{{ define "title" }}new pull | {{ .RepoInfo.FullName }}{{ end }}
2
+
3
+
{{ define "repoContent" }}
4
+
<form
5
+
hx-post="/{{ .RepoInfo.FullName }}/pulls/new"
6
+
class="mt-6 space-y-6"
7
+
hx-swap="none"
8
+
>
9
+
<div class="flex flex-col gap-4">
10
+
<div>
11
+
<label for="title">title</label>
12
+
<input type="text" name="title" id="title" class="w-full" />
13
+
<input type="text" name="targetBranch" id="targetBranch" />
14
+
</div>
15
+
<div>
16
+
<label for="body">body</label>
17
+
<textarea
18
+
name="body"
19
+
id="body"
20
+
rows="6"
21
+
class="w-full resize-y"
22
+
placeholder="Describe your change. Markdown is supported."
23
+
></textarea>
24
+
<textarea
25
+
name="patch"
26
+
id="patch"
27
+
rows="10"
28
+
class="w-full resize-y font-mono"
29
+
placeholder="Paste your git-format-patch output here."
30
+
></textarea>
31
+
</div>
32
+
<div>
33
+
<button type="submit" class="btn">create</button>
34
+
</div>
35
+
</div>
36
+
<div id="pull" class="error"></div>
37
+
</form>
38
+
{{ end }}
+133
appview/pages/templates/repo/pulls/pull.html
+133
appview/pages/templates/repo/pulls/pull.html
···
1
+
{{ define "title" }}
2
+
{{ .Pull.Title }} ·
3
+
{{ .RepoInfo.FullName }}
4
+
{{ end }}
5
+
6
+
{{ define "repoContent" }}
7
+
<h1>
8
+
{{ .Pull.Title }}
9
+
<span class="text-gray-400">#{{ .Pull.PullId }}</span>
10
+
</h1>
11
+
12
+
{{ $bgColor := "bg-gray-800" }}
13
+
{{ $icon := "ban" }}
14
+
{{ if eq .State "open" }}
15
+
{{ $bgColor = "bg-green-600" }}
16
+
{{ $icon = "circle-dot" }}
17
+
{{ end }}
18
+
19
+
20
+
<section>
21
+
<div class="flex items-center gap-2">
22
+
<div
23
+
id="state"
24
+
class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}"
25
+
>
26
+
<i
27
+
data-lucide="{{ $icon }}"
28
+
class="w-4 h-4 mr-1.5 text-white"
29
+
></i>
30
+
<span class="text-white">{{ .State }}</span>
31
+
</div>
32
+
<span class="text-gray-400 text-sm">
33
+
opened by
34
+
{{ $owner := didOrHandle .Pull.OwnerDid .PullOwnerHandle }}
35
+
<a href="/{{ $owner }}" class="no-underline hover:underline"
36
+
>{{ $owner }}</a
37
+
>
38
+
<span class="px-1 select-none before:content-['\00B7']"></span>
39
+
<time>{{ .Pull.Created | timeFmt }}</time>
40
+
</span>
41
+
</div>
42
+
43
+
{{ if .Pull.Body }}
44
+
<article id="body" class="mt-8 prose">
45
+
{{ .Pull.Body | markdown }}
46
+
</article>
47
+
{{ end }}
48
+
</section>
49
+
{{ end }}
50
+
51
+
{{ define "repoAfter" }}
52
+
<section id="comments" class="mt-8 space-y-4 relative">
53
+
{{ range $index, $comment := .Comments }}
54
+
<div
55
+
id="comment-{{ .CommentId }}"
56
+
class="rounded bg-white p-4 relative"
57
+
>
58
+
{{ if eq $index 0 }}
59
+
<div
60
+
class="absolute left-8 -top-8 w-px h-8 bg-gray-300"
61
+
></div>
62
+
{{ else }}
63
+
<div
64
+
class="absolute left-8 -top-4 w-px h-4 bg-gray-300"
65
+
></div>
66
+
{{ end }}
67
+
<div class="flex items-center gap-2 mb-2 text-gray-400">
68
+
{{ $owner := index $.DidHandleMap .OwnerDid }}
69
+
<span class="text-sm">
70
+
<a
71
+
href="/{{ $owner }}"
72
+
class="no-underline hover:underline"
73
+
>{{ $owner }}</a
74
+
>
75
+
</span>
76
+
<span
77
+
class="px-1 select-none before:content-['\00B7']"
78
+
></span>
79
+
<a
80
+
href="#{{ .CommentId }}"
81
+
class="text-gray-500 text-sm hover:text-gray-500 hover:underline no-underline"
82
+
id="{{ .CommentId }}"
83
+
>
84
+
{{ .Created | timeFmt }}
85
+
</a>
86
+
</div>
87
+
<div class="prose">
88
+
{{ .Body | markdown }}
89
+
</div>
90
+
</div>
91
+
{{ end }}
92
+
</section>
93
+
94
+
{{ if .LoggedInUser }}
95
+
<form
96
+
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/comment"
97
+
class="mt-8"
98
+
>
99
+
<textarea
100
+
name="body"
101
+
class="w-full p-2 rounded border border-gray-200"
102
+
placeholder="Add to the discussion..."
103
+
></textarea>
104
+
<button type="submit" class="btn mt-2">comment</button>
105
+
<div id="pull-comment"></div>
106
+
</form>
107
+
{{ end }}
108
+
109
+
{{ if eq .LoggedInUser.Did .Pull.OwnerDid }}
110
+
{{ $action := "close" }}
111
+
{{ $icon := "circle-x" }}
112
+
{{ $hoverColor := "red" }}
113
+
{{ if eq .State "closed" }}
114
+
{{ $action = "reopen" }}
115
+
{{ $icon = "circle-dot" }}
116
+
{{ $hoverColor = "green" }}
117
+
{{ end }}
118
+
<form
119
+
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/{{ $action }}"
120
+
hx-swap="none"
121
+
class="mt-8"
122
+
>
123
+
<button type="submit" class="btn hover:bg-{{ $hoverColor }}-300">
124
+
<i
125
+
data-lucide="{{ $icon }}"
126
+
class="w-4 h-4 mr-2 text-{{ $hoverColor }}-400"
127
+
></i>
128
+
<span class="text-black">{{ $action }}</span>
129
+
</button>
130
+
<div id="pull-action" class="error"></div>
131
+
</form>
132
+
{{ end }}
133
+
{{ end }}
+221
-6
appview/state/repo.go
+221
-6
appview/state/repo.go
···
234
234
}
235
235
}
236
236
237
+
// MergeCheck gets called async, every time the patch diff is updated in a pull.
238
+
func (s *State) MergeCheck(w http.ResponseWriter, r *http.Request) {
239
+
user := s.auth.GetUser(r)
240
+
f, err := fullyResolvedRepo(r)
241
+
if err != nil {
242
+
log.Println("failed to get repo and knot", err)
243
+
s.pages.Notice(w, "pull", "Failed to check mergeability. Try again later.")
244
+
return
245
+
}
246
+
247
+
patch := r.FormValue("patch")
248
+
targetBranch := r.FormValue("targetBranch")
249
+
250
+
if patch == "" || targetBranch == "" {
251
+
s.pages.Notice(w, "pull", "Patch and target branch are required.")
252
+
return
253
+
}
254
+
255
+
secret, err := db.GetRegistrationKey(s.db, f.Knot)
256
+
if err != nil {
257
+
log.Printf("no key found for domain %s: %s\n", f.Knot, err)
258
+
s.pages.Notice(w, "pull", "Failed to check mergeability. Try again later.")
259
+
return
260
+
}
261
+
262
+
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
263
+
if err != nil {
264
+
log.Printf("failed to create signed client for %s", f.Knot)
265
+
s.pages.Notice(w, "pull", "Failed to check mergeability. Try again later.")
266
+
return
267
+
}
268
+
269
+
resp, err := ksClient.MergeCheck([]byte(patch), user.Did, f.RepoName, targetBranch)
270
+
if err != nil {
271
+
log.Println("failed to check mergeability", err)
272
+
s.pages.Notice(w, "pull", "Unable to check for mergeability. Try again later.")
273
+
return
274
+
}
275
+
276
+
respBody, err := io.ReadAll(resp.Body)
277
+
if err != nil {
278
+
log.Println("failed to read knotserver response body")
279
+
s.pages.Notice(w, "pull", "Unable to check for mergeability. Try again later.")
280
+
return
281
+
}
282
+
283
+
var mergeCheckResponse types.MergeCheckResponse
284
+
err = json.Unmarshal(respBody, &mergeCheckResponse)
285
+
if err != nil {
286
+
log.Println("failed to unmarshal merge check response", err)
287
+
s.pages.Notice(w, "pull", "Failed to check mergeability. Try again later.")
288
+
return
289
+
}
290
+
291
+
// TODO: this has to return a html fragment
292
+
w.Header().Set("Content-Type", "application/json")
293
+
json.NewEncoder(w).Encode(mergeCheckResponse)
294
+
}
295
+
296
+
func (s *State) NewPull(w http.ResponseWriter, r *http.Request) {
297
+
user := s.auth.GetUser(r)
298
+
f, err := fullyResolvedRepo(r)
299
+
if err != nil {
300
+
log.Println("failed to get repo and knot", err)
301
+
return
302
+
}
303
+
304
+
switch r.Method {
305
+
case http.MethodGet:
306
+
s.pages.RepoNewPull(w, pages.RepoNewPullParams{
307
+
LoggedInUser: user,
308
+
RepoInfo: f.RepoInfo(s, user),
309
+
})
310
+
case http.MethodPost:
311
+
title := r.FormValue("title")
312
+
body := r.FormValue("body")
313
+
targetBranch := r.FormValue("targetBranch")
314
+
patch := r.FormValue("patch")
315
+
316
+
if title == "" || body == "" || patch == "" {
317
+
s.pages.Notice(w, "pull", "Title, body and patch diff are required.")
318
+
return
319
+
}
320
+
321
+
tx, err := s.db.BeginTx(r.Context(), nil)
322
+
if err != nil {
323
+
log.Println("failed to start tx")
324
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
325
+
return
326
+
}
327
+
328
+
defer func() {
329
+
tx.Rollback()
330
+
err = s.enforcer.E.LoadPolicy()
331
+
if err != nil {
332
+
log.Println("failed to rollback policies")
333
+
}
334
+
}()
335
+
336
+
err = db.NewPull(tx, &db.Pull{
337
+
Title: title,
338
+
Body: body,
339
+
TargetBranch: targetBranch,
340
+
Patch: patch,
341
+
OwnerDid: user.Did,
342
+
RepoAt: f.RepoAt,
343
+
})
344
+
if err != nil {
345
+
log.Println("failed to create pull request", err)
346
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
347
+
return
348
+
}
349
+
client, _ := s.auth.AuthorizedClient(r)
350
+
pullId, err := db.GetPullId(s.db, f.RepoAt)
351
+
if err != nil {
352
+
log.Println("failed to get pull id", err)
353
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
354
+
return
355
+
}
356
+
357
+
atResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
358
+
Collection: tangled.RepoPullNSID,
359
+
Repo: user.Did,
360
+
Rkey: s.TID(),
361
+
Record: &lexutil.LexiconTypeDecoder{
362
+
Val: &tangled.RepoPull{
363
+
Title: title,
364
+
PullId: int64(pullId),
365
+
TargetRepo: string(f.RepoAt),
366
+
TargetBranch: targetBranch,
367
+
Patch: patch,
368
+
},
369
+
},
370
+
})
371
+
372
+
err = db.SetPullAt(s.db, f.RepoAt, pullId, atResp.Uri)
373
+
if err != nil {
374
+
log.Println("failed to get pull id", err)
375
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
376
+
return
377
+
}
378
+
379
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pullId))
380
+
return
381
+
}
382
+
}
383
+
384
+
func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
385
+
user := s.auth.GetUser(r)
386
+
f, err := fullyResolvedRepo(r)
387
+
if err != nil {
388
+
log.Println("failed to get repo and knot", err)
389
+
return
390
+
}
391
+
392
+
prId := chi.URLParam(r, "pull")
393
+
prIdInt, err := strconv.Atoi(prId)
394
+
if err != nil {
395
+
http.Error(w, "bad pr id", http.StatusBadRequest)
396
+
log.Println("failed to parse pr id", err)
397
+
return
398
+
}
399
+
400
+
pr, comments, err := db.GetPullWithComments(s.db, f.RepoAt, prIdInt)
401
+
if err != nil {
402
+
log.Println("failed to get pr and comments", err)
403
+
s.pages.Notice(w, "pull", "Failed to load pull request. Try again later.")
404
+
return
405
+
}
406
+
407
+
identsToResolve := make([]string, len(comments))
408
+
for i, comment := range comments {
409
+
identsToResolve[i] = comment.OwnerDid
410
+
}
411
+
resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve)
412
+
didHandleMap := make(map[string]string)
413
+
for _, identity := range resolvedIds {
414
+
if !identity.Handle.IsInvalidHandle() {
415
+
didHandleMap[identity.DID.String()] = fmt.Sprintf("@%s", identity.Handle.String())
416
+
} else {
417
+
didHandleMap[identity.DID.String()] = identity.DID.String()
418
+
}
419
+
}
420
+
421
+
s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{
422
+
LoggedInUser: user,
423
+
RepoInfo: f.RepoInfo(s, user),
424
+
Pull: *pr,
425
+
Comments: comments,
426
+
427
+
DidHandleMap: didHandleMap,
428
+
})
429
+
}
430
+
237
431
func (s *State) RepoCommit(w http.ResponseWriter, r *http.Request) {
238
432
f, err := fullyResolvedRepo(r)
239
433
if err != nil {
···
1071
1265
return
1072
1266
}
1073
1267
1074
-
switch r.Method {
1075
-
case http.MethodGet:
1076
-
s.pages.RepoPulls(w, pages.RepoPullsParams{
1077
-
LoggedInUser: user,
1078
-
RepoInfo: f.RepoInfo(s, user),
1079
-
})
1268
+
pulls, err := db.GetPulls(s.db, f.RepoAt)
1269
+
if err != nil {
1270
+
log.Println("failed to get pulls", err)
1271
+
s.pages.Notice(w, "pulls", "Failed to load pulls. Try again later.")
1272
+
return
1273
+
}
1274
+
1275
+
identsToResolve := make([]string, len(pulls))
1276
+
for i, pull := range pulls {
1277
+
identsToResolve[i] = pull.OwnerDid
1278
+
}
1279
+
resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve)
1280
+
didHandleMap := make(map[string]string)
1281
+
for _, identity := range resolvedIds {
1282
+
if !identity.Handle.IsInvalidHandle() {
1283
+
didHandleMap[identity.DID.String()] = fmt.Sprintf("@%s", identity.Handle.String())
1284
+
} else {
1285
+
didHandleMap[identity.DID.String()] = identity.DID.String()
1286
+
}
1080
1287
}
1288
+
1289
+
s.pages.RepoPulls(w, pages.RepoPullsParams{
1290
+
LoggedInUser: s.auth.GetUser(r),
1291
+
RepoInfo: f.RepoInfo(s, user),
1292
+
Pulls: pulls,
1293
+
DidHandleMap: didHandleMap,
1294
+
})
1295
+
return
1081
1296
}
1082
1297
1083
1298
func fullyResolvedRepo(r *http.Request) (*FullyResolvedRepo, error) {
+19
appview/state/signer.go
+19
appview/state/signer.go
···
174
174
175
175
return s.client.Do(req)
176
176
}
177
+
178
+
func (s *SignedClient) MergeCheck(patch []byte, ownerDid, targetRepo, branch string) (*http.Response, error) {
179
+
const (
180
+
Method = "POST"
181
+
)
182
+
endpoint := fmt.Sprintf("/%s/%s/merge/check", ownerDid, targetRepo)
183
+
184
+
body, _ := json.Marshal(map[string]interface{}{
185
+
"patch": string(patch),
186
+
"branch": branch,
187
+
})
188
+
189
+
req, err := s.newRequest(Method, endpoint, body)
190
+
if err != nil {
191
+
return nil, err
192
+
}
193
+
194
+
return s.client.Do(req)
195
+
}
+11
appview/state/state.go
+11
appview/state/state.go
···
881
881
882
882
r.Route("/pulls", func(r chi.Router) {
883
883
r.Get("/", s.RepoPulls)
884
+
r.Get("/{pull}", s.RepoSinglePull)
885
+
886
+
r.Group(func(r chi.Router) {
887
+
r.Use(AuthMiddleware(s))
888
+
r.Get("/new", s.NewPull)
889
+
r.Post("/new", s.NewPull)
890
+
// r.Post("/{pull}/comment", s.PullComment)
891
+
// r.Post("/{pull}/close", s.ClosePull)
892
+
// r.Post("/{pull}/reopen", s.ReopenPull)
893
+
// r.Post("/{pull}/merge", s.MergePull)
894
+
})
884
895
})
885
896
886
897
// These routes get proxied to the knot
+2
-2
cmd/gen.go
+2
-2
cmd/gen.go