Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Assemble an issue or change from the indexed rows

9d8dd1bc7f52d0fcdfcf286734a2c7735c1d051d · Keenan Nemetz · 10d ago · parent 6b8f84c4

Assemble an issue or change from the indexed rows

The detail pages can read the same rows the lists do, as long as the
refresh runs first (it does) and the assembled record is exactly what the
branch says. Add Store.Issue and Store.Request, which put one entity back
together from its row, its comments, and — for a change — its closes and
approvals.

Two orderings had to be stored rather than inferred:

- request_closes keeps the file's position, because the branch lists the
  issues a change closes in the order the author wrote them, not in id
  order.
- comments and approvals are read in the same id/principal order git's
  path listing gives, so a rebuilt thread matches the one read from git.

The tests compare both readers field by field (reflect.DeepEqual) on an
issue with labels, assignees, a reply and a comment, and on a change with
two closes, an anchored comment and an approval. The schema version is
bumped so existing rows are rebuilt with the new column.

forge/index/requests.go +10−6

@@ -133,6 +133,7 @@ type ApprovalRow struct {
133 133 Principal string
134 134 Head string
135 135 Base string
136 Created time.Time
136 137 }
137 138
138 139 // Approvals returns the approvals for the named requests, keyed by request id.
@@ -148,8 +149,9 @@ func (s *Store) Approvals(repoID string, requestIDs []string) (map[string][]Appr
148 149 for _, id := range requestIDs {
149 150 args = append(args, id)
150 151 }
151 q := `SELECT request_id, principal, head, base FROM request_approvals
152 WHERE repo_id=? AND request_id IN (?` + strings.Repeat(",?", len(requestIDs)-1) + `)`
152 q := `SELECT request_id, principal, head, base, created FROM request_approvals
153 WHERE repo_id=? AND request_id IN (?` + strings.Repeat(",?", len(requestIDs)-1) + `)
154 ORDER BY request_id, principal`
153 155 rows, err := s.db.Query(q, args...)
154 156 if err != nil {
155 157 return nil, err
@@ -158,9 +160,11 @@ func (s *Store) Approvals(repoID string, requestIDs []string) (map[string][]Appr
158 160 for rows.Next() {
159 161 var id string
160 162 var a ApprovalRow
161 if err := rows.Scan(&id, &a.Principal, &a.Head, &a.Base); err != nil {
163 var created int64
164 if err := rows.Scan(&id, &a.Principal, &a.Head, &a.Base, &created); err != nil {
162 165 return nil, err
163 166 }
167 a.Created = unixTime(created)
164 168 out[id] = append(out[id], a)
165 169 }
166 170 return out, rows.Err()
@@ -202,10 +206,10 @@ func insertRequest(tx execer, repoID string, req *metadata.Request) error {
202 206 ); err != nil {
203 207 return err
204 208 }
205 for _, id := range req.Closes {
209 for i, id := range req.Closes {
206 210 if _, err := tx.Exec(
207 `INSERT OR IGNORE INTO request_closes(repo_id, request_id, issue_id) VALUES(?,?,?)`,
208 repoID, req.ID, id); err != nil {
211 `INSERT OR IGNORE INTO request_closes(repo_id, request_id, issue_id, position) VALUES(?,?,?,?)`,
212 repoID, req.ID, id, i); err != nil {
209 213 return err
210 214 }
211 215 }