Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
id: bugfix-1137
title: gitea-forge-preset-is-broken-a
protocol: bugfix
phase: fix
plan_phases: []
current_plan_phase: null
gates:
merge-approval:
status: pending
iteration: 1
build_complete: false
history: []
started_at: '2026-07-06T19:06:00.466Z'
updated_at: '2026-07-06T19:12:31.039Z'
7 changes: 6 additions & 1 deletion packages/codev/scripts/forge/gitea/issue-comment.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#!/bin/sh
# Forge concept: issue-comment (Gitea via tea CLI)
exec tea issues comment "$CODEV_ISSUE_ID" "$CODEV_COMMENT_BODY"
# Input: CODEV_ISSUE_ID, CODEV_COMMENT_BODY
# Output: exit code only
#
# `tea issues` has no `comment` subcommand (its subcommands are list/create/
# edit/close). Commenting lives under the top-level `tea comments add`.
exec tea comments add "$CODEV_ISSUE_ID" "$CODEV_COMMENT_BODY"
37 changes: 33 additions & 4 deletions packages/codev/scripts/forge/gitea/issue-view.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
#!/bin/sh
# Forge concept: issue-view (Gitea via tea CLI)
# Sets `url` to the issue's browser page (`html_url`). Gitea's own `url` field is
# the API endpoint (would render raw JSON in a browser), so we prefer `html_url`
# and fall back to the existing `url` only if `html_url` is absent.
tea issues view "$CODEV_ISSUE_ID" --output json | jq '.url = (.html_url // .url)'
# Input: CODEV_ISSUE_ID
# Output: JSON {title, body, state, url, comments[]} (IssueViewResult)
#
# `tea issues view N --output json` returns a flattened single-element list
# (no body/html_url/url), so route through the raw REST passthrough. `tea api`
# needs an explicit owner/repo in the path (unlike `tea issues`, which
# auto-detects it from the local git remote), so resolve it here: honor
# CODEV_REPO when set, else derive owner/repo from origin's URL (handles
# https, ssh, and scp-style remotes, with or without a .git suffix).
#
# `url` is mapped to the issue's browser page (`html_url`); Gitea's own `url`
# is the API endpoint (would render raw JSON in a browser), so we fall back to
# it only if `html_url` is absent.
#
# Gitea's issue object reports `comments` as an integer count, not the array
# the contract requires (consumers call `.comments.filter(...)`), so the
# comments array is fetched separately and merged in. A failed/empty comments
# fetch degrades to [].
REPO="${CODEV_REPO:-$(git remote get-url origin 2>/dev/null | sed -E -e 's#\.git$##' -e 's#.*[/:]([^/]+/[^/]+)$#\1#')}"
COMMENTS_JSON="$(tea api "repos/${REPO}/issues/${CODEV_ISSUE_ID}/comments" 2>/dev/null)"
[ -n "$COMMENTS_JSON" ] || COMMENTS_JSON="[]"
tea api "repos/${REPO}/issues/${CODEV_ISSUE_ID}" \
| jq --argjson comments "$COMMENTS_JSON" '{
title,
body: (.body // ""),
state,
url: (.html_url // .url),
comments: [ $comments[] | {
body: (.body // ""),
createdAt: .created_at,
author: {login: .user.login}
} ]
}'
26 changes: 22 additions & 4 deletions packages/codev/scripts/forge/gitea/pr-exists.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
#!/bin/sh
# Forge concept: pr-exists (Gitea via tea CLI)
# Returns true for open or merged pulls only. Closed-not-merged pulls are excluded.
# --state all fetches pulls in all states; without it, only open pulls are returned.
# Gitea: merged PRs have state="closed" + merged=true; abandoned PRs have state="closed" + merged=false
tea pulls list --state all --fields index --output json | jq "[.[] | select(.head.ref == \"$CODEV_BRANCH_NAME\" and (.state == \"open\" or (.state == \"closed\" and .merged == true)))] | length > 0"
# Input: CODEV_BRANCH_NAME
# Output: "true" or "false"
#
# Returns true for OPEN or MERGED pulls only; closed-not-merged pulls are
# excluded. `tea pulls list` emits `.head` as a string (not `{ref}`) and reports
# merged PRs as state "merged" with no `.merged` boolean, so its output can't
# satisfy the `.head.ref` / `.merged` predicate below. Route through the raw
# REST passthrough, whose PR objects carry nested `.head.ref` and a `.merged`
# bool. `tea api` needs an explicit owner/repo in the path (unlike `tea pulls`,
# which auto-detects it from the local git remote), so resolve it here: honor
# CODEV_REPO when set, else derive owner/repo from origin's URL (handles https,
# ssh, and scp-style remotes, with or without a .git suffix).
#
# Caveat (Gitea behavior, not a codev bug): for a merged PR whose source branch
# was deleted, Gitea returns `.head.ref == "refs/pull/N/head"` instead of the
# original branch name, so a branch-name match won't hit a merged+deleted
# branch. That doesn't affect the "does an open/merged PR exist for the branch
# I'm about to push" use case.
REPO="${CODEV_REPO:-$(git remote get-url origin 2>/dev/null | sed -E -e 's#\.git$##' -e 's#.*[/:]([^/]+/[^/]+)$#\1#')}"
tea api "repos/${REPO}/pulls?state=all&limit=200" \
| jq --arg branch "$CODEV_BRANCH_NAME" \
'[.[] | select(.head.ref == $branch and (.state == "open" or .merged == true))] | length > 0'
59 changes: 29 additions & 30 deletions packages/codev/scripts/forge/gitea/pr-list.sh
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
#!/bin/sh
# Forge concept: pr-list (Gitea via tea CLI)
# Forge concept: pr-list (Gitea via tea CLI) — open pulls
# Output: JSON [{number, title, url, reviewDecision, body, createdAt, author,
# reviewRequests, isDraft}] (PrListItem in forge-contracts.ts)
#
# Normalize tea's PR shape to the GitHub-compatible shape codev expects
# (see PrListItem in codev/src/lib/forge-contracts.ts):
# index -> number (int)
# description -> body
# created -> createdAt
# author (string) -> author.login
# reviewDecision -> "" (Gitea has no GitHub-equivalent review-decision summary)
# reviewRequests -> [] (verified against tea 0.14.1: `pulls list` exposes
# no `reviewers` field, and its JSON output is limited
# to the selectable `--fields`, so requested reviewers
# are unreachable here. The VSCode sort silently skips
# the review-requested bucket when empty.)
# isDraft -> false (verified: tea 0.14.1 `pulls list` exposes no
# `draft` field among its selectable `--fields`.)
# The underlying Gitea API PR object does carry `draft` and `requested_reviewers`,
# but only the raw `tea api` passthrough can reach them — populating these two
# fields for Gitea would mean reworking this concept onto `tea api`, which is a
# separate, larger change than #787's scope.
exec tea pulls list --limit 200 \
--fields index,title,state,author,url,created,description \
--output json \
# `tea pulls list --fields …,description` errors ("invalid field 'description'")
# and its flattened output can't carry a PR body, draft flag, or requested
# reviewers. Route through the raw REST passthrough instead, whose PR objects
# expose all of them. `tea api` needs an explicit owner/repo in the path (unlike
# `tea pulls`, which auto-detects it from the local git remote), so resolve it
# here: honor CODEV_REPO when set, else derive owner/repo from origin's URL
# (handles https, ssh, and scp-style remotes, with or without a .git suffix).
#
# Field mapping:
# .number -> number (already an int in the REST shape)
# .html_url -> url (browser page; Gitea `.url` is the API endpoint)
# .body -> body
# .created_at -> createdAt
# .user.login -> author.login
# .requested_reviewers[].login -> reviewRequests (user logins; teams have no login → dropped)
# .draft -> isDraft
# reviewDecision -> "" (Gitea has no GitHub-equivalent review-decision summary)
REPO="${CODEV_REPO:-$(git remote get-url origin 2>/dev/null | sed -E -e 's#\.git$##' -e 's#.*[/:]([^/]+/[^/]+)$#\1#')}"
tea api "repos/${REPO}/pulls?state=open&limit=200" \
| jq '[.[] | {
number: (.index | tonumber),
number,
title,
state,
url,
url: (.html_url // .url),
reviewDecision: "",
body: (.description // ""),
createdAt: .created,
author: {login: .author},
reviewRequests: [],
isDraft: false
body: (.body // ""),
createdAt: .created_at,
author: {login: .user.login},
reviewRequests: [ (.requested_reviewers // [])[] | .login // empty ],
isDraft: (.draft // false)
}]'
22 changes: 21 additions & 1 deletion packages/codev/scripts/forge/gitea/pr-view.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
#!/bin/sh
# Forge concept: pr-view (Gitea via tea CLI)
exec tea pulls view "$CODEV_PR_NUMBER" --output json
# Input: CODEV_PR_NUMBER
# Output: JSON {title, body, state, author{login}, baseRefName, headRefName,
# additions, deletions} (see PrViewResult in forge-contracts.ts)
#
# `tea pulls view N --output json` returns a table header / empty list rather
# than the PR object, so route through the raw REST passthrough. `tea api`
# needs an explicit owner/repo in the path (unlike `tea pulls`, which
# auto-detects it from the local git remote), so resolve it here: honor
# CODEV_REPO when set, else derive owner/repo from origin's URL (handles
# https, ssh, and scp-style remotes, with or without a .git suffix).
REPO="${CODEV_REPO:-$(git remote get-url origin 2>/dev/null | sed -E -e 's#\.git$##' -e 's#.*[/:]([^/]+/[^/]+)$#\1#')}"
tea api "repos/${REPO}/pulls/${CODEV_PR_NUMBER}" | jq '{
title,
body: (.body // ""),
state,
author: {login: .user.login},
baseRefName: .base.ref,
headRefName: .head.ref,
additions: (.additions // 0),
deletions: (.deletions // 0)
}'
38 changes: 18 additions & 20 deletions packages/codev/scripts/forge/gitea/recently-merged.sh
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
#!/bin/sh
# Forge concept: recently-merged (Gitea via tea CLI)
# Output: JSON [{number, title, url, body, createdAt, mergedAt, headRefName}]
# (MergedPrItem in forge-contracts.ts)
#
# `tea pulls list --state closed` returns both merged PRs and closed-without-
# merge PRs. Filter to merged only via `.merged == true` (the same predicate
# scripts/forge/gitea/pr-exists.sh already relies on), then map to the
# GitHub-compatible shape:
# index -> number (int)
# created -> createdAt
# updated -> mergedAt (tea exposes no merged_at field via --fields;
# close-then-edit overestimates merged time
# but is acceptable for the 24h overview window)
# head.ref -> headRefName
# description -> body
exec tea pulls list --state closed --limit 1000 \
--fields index,title,state,author,url,created,updated,head,description,merged \
--output json \
# `tea pulls list --fields …,head,description,merged` errors on the `description`
# field and emits `.head` as a string, so it can't populate `body` or
# `.head.ref`. Route through the raw REST passthrough instead, whose closed
# pulls carry `.merged`, `.merged_at`, nested `.head.ref`, and `.body`. Keep
# only merged pulls (closed-without-merge have `.merged == false`). `tea api`
# needs an explicit owner/repo in the path (unlike `tea pulls`, which
# auto-detects it from the local git remote), so resolve it here: honor
# CODEV_REPO when set, else derive owner/repo from origin's URL (handles https,
# ssh, and scp-style remotes, with or without a .git suffix).
REPO="${CODEV_REPO:-$(git remote get-url origin 2>/dev/null | sed -E -e 's#\.git$##' -e 's#.*[/:]([^/]+/[^/]+)$#\1#')}"
tea api "repos/${REPO}/pulls?state=closed&limit=200" \
| jq '[.[] | select(.merged == true) | {
number: (.index | tonumber),
number,
title,
state,
url,
body: (.description // ""),
createdAt: .created,
mergedAt: .updated,
url: (.html_url // .url),
body: (.body // ""),
createdAt: .created_at,
mergedAt: .merged_at,
headRefName: (.head.ref // "")
}]'
8 changes: 7 additions & 1 deletion packages/codev/scripts/forge/gitea/user-identity.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#!/bin/sh
# Forge concept: user-identity (Gitea via tea CLI)
tea whoami --output json | jq -r ".login"
# Output: plain text username
#
# `tea whoami` has no `--output json` flag (its only documented option is
# --help), so it can't feed a jq pipeline. Route through the raw REST
# passthrough instead: `tea api user` returns the Gitea `User` object, whose
# `.login` is the authenticated username (mirrors `gh api user --jq .login`).
tea api user | jq -r ".login"
Loading