repos / git-pr

a self-hosted git collaboration server
git clone https://github.com/picosh/git-pr.git

commit
038aecf
parent
8c56369
author
Eric Bower
date
2024-06-27 17:34:09 -0400 EDT
docs: copy
6 files changed,  +170, -12
M cli.go
M mdw.go
M pr.go
M README.md
+16, -12
 1@@ -1,8 +1,8 @@
 2 # `pico/git-pr` a self-hosted git collaboration server
 3 
 4 We are trying to build the simplest git collaboration tool. The goal is to make
 5-self-hosting a git server as simple as running an SSH server and hosting static
 6-web assets -- all without sacrificing external collaborators.
 7+self-hosting a git server as simple as running an SSH server -- all without
 8+sacrificing external collaborators time and energy.
 9 
10 > `git format-patch` isn't the problem and pull requests aren't the solution.
11 
12@@ -15,7 +15,6 @@ simple self-hosted git solution with the ability to collaborate with external
13 contributors. All the code owner needs to setup a running git server:
14 
15 - A single golang binary
16-- sqlite to store patch requests and other repo metadata
17 
18 All an external contributor needs is:
19 
20@@ -37,7 +36,9 @@ Github pull requests are easy to use, easy to edit, and easy to manage. The
21 downside is it forces the user to be inside their website to perform reviews.
22 For quick changes, this is great, but when you start reading code within a web
23 browser, there are quite a few downsides. At a certain point, it makes more
24-sense to review code inside your local development environment, IDE, etc.
25+sense to review code inside your local development environment, IDE, etc. There
26+are tools and plugins that allow users to review PRs inside their IDE, but it
27+requires a herculean effort to make it usable.
28 
29 Further, self-hosted solutions that mimic a pull request require a lot of
30 infrastructure in order to manage it. A database, a web site connected to git,
31@@ -55,8 +56,9 @@ Instead, we want to create a self-hosted git "server" that can handle sending
32 and receiving patches without the cumbersome nature of setting up email or the
33 limitations imposed by the email protocol. Further, we want the primary workflow
34 to surround the local development environment. Github is bringing the IDE to the
35-browser in order to support their workflow, we want to bring the workflow to the
36-local dev environment.
37+browser in order to support their workflow, we want to flip that idea on its
38+head by making code reviews a first-class citizen inside your local development
39+environment.
40 
41 We see this as a hybrid between the github workflow of a pull request and
42 sending and receiving patches over email.
43@@ -82,18 +84,18 @@ git clone git@github.com:user/noice.git
44 git add -A && git commit -m "fix: some bugs"
45 
46 # Contributor runs:
47-git format-patch --stdout | ssh pr.pico.sh pr create noice
48+git format-patch origin/main --stdout | ssh pr.pico.sh pr create noice
49 # > Patch Request has been created (ID: 1)
50 
51 # Owner can checkout patch:
52-ssh pr.pico.sh pr print 1 | git am -3 -i
53+ssh pr.pico.sh pr print 1 | git am -3
54 # Owner can comment (IN CODE), commit, then send another format-patch
55 # on top of the PR:
56-git format-patch HEAD~1 --stdout | ssh pr.pico.sh pr review 1
57+git format-patch origin/main --stdout | ssh pr.pico.sh pr add --review 1
58 # UI clearly marks patch as a review
59 
60 # Contributor can checkout reviews
61-ssh pr.pico.sh pr print 1 | git am -3 -i
62+ssh pr.pico.sh pr print 1 | git am -3
63 
64 # Owner can reject a pr:
65 ssh pr.pico.sh pr close 1
66@@ -102,7 +104,7 @@ ssh pr.pico.sh pr close 1
67 ssh pr.pico.sh pr accept 1
68 
69 # Owner can cleanup PR:
70-ssh pr.pico.sh pr print 1 | git am -3 -i
71+ssh pr.pico.sh pr print 1 | git am -3
72 
73 # Then push to upstream
74 git push origin main
75@@ -127,7 +129,9 @@ We could figure out a way to leverage `git notes` for reviews / comments, but
76 honestly, that solution feels brutal and outside the comfort level of most git
77 users. Just send reviews as code and write comments in the programming language
78 you are using. It's the job of the contributor to "address" those comments and
79-then remove them in subsequent patches.
80+then remove them in subsequent patches. This is the forcing function to address
81+all comments: the patch won't be merged if there are comment unaddressed in
82+code; they cannot be ignored or else they will be upstreamed erroneously.
83 
84 # research
85 
M cli.go
+7, -0
 1@@ -49,6 +49,13 @@ Here's how it works:
 2 		Usage:       "Collaborate with contributors for your git project",
 3 		Writer:      sesh,
 4 		ErrWriter:   sesh,
 5+		ExitErrHandler: func(cCtx *cli.Context, err error) {
 6+			wish.Fatalln(sesh, err)
 7+		},
 8+		OnUsageError: func(cCtx *cli.Context, err error, isSubcommand bool) error {
 9+			wish.Fatalln(sesh, err)
10+			return nil
11+		},
12 		Commands: []*cli.Command{
13 			/* {
14 				Name:  "git-receive-pack",
M mdw.go
+1, -0
1@@ -15,6 +15,7 @@ func GitPatchRequestMiddleware(be *Backend, pr GitPatchRequest) wish.Middleware
2 			if err != nil {
3 				be.Logger.Error("error when running cli", "err", err)
4 				wish.Fatalln(sesh, err)
5+				next(sesh)
6 				return
7 			}
8 		}
M pr.go
+10, -0
 1@@ -391,6 +391,11 @@ func (cmd PrCmd) parsePatchSet(patchset io.Reader) ([]*Patch, error) {
 2 			return nil, err
 3 		}
 4 
 5+		if len(diffFiles) == 0 {
 6+			cmd.Backend.Logger.Info("not diff files found for patch, skipping")
 7+			continue
 8+		}
 9+
10 		authorName := "Unknown"
11 		authorEmail := ""
12 		if header.Author != nil {
13@@ -463,6 +468,11 @@ func (cmd PrCmd) SubmitPatchRequest(repoID string, userID int64, patchset io.Rea
14 	if err != nil {
15 		return nil, err
16 	}
17+
18+	if len(patches) == 0 {
19+		return nil, fmt.Errorf("after parsing patchset we did't find any patches, did you send us an empty patchset?")
20+	}
21+
22 	prName := ""
23 	prText := ""
24 	if len(patches) > 0 {
M tmpl/pr-header.html
+4, -0
 1@@ -16,6 +16,10 @@
 2     <div class="group">
 3       <pre class="m-0"># add changes to patch request
 4 git format-patch {{.Branch}} --stdout | ssh pr.pico.sh pr add {{.Pr.ID}}</pre>
 5+      <pre class="m-0"># add review to patch request
 6+git format-patch {{.Branch}} --stdout | ssh pr.pico.sh pr add --review {{.Pr.ID}}</pre>
 7+      <pre class="m-0"># overwrite patches
 8+git format-patch {{.Branch}} --stdout | ssh pr.pico.sh pr add --force {{.Pr.ID}}</pre>
 9       <pre class="m-0"># checkout all patches
10 ssh pr.pico.sh pr print {{.Pr.ID}} | git am -3</pre>
11       <pre class="m-0"># checkout specific patch
M tmpl/repo-list.html
+132, -0
  1@@ -13,6 +13,138 @@
  2   <h1 class="text-2xl">git-pr</h1>
  3   <div>A new git collaboration service.</div>
  4   <pre class="m-0">ssh pr.pico.sh help</pre>
  5+  <details>
  6+    <summary>Intro</summary>
  7+
  8+    <div>
  9+      <p>
 10+        We are trying to build the simplest git collaboration tool. The goal is to make
 11+        self-hosting a git server as simple as running an SSH server -- all without
 12+        sacrificing external collaborators time and energy.
 13+      </p>
 14+
 15+      <blockquote>
 16+        <code>git format-patch</code> isn't the problem and pull requests aren't the solution.
 17+      </blockquote>
 18+
 19+      <p>
 20+        We are combining mailing list and pull request workflows. In order to build the
 21+        simplest collaboration tool, we needed something as simple as generating patches
 22+        but the ease-of-use of pull requests.
 23+      </p>
 24+
 25+      <p>
 26+        The goal is not to create another code forge here. The goal is to create a very
 27+        simple self-hosted git solution with the ability to collaborate with external
 28+        contributors. All the code owner needs to setup a running git server:
 29+      </p>
 30+
 31+      <ul><li>A single golang binary</li></ul>
 32+
 33+      <div>
 34+        All an external contributor needs is:
 35+      </div>
 36+
 37+      <ul>
 38+        <li>An SSH keypair</li>
 39+        <li>An SSH client</li>
 40+      </ul>
 41+
 42+      <h2 class="text-xl">the problem</h2>
 43+
 44+      <p>
 45+        Email is great as a decentralized system to send and receive changes (patchsets)
 46+        to a git repo. However, onboarding a new user to a mailing list, properly
 47+        setting up their email client, and then finally submitting the code contribution
 48+        is enough to make many developers give up. Further, because we are leveraging
 49+        the email protocol for collaboration, we are limited by its feature-set. For
 50+        example, it is not possible to make edits to emails, everyone has a different
 51+        client, those clients have different limitations around plain text email and
 52+        downloading patches from it.
 53+      </p>
 54+
 55+      <p>
 56+        Github pull requests are easy to use, easy to edit, and easy to manage. The
 57+        downside is it forces the user to be inside their website to perform reviews.
 58+        For quick changes, this is great, but when you start reading code within a web
 59+        browser, there are quite a few downsides. At a certain point, it makes more
 60+        sense to review code inside your local development environment, IDE, etc. There
 61+        are tools and plugins that allow users to review PRs inside their IDE, but it
 62+        requires a herculean effort to make it usable.
 63+      </p>
 64+
 65+      <p>
 66+        Further, self-hosted solutions that mimic a pull request require a lot of
 67+        infrastructure in order to manage it. A database, a web site connected to git,
 68+        admin management, and services to manage it all. Another big point of friction:
 69+        before an external user submits a code change, they first need to create an
 70+        account and then login. This adds quite a bit of friction for a self-hosted
 71+        solution, not only for an external contributor, but also for the code owner who
 72+        has to provision the infra. Often times they also have to fork the repo within
 73+        the code forge before submitting a PR. Then they never make a contribution ever
 74+        again and keep a forked repo around forever. That seems silly.
 75+      </p>
 76+
 77+      <h2 class="text-xl">introducing patch requests (PR)</h2>
 78+
 79+      <p>
 80+        Instead, we want to create a self-hosted git "server" that can handle sending
 81+        and receiving patches without the cumbersome nature of setting up email or the
 82+        limitations imposed by the email protocol. Further, we want the primary workflow
 83+        to surround the local development environment. Github is bringing the IDE to the
 84+        browser in order to support their workflow, we want to flip that idea on its
 85+        head by making code reviews a first-class citizen inside your local development
 86+        environment.
 87+      </p>
 88+
 89+      <p>
 90+        We see this as a hybrid between the github workflow of a pull request and
 91+        sending and receiving patches over email.
 92+      </p>
 93+
 94+      <p>
 95+        The basic idea is to leverage an SSH app to handle most of the interaction
 96+        between contributor and owner of a project. Everything can be done completely
 97+        within the terminal, in a way that is ergonomic and fully featured.
 98+      </p>
 99+
100+      <p>
101+        Notifications would happen with RSS and all state mutations would result in the
102+        generation of static web assets so it can all be hosted using a simple file web
103+        server.
104+      </p>
105+
106+      <h3 class="text-lg">format-patch workflow</h3>
107+
108+      <p>
109+        The fundamental collaboration tool here is <code>format-patch</code>. Whether you a
110+        submitting code changes or you are reviewing code changes, it all happens in
111+        code. Both contributor and owner are simply creating new commits and generating
112+        patches on top of each other. This obviates the need to have a web viewer where
113+        the reviewing can "comment" on a line of code block. There's no need, apply the
114+        contributor's patches, write comments or code changes, generate a new patch,
115+        send the patch to the git server as a "review." This flow also works the exact
116+        same if two users are collaborating on a set of changes.
117+      </p>
118+
119+      <p>
120+        This also solves the problem of sending multiple patchsets for the same code
121+        change. There's a single, central Patch Request where all changes and
122+        collaboration happens.
123+      </p>
124+
125+      <p>
126+        We could figure out a way to leverage <code>git notes</code> for reviews / comments, but
127+        honestly, that solution feels brutal and outside the comfort level of most git
128+        users. Just send reviews as code and write comments in the programming language
129+        you are using. It's the job of the contributor to "address" those comments and
130+        then remove them in subsequent patches. This is the forcing function to address
131+        all comments: the patch won't be merged if there are comment unaddressed in
132+        code; they cannot be ignored or else they will be upstreamed erroneously.
133+      </p>
134+    </div>
135+  </details>
136+
137   <details>
138     <summary>How do Patch Requests work?</summary>
139       <div>