Monorepo for Tangled tangled.org
at sl/shared-stacks 188 lines 4.1 kB view raw
1package models 2 3import ( 4 "fmt" 5 "time" 6 7 "github.com/bluesky-social/indigo/atproto/syntax" 8 "tangled.org/core/api/tangled" 9) 10 11type Pull2 struct { 12 // TODO: PullId is not atprotated yet 13 PullId int 14 Did syntax.DID 15 Rkey syntax.RecordKey 16 17 Submissions []*PullRound // PR submission history 18 19 // backlinked records 20 21 State PullState 22 Labels LabelState 23 Comments []Comment 24 25 // optionally, populate these when querying for reverse mappings 26 27 Repo *Repo 28} 29 30// PullRound represents snapshot of `sh.tangled.repo.pull` record 31// NOTE: Non-patch change can make new submission 32type PullRound struct { 33 Id int64 34 Round int 35 Did syntax.DID 36 Rkey syntax.RecordKey 37 Cid syntax.CID 38 39 // content 40 41 Target PullTarget 42 Source *PullSource2 // optional for patch based PR 43 Patch string // list of commits encoded in patch object 44 Title string 45 Body string 46 Mentions []syntax.DID 47 References []syntax.ATURI 48 Created time.Time 49} 50 51type PullTarget struct { 52 RepoAt syntax.ATURI 53 Branch string 54} 55 56// PullSource2 is not a source of truth but rather a metadata to help resubmitting 57type PullSource2 struct { 58 RepoAt syntax.ATURI 59 Branch string 60} 61 62func (p Pull2) AsRecord() tangled.RepoPull { 63 return p.Latest().AsRecord() 64} 65 66func (p *Pull2) AtUri() syntax.ATURI { 67 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", p.Did, tangled.RepoPullNSID, p.Rkey)) 68} 69 70func (p *Pull2) Latest() *PullRound { 71 return p.Submissions[len(p.Submissions)-1] 72} 73 74func (p *Pull2) CID() syntax.CID { 75 return p.Latest().Cid 76} 77 78func (p *Pull2) Created() time.Time { 79 return p.Submissions[0].Created 80} 81 82func (p *Pull2) Edited() time.Time { 83 return p.Latest().Created 84} 85 86func (p *Pull2) RepoAt() syntax.ATURI { 87 return p.Latest().Target.RepoAt 88} 89 90func (p *Pull2) Validate() error { 91 if len(p.Submissions) == 0 { 92 return fmt.Errorf("Pull should include at least one submission") 93 } 94 // we don't need to validate existing records 95 if err := p.Latest().Validate(); err != nil { 96 return fmt.Errorf("validate latest stack: %w", err) 97 } 98 return nil 99} 100 101func PullContentFromRecord(cid syntax.CID, record tangled.RepoPull) PullRound { 102 var source *PullSource2 103 if record.Source != nil { 104 source = &PullSource2{} 105 source.Branch = record.Source.Branch 106 if record.Source.Repo != nil { 107 source.RepoAt = syntax.ATURI(*record.Source.Repo) 108 } else { 109 source.RepoAt = syntax.ATURI(record.Target.Repo) 110 } 111 } 112 var ( 113 body string 114 mentions = make([]syntax.DID, len(record.Mentions)) 115 references = make([]syntax.ATURI, len(record.References)) 116 ) 117 if record.Body != nil { 118 body = *record.Body 119 } 120 for i, v := range record.Mentions { 121 mentions[i] = syntax.DID(v) 122 } 123 for i, v := range record.References { 124 references[i] = syntax.ATURI(v) 125 } 126 created, err := time.Parse(record.CreatedAt, time.RFC3339) 127 if err != nil { 128 created = time.Now() 129 } 130 return PullRound{ 131 Cid: cid, 132 Target: PullTarget{ 133 RepoAt: syntax.ATURI(record.Target.Repo), 134 Branch: record.Target.Branch, 135 }, 136 Source: source, 137 Patch: record.Patch, 138 Title: record.Title, 139 Body: body, 140 Created: created, 141 } 142} 143 144// NOTE: AsRecord doesn't include the patch blob id in returned atproto record 145func (p PullRound) AsRecord() tangled.RepoPull { 146 var source *tangled.RepoPull_Source 147 148 if p.Source != nil { 149 repoAt := p.Source.RepoAt.String() 150 source = &tangled.RepoPull_Source{ 151 Repo: &repoAt, 152 Branch: p.Source.Branch, 153 } 154 } 155 156 var body *string 157 if p.Body != "" { 158 body = &p.Body 159 } 160 return tangled.RepoPull{ 161 Target: &tangled.RepoPull_Target{ 162 Repo: p.Target.RepoAt.String(), 163 Branch: p.Target.Branch, 164 }, 165 Source: source, 166 Title: p.Title, 167 Body: body, 168 Mentions: toStringList(p.Mentions), 169 References: toStringList(p.References), 170 } 171} 172 173func (p *PullRound) AtUri() syntax.ATURI { 174 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", p.Did, tangled.RepoPullNSID, p.Rkey)) 175} 176 177func (p *PullRound) Validate() error { 178 // TODO: validate patches 179 return nil 180} 181 182func toStringList[T fmt.Stringer](list []T) []string { 183 slist := make([]string, len(list)) 184 for i, v := range list { 185 slist[i] = v.String() 186 } 187 return slist 188}