From 80082fbe8f2a4aa115e61a1670c1386c9ce423e6 Mon Sep 17 00:00:00 2001 From: Vlad Mocanu Date: Fri, 27 Feb 2026 13:38:41 +0200 Subject: [PATCH] fix: use label ID for Forgejo issue search and prevent duplicate labels Forgejo's /issues?labels= filter requires integer IDs, not label names. The workflow was searching by name (returning 0 results) then creating a new issue every run. Fix: look up label first, only create if missing, then use the ID for both issue search and issue creation. This prevents both duplicate issues and duplicate labels. Co-Authored-By: Claude Opus 4.6 --- .forgejo/kcl-ci/main.k | 49 ++++++++++++++++------------ .forgejo/workflows/upstream-sync.yml | 43 ++++++++++++++---------- 2 files changed, 53 insertions(+), 39 deletions(-) diff --git a/.forgejo/kcl-ci/main.k b/.forgejo/kcl-ci/main.k index 29420ba..6817622 100644 --- a/.forgejo/kcl-ci/main.k +++ b/.forgejo/kcl-ci/main.k @@ -380,16 +380,43 @@ else echo "needs_sync=false" >> "${"$"}GITHUB_OUTPUT" echo "Already up to date with upstream" fi""" + } + { + name = "Ensure upstream-sync label exists" + "if" = h.gha_steps_eq("compare", "needs_sync", "true") + id = "label" + run = """\ +API="${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}" +AUTH="Authorization: token ${h.gha_secret("CLAUDE_BOT_TOKEN")}" + +# Look up the label ID first (Forgejo needs integer IDs, not names) +LABEL_ID=${"$"}(curl -s -H "${"$"}AUTH" "${"$"}API/labels" | jq -r '[.[] | select(.name == "upstream-sync")] | .[0].id // ""') + +# Only create label if it doesn't exist yet +if [ -z "${"$"}LABEL_ID" ]; then + curl -s -o /dev/null \\ + -X POST -H "${"$"}AUTH" -H "Content-Type: application/json" \\ + -d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \\ + "${"$"}API/labels" + LABEL_ID=${"$"}(curl -s -H "${"$"}AUTH" "${"$"}API/labels" | jq -r '[.[] | select(.name == "upstream-sync")] | .[0].id // ""') + echo "Created upstream-sync label with ID: ${"$"}LABEL_ID" +else + echo "Found existing upstream-sync label ID: ${"$"}LABEL_ID" +fi + +echo "label_id=${"$"}LABEL_ID" >> "${"$"}GITHUB_OUTPUT" +""" } { name = "Check for existing sync issue" "if" = h.gha_steps_eq("compare", "needs_sync", "true") id = "existing" run = """\ +# Forgejo's labels filter requires integer IDs, not names RESPONSE=${"$"}(curl -s \\ -H "Authorization: token ${h.gha_secret("CLAUDE_BOT_TOKEN")}" \\ -H "Content-Type: application/json" \\ - "${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues?state=open&labels=upstream-sync&limit=1") + "${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues?state=open&labels=${h.gha_steps("label", "label_id")}&limit=1") ISSUE_COUNT=${"$"}(echo "${"$"}RESPONSE" | jq 'length') @@ -402,26 +429,6 @@ else echo "issue_exists=false" >> "${"$"}GITHUB_OUTPUT" echo "No existing sync issue found" fi""" - } - { - name = "Ensure upstream-sync label exists" - "if" = h.gha_steps_eq("compare", "needs_sync", "true") - id = "label" - run = """\ -API="${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}" -AUTH="Authorization: token ${h.gha_secret("CLAUDE_BOT_TOKEN")}" - -# Try to create the label (409 = already exists, which is fine) -curl -s -o /dev/null -w "%{http_code}" \\ - -X POST -H "${"$"}AUTH" -H "Content-Type: application/json" \\ - -d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \\ - "${"$"}API/labels" || true - -# Look up the label ID (Forgejo needs integer IDs, not names) -LABEL_ID=${"$"}(curl -s -H "${"$"}AUTH" "${"$"}API/labels" | jq -r '[.[] | select(.name == "upstream-sync")] | .[0].id // ""') -echo "label_id=${"$"}LABEL_ID" >> "${"$"}GITHUB_OUTPUT" -echo "upstream-sync label ID: ${"$"}LABEL_ID" -""" } { name = "Create or update sync issue" diff --git a/.forgejo/workflows/upstream-sync.yml b/.forgejo/workflows/upstream-sync.yml index b720ca9..942e991 100644 --- a/.forgejo/workflows/upstream-sync.yml +++ b/.forgejo/workflows/upstream-sync.yml @@ -68,14 +68,38 @@ jobs: echo "needs_sync=false" >> "$GITHUB_OUTPUT" echo "Already up to date with upstream" fi + - name: Ensure upstream-sync label exists + if: steps.compare.outputs.needs_sync == 'true' + id: label + run: | + API="${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}" + AUTH="Authorization: token ${{ secrets.CLAUDE_BOT_TOKEN }}" + + # Look up the label ID first (Forgejo needs integer IDs, not names) + LABEL_ID=$(curl -s -H "$AUTH" "$API/labels" | jq -r '[.[] | select(.name == "upstream-sync")] | .[0].id // ""') + + # Only create label if it doesn't exist yet + if [ -z "$LABEL_ID" ]; then + curl -s -o /dev/null \ + -X POST -H "$AUTH" -H "Content-Type: application/json" \ + -d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \ + "$API/labels" + LABEL_ID=$(curl -s -H "$AUTH" "$API/labels" | jq -r '[.[] | select(.name == "upstream-sync")] | .[0].id // ""') + echo "Created upstream-sync label with ID: $LABEL_ID" + else + echo "Found existing upstream-sync label ID: $LABEL_ID" + fi + + echo "label_id=$LABEL_ID" >> "$GITHUB_OUTPUT" - name: Check for existing sync issue if: steps.compare.outputs.needs_sync == 'true' id: existing run: |- + # Forgejo's labels filter requires integer IDs, not names RESPONSE=$(curl -s \ -H "Authorization: token ${{ secrets.CLAUDE_BOT_TOKEN }}" \ -H "Content-Type: application/json" \ - "${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues?state=open&labels=upstream-sync&limit=1") + "${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues?state=open&labels=${{ steps.label.outputs.label_id }}&limit=1") ISSUE_COUNT=$(echo "$RESPONSE" | jq 'length') @@ -88,23 +112,6 @@ jobs: echo "issue_exists=false" >> "$GITHUB_OUTPUT" echo "No existing sync issue found" fi - - name: Ensure upstream-sync label exists - if: steps.compare.outputs.needs_sync == 'true' - id: label - run: | - API="${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}" - AUTH="Authorization: token ${{ secrets.CLAUDE_BOT_TOKEN }}" - - # Try to create the label (409 = already exists, which is fine) - curl -s -o /dev/null -w "%{http_code}" \ - -X POST -H "$AUTH" -H "Content-Type: application/json" \ - -d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \ - "$API/labels" || true - - # Look up the label ID (Forgejo needs integer IDs, not names) - LABEL_ID=$(curl -s -H "$AUTH" "$API/labels" | jq -r '[.[] | select(.name == "upstream-sync")] | .[0].id // ""') - echo "label_id=$LABEL_ID" >> "$GITHUB_OUTPUT" - echo "upstream-sync label ID: $LABEL_ID" - name: Create or update sync issue if: steps.compare.outputs.needs_sync == 'true' id: sync-issue