+3
appview/oauth/oauth.go
+3
appview/oauth/oauth.go
+8
-8
appview/pages/pages.go
+8
-8
appview/pages/pages.go
···
531
}
532
533
type RepoIndexParams struct {
534
-
LoggedInUser *oauth.User
535
-
RepoInfo repoinfo.RepoInfo
536
-
Active string
537
-
TagMap map[string][]string
538
-
CommitsTrunc []*object.Commit
539
-
TagsTrunc []*types.TagReference
540
-
BranchesTrunc []types.Branch
541
-
ForkInfo *types.ForkInfo
542
HTMLReadme template.HTML
543
Raw bool
544
EmailToDidOrHandle map[string]string
···
531
}
532
533
type RepoIndexParams struct {
534
+
LoggedInUser *oauth.User
535
+
RepoInfo repoinfo.RepoInfo
536
+
Active string
537
+
TagMap map[string][]string
538
+
CommitsTrunc []*object.Commit
539
+
TagsTrunc []*types.TagReference
540
+
BranchesTrunc []types.Branch
541
+
// ForkInfo *types.ForkInfo
542
HTMLReadme template.HTML
543
Raw bool
544
EmailToDidOrHandle map[string]string
-33
appview/pages/templates/repo/index.html
-33
appview/pages/templates/repo/index.html
···
84
</optgroup>
85
</select>
86
<div class="flex items-center gap-2">
87
-
{{ $isOwner := and .LoggedInUser .RepoInfo.Roles.IsOwner }}
88
-
{{ $isCollaborator := and .LoggedInUser .RepoInfo.Roles.IsCollaborator }}
89
-
{{ if and (or $isOwner $isCollaborator) .ForkInfo .ForkInfo.IsFork }}
90
-
{{ $disabled := "" }}
91
-
{{ $title := "" }}
92
-
{{ if eq .ForkInfo.Status 0 }}
93
-
{{ $disabled = "disabled" }}
94
-
{{ $title = "This branch is not behind the upstream" }}
95
-
{{ else if eq .ForkInfo.Status 2 }}
96
-
{{ $disabled = "disabled" }}
97
-
{{ $title = "This branch has conflicts that must be resolved" }}
98
-
{{ else if eq .ForkInfo.Status 3 }}
99
-
{{ $disabled = "disabled" }}
100
-
{{ $title = "This branch does not exist on the upstream" }}
101
-
{{ end }}
102
-
103
-
<button
104
-
id="syncBtn"
105
-
{{ $disabled }}
106
-
{{ if $title }}title="{{ $title }}"{{ end }}
107
-
class="btn flex gap-2 items-center disabled:opacity-50 disabled:cursor-not-allowed"
108
-
hx-post="/{{ .RepoInfo.FullName }}/fork/sync"
109
-
hx-trigger="click"
110
-
hx-swap="none"
111
-
>
112
-
{{ if $disabled }}
113
-
{{ i "refresh-cw-off" "w-4 h-4" }}
114
-
{{ else }}
115
-
{{ i "refresh-cw" "w-4 h-4" }}
116
-
{{ end }}
117
-
<span>sync</span>
118
-
</button>
119
-
{{ end }}
120
<a
121
href="/{{ .RepoInfo.FullName }}/compare?base={{ $.Ref | urlquery }}"
122
class="btn flex items-center gap-2 no-underline hover:no-underline"
+163
-120
appview/repo/index.go
+163
-120
appview/repo/index.go
···
1
package repo
2
3
import (
4
-
"encoding/json"
5
-
"fmt"
6
"log"
7
"net/http"
8
"slices"
···
11
12
"tangled.sh/tangled.sh/core/appview/commitverify"
13
"tangled.sh/tangled.sh/core/appview/db"
14
-
"tangled.sh/tangled.sh/core/appview/oauth"
15
"tangled.sh/tangled.sh/core/appview/pages"
16
-
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
17
"tangled.sh/tangled.sh/core/appview/reporesolver"
18
"tangled.sh/tangled.sh/core/knotclient"
19
"tangled.sh/tangled.sh/core/types"
···
105
user := rp.oauth.GetUser(r)
106
repoInfo := f.RepoInfo(user)
107
108
-
secret, err := db.GetRegistrationKey(rp.db, f.Knot)
109
-
if err != nil {
110
-
log.Printf("failed to get registration key for %s: %s", f.Knot, err)
111
-
rp.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
112
-
}
113
114
-
signedClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
115
-
if err != nil {
116
-
log.Printf("failed to create signed client for %s: %s", f.Knot, err)
117
-
return
118
-
}
119
120
-
var forkInfo *types.ForkInfo
121
-
if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) {
122
-
forkInfo, err = getForkInfo(r, repoInfo, rp, f, result.Ref, user, signedClient)
123
-
if err != nil {
124
-
log.Printf("Failed to fetch fork information: %v", err)
125
-
return
126
-
}
127
-
}
128
129
// TODO: a bit dirty
130
-
languageInfo, err := rp.getLanguageInfo(f, signedClient, result.Ref, ref == "")
131
if err != nil {
132
log.Printf("failed to compute language percentages: %s", err)
133
// non-fatal
···
144
}
145
146
rp.pages.RepoIndexPage(w, pages.RepoIndexParams{
147
-
LoggedInUser: user,
148
-
RepoInfo: repoInfo,
149
-
TagMap: tagMap,
150
-
RepoIndexResponse: *result,
151
-
CommitsTrunc: commitsTrunc,
152
-
TagsTrunc: tagsTrunc,
153
-
ForkInfo: forkInfo,
154
BranchesTrunc: branchesTrunc,
155
EmailToDidOrHandle: emailToDidOrHandle(rp, emailToDidMap),
156
VerifiedCommits: vc,
···
161
162
func (rp *Repo) getLanguageInfo(
163
f *reporesolver.ResolvedRepo,
164
-
signedClient *knotclient.SignedClient,
165
currentRef string,
166
isDefaultRef bool,
167
) ([]types.RepoLanguageDetails, error) {
···
174
175
if err != nil || langs == nil {
176
// non-fatal, fetch langs from ks
177
-
ls, err := signedClient.RepoLanguages(f.OwnerDid(), f.Name, currentRef)
178
if err != nil {
179
return nil, err
180
}
···
232
return languageStats, nil
233
}
234
235
-
func getForkInfo(
236
-
r *http.Request,
237
-
repoInfo repoinfo.RepoInfo,
238
-
rp *Repo,
239
-
f *reporesolver.ResolvedRepo,
240
-
currentRef string,
241
-
user *oauth.User,
242
-
signedClient *knotclient.SignedClient,
243
-
) (*types.ForkInfo, error) {
244
-
if user == nil {
245
-
return nil, nil
246
-
}
247
-
248
-
forkInfo := types.ForkInfo{
249
-
IsFork: repoInfo.Source != nil,
250
-
Status: types.UpToDate,
251
-
}
252
-
253
-
if !forkInfo.IsFork {
254
-
forkInfo.IsFork = false
255
-
return &forkInfo, nil
256
-
}
257
-
258
-
us, err := knotclient.NewUnsignedClient(repoInfo.Source.Knot, rp.config.Core.Dev)
259
-
if err != nil {
260
-
log.Printf("failed to create unsigned client for %s", repoInfo.Source.Knot)
261
-
return nil, err
262
-
}
263
-
264
-
result, err := us.Branches(repoInfo.Source.Did, repoInfo.Source.Name)
265
-
if err != nil {
266
-
log.Println("failed to reach knotserver", err)
267
-
return nil, err
268
-
}
269
-
270
-
if !slices.ContainsFunc(result.Branches, func(branch types.Branch) bool {
271
-
return branch.Name == currentRef
272
-
}) {
273
-
forkInfo.Status = types.MissingBranch
274
-
return &forkInfo, nil
275
-
}
276
-
277
-
client, err := rp.oauth.ServiceClient(
278
-
r,
279
-
oauth.WithService(f.Knot),
280
-
oauth.WithLxm(tangled.RepoHiddenRefNSID),
281
-
oauth.WithDev(rp.config.Core.Dev),
282
-
)
283
-
if err != nil {
284
-
log.Printf("failed to connect to knot server: %v", err)
285
-
return nil, err
286
-
}
287
-
288
-
resp, err := tangled.RepoHiddenRef(
289
-
r.Context(),
290
-
client,
291
-
&tangled.RepoHiddenRef_Input{
292
-
ForkRef: currentRef,
293
-
RemoteRef: currentRef,
294
-
Repo: f.RepoAt().String(),
295
-
},
296
-
)
297
-
if err != nil || !resp.Success {
298
-
if err != nil {
299
-
log.Printf("failed to update tracking branch: %s", err)
300
-
} else {
301
-
log.Printf("failed to update tracking branch: success=false")
302
-
}
303
-
return nil, fmt.Errorf("failed to update tracking branch")
304
-
}
305
-
306
-
hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef)
307
-
308
-
var status types.AncestorCheckResponse
309
-
forkSyncableResp, err := signedClient.RepoForkAheadBehind(user.Did, string(f.RepoAt()), repoInfo.Name, currentRef, hiddenRef)
310
-
if err != nil {
311
-
log.Printf("failed to check if fork is ahead/behind: %s", err)
312
-
return nil, err
313
-
}
314
-
315
-
if err := json.NewDecoder(forkSyncableResp.Body).Decode(&status); err != nil {
316
-
log.Printf("failed to decode fork status: %s", err)
317
-
return nil, err
318
-
}
319
-
320
-
forkInfo.Status = status.Status
321
-
return &forkInfo, nil
322
-
}
···
1
package repo
2
3
import (
4
"log"
5
"net/http"
6
"slices"
···
9
10
"tangled.sh/tangled.sh/core/appview/commitverify"
11
"tangled.sh/tangled.sh/core/appview/db"
12
"tangled.sh/tangled.sh/core/appview/pages"
13
"tangled.sh/tangled.sh/core/appview/reporesolver"
14
"tangled.sh/tangled.sh/core/knotclient"
15
"tangled.sh/tangled.sh/core/types"
···
101
user := rp.oauth.GetUser(r)
102
repoInfo := f.RepoInfo(user)
103
104
+
// secret, err := db.GetRegistrationKey(rp.db, f.Knot)
105
+
// if err != nil {
106
+
// log.Printf("failed to get registration key for %s: %s", f.Knot, err)
107
+
// rp.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
108
+
// }
109
110
+
// signedClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
111
+
// if err != nil {
112
+
// log.Printf("failed to create signed client for %s: %s", f.Knot, err)
113
+
// return
114
+
// }
115
116
+
// var forkInfo *types.ForkInfo
117
+
// if user != nil && (repoInfo.Roles.IsOwner() || repoInfo.Roles.IsCollaborator()) {
118
+
// forkInfo, err = getForkInfo(r, repoInfo, rp, f, result.Ref, user, signedClient)
119
+
// if err != nil {
120
+
// log.Printf("Failed to fetch fork information: %v", err)
121
+
// return
122
+
// }
123
+
// }
124
125
// TODO: a bit dirty
126
+
languageInfo, err := rp.getLanguageInfo(f, us, result.Ref, ref == "")
127
if err != nil {
128
log.Printf("failed to compute language percentages: %s", err)
129
// non-fatal
···
140
}
141
142
rp.pages.RepoIndexPage(w, pages.RepoIndexParams{
143
+
LoggedInUser: user,
144
+
RepoInfo: repoInfo,
145
+
TagMap: tagMap,
146
+
RepoIndexResponse: *result,
147
+
CommitsTrunc: commitsTrunc,
148
+
TagsTrunc: tagsTrunc,
149
+
// ForkInfo: forkInfo, // TODO: reinstate this after xrpc properly lands
150
BranchesTrunc: branchesTrunc,
151
EmailToDidOrHandle: emailToDidOrHandle(rp, emailToDidMap),
152
VerifiedCommits: vc,
···
157
158
func (rp *Repo) getLanguageInfo(
159
f *reporesolver.ResolvedRepo,
160
+
us *knotclient.UnsignedClient,
161
currentRef string,
162
isDefaultRef bool,
163
) ([]types.RepoLanguageDetails, error) {
···
170
171
if err != nil || langs == nil {
172
// non-fatal, fetch langs from ks
173
+
ls, err := us.RepoLanguages(f.OwnerDid(), f.Name, currentRef)
174
if err != nil {
175
return nil, err
176
}
···
228
return languageStats, nil
229
}
230
231
+
// func getForkInfo(
232
+
// r *http.Request,
233
+
// repoInfo repoinfo.RepoInfo,
234
+
// rp *Repo,
235
+
// f *reporesolver.ResolvedRepo,
236
+
// currentRef string,
237
+
// user *oauth.User,
238
+
// signedClient *knotclient.SignedClient,
239
+
// ) (*types.ForkInfo, error) {
240
+
// if user == nil {
241
+
// return nil, nil
242
+
// }
243
+
//
244
+
// forkInfo := types.ForkInfo{
245
+
// IsFork: repoInfo.Source != nil,
246
+
// Status: types.UpToDate,
247
+
// }
248
+
//
249
+
// if !forkInfo.IsFork {
250
+
// forkInfo.IsFork = false
251
+
// return &forkInfo, nil
252
+
// }
253
+
//
254
+
// us, err := knotclient.NewUnsignedClient(repoInfo.Source.Knot, rp.config.Core.Dev)
255
+
// if err != nil {
256
+
// log.Printf("failed to create unsigned client for %s", repoInfo.Source.Knot)
257
+
// return nil, err
258
+
// }
259
+
//
260
+
// result, err := us.Branches(repoInfo.Source.Did, repoInfo.Source.Name)
261
+
// if err != nil {
262
+
// log.Println("failed to reach knotserver", err)
263
+
// return nil, err
264
+
// }
265
+
//
266
+
// if !slices.ContainsFunc(result.Branches, func(branch types.Branch) bool {
267
+
// return branch.Name == currentRef
268
+
// }) {
269
+
// forkInfo.Status = types.MissingBranch
270
+
// return &forkInfo, nil
271
+
// }
272
+
//
273
+
// <<<<<<< Conflict 1 of 2
274
+
// %%%%%%% Changes from base #1 to side #1
275
+
// client, err := rp.oauth.ServiceClient(
276
+
// r,
277
+
// oauth.WithService(f.Knot),
278
+
// oauth.WithLxm(tangled.RepoHiddenRefNSID),
279
+
// oauth.WithDev(rp.config.Core.Dev),
280
+
// )
281
+
// if err != nil {
282
+
// log.Printf("failed to connect to knot server: %v", err)
283
+
// %%%%%%% Changes from base #2 to side #2
284
+
// - newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, currentRef, currentRef)
285
+
// + newHiddenRefResp, err := signedClient.NewHiddenRef(user.Did, repoInfo.Name, f.Ref, f.Ref)
286
+
// if err != nil || newHiddenRefResp.StatusCode != http.StatusNoContent {
287
+
// log.Printf("failed to update tracking branch: %s", err)
288
+
// +++++++ Contents of side #3
289
+
// client, err := rp.oauth.ServiceClient(
290
+
// r,
291
+
// oauth.WithService(f.Knot),
292
+
// oauth.WithLxm(tangled.RepoHiddenRefNSID),
293
+
// oauth.WithDev(rp.config.Core.Dev),
294
+
// )
295
+
// if err != nil {
296
+
// log.Printf("failed to connect to knot server: %v", err)
297
+
// >>>>>>> Conflict 1 of 2 ends
298
+
// return nil, err
299
+
// }
300
+
//
301
+
// <<<<<<< Conflict 2 of 2
302
+
// %%%%%%% Changes from base #1 to side #1
303
+
// resp, err := tangled.RepoHiddenRef(
304
+
// r.Context(),
305
+
// client,
306
+
// &tangled.RepoHiddenRef_Input{
307
+
// - ForkRef: f.Ref,
308
+
// - RemoteRef: f.Ref,
309
+
// + ForkRef: currentRef,
310
+
// + RemoteRef: currentRef,
311
+
// Repo: f.RepoAt().String(),
312
+
// },
313
+
// )
314
+
// if err != nil || !resp.Success {
315
+
// if err != nil {
316
+
// log.Printf("failed to update tracking branch: %s", err)
317
+
// } else {
318
+
// log.Printf("failed to update tracking branch: success=false")
319
+
// }
320
+
// return nil, fmt.Errorf("failed to update tracking branch")
321
+
// }
322
+
//
323
+
// - hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref)
324
+
// + hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef)
325
+
//
326
+
// %%%%%%% Changes from base #2 to side #2
327
+
// - hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef)
328
+
// + hiddenRef := fmt.Sprintf("hidden/%s/%s", f.Ref, f.Ref)
329
+
//
330
+
// +++++++ Contents of side #3
331
+
// resp, err := tangled.RepoHiddenRef(
332
+
// r.Context(),
333
+
// client,
334
+
// &tangled.RepoHiddenRef_Input{
335
+
// ForkRef: currentRef,
336
+
// RemoteRef: currentRef,
337
+
// Repo: f.RepoAt().String(),
338
+
// },
339
+
// )
340
+
// if err != nil || !resp.Success {
341
+
// if err != nil {
342
+
// log.Printf("failed to update tracking branch: %s", err)
343
+
// } else {
344
+
// log.Printf("failed to update tracking branch: success=false")
345
+
// }
346
+
// return nil, fmt.Errorf("failed to update tracking branch")
347
+
// }
348
+
//
349
+
// hiddenRef := fmt.Sprintf("hidden/%s/%s", currentRef, currentRef)
350
+
// >>>>>>> Conflict 2 of 2 ends
351
+
// var status types.AncestorCheckResponse
352
+
// forkSyncableResp, err := signedClient.RepoForkAheadBehind(user.Did, string(f.RepoAt()), repoInfo.Name, currentRef, hiddenRef)
353
+
// if err != nil {
354
+
// log.Printf("failed to check if fork is ahead/behind: %s", err)
355
+
// return nil, err
356
+
// }
357
+
//
358
+
// if err := json.NewDecoder(forkSyncableResp.Body).Decode(&status); err != nil {
359
+
// log.Printf("failed to decode fork status: %s", err)
360
+
// return nil, err
361
+
// }
362
+
//
363
+
// forkInfo.Status = status.Status
364
+
// return &forkInfo, nil
365
+
// }