Prove the pull-request merge path before anything depends on it #78

Closed
opened 2026-09-22 15:46:33 +01:00 by cruelacid · 1 comment
Owner

Part of #77.

Why

Of the 15 pull requests this repository has ever had — all Renovate — not
one has been merged
. Every single one was closed. The review path is
exercised; the merge path has never run here once.

The changelog design maps a PR to its commits, so it needs Forgejo to record
which commit a merge produced. Under fast-forward-only merging there is no
merge commit, and whether merged_commit_id is populated in that case is
unknown. Nothing else in #77 should be built until it is known.

What to do

Open a throwaway PR from a scratch branch, merge it fast-forward-only, then read
the row back:

ssh clconsole "docker exec forgejo sqlite3 -readonly /data/gitea/gitea.db \
  \"SELECT \\\"index\\\", has_merged, merged_commit_id FROM pull_request \
     WHERE base_repo_id=(SELECT id FROM repository WHERE name='nectenda');\""

Assert through something that can actually observe it: merged_commit_id is
non-empty and names a commit that is an ancestor of main.

If it is not recorded

Two fallbacks, in order of preference:

  • a Closes: #NN / PR: #NN git trailer, which this repo already proves works —
    Co-Authored-By: and Claude-Session: appear on 92 of the last 100 commits,
    and git log --format=%(trailers:key=...) parses only the real trailer block
    (a naive ^\w+: grep finds 14 false positives in prose);
  • rebase-merge, which keeps a recorded merge commit at the cost of a slightly
    less linear history.
Part of #77. ## Why Of the **15 pull requests this repository has ever had** — all Renovate — **not one has been merged**. Every single one was closed. The review path is exercised; the merge path has never run here once. The changelog design maps a PR to its commits, so it needs Forgejo to record which commit a merge produced. Under **fast-forward-only** merging there is no merge commit, and whether `merged_commit_id` is populated in that case is **unknown**. Nothing else in #77 should be built until it is known. ## What to do Open a throwaway PR from a scratch branch, merge it fast-forward-only, then read the row back: ``` ssh clconsole "docker exec forgejo sqlite3 -readonly /data/gitea/gitea.db \ \"SELECT \\\"index\\\", has_merged, merged_commit_id FROM pull_request \ WHERE base_repo_id=(SELECT id FROM repository WHERE name='nectenda');\"" ``` Assert through something that can actually observe it: `merged_commit_id` is non-empty **and** names a commit that is an ancestor of `main`. ## If it is not recorded Two fallbacks, in order of preference: - a `Closes: #NN` / `PR: #NN` git trailer, which this repo already proves works — `Co-Authored-By:` and `Claude-Session:` appear on 92 of the last 100 commits, and `git log --format=%(trailers:key=...)` parses only the real trailer block (a naive `^\w+:` grep finds 14 false positives in prose); - rebase-merge, which keeps a recorded merge commit at the cost of a slightly less linear history.
Author
Owner

Proven, on Forgejo 16.0.5, without touching main.

Throwaway PR #111 from probe-78-head (one empty commit 4413b47) into probe-78-base (cut from main at 1d3234a), merged with POST /pulls/111/merge {"Do":"fast-forward-only"}.

Read back through three things that can observe it:

  • sqlite pull_request: has_merged=1, merged_commit_id=4413b47e…, and merge_base=1d3234a1…, so a PR's commits are exactly merge_base..merged_commit_id.
  • REST GET /pulls?state=closed: merged: true, merge_commit_sha: 4413b47e…. This is the read path changelog.mjs will use. tea cannot see these fields, but plain REST with the tea token can.
  • git: 4413b47 is an ancestor of origin/probe-78-base, and GET /pulls/111/commits lists it.

Under fast-forward-only, merged_commit_id is the head tip, not a merge commit. That is all the changelog needs: "merge commit is an ancestor of HEAD and not of --since" works unchanged. No trailer fallback is needed.

Both probe branches are deleted.

Proven, on Forgejo 16.0.5, without touching `main`. Throwaway PR #111 from `probe-78-head` (one empty commit `4413b47`) into `probe-78-base` (cut from `main` at `1d3234a`), merged with `POST /pulls/111/merge {"Do":"fast-forward-only"}`. Read back through three things that can observe it: - **sqlite** `pull_request`: `has_merged=1`, `merged_commit_id=4413b47e…`, **and `merge_base=1d3234a1…`**, so a PR's commits are exactly `merge_base..merged_commit_id`. - **REST** `GET /pulls?state=closed`: `merged: true`, `merge_commit_sha: 4413b47e…`. This is the read path `changelog.mjs` will use. `tea` cannot see these fields, but plain REST with the tea token can. - **git**: `4413b47` is an ancestor of `origin/probe-78-base`, and `GET /pulls/111/commits` lists it. Under fast-forward-only, `merged_commit_id` is the head tip, not a merge commit. That is all the changelog needs: "merge commit is an ancestor of HEAD and not of `--since`" works unchanged. No trailer fallback is needed. Both probe branches are deleted.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Nectenda/nectenda#78
No description provided.