Skip to content
Merged
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
41 changes: 23 additions & 18 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ permissions:
contents: read
pull-requests: read

env:
TARGET_REPOSITORY: hyperifyio/goagent

concurrency:
group: pr-${{ github.event.pull_request.number }}-dispatch
cancel-in-progress: true

jobs:
dispatch:
if: ${{ !github.event.pull_request.head.repo.fork && github.repository == env.TARGET_REPOSITORY }}
# Require: internal actor, not a fork, and PR targets main (tweak branch if needed)
if: ${{ !github.event.pull_request.head.repo.fork
&& contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.actor_association)
&& github.event.pull_request.base.ref == 'main' }}
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Build payload
id: payload
Expand All @@ -36,37 +38,40 @@ jobs:
head_repo:$head_repo,head_ref:$head_ref,base_ref:$base_ref}}' \
> payload.json

- name: Send repository_dispatch to aibuddy
- name: Preflight (token & target repo access)
env:
GH_TOKEN: ${{ secrets.AIBUDDY_DISPATCH_PAT }}
run: |
set -euo pipefail

# Secret present?
TARGET="hyperifyio/aibuddy"

if [[ -z "${GH_TOKEN:-}" ]]; then
echo "::error title=Missing secret::AIBUDDY_DISPATCH_PAT is not set."
exit 1
fi

# Payload present?
if [[ ! -s payload.json ]]; then
echo "::error title=Missing payload::payload.json was not created."
# Verify token can see the private repo; prints a helpful error otherwise
if ! gh api "repos/$TARGET" >/dev/null 2>err.txt; then
echo "::error title=Token cannot access target repo::$TARGET not accessible with provided token."
cat err.txt || true
exit 1
fi

# Validate JSON if jq exists
if command -v jq >/dev/null 2>&1; then
jq -e . payload.json >/dev/null || {
echo "::error title=Invalid JSON payload::payload.json is not valid JSON"
cat payload.json
exit 1
}
# Validate payload JSON
if [[ ! -s payload.json ]] || ! jq -e . payload.json >/dev/null; then
echo "::error title=Invalid payload::payload.json missing or not valid JSON"
[[ -f payload.json ]] && cat payload.json || true
exit 1
fi

# Dispatch (GitHub returns 204 No Content on success)
- name: Send repository_dispatch to aibuddy (gh api)
env:
GH_TOKEN: ${{ secrets.AIBUDDY_DISPATCH_PAT }}
run: |
set -euo pipefail
gh api repos/hyperifyio/aibuddy/dispatches \
--method POST \
-H "Accept: application/vnd.github+json" \
--input payload.json

echo "repository_dispatch sent successfully."
102 changes: 48 additions & 54 deletions .github/workflows/task-or-bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,34 @@ on:
- opened
- edited
- reopened
- labeled
- unlabeled
- assigned
- unassigned

permissions:
contents: read
issues: read

# Optional: set in Settings → Variables → Repository variables
# CODING_AGENT_USER = <agent-gh-handle> (leave empty to disable the assignee filter)
env:
TARGET_REPOSITORY: hyperifyio/goagent
CODING_AGENT_USER: ${{ vars.CODING_AGENT_USER }}

concurrency:
group: coding-agent
cancel-in-progress: false
group: issue-${{ github.event.issue.number }}-dispatch
cancel-in-progress: true

jobs:
dispatch:
if: ${{ github.repository == env.TARGET_REPOSITORY }}
# Only members/maintainers/collaborators can trigger runs from a public repo
if: ${{ contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.actor_association) }}
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Determine issue type and assignment (GraphQL, with label fallback)
- name: Determine issue type and assignment (Issue Types only)
id: meta
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # gh uses GH_TOKEN
CODING_AGENT_USER: ${{ env.CODING_AGENT_USER }}
run: |
set -euo pipefail
Expand All @@ -40,7 +42,7 @@ jobs:
REPO="${GITHUB_REPOSITORY#*/}"
NUMBER="${{ github.event.issue.number }}"

# Query metadata, including Issue Types, labels, and assignees
# Query: issue type + assignees (no labels)
RESP="$(gh api graphql \
-H 'GraphQL-Features: issue_types' \
-f owner="$OWNER" \
Expand All @@ -53,7 +55,6 @@ jobs:
number
title
issueType { name }
labels(first: 50) { nodes { name } }
assignees(first: 100) { nodes { login } }
}
}
Expand All @@ -62,24 +63,12 @@ jobs:

TYPE="$(jq -r '.data.repository.issue.issueType.name // empty' <<< "$RESP")"

if [[ -z "$TYPE" ]]; then
# Fallback to labels if Issue Types are not enabled/used
TYPE="$(jq -r '
[.data.repository.issue.labels.nodes[].name // empty
| ascii_downcase] as $L
| if ($L | index("bug")) then "Bug"
elif ($L | index("task")) then "Task"
else "" end
' <<< "$RESP")"
fi

# Assignment filter
# Optional assignee filter
RAW_AGENT="${CODING_AGENT_USER:-}"
# Strip leading @ and lowercase
AGENT_CLEAN="$(tr -d '\n' <<< "${RAW_AGENT#@}" | tr '[:upper:]' '[:lower:]')"

if [[ -z "$AGENT_CLEAN" ]]; then
ASSIGNED_OK="true" # no filter requested
ASSIGNED_OK="true"
else
ASSIGNED_OK="$(
jq -r --arg agent "$AGENT_CLEAN" '
Expand All @@ -89,40 +78,37 @@ jobs:
)"
fi

# Type filter
LOWER_TYPE="$(tr '[:upper:]' '[:lower:]' <<< "${TYPE}")"
case "$LOWER_TYPE" in
# Type filter: only "Task" or "Bug"
case "$(tr '[:upper:]' '[:lower:]' <<< "${TYPE}")" in
bug|task) TYPE_OK="true" ;;
*) TYPE_OK="false" ;;
esac

# Final decision
if [[ "$TYPE_OK" == "true" && "$ASSIGNED_OK" == "true" ]]; then
SHOULD="true"
else
SHOULD="false"
fi
SHOULD=$([[ "$TYPE_OK" == "true" && "$ASSIGNED_OK" == "true" ]] && echo true || echo false)

echo "issue_type=${TYPE}" >> "$GITHUB_OUTPUT"
echo "assigned_ok=${ASSIGNED_OK}" >> "$GITHUB_OUTPUT"
echo "type_ok=${TYPE_OK}" >> "$GITHUB_OUTPUT"
echo "should_dispatch=${SHOULD}" >> "$GITHUB_OUTPUT"
echo "agent_user=${AGENT_CLEAN}" >> "$GITHUB_OUTPUT"
{
echo "issue_type=${TYPE}"
echo "assigned_ok=${ASSIGNED_OK}"
echo "type_ok=${TYPE_OK}"
echo "should_dispatch=${SHOULD}"
echo "agent_user=${AGENT_CLEAN}"
} >> "$GITHUB_OUTPUT"

- name: Log & skip if not eligible
if: ${{ steps.meta.outputs.should_dispatch != 'true' }}
run: |
echo "Issue #${{ github.event.issue.number }} not eligible for dispatch."
echo " Detected type: '${{ steps.meta.outputs.issue_type }}' (type_ok=${{ steps.meta.outputs.type_ok }})"
echo " CODING_AGENT_USER='${{ steps.meta.outputs.agent_user }}' assigned_ok=${{ steps.meta.outputs.assigned_ok }}"
echo " issue_type='${{ steps.meta.outputs.issue_type }}' (type_ok=${{ steps.meta.outputs.type_ok }})"
echo " assigned_ok=${{ steps.meta.outputs.assigned_ok }} agent='${{ steps.meta.outputs.agent_user }}'"
echo " Note: This workflow requires GitHub Issue Types ('Task' or 'Bug')."

- name: Build payload
if: ${{ steps.meta.outputs.should_dispatch == 'true' }}
id: payload
env:
ISSUE_TYPE: ${{ steps.meta.outputs.issue_type }}
AGENT_USER: ${{ steps.meta.outputs.agent_user }}
ASSIGNED_OK: ${{ steps.meta.outputs.assigned_ok }}
ISSUE_TYPE: ${{ steps.meta.outputs.issue_type }}
AGENT_USER: ${{ steps.meta.outputs.agent_user }}
ASSIGNED_OK: ${{ steps.meta.outputs.assigned_ok }}
run: |
jq -n \
--arg repo "${{ github.repository }}" \
Expand All @@ -147,35 +133,43 @@ jobs:
assigned_ok:$assigned_ok
}}' \
> payload.json
echo "payload=$(cat payload.json)" >> "$GITHUB_OUTPUT"

- name: Send repository_dispatch to aibuddy (gh api)
- name: Preflight (token & target repo access)
if: ${{ steps.meta.outputs.should_dispatch == 'true' }}
env:
GH_TOKEN: ${{ secrets.AIBUDDY_DISPATCH_PAT }}
run: |
set -euo pipefail
TARGET="hyperifyio/aibuddy"

if [[ -z "${GH_TOKEN:-}" ]]; then
echo "::error title=Missing secret::AIBUDDY_DISPATCH_PAT is not set."
exit 1
fi

echo "::error title=Missing payload::payload.json was not created or is empty."
# Verify token can access the private repo
if ! gh api "repos/$TARGET" >/dev/null 2>err.txt; then
echo "::error title=Token cannot access target repo::$TARGET not accessible with provided token."
cat err.txt || true
exit 1
fi

if command -v jq >/dev/null 2>&1; then
jq -e . payload.json >/dev/null || {
echo "::error title=Invalid JSON payload::payload.json is not valid JSON"
cat payload.json
exit 1
}
fi
# Validate payload JSON
jq -e . payload.json >/dev/null || {
echo "::error title=Invalid payload::payload.json is not valid JSON"
cat payload.json
exit 1
}

- name: Send repository_dispatch to aibuddy (gh api)
if: ${{ steps.meta.outputs.should_dispatch == 'true' }}
env:
GH_TOKEN: ${{ secrets.AIBUDDY_DISPATCH_PAT }}
run: |
set -euo pipefail
gh api repos/hyperifyio/aibuddy/dispatches \
--method POST \
-H "Accept: application/vnd.github+json" \
--input payload.json

echo "repository_dispatch sent for issue #${{ github.event.issue.number }} (type=${{ steps.meta.outputs.issue_type }}, agent='${{ steps.meta.outputs.agent_user }}')"