cmd/gitbayd/adminabout.go
98 lines · 3008 bytes
1package main
2
3import (
4 "fmt"
5
6 "github.com/spf13/cobra"
7
8 "gitbay.org/gitbay/internal/config"
9 "gitbay.org/gitbay/internal/control"
10 "gitbay.org/gitbay/internal/gitutil"
11 "gitbay.org/gitbay/internal/store"
12)
13
14// adminMigrateProfileAboutCmd drains profile_about_backfill: each owner's
15// parked about text becomes profile/README.* in <owner>/.gitbay. Idempotent
16// — an owner who already has the file keeps it and loses the row.
17func adminMigrateProfileAboutCmd() *cobra.Command {
18 return &cobra.Command{
19 Use: "migrate-profile-about",
20 Short: "write parked profile about text into each owner's .gitbay repository",
21 RunE: func(cmd *cobra.Command, args []string) error {
22 cfg, err := config.Load(configPath)
23 if err != nil {
24 return err
25 }
26 st, err := openStore(cfg)
27 if err != nil {
28 return err
29 }
30 defer st.Close()
31 rows, err := st.PendingAboutBackfill()
32 if err != nil {
33 return err
34 }
35 n := 0
36 for _, row := range rows {
37 written, err := writeAbout(cfg, st, row)
38 if err != nil {
39 return fmt.Errorf("%s: %w", row.OwnerName, err)
40 }
41 if err := st.ClearAboutBackfill(row.OwnerKind, row.OwnerID); err != nil {
42 return err
43 }
44 if written {
45 n++
46 }
47 }
48 fmt.Printf("wrote %d profile about file(s)\n", n)
49 return nil
50 },
51 }
52}
53
54// writeAbout creates <owner>/.gitbay if it does not exist and commits the
55// about at the recorded format. It reports whether it wrote anything: an
56// owner who already has the file is left alone.
57func writeAbout(cfg config.Config, st *store.Store, row store.AboutRow) (bool, error) {
58 path := row.OwnerName + "/" + control.ProfileRepoName
59 repo, err := st.RepoByPath(path)
60 if err != nil {
61 // Public, because the about it carries was public where it was.
62 id, cerr := st.CreateRepo(row.OwnerKind, row.OwnerID, control.ProfileRepoName, "public")
63 if cerr != nil {
64 return false, cerr
65 }
66 dir := control.RepoDir(cfg.Server.Root, row.OwnerName, control.ProfileRepoName)
67 if ierr := gitutil.InitBare(dir, "main", control.HooksDir(cfg.Server.Root)); ierr != nil {
68 st.DeleteRepo(id)
69 return false, ierr
70 }
71 if repo, err = st.RepoByPath(path); err != nil {
72 return false, err
73 }
74 }
75 dir := control.RepoDir(cfg.Server.Root, repo.OwnerName, repo.Name)
76 ext := ".md"
77 if row.Format == "org" {
78 ext = ".org"
79 }
80 file := control.AboutBase + ext
81 if _, err := gitutil.ReadBlob(dir, repo.DefaultBranch, file, 1); err == nil {
82 return false, nil // already there
83 }
84 // A commit carries an identity. An owner without a verified address,
85 // and every org, gets the noreply form rather than no commit.
86 email := row.OwnerName + "@users.noreply." + cfg.SiteHost()
87 if row.OwnerKind == "user" {
88 if addr, _ := st.PrimaryVerifiedEmail(row.OwnerID); addr != "" {
89 email = addr
90 }
91 }
92 if _, err := gitutil.CommitFileChange(dir, repo.DefaultBranch, file,
93 []byte(row.About), row.OwnerName, email,
94 "move profile about out of the database"); err != nil {
95 return false, err
96 }
97 return true, nil
98}