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/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

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

Code

392 commit(s) on main

Merge change request 01M70WES5ZZDJ6RP226WB11BBZ: Let people rename and remove their own passkeys keenan · 2h ago 4b8c9e1d
history blame raw 2.2 KiB
1package index
2
3// The activity feed's state changes: closed, reopened and merged events.
4//
5// The event is a metadata commit subject, so the refresh derives it from the
6// commits in the range it is applying. The rows are keyed by commit, which is
7// what makes an interrupted refresh safe to retry: the work it already did is
8// ignored rather than duplicated.
9
10import (
11 "database/sql"
12 "time"
13
14 "rodent.software/vole/core/git"
15 "rodent.software/vole/metadata"
16)
17
18// insertStateChanges records the events among a set of metadata commits, which
19// arrive newest first. The ordinal is assigned oldest first so that two events in
20// the same second keep the order the branch has them; commit times are seconds,
21// and a close followed by a reopen often lands inside one.
22func insertStateChanges(tx *sql.Tx, repoID string, commits []git.Commit) error {
23 var next int
24 if err := tx.QueryRow(
25 `SELECT COALESCE(MAX(ordinal), 0) FROM state_changes WHERE repo_id=?`, repoID).Scan(&next); err != nil {
26 return err
27 }
28 for i := len(commits) - 1; i >= 0; i-- {
29 c := commits[i]
30 kind, id, state, ok := metadata.ParseStateSubject(c.Subject)
31 if !ok {
32 continue
33 }
34 next++
35 if _, err := tx.Exec(
36 `INSERT OR IGNORE INTO state_changes(repo_id, sha, kind, id, state, actor, at, ordinal)
37 VALUES(?,?,?,?,?,?,?,?)`,
38 repoID, c.SHA, kind, id, state, c.Author, c.When, next); err != nil {
39 return err
40 }
41 }
42 return nil
43}
44
45// StateChanges returns a repo's state changes newest first. A limit of zero
46// returns all of them; the feed asks for a window, the rebuild needs none.
47func (s *Store) StateChanges(repoID string, limit int) ([]metadata.StateChange, error) {
48 q := `SELECT kind, id, state, actor, at FROM state_changes
49 WHERE repo_id=? ORDER BY ordinal DESC`
50 args := []any{repoID}
51 if limit > 0 {
52 q += ` LIMIT ?`
53 args = append(args, limit)
54 }
55 rows, err := s.db.Query(q, args...)
56 if err != nil {
57 return nil, err
58 }
59 defer rows.Close()
60 var out []metadata.StateChange
61 for rows.Next() {
62 var (
63 sc metadata.StateChange
64 at int64
65 )
66 if err := rows.Scan(&sc.Kind, &sc.ID, &sc.State, &sc.Actor, &at); err != nil {
67 return nil, err
68 }
69 sc.Time = time.Unix(at, 0).UTC()
70 out = append(out, sc)
71 }
72 return out, rows.Err()
73}
74