git-pr / contrib: add dev script #13

accepted · opened on 2024-07-22T18:12:32Z by jolheiser
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

Diff ↕

contrib: add dev script

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

REVIEW nice!

Eric Bower <me@erock.io>
Since you mentioned automated testing, I wonder if we could incorporate this into CI?

jolheiser (1):
  contrib: add dev script

 contrib/dev/README.md |  12 +++
 contrib/dev/main.go   | 203 ++++++++++++++++++++++++++++++++++++++++++
 fixtures/fixtures.go  |   6 ++
 3 files changed, 221 insertions(+)
 create mode 100644 contrib/dev/README.md
 create mode 100644 contrib/dev/main.go
 create mode 100644 fixtures/fixtures.go

base-commit: 31fcd4a1f446368c4f1db8427282ee0222962f1f
--
2.45.2
 1From 605c47b7525ae11cba1622c508781c3166a41530 Mon Sep 17 00:00:00 2001
 2From: Eric Bower <me@erock.io>
 3Date: Mon, 22 Jul 2024 14:33:12 -0400
 4Subject: [PATCH 0/1] nice!
 5
 6Since you mentioned automated testing, I wonder if we could incorporate this into CI?
 7
 8jolheiser (1):
 9  contrib: add dev script
10
11 contrib/dev/README.md |  12 +++
12 contrib/dev/main.go   | 203 ++++++++++++++++++++++++++++++++++++++++++
13 fixtures/fixtures.go  |   6 ++
14 3 files changed, 221 insertions(+)
15 create mode 100644 contrib/dev/README.md
16 create mode 100644 contrib/dev/main.go
17 create mode 100644 fixtures/fixtures.go
18
19
20base-commit: 31fcd4a1f446368c4f1db8427282ee0222962f1f
21-- 
222.45.2
ps-24 by erock on 2024-07-22T18:36:17Z

REVIEW nice!

Eric Bower <me@erock.io> 2024-07-22T18:33:12Z
Since you mentioned automated testing, I wonder if we could incorporate this into CI?

jolheiser (1):
  contrib: add dev script

 contrib/dev/README.md |  12 +++
 contrib/dev/main.go   | 203 ++++++++++++++++++++++++++++++++++++++++++
 fixtures/fixtures.go  |   6 ++
 3 files changed, 221 insertions(+)
 create mode 100644 contrib/dev/README.md
 create mode 100644 contrib/dev/main.go
 create mode 100644 fixtures/fixtures.go

base-commit: 31fcd4a1f446368c4f1db8427282ee0222962f1f
--
2.45.2
 1From 605c47b7525ae11cba1622c508781c3166a41530 Mon Sep 17 00:00:00 2001
 2From: Eric Bower <me@erock.io>
 3Date: Mon, 22 Jul 2024 14:33:12 -0400
 4Subject: [PATCH 0/1] nice!
 5
 6Since you mentioned automated testing, I wonder if we could incorporate this into CI?
 7
 8jolheiser (1):
 9  contrib: add dev script
10
11 contrib/dev/README.md |  12 +++
12 contrib/dev/main.go   | 203 ++++++++++++++++++++++++++++++++++++++++++
13 fixtures/fixtures.go  |   6 ++
14 3 files changed, 221 insertions(+)
15 create mode 100644 contrib/dev/README.md
16 create mode 100644 contrib/dev/main.go
17 create mode 100644 fixtures/fixtures.go
18
19
20base-commit: 31fcd4a1f446368c4f1db8427282ee0222962f1f
21-- 
222.45.2

contrib: add dev script

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