feat(gitea-skill): Add integration tests and fix workflow label swap

- Add test-gitea-skill.sh with 10 tests (26 assertions) against live Gitea
- Fix: API POST /labels only appends, does not enforce scoped exclusivity
- Fix: Use PUT with label swap pattern to atomically replace workflow labels
- Fix: Use PATCH /issues/{index} for assignees (POST /assignees not in 1.22.6)
- All 26 assertions pass against live Gitea 1.22.6

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-18 12:45:18 +01:00
parent c6d425be63
commit 654e03dc71
2 changed files with 457 additions and 14 deletions
+28 -14
View File
@@ -228,17 +228,37 @@ Inspired by the br (beads_rust) pattern: ready -> claim -> implement -> close.
+---------------+
```
Scoped labels enforce mutual exclusivity: applying `workflow:in-progress` auto-removes `workflow:ready`.
Scoped labels are visually exclusive in the Gitea UI, but the API POST endpoint only appends labels. The helpers below use a swap pattern: get current labels, remove old workflow labels, add the new one, then PUT the full set.
### Swap Workflow Label (internal helper)
```bash
gitea_swap_workflow() {
local index="$1" new_label="$2" owner="${3:-$GITEA_OWNER}" repo="${4:-$GITEA_REPO}"
local repo_labels issue_labels new_id kept_ids all_ids
# Get the ID of the new workflow label
repo_labels=$(gitea_api GET "/repos/$owner/$repo/labels")
new_id=$(echo "$repo_labels" | jq -r --arg n "$new_label" '.[] | select(.name==$n) | .id')
# Get current issue label IDs, filtering out all workflow:* labels
issue_labels=$(gitea_api GET "/repos/$owner/$repo/issues/$index")
kept_ids=$(echo "$issue_labels" | jq '[.labels[] | select(.name | startswith("workflow:") | not) | .id]')
# Combine kept labels + new workflow label
all_ids=$(echo "$kept_ids" | jq --argjson nid "$new_id" '. + [$nid]')
# Replace all labels atomically
gitea_api PUT "/repos/$owner/$repo/issues/$index/labels" "{\"labels\": $all_ids}"
}
```
### Mark Ready
```bash
gitea_ready() {
local index="$1" owner="${2:-$GITEA_OWNER}" repo="${3:-$GITEA_REPO}"
local ready_id
ready_id=$(gitea_api GET "/repos/$owner/$repo/labels" | \
jq -r '.[] | select(.name=="workflow:ready") | .id')
gitea_api POST "/repos/$owner/$repo/issues/$index/labels" "{\"labels\": [$ready_id]}"
gitea_swap_workflow "$index" "workflow:ready" "$owner" "$repo"
}
```
@@ -247,12 +267,9 @@ gitea_ready() {
```bash
gitea_claim() {
local index="$1" user="${2:-}" owner="${3:-$GITEA_OWNER}" repo="${4:-$GITEA_REPO}"
local ip_id
ip_id=$(gitea_api GET "/repos/$owner/$repo/labels" | \
jq -r '.[] | select(.name=="workflow:in-progress") | .id')
gitea_api POST "/repos/$owner/$repo/issues/$index/labels" "{\"labels\": [$ip_id]}"
gitea_swap_workflow "$index" "workflow:in-progress" "$owner" "$repo"
if [ -n "$user" ]; then
gitea_api POST "/repos/$owner/$repo/issues/$index/assignees" "{\"assignees\": [\"$user\"]}"
gitea_api PATCH "/repos/$owner/$repo/issues/$index" "{\"assignees\": [\"$user\"]}"
fi
}
```
@@ -262,10 +279,7 @@ gitea_claim() {
```bash
gitea_close_task() {
local index="$1" comment="${2:-}" owner="${3:-$GITEA_OWNER}" repo="${4:-$GITEA_REPO}"
local done_id
done_id=$(gitea_api GET "/repos/$owner/$repo/labels" | \
jq -r '.[] | select(.name=="workflow:done") | .id')
gitea_api POST "/repos/$owner/$repo/issues/$index/labels" "{\"labels\": [$done_id]}"
gitea_swap_workflow "$index" "workflow:done" "$owner" "$repo"
gitea_api PATCH "/repos/$owner/$repo/issues/$index" '{"state": "closed"}'
if [ -n "$comment" ]; then
gitea_api POST "/repos/$owner/$repo/issues/$index/comments" \