Monorepo for Tangled
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

appview/models: update pull model

Signed-off-by: oppiliappan <me@oppi.li>

authored by

oppiliappan and committed by tangled.org 9592f2ef 9319da61

+199 -21
+199 -21
appview/models/pull.go
··· 1 1 package models 2 2 3 3 import ( 4 + "bytes" 5 + "compress/gzip" 4 6 "fmt" 7 + "io" 5 8 "log" 6 9 "slices" 7 10 "strings" 8 11 "time" 9 12 10 - "github.com/bluesky-social/indigo/atproto/syntax" 11 13 "tangled.org/core/api/tangled" 12 14 "tangled.org/core/patchutil" 13 15 "tangled.org/core/types" 16 + 17 + "github.com/bluesky-social/indigo/atproto/syntax" 18 + lexutil "github.com/bluesky-social/indigo/lex/util" 14 19 ) 15 20 16 21 type PullState int ··· 19 24 PullClosed PullState = iota 20 25 PullOpen 21 26 PullMerged 22 - PullDeleted 27 + PullAbandoned 23 28 ) 24 29 25 30 func (p PullState) String() string { ··· 30 35 return "merged" 31 36 case PullClosed: 32 37 return "closed" 33 - case PullDeleted: 34 - return "deleted" 38 + case PullAbandoned: 39 + return "abandoned" 35 40 default: 36 41 return "closed" 37 42 } ··· 46 51 func (p PullState) IsClosed() bool { 47 52 return p == PullClosed 48 53 } 49 - func (p PullState) IsDeleted() bool { 50 - return p == PullDeleted 54 + func (p PullState) IsAbandoned() bool { 55 + return p == PullAbandoned 51 56 } 52 57 53 58 type Pull struct { ··· 70 75 References []syntax.ATURI 71 76 72 77 // stacking 73 - StackId string // nullable string 74 - ChangeId string // nullable string 75 - ParentChangeId string // nullable string 78 + DependentOn *syntax.ATURI 76 79 77 80 // meta 78 81 Created time.Time ··· 89 92 if p.PullSource != nil { 90 93 source = &tangled.RepoPull_Source{} 91 94 source.Branch = p.PullSource.Branch 92 - source.Sha = p.LatestSha() 93 95 if p.PullSource.RepoAt != nil { 94 96 s := p.PullSource.RepoAt.String() 95 97 source.Repo = &s ··· 104 106 references[i] = string(uri) 105 107 } 106 108 107 - targetRepoStr := p.RepoAt.String() 109 + var targetRepoAt, targetRepoDid string 110 + if p.Repo != nil && p.Repo.RepoDid != "" { 111 + targetRepoDid = p.Repo.RepoDid 112 + } 113 + targetRepoAt = p.RepoAt.String() 114 + 115 + rounds := make([]*tangled.RepoPull_Round, len(p.Submissions)) 116 + for i, submission := range p.Submissions { 117 + rounds[i] = submission.AsRecord() 118 + } 119 + 120 + var dependentOn *string 121 + if p.DependentOn != nil { 122 + x := p.DependentOn.String() 123 + dependentOn = &x 124 + } 125 + 108 126 record := tangled.RepoPull{ 109 127 Title: p.Title, 110 128 Body: &p.Body, ··· 112 130 References: references, 113 131 CreatedAt: p.Created.Format(time.RFC3339), 114 132 Target: &tangled.RepoPull_Target{ 115 - Repo: &targetRepoStr, 116 - Branch: p.TargetBranch, 133 + Repo: &targetRepoAt, 134 + RepoDid: &targetRepoDid, 135 + Branch: p.TargetBranch, 117 136 }, 118 - Source: source, 137 + Rounds: rounds, 138 + Source: source, 139 + DependentOn: dependentOn, 119 140 } 120 141 return record 121 142 } 122 143 144 + func PullFromRecord(did, rkey string, record tangled.RepoPull, blobs []*io.ReadCloser) Pull { 145 + created, err := time.Parse(time.RFC3339, record.CreatedAt) 146 + if err != nil { 147 + created = time.Now() 148 + } 149 + 150 + body := "" 151 + if record.Body != nil { 152 + body = *record.Body 153 + } 154 + 155 + var mentions []syntax.DID 156 + for _, m := range record.Mentions { 157 + if did, err := syntax.ParseDID(m); err == nil { 158 + mentions = append(mentions, did) 159 + } 160 + } 161 + 162 + var targetRepoAt syntax.ATURI 163 + var targetBranch string 164 + if record.Target != nil { 165 + if uri, err := syntax.ParseATURI(record.Target.Repo); err == nil { 166 + targetRepoAt = uri 167 + } 168 + targetBranch = record.Target.Branch 169 + } 170 + 171 + var pullSource *PullSource 172 + if record.Source != nil { 173 + pullSource = &PullSource{ 174 + Branch: record.Source.Branch, 175 + } 176 + 177 + if record.Source.Repo != nil { 178 + if uri, err := syntax.ParseATURI(*record.Source.Repo); err == nil { 179 + pullSource.RepoAt = &uri 180 + } 181 + } 182 + } 183 + 184 + var dependentOn *syntax.ATURI 185 + if record.DependentOn != nil { 186 + if uri, err := syntax.ParseATURI(*record.DependentOn); err == nil { 187 + dependentOn = &uri 188 + } 189 + } 190 + 191 + var submissions []*PullSubmission 192 + for i, s := range record.Rounds { 193 + var blob *io.ReadCloser 194 + if i < len(blobs) { 195 + blob = blobs[i] 196 + } 197 + submission, err := PullSubmissionFromRecord(did, rkey, i, s, blob) 198 + if err != nil { 199 + submissions = append(submissions, nil) 200 + } else { 201 + submissions = append(submissions, submission) 202 + } 203 + } 204 + 205 + return Pull{ 206 + RepoAt: targetRepoAt, 207 + OwnerDid: did, 208 + Rkey: rkey, 209 + Title: record.Title, 210 + Body: body, 211 + TargetBranch: targetBranch, 212 + PullSource: pullSource, 213 + State: PullOpen, 214 + Submissions: submissions, 215 + Created: created, 216 + DependentOn: dependentOn, 217 + } 218 + } 219 + 220 + func PullSubmissionFromRecord(did, rkey string, roundNumber int, round *tangled.RepoPull_Round, blob *io.ReadCloser) (*PullSubmission, error) { 221 + created, err := time.Parse(time.RFC3339, round.CreatedAt) 222 + if err != nil { 223 + created = time.Now() 224 + } 225 + 226 + var patch, sourceRev string 227 + if blob != nil { 228 + p, err := extractGzip(*blob) 229 + if err != nil { 230 + return nil, fmt.Errorf("failed to extract gzip: %w", err) 231 + } 232 + patch = p 233 + if patchutil.IsFormatPatch(p) { 234 + patches, err := patchutil.ExtractPatches(p) 235 + if err != nil { 236 + return nil, fmt.Errorf("failed to extract patches: %w", err) 237 + } 238 + 239 + for _, part := range patches { 240 + sourceRev = part.SHA 241 + } 242 + } 243 + } 244 + 245 + return &PullSubmission{ 246 + PullAt: syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", did, tangled.RepoPullNSID, rkey)), 247 + RoundNumber: roundNumber, 248 + Blob: *round.PatchBlob, 249 + Created: created, 250 + Patch: patch, 251 + SourceRev: sourceRev, 252 + }, nil 253 + } 254 + 123 255 type PullSource struct { 124 256 Branch string 125 257 RepoAt *syntax.ATURI ··· 137 269 138 270 // content 139 271 RoundNumber int 272 + Blob lexutil.LexBlob 140 273 Patch string 141 274 Combined string 142 275 Comments []PullComment ··· 224 357 } 225 358 } 226 359 return false 227 - } 228 - 229 - func (p *Pull) IsStacked() bool { 230 - return p.StackId != "" 231 360 } 232 361 233 362 func (p *Pull) Participants() []string { ··· 266 395 return patches 267 396 } 268 397 398 + // empty if invalid, not otherwise 399 + func (s PullSubmission) ChangeId() string { 400 + patches := s.AsFormatPatch() 401 + if len(patches) != 1 { 402 + return "" 403 + } 404 + 405 + c, err := patches[0].ChangeId() 406 + if err != nil { 407 + return "" 408 + } 409 + 410 + return c 411 + } 412 + 269 413 func (s *PullSubmission) Participants() []string { 270 414 participantSet := make(map[string]struct{}) 271 415 participants := []string{} ··· 294 438 return s.Combined 295 439 } 296 440 441 + func (s *PullSubmission) GetBlob() *lexutil.LexBlob { 442 + if !s.Blob.Ref.Defined() { 443 + return nil 444 + } 445 + 446 + return &s.Blob 447 + } 448 + 449 + func (s *PullSubmission) AsRecord() *tangled.RepoPull_Round { 450 + return &tangled.RepoPull_Round{ 451 + CreatedAt: s.Created.Format(time.RFC3339), 452 + PatchBlob: s.GetBlob(), 453 + } 454 + } 455 + 297 456 type Stack []*Pull 298 457 299 458 // position of this pull in the stack 300 459 func (stack Stack) Position(pull *Pull) int { 301 460 return slices.IndexFunc(stack, func(p *Pull) bool { 302 - return p.ChangeId == pull.ChangeId 461 + return p.AtUri() == pull.AtUri() 303 462 }) 304 463 } 305 464 ··· 373 532 break 374 533 } 375 534 376 - // skip over deleted PRs 377 - if p.State != PullDeleted { 535 + // skip over abandoned PRs 536 + if p.State != PullAbandoned { 378 537 mergeable = append(mergeable, p) 379 538 } 380 539 } ··· 386 545 Repo *Repo 387 546 Branch string 388 547 } 548 + 549 + func extractGzip(blob io.Reader) (string, error) { 550 + var b bytes.Buffer 551 + r, err := gzip.NewReader(blob) 552 + if err != nil { 553 + return "", err 554 + } 555 + defer r.Close() 556 + 557 + const maxSize = 15 * 1024 * 1024 558 + limitedReader := io.LimitReader(r, maxSize) 559 + 560 + _, err = io.Copy(&b, limitedReader) 561 + if err != nil { 562 + return "", err 563 + } 564 + 565 + return b.String(), nil 566 + }