dashboard / pico / feat: private obj store service #13 rss

closed · opened on 2024-08-18T15:28:14Z by erock
Help
# add changes to patch request
git format-patch main --stdout | ssh pr.pico.sh pr add 13
# add review to patch request
git format-patch main --stdout | ssh pr.pico.sh pr add --review 13
# remove patchset
ssh pr.pico.sh ps rm ps-x
# checkout all patches
ssh pr.pico.sh pr print 13 | git am -3
# print a diff between the last two patches in a patch request
ssh pr.pico.sh pr diff 13
# accept PR
ssh pr.pico.sh pr accept 13
# close PR
ssh pr.pico.sh pr close 13

Logs

jolheiser created pr with ps-21 on 2024-07-22T18:12:32Z
erock added ps-24 on 2024-07-22T18:36:17Z
erock changed status on 2024-07-22T18:36:17Z {"status":"accepted"}

Patchsets

ps-21 by jolheiser on 2024-07-22T18:12:32Z
Range Diff ↕
-: ------- > 1: 605c47b nice!
1: be8edcf = 2: 605c47b contrib: add dev script
ps-24 by erock on 2024-07-22T18:36:17Z

Patchset ps-21

contrib: add dev script

jolheiser
2024-07-22T18:05:39Z
Back to top

contrib: add dev script

This patch adds a fairly contained dev script that almost doubles as an integration test if you squint hard enough.
It runs an isolated instance that we can add more things to, it at least seems handy to me for quickly testing how changes affect e.g. the web UI, RSS feed, etc.

Signed-off-by: jolheiser <git@jolheiser.com>
contrib/dev/README.md link
+12 -0
 1diff --git a/contrib/dev/README.md b/contrib/dev/README.md
 2new file mode 100644
 3index 0000000..9ad8950
 4--- /dev/null
 5+++ b/contrib/dev/README.md
 6@@ -0,0 +1,12 @@
 7+# dev script
 8+
 9+`go run ./contrib/dev/`
10+
11+If you want to instead use this to bootstrap:
12+
13+1. `go run ./contrib/dev/ --cleanup=false`
14+2. Note the tmp dir printed out
15+3. Stop the program `Ctrl+C`
16+4. Modify as needed within the tmp dir
17+5. Run `git-dir` and point at the config contained within the tmp dir
18+6. Remember to clean up the tmp dir yourself when finished
contrib/dev/main.go link
+203 -0
  1diff --git a/contrib/dev/main.go b/contrib/dev/main.go
  2new file mode 100644
  3index 0000000..088e8cf
  4--- /dev/null
  5+++ b/contrib/dev/main.go
  6@@ -0,0 +1,203 @@
  7+package main
  8+
  9+import (
 10+	"crypto/ed25519"
 11+	"crypto/rand"
 12+	"flag"
 13+	"fmt"
 14+	"log/slog"
 15+	"os"
 16+	"os/signal"
 17+	"path/filepath"
 18+	"time"
 19+
 20+	"github.com/picosh/git-pr"
 21+	"github.com/picosh/git-pr/fixtures"
 22+	"golang.org/x/crypto/ssh"
 23+)
 24+
 25+func main() {
 26+	cleanupFlag := flag.Bool("cleanup", true, "Clean up tmp dir after quitting (default: true)")
 27+	flag.Parse()
 28+
 29+	tmp, err := os.MkdirTemp(os.TempDir(), "git-pr*")
 30+	if err != nil {
 31+		panic(err)
 32+	}
 33+	defer func() {
 34+		if *cleanupFlag {
 35+			os.RemoveAll(tmp)
 36+		}
 37+	}()
 38+	fmt.Println(tmp)
 39+
 40+	adminKey, userKey := generateKeys()
 41+
 42+	cfgPath := filepath.Join(tmp, "git-pr.toml")
 43+	cfgFi, err := os.Create(cfgPath)
 44+	if err != nil {
 45+		panic(err)
 46+	}
 47+	cfgFi.WriteString(fmt.Sprintf(cfgTmpl, tmp, adminKey.public()))
 48+	cfgFi.Close()
 49+
 50+	opts := &slog.HandlerOptions{
 51+		AddSource: true,
 52+	}
 53+	logger := slog.New(
 54+		slog.NewTextHandler(os.Stdout, opts),
 55+	)
 56+	cfg := git.NewGitCfg(cfgPath, logger)
 57+	go git.GitSshServer(cfg)
 58+	time.Sleep(time.Second)
 59+	go git.StartWebServer(cfg)
 60+
 61+	// Hack to wait for startup
 62+	time.Sleep(time.Second)
 63+
 64+	patch, err := fixtures.Fixtures.ReadFile("single.patch")
 65+	if err != nil {
 66+		panic(err)
 67+	}
 68+	otherPatch, err := fixtures.Fixtures.ReadFile("with-cover.patch")
 69+	if err != nil {
 70+		panic(err)
 71+	}
 72+
 73+	// Accepted patch
 74+	userKey.cmd(patch, "pr create test")
 75+	userKey.cmd(nil, "pr edit 1 Accepted patch")
 76+	adminKey.cmd(nil, "pr accept 1")
 77+
 78+	// Closed patch (admin)
 79+	userKey.cmd(patch, "pr create test")
 80+	userKey.cmd(nil, "pr edit 2 Closed patch (admin)")
 81+	adminKey.cmd(nil, "pr close 2")
 82+
 83+	// Closed patch (contributor)
 84+	userKey.cmd(patch, "pr create test")
 85+	userKey.cmd(nil, "pr edit 3 Closed patch (contributor)")
 86+	userKey.cmd(nil, "pr close 3")
 87+
 88+	// Reviewed patch
 89+	userKey.cmd(patch, "pr create test")
 90+	userKey.cmd(nil, "pr edit 4 Reviewed patch")
 91+	adminKey.cmd(otherPatch, "pr add --review 4")
 92+
 93+	// Accepted patch with review
 94+	userKey.cmd(patch, "pr create test")
 95+	userKey.cmd(nil, "pr edit 5 Accepted patch with review")
 96+	adminKey.cmd(otherPatch, "pr add --accept 5")
 97+
 98+	// Closed patch with review
 99+	userKey.cmd(patch, "pr create test")
100+	userKey.cmd(nil, "pr edit 6 Closed patch with review")
101+	adminKey.cmd(otherPatch, "pr add --close 6")
102+
103+	fmt.Println("time to do some testing...")
104+	ch := make(chan os.Signal, 1)
105+	signal.Notify(ch, os.Interrupt, os.Kill)
106+	<-ch
107+}
108+
109+type sshKey struct {
110+	username string
111+	signer   ssh.Signer
112+}
113+
114+func (s sshKey) public() string {
115+	pubkey := s.signer.PublicKey()
116+	return string(ssh.MarshalAuthorizedKey(pubkey))
117+}
118+
119+func (s sshKey) cmd(patch []byte, cmd string) {
120+	host := "localhost:2222"
121+
122+	config := &ssh.ClientConfig{
123+		User: s.username,
124+		Auth: []ssh.AuthMethod{
125+			ssh.PublicKeys(s.signer),
126+		},
127+		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
128+	}
129+
130+	client, err := ssh.Dial("tcp", host, config)
131+	if err != nil {
132+		panic(err)
133+	}
134+	defer client.Close()
135+
136+	session, err := client.NewSession()
137+	if err != nil {
138+		panic(err)
139+	}
140+	defer session.Close()
141+
142+	stdinPipe, err := session.StdinPipe()
143+	if err != nil {
144+		panic(err)
145+	}
146+
147+	if err := session.Start(cmd); err != nil {
148+		panic(err)
149+	}
150+
151+	if patch != nil {
152+		_, err = stdinPipe.Write(patch)
153+		if err != nil {
154+			panic(err)
155+		}
156+	}
157+
158+	stdinPipe.Close()
159+
160+	if err := session.Wait(); err != nil {
161+		panic(err)
162+	}
163+}
164+
165+func generateKeys() (sshKey, sshKey) {
166+	_, adminKey, err := ed25519.GenerateKey(rand.Reader)
167+	if err != nil {
168+		panic(err)
169+	}
170+
171+	adminSigner, err := ssh.NewSignerFromKey(adminKey)
172+	if err != nil {
173+		panic(err)
174+	}
175+
176+	_, userKey, err := ed25519.GenerateKey(rand.Reader)
177+	if err != nil {
178+		panic(err)
179+	}
180+
181+	userSigner, err := ssh.NewSignerFromKey(userKey)
182+	if err != nil {
183+		panic(err)
184+	}
185+
186+	return sshKey{
187+			username: "admin",
188+			signer:   adminSigner,
189+		}, sshKey{
190+			username: "contributor",
191+			signer:   userSigner,
192+		}
193+}
194+
195+// args: tmpdir, adminKey
196+var cfgTmpl = `# url is used for help commands, exclude protocol
197+url = "localhost"
198+# where we store the sqlite db, this toml file, git repos, and ssh host keys
199+data_dir = %q
200+# this gives users the ability to submit reviews and other admin permissions
201+admins = [%q]
202+# set datetime format for our clients
203+time_format = "01/02/2006 15:04:05 07:00"
204+
205+# add as many repos as you want
206+[[repo]]
207+id = "test"
208+clone_addr = "https://github.com/picosh/test.git"
209+desc = "Test repo"`
fixtures/fixtures.go link
+6 -0
 1diff --git a/fixtures/fixtures.go b/fixtures/fixtures.go
 2new file mode 100644
 3index 0000000..fc24d94
 4--- /dev/null
 5+++ b/fixtures/fixtures.go
 6@@ -0,0 +1,6 @@
 7+package fixtures
 8+
 9+import "embed"
10+
11+//go:embed *
12+var Fixtures embed.FS