From ecabe360d1ad9459ad9c8cf3b06c26eb140fc359 Mon Sep 17 00:00:00 2001 From: fullsend-code Date: Wed, 29 Apr 2026 14:41:10 +0000 Subject: [PATCH] feat(#529): post workflow run links on issue/PR at start of agent run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each dispatch job (triage, code, review) now posts a comment on the triggering issue or PR with two links: 1. The shim workflow run URL on the target repo 2. The dispatched agent workflow run URL on .fullsend The dispatched run URL is discovered by polling gh run list up to 3 times (3s apart) after dispatch. If the run is not found, a fallback link to the workflow runs page is used instead. Comments use per-agent HTML marker comments () for idempotent updates on retries — re-triggering the same agent updates the existing comment rather than posting a duplicate. The step runs with if: always() so the shim URL is posted even when dispatch fails, aiding debugging. Added issues: write and pull-requests: write permissions to support posting comments via GITHUB_TOKEN. Note: pre-commit and actionlint could not run in-sandbox due to network restrictions. YAML syntax was validated. Manual verification of actionlint is required. Closes #529 --- .../templates/shim-workflow.yaml | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/internal/scaffold/fullsend-repo/templates/shim-workflow.yaml b/internal/scaffold/fullsend-repo/templates/shim-workflow.yaml index e21d0f216f..dd8ab61215 100644 --- a/internal/scaffold/fullsend-repo/templates/shim-workflow.yaml +++ b/internal/scaffold/fullsend-repo/templates/shim-workflow.yaml @@ -17,6 +17,8 @@ name: fullsend permissions: contents: read + issues: write + pull-requests: write on: issues: @@ -70,6 +72,48 @@ jobs: --field event_type="$EVENT_TYPE" \ --field source_repo="$SOURCE_REPO" \ --field event_payload="$EVENT_PAYLOAD" + - name: Post run links + if: always() + env: + GH_TOKEN: ${{ github.token }} + DISPATCH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }} + DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend + ITEM_NUMBER: ${{ github.event.issue.number }} + WORKFLOW_FILE: triage.yml + AGENT_LABEL: triage + run: | + set -euo pipefail + SHIM_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + DISPATCH_RUN_URL="" + for attempt in 1 2 3; do + sleep 3 + DISPATCH_RUN_URL=$(GH_TOKEN="$DISPATCH_TOKEN" gh run list \ + --repo "$DISPATCH_REPO" \ + --workflow "$WORKFLOW_FILE" \ + --limit 1 \ + --json url \ + --jq '.[0].url' 2>/dev/null) && [ -n "$DISPATCH_RUN_URL" ] && break + DISPATCH_RUN_URL="" + done + DISPATCH_FALLBACK="${GITHUB_SERVER_URL}/${DISPATCH_REPO}/actions/workflows/${WORKFLOW_FILE}" + DISPATCH_LINK="${DISPATCH_RUN_URL:-$DISPATCH_FALLBACK}" + MARKER="" + BODY=$(cat </dev/null | head -1 || true) + if [ -n "$EXISTING_ID" ]; then + gh api "repos/${GITHUB_REPOSITORY}/issues/comments/${EXISTING_ID}" \ + -X PATCH -f body="$BODY" + else + gh issue comment "$ITEM_NUMBER" --repo "${GITHUB_REPOSITORY}" --body "$BODY" + fi dispatch-code: runs-on: ubuntu-latest @@ -106,6 +150,48 @@ jobs: --field event_type="$EVENT_TYPE" \ --field source_repo="$SOURCE_REPO" \ --field event_payload="$EVENT_PAYLOAD" + - name: Post run links + if: always() + env: + GH_TOKEN: ${{ github.token }} + DISPATCH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }} + DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend + ITEM_NUMBER: ${{ github.event.issue.number }} + WORKFLOW_FILE: code.yml + AGENT_LABEL: code + run: | + set -euo pipefail + SHIM_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + DISPATCH_RUN_URL="" + for attempt in 1 2 3; do + sleep 3 + DISPATCH_RUN_URL=$(GH_TOKEN="$DISPATCH_TOKEN" gh run list \ + --repo "$DISPATCH_REPO" \ + --workflow "$WORKFLOW_FILE" \ + --limit 1 \ + --json url \ + --jq '.[0].url' 2>/dev/null) && [ -n "$DISPATCH_RUN_URL" ] && break + DISPATCH_RUN_URL="" + done + DISPATCH_FALLBACK="${GITHUB_SERVER_URL}/${DISPATCH_REPO}/actions/workflows/${WORKFLOW_FILE}" + DISPATCH_LINK="${DISPATCH_RUN_URL:-$DISPATCH_FALLBACK}" + MARKER="" + BODY=$(cat </dev/null | head -1 || true) + if [ -n "$EXISTING_ID" ]; then + gh api "repos/${GITHUB_REPOSITORY}/issues/comments/${EXISTING_ID}" \ + -X PATCH -f body="$BODY" + else + gh issue comment "$ITEM_NUMBER" --repo "${GITHUB_REPOSITORY}" --body "$BODY" + fi dispatch-review: runs-on: ubuntu-latest @@ -148,3 +234,45 @@ jobs: --field event_type="$EVENT_TYPE" \ --field source_repo="$SOURCE_REPO" \ --field event_payload="$EVENT_PAYLOAD" + - name: Post run links + if: always() + env: + GH_TOKEN: ${{ github.token }} + DISPATCH_TOKEN: ${{ secrets.FULLSEND_DISPATCH_TOKEN }} + DISPATCH_REPO: ${{ github.repository_owner }}/.fullsend + ITEM_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }} + WORKFLOW_FILE: review.yml + AGENT_LABEL: review + run: | + set -euo pipefail + SHIM_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + DISPATCH_RUN_URL="" + for attempt in 1 2 3; do + sleep 3 + DISPATCH_RUN_URL=$(GH_TOKEN="$DISPATCH_TOKEN" gh run list \ + --repo "$DISPATCH_REPO" \ + --workflow "$WORKFLOW_FILE" \ + --limit 1 \ + --json url \ + --jq '.[0].url' 2>/dev/null) && [ -n "$DISPATCH_RUN_URL" ] && break + DISPATCH_RUN_URL="" + done + DISPATCH_FALLBACK="${GITHUB_SERVER_URL}/${DISPATCH_REPO}/actions/workflows/${WORKFLOW_FILE}" + DISPATCH_LINK="${DISPATCH_RUN_URL:-$DISPATCH_FALLBACK}" + MARKER="" + BODY=$(cat </dev/null | head -1 || true) + if [ -n "$EXISTING_ID" ]; then + gh api "repos/${GITHUB_REPOSITORY}/issues/comments/${EXISTING_ID}" \ + -X PATCH -f body="$BODY" + else + gh issue comment "$ITEM_NUMBER" --repo "${GITHUB_REPOSITORY}" --body "$BODY" + fi