Slice 10: create_pr (open a pull request)
forge CreatePullRequest (Gitea; empty base resolves to the repo default branch). Service CreatePR records a pr-created event. HTTP POST /api/repo/pr/create; MCP tool create_pr; <pr-list> New pull request button (head = selected repo current branch, base = default). Live-tested end-to-end: app create_pr opened a real PR (base auto-resolved), listed, then cleaned up; main untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ class PRList extends HTMLElement {
|
||||
#controller = null;
|
||||
#onSelect = null;
|
||||
#path = '';
|
||||
#repo = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -18,7 +19,7 @@ class PRList extends HTMLElement {
|
||||
|
||||
connectedCallback() {
|
||||
this.#renderShell();
|
||||
this.#onSelect = (e) => this.#load(e.detail?.path);
|
||||
this.#onSelect = (e) => { this.#repo = e.detail; this.#load(e.detail?.path); };
|
||||
document.addEventListener('repo:select', this.#onSelect);
|
||||
}
|
||||
|
||||
@@ -64,6 +65,25 @@ class PRList extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
async #create() {
|
||||
const branch = this.#repo?.branch;
|
||||
if (!branch) return;
|
||||
const title = window.prompt(`Open a pull request from "${branch}" (into the default branch).\nTitle:`, branch);
|
||||
if (title === null) return;
|
||||
try {
|
||||
const res = await fetch('/api/repo/pr/create', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: this.#path, head: branch, base: '', title: title.trim() || branch }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
|
||||
this.#load(this.#path); // refresh so the new PR appears
|
||||
} catch (err) {
|
||||
window.alert(`Create PR failed: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
#render(prs) {
|
||||
const body = this.shadowRoot.getElementById('body');
|
||||
if (prs.length === 0) {
|
||||
@@ -102,8 +122,13 @@ class PRList extends HTMLElement {
|
||||
:host { display: block; }
|
||||
.box { background: var(--surface-1); border: 1px solid var(--border);
|
||||
border-radius: var(--radius); padding: 14px 16px; }
|
||||
.hd { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
|
||||
h3 { font-size: 12px; text-transform: uppercase; letter-spacing: .04em;
|
||||
color: var(--color-fg-muted); margin: 0 0 8px; }
|
||||
color: var(--color-fg-muted); margin: 0; }
|
||||
#new { margin-left: auto; font: inherit; cursor: pointer; padding: 3px 10px;
|
||||
border-radius: var(--radius-sm); border: 1px solid var(--fill-accent);
|
||||
color: var(--fill-accent); background: transparent; }
|
||||
#new:hover { background: var(--surface-2); }
|
||||
ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
|
||||
li { border-top: 1px solid var(--border); padding-top: 8px; }
|
||||
li:first-child { border-top: none; padding-top: 0; }
|
||||
@@ -124,9 +149,13 @@ class PRList extends HTMLElement {
|
||||
.error { color: var(--color-danger); }
|
||||
</style>
|
||||
<div class="box">
|
||||
<h3>Pull requests</h3>
|
||||
<div class="hd">
|
||||
<h3>Pull requests</h3>
|
||||
<button id="new" title="Open a PR from the current branch">New pull request…</button>
|
||||
</div>
|
||||
<div id="body"><p class="muted">Select a repository.</p></div>
|
||||
</div>`;
|
||||
this.shadowRoot.getElementById('new').addEventListener('click', () => this.#create());
|
||||
}
|
||||
|
||||
#esc(s) {
|
||||
|
||||
@@ -13,10 +13,14 @@ naming the PR, base, and branch to be deleted.
|
||||
configured or the repo isn't on the forge host.
|
||||
- **Listens:** `repo:select` on `document` — loads PRs for `event.detail.path`.
|
||||
- **Fetches:** `GET /api/repo/prs?path=…` (`{supported:false}` → hidden).
|
||||
- **Writes:** `POST /api/repo/pr/merge {path, number}` after a `confirm()`.
|
||||
- **Writes:** `POST /api/repo/pr/merge {path, number}` after a `confirm()`;
|
||||
`POST /api/repo/pr/create {path, head, base, title}` via the "New pull request…"
|
||||
button (head = the selected repo's current branch, base = the repo default).
|
||||
|
||||
## History
|
||||
- 2026-09-20: created — slice 5 (forge); list open PRs + "Merge & clean up".
|
||||
- 2026-09-20: added "New pull request…" (create_pr) — opens a PR from the
|
||||
selected repo's current branch into the default branch (slice 10).
|
||||
|
||||
## Notes / gotchas
|
||||
- Requires `GITEA_URL` + `GITEA_TOKEN` on the server; otherwise the component
|
||||
|
||||
Reference in New Issue
Block a user