internal/store/commentmigrate.go

ac6714f569b1b7f1cf59ffa97b99c505ae2d6698
gitbay/internal/store/commentmigrate.go history · blame · raw

80 lines · 2466 bytes

 1package store
 2
 3import (
 4	"fmt"
 5	"regexp"
 6)
 7
 8// commitRefPat matches the legacy commit-reference comment format, written
 9// before these entries were system messages: "closed by commit <sha>: …"
10// or "referenced in commit <sha>: …" with a bare short sha.
11var commitRefPat = regexp.MustCompile(`^((?:closed by|referenced in) commit )([0-9a-f]{7,40})(: [\s\S]*)$`)
12
13// MigrateCommitRefComments converts legacy commit-reference comments into
14// system messages with a linked sha, matching what new references produce.
15// It is idempotent: only kind='comment' rows are considered, and converted
16// rows become kind='system'. Returns the number converted.
17func (s *Store) MigrateCommitRefComments() (int, error) {
18	n1, err := s.migrateRefTable(
19		"issue_comments", "issues", "issue_id",
20		"'closed by commit %' OR c.body LIKE 'referenced in commit %'")
21	if err != nil {
22		return n1, err
23	}
24	n2, err := s.migrateRefTable(
25		"mr_comments", "merge_requests", "mr_id",
26		"'closed by commit %' OR c.body LIKE 'referenced in commit %'")
27	return n1 + n2, err
28}
29
30func (s *Store) migrateRefTable(table, itemTable, fk, likeClause string) (int, error) {
31	q := fmt.Sprintf(`
32		SELECT c.id, c.body, COALESCE(u.username, o.name) || '/' || r.name
33		FROM %s c
34		JOIN %s it ON it.id = c.%s
35		JOIN repos r ON r.id = it.repo_id
36		LEFT JOIN users u ON r.owner_kind = 'user' AND u.id = r.owner_id
37		LEFT JOIN orgs  o ON r.owner_kind = 'org'  AND o.id = r.owner_id
38		WHERE c.kind = 'comment' AND (c.body LIKE %s)`, table, itemTable, fk, likeClause)
39	rows, err := s.DB.Query(q)
40	if err != nil {
41		return 0, err
42	}
43	type conv struct {
44		id   int64
45		body string
46	}
47	var todo []conv
48	for rows.Next() {
49		var id int64
50		var body, path string
51		if err := rows.Scan(&id, &body, &path); err != nil {
52			rows.Close()
53			return 0, err
54		}
55		m := commitRefPat.FindStringSubmatch(body)
56		if m == nil {
57			continue // LIKE candidate that isn't the exact format
58		}
59		verb, sha, rest := m[1], m[2], m[3]
60		newBody := fmt.Sprintf("%s[%s](/%s/commit/%s)%s", verb, sha, path, sha, rest)
61		todo = append(todo, conv{id, newBody})
62	}
63	rows.Close()
64	if err := rows.Err(); err != nil {
65		return 0, err
66	}
67
68	tx, err := s.DB.Begin()
69	if err != nil {
70		return 0, err
71	}
72	defer tx.Rollback()
73	upd := fmt.Sprintf("UPDATE %s SET body = ?, kind = 'system' WHERE id = ?", table)
74	for _, c := range todo {
75		if _, err := tx.Exec(upd, c.body, c.id); err != nil {
76			return 0, err
77		}
78	}
79	return len(todo), tx.Commit()
80}