add comments for pull requests

Commit 504cc82912e2 · Harrison Erd · 2026-05-03 23:05 -0400

Changeset
504cc82912e28aa428a86a1c0b46970a0a812343

View source at this commit

Comments

No comments yet.

Log in to comment

Diff

diff --git a/app.py b/app.py
--- a/app.py
+++ b/app.py
@@ -233,6 +233,15 @@
                 UNIQUE(target_repo_id, number)
             );
 
+            CREATE TABLE IF NOT EXISTS pull_request_comments (
+                id INTEGER PRIMARY KEY AUTOINCREMENT,
+                pull_request_id INTEGER NOT NULL REFERENCES pull_requests(id) ON DELETE CASCADE,
+                author_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
+                body TEXT NOT NULL,
+                created_at TEXT NOT NULL,
+                updated_at TEXT NOT NULL
+            );
+
             CREATE INDEX IF NOT EXISTS idx_repositories_owner ON repositories(owner_id);
             CREATE INDEX IF NOT EXISTS idx_issues_repo_number ON issues(repo_id, number);
             CREATE INDEX IF NOT EXISTS idx_issues_repo_status ON issues(repo_id, status);
@@ -241,6 +250,7 @@
             CREATE INDEX IF NOT EXISTS idx_repo_stars_user ON repo_stars(user_id);
             CREATE INDEX IF NOT EXISTS idx_pull_requests_target_status ON pull_requests(target_repo_id, status);
             CREATE INDEX IF NOT EXISTS idx_pull_requests_source ON pull_requests(source_repo_id);
+            CREATE INDEX IF NOT EXISTS idx_pull_request_comments_pull_request ON pull_request_comments(pull_request_id);
             """
         )
         ensure_user_profile_columns(conn)
@@ -1036,6 +1046,20 @@
         ).fetchall()
 
 
+def list_pull_request_comments(pull_request_id):
+    with db_connect() as conn:
+        return conn.execute(
+            """
+            SELECT pull_request_comments.*, users.username AS author_username
+            FROM pull_request_comments
+            JOIN users ON users.id = pull_request_comments.author_id
+            WHERE pull_request_comments.pull_request_id = ?
+            ORDER BY pull_request_comments.created_at ASC, pull_request_comments.id ASC
+            """,
+            (pull_request_id,),
+        ).fetchall()
+
+
 def pull_request_select_sql(where_clause):
     return f"""
         SELECT
@@ -1229,7 +1253,7 @@
     return merge_node
 
 
-def render_pull_request_detail(repo, path, pr, error=None, notice=None):
+def render_pull_request_detail(repo, path, pr, error=None, notice=None, comment_value=""):
     diff = ""
     diff_error = None
     current_source_node = pr["source_node"]
@@ -1241,6 +1265,8 @@
         "pull_request_detail.tpl",
         repo=repo,
         pr=pr,
+        comments=list_pull_request_comments(pr["id"]),
+        comment_value=comment_value,
         diff=diff,
         diff_error=diff_error,
         current_source_node=current_source_node,
@@ -1846,9 +1872,34 @@
 
     if request.method == "POST":
         user = require_login()
+        action = request.forms.get("action")
+        now = utcnow()
+        if action == "comment":
+            body = request.forms.get("body", "").strip()
+            if not body:
+                return render_pull_request_detail(
+                    repo,
+                    path,
+                    pr,
+                    error="Comment body is required.",
+                    comment_value=body,
+                )
+            with db_connect() as conn:
+                conn.execute(
+                    """
+                    INSERT INTO pull_request_comments (pull_request_id, author_id, body, created_at, updated_at)
+                    VALUES (?, ?, ?, ?, ?)
+                    """,
+                    (pr["id"], user["id"], body[:5000], now, now),
+                )
+                conn.execute(
+                    "UPDATE pull_requests SET updated_at = ? WHERE id = ?",
+                    (now, pr["id"]),
+                )
+            redirect(f"/{owner}/{repo_name}/pulls/{number}")
+
         if not user_can_maintain_repo(user, repo):
             abort(403, "Only maintainers can update pull requests.")
-        action = request.forms.get("action")
         if action == "merge":
             try:
                 merge_pull_request(pr, user)
diff --git a/templates/pull_request_detail.tpl b/templates/pull_request_detail.tpl
--- a/templates/pull_request_detail.tpl
+++ b/templates/pull_request_detail.tpl
@@ -41,6 +41,35 @@
 </section>
 
 <section class="panel">
+  <h2>Comments</h2>
+  % if comments:
+    <div class="comment-list">
+      % for comment in comments:
+        <article class="comment">
+          <p class="muted">{{comment["author_username"]}} commented on {{comment["created_at"]}}</p>
+          <pre class="readme">{{comment["body"]}}</pre>
+        </article>
+      % end
+    </div>
+  % else:
+    <p class="empty">No comments yet.</p>
+  % end
+
+  % if user:
+    <form method="post">
+      <input type="hidden" name="action" value="comment">
+      <label>
+        Add a comment
+        <textarea name="body" rows="5">{{comment_value}}</textarea>
+      </label>
+      <button class="button" type="submit">Comment</button>
+    </form>
+  % else:
+    <p><a href="/login?next=/{{repo['owner_username']}}/{{repo['name']}}/pulls/{{pr['number']}}">Log in to comment</a></p>
+  % end
+</section>
+
+<section class="panel">
   <h2>Diff</h2>
   <p class="muted">Base <code>{{pr["base_node"]}}</code> to source <code>{{current_source_node}}</code></p>
   % if diff_error:
diff --git a/templates/repo.tpl b/templates/repo.tpl
--- a/templates/repo.tpl
+++ b/templates/repo.tpl
@@ -15,10 +15,6 @@
 </section>
 
 <section class="panel">
-  <div class="panel-heading">
-    <h2>{{readme_name or "README"}}</h2>
-    <a href="/{{repo['owner_username']}}/{{repo['name']}}/src">Browse source</a>
-  </div>
   % if readme_html is not None:
     <div class="readme markdown-body">{{!readme_html}}</div>
   % elif readme is not None:
@@ -48,3 +44,4 @@
     </div>
   % end
 </section>
+