dashboard / erock/git-pr / refactor: custom index page #56 rss

accepted · opened on 2025-03-27T20:16:09Z by erock
Help
checkout latest patchset:
ssh pr.pico.sh print pr-56 | git am -3
checkout any patchset in a patch request:
ssh pr.pico.sh print ps-X | git am -3
add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 56
add review to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add --review 56
accept PR:
ssh pr.pico.sh pr accept 56
close PR:
ssh pr.pico.sh pr close 56
Timeline Patchsets

Range-diff rd-116

title
feat: allow config `desc` to add a description box to index page
description
Patch changed
old #1
a2710a3
new #1
7338b44
Back to top
1: a2710a3 ! 1: 7338b44 feat: allow config `desc` to add a description box to index page
title changed
- refactor: custom index page
+ feat: allow config `desc` to add a description box to index page
message changed
- This commit will support a custom landing page for git-pr instances that
maintainers can fully customize.

Maintainers can run `ssh {server} index` to print the index template
that they can place inside their `data_dir`.
+ refactor: consolidate docs page onto index

This change will allow maintainers to add a description box to the top
of their git-pr instance as an introduction to their service.

old

old:cli.go new:cli.go
 }
 
 func NewCli(sesh ssh.Session, be *Backend, pr GitPatchRequest) *cli.App {
-	desc := `Patchbin: a supercharged pastebin for git collaboration.
+	desc := `git-pr: the simplest git collaboration tool.
 
 Here's how it works:
 	- External contributor clones repo (git-clone)
 	app := &cli.App{
 		Name:        "ssh",
 		Description: desc,
-		Usage:       "Collaborate with contributors for your git project",
+		Usage:       "Send, receive, and review git patches",
 		Writer:      sesh,
 		ErrWriter:   sesh,
 		ExitErrHandler: func(cCtx *cli.Context, err error) {
 			return nil
 		},
 		Commands: []*cli.Command{
+			{
+				Name:  "index",
+				Usage: "Generate an index page",
+				Args:  true,
+				Action: func(cCtx *cli.Context) error {
+					indexFile := `{{template "base" .}}
+{{define "title"}}git-pr{{end}}
+
+{{define "meta"}}
+{{end}}
+
+{{define "body"}}
+<header class="group">
+  <h1 class="text-2xl">git-pr</h1>
+  <div>
+    <span>The simplest git collaboration service</span> &middot; <a href="/e">explore</a>
+  </div>
+</header>
+
+<main></main>
+
+<footer class="mt">Built by <a href="https://pico.sh">pico.sh</a></footer>
+{{end}}`
+					wish.Println(sesh, indexFile)
+					return nil
+				},
+			},
 			{
 				Name:  "logs",
 				Usage: "List event logs with filters",

new


                    

old

new:tmpl/explore.html
+{{template "base" .}}
+
+{{define "title"}}explore prs{{end}}
+
+{{define "meta"}}
+<link rel="alternate" type="application/atom+xml"
+      title="RSS feed for git collaboration server"
+      href="/rss" />
+{{end}}
+
+{{define "body"}}
+<header class="group">
+  <h1 class="text-2xl">explore</h1>
+  <div>
+    <span>View all of the latest patch requests</span>
+  </div>
+</header>
+
+<main>
+  <div>
+    filter
+    <a href="/">open</a> <code>{{.NumOpen}}</code>
+    &middot;
+    <a href="/?status=accepted">accepted</a> <code>{{.NumAccepted}}</code>
+    &middot;
+    <a href="/?status=closed">closed</a> <code>{{.NumClosed}}</code>
+  </div>
+  {{template "pr-table" .Prs}}
+</main>
+
+<footer class="mt">
+  <div><a href="/rss">rss</a></div>
+</footer>
+{{end}}

new


                    

old

old:tmpl/index.html new:tmpl/index.html
 {{define "title"}}git-pr{{end}}
 
 {{define "meta"}}
-<link rel="alternate" type="application/atom+xml"
-      title="RSS feed for git collaboration server"
-      href="/rss" />
 {{end}}
 
 {{define "body"}}
 <header class="group">
-  <h1 class="text-2xl">patchbin</h1>
+  <h1 class="text-2xl">git-pr</h1>
   <div>
-    <span>A pastebin supercharged for git collaboration</span> &middot;
-    <a href="/docs">docs</a>
-  </div>
-
-  <div class="box-sm">
-    <div>
-      Welcome to <a href="https://pico.sh">pico's</a> managed patchbin service!
-      This is a <strong>public</strong> service that is free to anyone who wants
-      to collaborate on git patches.  The idea is simple: submit a patchset to
-      our service and let anyone collaborate on it by submitting follow-up patchsets.
-      Using this service for the first time?  Creating a patch request is simple:
-    </div>
-
-    <pre class="text-sm">git format-patch main --stdout | ssh pr.pico.sh pr create {repo}</pre>
-
-    <div>
-      When running that command we will automatically create a user and a repo
-      if one doesn't exist. Once the patches have been submitted you'll receive
-      a link that you can send to a reviewer.  Anyone can review patch requests.
-      Want to submit a v2 of the patch request?
-    </div>
-
-    <pre class="text-sm">git format-patch main --stdout | ssh pr.pico.sh pr add {prID}</pre>
-
-    <div>
-      Downloading a patchset is easy as well:
-    </div>
-
-    <pre class="text-sm">ssh pr.pico.sh print pr-{prID}</pre>
+    <span>The simplest git collaboration service</span> &middot; <a href="/e">explore</a>
   </div>
 </header>
 
 <main>
-  <div>
-    filter
-    <a href="/">open</a> <code>{{.NumOpen}}</code>
-    &middot;
-    <a href="/?status=accepted">accepted</a> <code>{{.NumAccepted}}</code>
-    &middot;
-    <a href="/?status=closed">closed</a> <code>{{.NumClosed}}</code>
+  <div class="box-sm container-sm">
+    <div>
+      Welcome to <code>git-pr</code>!  If you are the owner of this service we
+      recommend replacing this index page with your own custom one.  To do that,
+      copy the contents of this command into your <code>data_dir</code>:
+    </div>
+    
+    <pre class="m-0 mt">ssh {{.MetaData.URL}} index > ./data/index.html</pre>
   </div>
-  {{template "pr-table" .Prs}}
 </main>
 
-<footer class="mt">
-  <div><a href="/rss">rss</a></div>
-</footer>
+<footer class="mt">Built by <a href="https://pico.sh">pico.sh</a></footer>
 {{end}}

new

old:tmpl/index.html new:tmpl/index.html
 
 {{define "body"}}
 <header class="group">
-  <h1 class="text-2xl">patchbin</h1>
+  <h1 class="text-2xl">git-pr</h1>
   <div>
     <span>A pastebin supercharged for git collaboration</span> &middot;
-    <a href="/docs">docs</a>
+    <a href="https://github.com/picosh/git-pr">github</a> &middot;
+    <a href="https://youtu.be/d28Dih-BBUw">demo video</a>
   </div>
 
+  {{if .MetaData.Desc}}
   <div class="box-sm">
-    <div>
-      Welcome to <a href="https://pico.sh">pico's</a> managed patchbin service!
-      This is a <strong>public</strong> service that is free to anyone who wants
-      to collaborate on git patches.  The idea is simple: submit a patchset to
-      our service and let anyone collaborate on it by submitting follow-up patchsets.
-      Using this service for the first time?  Creating a patch request is simple:
-    </div>
+    <div>{{.MetaData.Desc}}</div>
+  </div>
+  {{end}}
 
-    <pre class="text-sm">git format-patch main --stdout | ssh pr.pico.sh pr create {repo}</pre>
+  <details>
+    <summary>Intro</summary>
 
     <div>
-      When running that command we will automatically create a user and a repo
-      if one doesn't exist. Once the patches have been submitted you'll receive
-      a link that you can send to a reviewer.  Anyone can review patch requests.
-      Want to submit a v2 of the patch request?
+      <p>
+        We are trying to build the simplest git collaboration tool. The goal is to make
+        self-hosting as simple as running an SSH server -- all without
+        sacrificing external collaborators time and energy.
+      </p>
+
+      <blockquote>
+        <code>git format-patch</code> isn't the problem and pull requests aren't the solution.
+      </blockquote>
+
+      <p>
+        We are combining mailing list and pull request workflows. In order to build the
+        simplest collaboration tool, we needed something as simple as generating patches
+        but the ease-of-use of pull requests.
+      </p>
+
+      <p>
+        The goal is not to create another code forge, the goal is to create a very
+        simple self-hosted git solution with the ability to collaborate with external
+        contributors. All the code owner needs to setup a running git server:
+      </p>
+
+      <ul><li>A single golang binary</li></ul>
+
+      <div>
+        All an external contributor needs is:
+      </div>
+
+      <ul>
+        <li>An SSH keypair</li>
+        <li>An SSH client</li>
+      </ul>
+
+      <p>Then everyone subscribes to our RSS feeds to receive updates to patch requests.</p>
+
+      <h2 class="text-xl">the problem</h2>
+
+      <p>
+        Email is great as a decentralized system to send and receive changes (patchsets)
+        to a git repo. However, onboarding a new user to a mailing list, properly
+        setting up their email client, and then finally submitting the code contribution
+        is enough to make many developers give up. Further, because we are leveraging
+        the email protocol for collaboration, we are limited by its feature-set. For
+        example, it is not possible to make edits to emails, everyone has a different
+        client, those clients have different limitations around plain text email and
+        downloading patches from it.
+      </p>
+
+      <p>
+        Github pull requests are easy to use, easy to edit, and easy to manage. The
+        downside is it forces the user to be inside their website to perform reviews.
+        For quick changes, this is great, but when you start reading code within a web
+        browser, there are quite a few downsides. At a certain point, it makes more
+        sense to review code inside your local development environment, IDE, etc. There
+        are tools and plugins that allow users to review PRs inside their IDE, but it
+        requires a herculean effort to make it usable.
+      </p>
+
+      <p>
+        Further, self-hosted solutions that mimic a pull request require a lot of
+        infrastructure in order to manage it. A database, a web site connected to git,
+        admin management, and services to manage it all. Another big point of friction:
+        before an external user submits a code change, they first need to create an
+        account and then login. This adds quite a bit of friction for a self-hosted
+        solution, not only for an external contributor, but also for the code owner who
+        has to provision the infra. Often times they also have to fork the repo within
+        the code forge before submitting a PR. Then they never make a contribution ever
+        again and keep a forked repo around forever. That seems silly.
+      </p>
+
+      <h2 class="text-xl">introducing patch requests (PR)</h2>
+
+      <p>
+        Instead, we want to create a self-hosted git "server" that can handle sending
+        and receiving patches without the cumbersome nature of setting up email or the
+        limitations imposed by the email protocol. Further, we want the primary workflow
+        to surround the local development environment. Github is bringing the IDE to the
+        browser in order to support their workflow, we want to flip that idea on its
+        head by making code reviews a first-class citizen inside your local development
+        environment.
+      </p>
+
+      <p>
+        We see this as a hybrid between the github workflow of a pull request and
+        sending and receiving patches over email.
+      </p>
+
+      <p>
+        The basic idea is to leverage an SSH app to handle most of the interaction
+        between contributor and owner of a project. Everything can be done completely
+        within the terminal, in a way that is ergonomic and fully featured.
+      </p>
+
+      <p>
+        Notifications would happen with RSS and all state mutations would result in the
+        generation of static web assets so it can all be hosted using a simple file web
+        server.
+      </p>
+
+      <h3 class="text-lg">format-patch workflow</h3>
+
+      <p>
+        The fundamental collaboration tool here is <code>format-patch</code>. Whether you a
+        submitting code changes or you are reviewing code changes, it all happens in
+        code. Both contributor and owner are simply creating new commits and generating
+        patches on top of each other. This obviates the need to have a web viewer where
+        the reviewing can "comment" on a line of code block. There's no need, apply the
+        contributor's patches, write comments or code changes, generate a new patch,
+        send the patch to the git server as a "review." This flow also works the exact
+        same if two users are collaborating on a set of changes.
+      </p>
+
+      <p>
+        This also solves the problem of sending multiple patchsets for the same code
+        change. There's a single, central Patch Request where all changes and
+        collaboration happens.
+      </p>
+
+      <p>
+        We could figure out a way to leverage <code>git notes</code> for reviews / comments, but
+        honestly, that solution feels brutal and outside the comfort level of most git
+        users. Just send reviews as code and write comments in the programming language
+        you are using. It's the job of the contributor to "address" those comments and
+        then remove them in subsequent patches. This is the forcing function to address
+        all comments: the patch won't be merged if there are comment unaddressed in
+        code; they cannot be ignored or else they will be upstreamed erroneously.
+      </p>
     </div>
+  </details>
+
+  <details>
+    <summary>How do Patch Requests work?</summary>
+      <div>
+        Patch requests (PR) are the simplest way to submit, review, and accept changes to your git repository.
+        Here's how it works:
+      </div>
+
+      <ol>
+        <li>External contributor clones repo (<code>git-clone</code>)</li>
+        <li>External contributor makes a code change (<code>git-add</code> & <code>git-commit</code>)</li>
+        <li>External contributor generates patches (<code>git-format-patch</code>)</li>
+        <li>External contributor submits a PR to SSH server</li>
+        <li>Owner receives RSS notification that there's a new PR</li>
+        <li>Owner applies patches locally (<code>git-am</code>) from SSH server</li>
+        <li>Owner makes suggestions in code! (<code>git-add</code> & <code>git-commit</code>)</li>
+        <li>Owner submits review by piping patch to SSH server (<code>git-format-patch</code>)</li>
+        <li>External contributor receives RSS notification of the PR review</li>
+        <li>External contributor re-applies patches (<code>git-am</code>)</li>
+        <li>External contributor reviews and removes comments in code!</li>
+        <li>External contributor submits another patch (<code>git-format-patch</code>)</li>
+        <li>Owner applies patches locally (<code>git-am</code>)</li>
+        <li>Owner marks PR as accepted and pushes code to main (<code>git-push</code>)</li>
+      </ol>
+
+      <div>Example commands</div>
+
+      <pre># Owner hosts repo `test.git` using github
+
+# Contributor clones repo
+git clone git@github.com:picosh/test.git
+
+# Contributor wants to make a change
+# Contributor makes changes via commits
+git add -A && git commit -m "fix: some bugs"
+
+# Contributor runs:
+git format-patch origin/main --stdout | ssh {{.MetaData.URL}} pr create test
+# > Patch Request has been created (ID: 1)
+
+# Owner can checkout patch:
+ssh {{.MetaData.URL}} pr print 1 | git am -3
+
+# Owner can comment (IN CODE), commit, then send another format-patch
+# on top of the PR:
+git format-patch origin/main --stdout | ssh {{.MetaData.URL}} pr add --review 1
+# UI clearly marks patch as a review
 
-    <pre class="text-sm">git format-patch main --stdout | ssh pr.pico.sh pr add {prID}</pre>
+# Contributor can checkout reviews
+ssh {{.MetaData.URL}} print pr-1 | git am -3
+
+# Owner can reject a pr:
+ssh {{.MetaData.URL}} pr close 1
+
+# Owner can accept a pr:
+ssh {{.MetaData.URL}} pr accept 1
+
+# Owner can prep PR for upstream:
+git rebase -i origin/main
+
+# Then push to upstream
+git push origin main
+
+# Done!
+</pre>
+  </details>
+
+  <details>
+    <summary>First time user?</summary>
 
     <div>
-      Downloading a patchset is easy as well:
+      Using this service for the first time?  Creating a patch request is simple:
     </div>
 
-    <pre class="text-sm">ssh pr.pico.sh print pr-{prID}</pre>
-  </div>
+    <pre>git format-patch main --stdout | ssh {{.MetaData.URL}} pr create {repo}</pre>
+
+    <div>When running that command we will automatically create a user and a repo if one doesn't exist.</div>
+
+    <div>Want to submit a v2 of the patch request?</div>
+
+    <pre>git format-patch main --stdout | ssh {{.MetaData.URL}} pr add {prID}</pre>
+  </details>
 </header>
 
 <main>
 </main>
 
 <footer class="mt">
-  <div><a href="/rss">rss</a></div>
+  <a href="/rss">rss</a>
 </footer>
 {{end}}

old

old:web.go new:web.go
 		return
 	}
 
+	w.Header().Set("content-type", "text/html")
+	tmpl := getTemplate("index.html")
+	err = tmpl.ExecuteTemplate(w, "index.html", BasicData{
+		MetaData: MetaData{
+			URL: web.Backend.Cfg.Url,
+		},
+	})
+	if err != nil {
+		web.Backend.Logger.Error("cannot execute template", "err", err)
+	}
+}
+
+func exploreHandler(w http.ResponseWriter, r *http.Request) {
+	web, err := getWebCtx(r)
+	if err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
 	prs, err := web.Pr.GetPatchRequests()
 	if err != nil {
 		web.Logger.Error("could not get prs", "err", err)
 	}
 
 	w.Header().Set("content-type", "text/html")
-	tmpl := getTemplate("index.html")
-	err = tmpl.ExecuteTemplate(w, "index.html", PrTableData{
+	tmpl := getTemplate("explore.html")
+	err = tmpl.ExecuteTemplate(w, "explore.html", PrTableData{
 		NumOpen:     numOpen,
 		NumAccepted: numAccepted,
 		NumClosed:   numClosed,
 	http.HandleFunc("GET /rss", ctxMdw(ctx, rssHandler))
 	http.HandleFunc("GET /docs", ctxMdw(ctx, docsHandler))
 	http.HandleFunc("GET /", ctxMdw(ctx, indexHandler))
+	http.HandleFunc("GET /e", ctxMdw(ctx, exploreHandler))
 	http.HandleFunc("GET /syntax.css", ctxMdw(ctx, chromaStyleHandler))
 	embedFS, err := getEmbedFS(embedStaticFS, "static")
 	if err != nil {

new

old:web.go new:web.go
 	return prdata, nil
 }
 
-func docsHandler(w http.ResponseWriter, r *http.Request) {
-	web, err := getWebCtx(r)
-	if err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		return
-	}
-
-	w.Header().Set("content-type", "text/html")
-	tmpl := getTemplate("docs.html")
-	err = tmpl.ExecuteTemplate(w, "docs.html", BasicData{
-		MetaData: MetaData{
-			URL: web.Backend.Cfg.Url,
-		},
-	})
-	if err != nil {
-		web.Backend.Logger.Error("cannot execute template", "err", err)
-	}
-}
-
 func indexHandler(w http.ResponseWriter, r *http.Request) {
 	web, err := getWebCtx(r)
 	if err != nil {
 		NumClosed:   numClosed,
 		Prs:         prdata,
 		MetaData: MetaData{
-			URL: web.Backend.Cfg.Url,
+			URL:  web.Backend.Cfg.Url,
+			Desc: template.HTML(web.Backend.Cfg.Desc),
 		},
 	})
 	if err != nil {
 }
 
 type MetaData struct {
-	URL string
+	URL  string
+	Desc template.HTML
 }
 
 type PrListData struct {
 	}
 	formatter := formatterHtml.New(
 		formatterHtml.WithLineNumbers(true),
+		formatterHtml.LineNumbersInTable(true),
 		formatterHtml.WithClasses(true),
 		formatterHtml.WithLinkableLineNumbers(true, "gitpr"),
 	)
 	http.HandleFunc("GET /r/{user}", ctxMdw(ctx, userDetailHandler))
 	http.HandleFunc("GET /rss/{user}", ctxMdw(ctx, rssHandler))
 	http.HandleFunc("GET /rss", ctxMdw(ctx, rssHandler))
-	http.HandleFunc("GET /docs", ctxMdw(ctx, docsHandler))
 	http.HandleFunc("GET /", ctxMdw(ctx, indexHandler))
 	http.HandleFunc("GET /syntax.css", ctxMdw(ctx, chromaStyleHandler))
 	embedFS, err := getEmbedFS(embedStaticFS, "static")

old


                    

new

old:cfg.go new:cfg.go
 	CreateRepo string          `koanf:"create_repo"`
 	Theme      string          `koanf:"theme"`
 	TimeFormat string          `koanf:"time_format"`
+	Desc       string          `koanf:"desc"`
 	Logger     *slog.Logger
 }
 
 		"theme", out.Theme,
 		"time_format", out.TimeFormat,
 		"create_repo", out.CreateRepo,
+		"desc", out.Desc,
 	)
 
 	for _, pubkey := range out.AdminsStr {

old


                    

new

old:git-pr.toml new:git-pr.toml
 #   admin: only admins
 #   user: admins and users
 create_repo = "user"
+desc = ""

old


                    

new

old:static/git-pr.css new:static/git-pr.css
 }
 
 pre {
-  font-size: 1rem;
+  padding: var(--grid-height);
 }
 
 table, tr {

old


                    

new

old:tmpl/docs.html
-{{template "base" .}}
-
-{{define "title"}}git-pr{{end}}
-
-{{define "meta"}}
-<link rel="alternate" type="application/atom+xml"
-      title="RSS feed for git collaboration server"
-      href="/rss" />
-{{end}}
-
-{{define "body"}}
-<header class="group">
-  <h1 class="text-2xl"><a href="/">DASHBOARD</a> / docs</h1>
-  <div>
-    <span>A pastebin supercharged for git collaboration</span> &middot;
-    <a href="https://github.com/picosh/git-pr">github</a> &middot;
-    <a href="https://youtu.be/d28Dih-BBUw">demo video</a>
-  </div>
-  <pre class="m-0">ssh {{.MetaData.URL}} help</pre>
-</header>
-
-<main class="group">
-  <details>
-    <summary>Intro</summary>
-
-    <div>
-      <p>
-        We are trying to build the simplest git collaboration tool. The goal is to make
-        self-hosting as simple as running an SSH server -- all without
-        sacrificing external collaborators time and energy.
-      </p>
-
-      <blockquote>
-        <code>git format-patch</code> isn't the problem and pull requests aren't the solution.
-      </blockquote>
-
-      <p>
-        We are combining mailing list and pull request workflows. In order to build the
-        simplest collaboration tool, we needed something as simple as generating patches
-        but the ease-of-use of pull requests.
-      </p>
-
-      <p>
-        The goal is not to create another code forge, the goal is to create a very
-        simple self-hosted git solution with the ability to collaborate with external
-        contributors. All the code owner needs to setup a running git server:
-      </p>
-
-      <ul><li>A single golang binary</li></ul>
-
-      <div>
-        All an external contributor needs is:
-      </div>
-
-      <ul>
-        <li>An SSH keypair</li>
-        <li>An SSH client</li>
-      </ul>
-
-      <div>Then everyone subscribes to our RSS feeds to receive updates to patch requests.</div>
-
-      <h2 class="text-xl">the problem</h2>
-
-      <p>
-        Email is great as a decentralized system to send and receive changes (patchsets)
-        to a git repo. However, onboarding a new user to a mailing list, properly
-        setting up their email client, and then finally submitting the code contribution
-        is enough to make many developers give up. Further, because we are leveraging
-        the email protocol for collaboration, we are limited by its feature-set. For
-        example, it is not possible to make edits to emails, everyone has a different
-        client, those clients have different limitations around plain text email and
-        downloading patches from it.
-      </p>
-
-      <p>
-        Github pull requests are easy to use, easy to edit, and easy to manage. The
-        downside is it forces the user to be inside their website to perform reviews.
-        For quick changes, this is great, but when you start reading code within a web
-        browser, there are quite a few downsides. At a certain point, it makes more
-        sense to review code inside your local development environment, IDE, etc. There
-        are tools and plugins that allow users to review PRs inside their IDE, but it
-        requires a herculean effort to make it usable.
-      </p>
-
-      <p>
-        Further, self-hosted solutions that mimic a pull request require a lot of
-        infrastructure in order to manage it. A database, a web site connected to git,
-        admin management, and services to manage it all. Another big point of friction:
-        before an external user submits a code change, they first need to create an
-        account and then login. This adds quite a bit of friction for a self-hosted
-        solution, not only for an external contributor, but also for the code owner who
-        has to provision the infra. Often times they also have to fork the repo within
-        the code forge before submitting a PR. Then they never make a contribution ever
-        again and keep a forked repo around forever. That seems silly.
-      </p>
-
-      <h2 class="text-xl">introducing patch requests (PR)</h2>
-
-      <p>
-        Instead, we want to create a self-hosted git "server" that can handle sending
-        and receiving patches without the cumbersome nature of setting up email or the
-        limitations imposed by the email protocol. Further, we want the primary workflow
-        to surround the local development environment. Github is bringing the IDE to the
-        browser in order to support their workflow, we want to flip that idea on its
-        head by making code reviews a first-class citizen inside your local development
-        environment.
-      </p>
-
-      <p>
-        We see this as a hybrid between the github workflow of a pull request and
-        sending and receiving patches over email.
-      </p>
-
-      <p>
-        The basic idea is to leverage an SSH app to handle most of the interaction
-        between contributor and owner of a project. Everything can be done completely
-        within the terminal, in a way that is ergonomic and fully featured.
-      </p>
-
-      <p>
-        Notifications would happen with RSS and all state mutations would result in the
-        generation of static web assets so it can all be hosted using a simple file web
-        server.
-      </p>
-
-      <h3 class="text-lg">format-patch workflow</h3>
-
-      <p>
-        The fundamental collaboration tool here is <code>format-patch</code>. Whether you a
-        submitting code changes or you are reviewing code changes, it all happens in
-        code. Both contributor and owner are simply creating new commits and generating
-        patches on top of each other. This obviates the need to have a web viewer where
-        the reviewing can "comment" on a line of code block. There's no need, apply the
-        contributor's patches, write comments or code changes, generate a new patch,
-        send the patch to the git server as a "review." This flow also works the exact
-        same if two users are collaborating on a set of changes.
-      </p>
-
-      <p>
-        This also solves the problem of sending multiple patchsets for the same code
-        change. There's a single, central Patch Request where all changes and
-        collaboration happens.
-      </p>
-
-      <p>
-        We could figure out a way to leverage <code>git notes</code> for reviews / comments, but
-        honestly, that solution feels brutal and outside the comfort level of most git
-        users. Just send reviews as code and write comments in the programming language
-        you are using. It's the job of the contributor to "address" those comments and
-        then remove them in subsequent patches. This is the forcing function to address
-        all comments: the patch won't be merged if there are comment unaddressed in
-        code; they cannot be ignored or else they will be upstreamed erroneously.
-      </p>
-    </div>
-  </details>
-
-  <details>
-    <summary>How do Patch Requests work?</summary>
-      <div>
-        Patch requests (PR) are the simplest way to submit, review, and accept changes to your git repository.
-        Here's how it works:
-      </div>
-
-      <ol>
-        <li>External contributor clones repo (<code>git-clone</code>)</li>
-        <li>External contributor makes a code change (<code>git-add</code> & <code>git-commit</code>)</li>
-        <li>External contributor generates patches (<code>git-format-patch</code>)</li>
-        <li>External contributor submits a PR to SSH server</li>
-        <li>Owner receives RSS notification that there's a new PR</li>
-        <li>Owner applies patches locally (<code>git-am</code>) from SSH server</li>
-        <li>Owner makes suggestions in code! (<code>git-add</code> & <code>git-commit</code>)</li>
-        <li>Owner submits review by piping patch to SSH server (<code>git-format-patch</code>)</li>
-        <li>External contributor receives RSS notification of the PR review</li>
-        <li>External contributor re-applies patches (<code>git-am</code>)</li>
-        <li>External contributor reviews and removes comments in code!</li>
-        <li>External contributor submits another patch (<code>git-format-patch</code>)</li>
-        <li>Owner applies patches locally (<code>git-am</code>)</li>
-        <li>Owner marks PR as accepted and pushes code to main (<code>git-push</code>)</li>
-      </ol>
-
-      <div>Example commands</div>
-
-      <pre># Owner hosts repo `test.git` using github
-
-# Contributor clones repo
-git clone git@github.com:picosh/test.git
-
-# Contributor wants to make a change
-# Contributor makes changes via commits
-git add -A && git commit -m "fix: some bugs"
-
-# Contributor runs:
-git format-patch origin/main --stdout | ssh {{.MetaData.URL}} pr create test
-# > Patch Request has been created (ID: 1)
-
-# Owner can checkout patch:
-ssh {{.MetaData.URL}} pr print 1 | git am -3
-# Owner can comment (IN CODE), commit, then send another format-patch
-# on top of the PR:
-git format-patch origin/main --stdout | ssh {{.MetaData.URL}} pr add --review 1
-# UI clearly marks patch as a review
-
-# Contributor can checkout reviews
-ssh {{.MetaData.URL}} pr print 1 | git am -3
-
-# Owner can reject a pr:
-ssh {{.MetaData.URL}} pr close 1
-
-# Owner can accept a pr:
-ssh {{.MetaData.URL}} pr accept 1
-
-# Owner can prep PR for upstream:
-git rebase -i origin/main
-
-# Then push to upstream
-git push origin main
-
-# Done!
-</pre>
-  </details>
-
-  <details>
-    <summary>What's a repo?</summary>
-
-    <div>
-      A repo is designed to mimick a git repo, but it's really just a tag.  When
-      submitting a patch request, if the user does not provide a repo name then
-      the default "bin" will be selected.  When a user creates a repo they become
-      the repo owner and have special privileges.
-    </div>
-  </details>
-
-  <details>
-    <summary>Can anyone use this service?</summary>
-
-    <div>
-      This service is a public space for anyone to freely create "repos" and
-      collaborate with users.  Anyone is able to add patchsets to a patch request
-      and anyone is able to review any other patch requests, regardless of repo.
-    </div>
-  </details>
-
-  <details>
-    <summary>First time user experience</summary>
-
-    <div>
-      Using this service for the first time?  Creating a patch request is simple:
-    </div>
-
-    <pre>git format-patch main --stdout | ssh pr.pico.sh pr create {repo}</pre>
-
-    <div>When running that command we will automatically create a user and a repo if one doesn't exist.</div>
-
-    <div>Want to submit a v2 of the patch request?</div>
-
-    <pre>git format-patch main --stdout | ssh pr.pico.sh pr add {prID}</pre>
-  </details>
-
-  <details>
-    <summary>How do I receive notifications?</summary>
-
-    <div>
-      We have different RSS feeds depending on the use case.  This is how you
-      can receive notifications for when someone submits or reviews patch requests.
-    </div>
-  </details>
-
-  <details>
-    <summary>Alternative git collaboration systems</summary>
-
-    <div>
-      <ol>
-        <li><a href="https://gerritcodereview.com/">Gerrit</a></li>
-        <li><a href="https://we.phorge.it/">Phorge</a> (fork of Phabricator)</li>
-        <li><a href="https://graphite.dev/docs/cli-quick-start">Graphite</a></li>
-        <li><a href="https://codeapprove.com/">CodeApprove</a></li>
-        <li><a href="https://reviewable.io/">Reviewable</a></li>
-      </ol>
-    </div>
-  </details>
-</main>
-
-{{end}}

old


                    

new

old:tmpl/pr-header.html new:tmpl/pr-header.html
   <details>
     <summary>Help</summary>
     <div class="group">
-      <pre class="m-0"># checkout latest patchset
-ssh {{.MetaData.URL}} print pr-{{.Pr.ID}} | git am -3</pre>
-      <pre class="m-0"># checkout any patchset in a patch request
-ssh {{.MetaData.URL}} print ps-X | git am -3</pre>
-      <pre class="m-0"># add changes to patch request
-git format-patch {{.Branch}} --stdout | ssh {{.MetaData.URL}} pr add {{.Pr.ID}}</pre>
-      <pre class="m-0"># add review to patch request
-git format-patch {{.Branch}} --stdout | ssh {{.MetaData.URL}} pr add --review {{.Pr.ID}}</pre>
-      <pre class="m-0"># accept PR
-ssh {{.MetaData.URL}} pr accept {{.Pr.ID}}</pre>
-      <pre class="m-0"># close PR
-ssh {{.MetaData.URL}} pr close {{.Pr.ID}}</pre>
+      checkout latest patchset:
+      <pre class="m-0">ssh {{.MetaData.URL}} print pr-{{.Pr.ID}} | git am -3</pre>
+
+      checkout any patchset in a patch request:
+      <pre class="m-0">ssh {{.MetaData.URL}} print ps-X | git am -3</pre>
+
+      add changes to patch request:
+      <pre class="m-0">git format-patch {{.Branch}} --stdout | ssh {{.MetaData.URL}} pr add {{.Pr.ID}}</pre>
+
+      add review to patch request:
+      <pre class="m-0">git format-patch {{.Branch}} --stdout | ssh {{.MetaData.URL}} pr add --review {{.Pr.ID}}</pre>
+
+      accept PR:
+      <pre class="m-0">ssh {{.MetaData.URL}} pr accept {{.Pr.ID}}</pre>
+
+      close PR:
+      <pre class="m-0">ssh {{.MetaData.URL}} pr close {{.Pr.ID}}</pre>
     </div>
   </details>
 </header>