name: Aider Auto-fix issues and PR comments via external prompt on: issue_comment: types: [created] jobs: check-membership: runs-on: ubicloud-standard-2 if: | github.event_name == 'issue_comment' && contains(github.event.comment.body, '/aider') && !contains(github.event.comment.user.login, '[bot]') outputs: is_member: ${{ steps.check-membership.outputs.is_member }} steps: - name: Check organization membership id: check-membership env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} COMMENTER: ${{ github.event.comment.user.login }} ORG_ACCESS_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }} run: | ORG="windmill-labs" STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: token $ORG_ACCESS_TOKEN" \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/orgs/$ORG/members/$COMMENTER") if [ "$STATUS" -eq 204 ]; then echo "is_member=true" >> $GITHUB_OUTPUT else echo "is_member=false" >> $GITHUB_OUTPUT fi check-and-prepare: needs: check-membership runs-on: ubicloud-standard-2 if: needs.check-membership.outputs.is_member == 'true' permissions: contents: write pull-requests: write issues: write env: GEMINI_API_KEY: ${{ secrets.GOOGLE_API_KEY }} GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} WINDMILL_TOKEN: ${{ secrets.WINDMILL_TOKEN }} outputs: issue_title: ${{ steps.determine_inputs.outputs.ISSUE_TITLE }} issue_body: ${{ steps.determine_inputs.outputs.ISSUE_BODY }} comment_content: ${{ steps.determine_inputs.outputs.COMMENT_CONTENT }} pr_branch: ${{ steps.checkout_pr.outputs.PR_BRANCH }} steps: - name: Acknowledge Request env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} run: | echo "Commenting on issue/PR #${{ github.event.issue.number }} to acknowledge the /aider command." gh issue comment ${{ github.event.issue.number }} --body "🤖 Aider is starting to work on your request. I'll update you here once I have a PR ready. Please be patient, this might take a few minutes." --repo $GITHUB_REPOSITORY - name: Determine inputs for Aider id: determine_inputs shell: bash env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COMMENT_BODY: ${{ github.event.comment.body }} ISSUE_NUMBER: ${{ github.event.issue.number }} GITHUB_REPOSITORY: ${{ github.repository }} LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }} run: | echo "Determining inputs for Aider..." ISSUE_TITLE_VAL="" ISSUE_BODY_VAL="" if [[ ! -z "${{ github.event.issue.pull_request }}" ]]; then echo "This is a comment on a Pull Request" PR_NUMBER="$ISSUE_NUMBER" PR_BODY_JSON=$(gh pr view "$PR_NUMBER" --json body --repo "$GITHUB_REPOSITORY") if [[ $? -ne 0 ]]; then echo "Error fetching PR body for PR #$PR_NUMBER" PR_BODY_VAL="" else PR_BODY_VAL=$(jq -r '.body // ""' <<< "$PR_BODY_JSON") fi if [[ ! -z "$PR_BODY_VAL" ]]; then REFERENCED_ISSUE="" if [[ "$PR_BODY_VAL" =~ \#linear:([a-f0-9-]+) ]]; then REFERENCED_ISSUE="${BASH_REMATCH[1]}" echo "Found referenced Linear issue #$REFERENCED_ISSUE in PR description" LINEAR_ISSUE_JSON=$(curl -s -H "Authorization: $LINEAR_API_KEY" \ "https://api.linear.app/graphql" \ -X POST \ -H "Content-Type: application/json" \ -d "{\"query\":\"query { issue(id: \\\"$REFERENCED_ISSUE\\\") { title description } }\"}") if [[ $? -eq 0 && ! "$LINEAR_ISSUE_JSON" =~ "error" ]]; then ISSUE_TITLE_VAL=$(jq -r '.data.issue.title // ""' <<< "$LINEAR_ISSUE_JSON") ISSUE_BODY_VAL=$(jq -r '.data.issue.description // ""' <<< "$LINEAR_ISSUE_JSON") echo "Successfully fetched Linear issue details" else echo "Error fetching Linear issue details for #$REFERENCED_ISSUE" fi elif [[ "$PR_BODY_VAL" =~ \#([0-9]+) ]]; then REFERENCED_ISSUE="${BASH_REMATCH[1]}" echo "Found referenced GitHub issue #$REFERENCED_ISSUE in PR description" ISSUE_DETAILS_JSON=$(gh issue view "$REFERENCED_ISSUE" --json title,body --repo "$GITHUB_REPOSITORY") if [[ $? -ne 0 ]]; then echo "Error fetching issue details for #$REFERENCED_ISSUE" else ISSUE_TITLE_VAL=$(jq -r '.title // ""' <<< "$ISSUE_DETAILS_JSON") ISSUE_BODY_VAL=$(jq -r '.body // ""' <<< "$ISSUE_DETAILS_JSON") fi fi else echo "PR body is empty or could not be fetched." fi else echo "This is a comment on a regular issue" ISSUE_DETAILS_JSON=$(gh issue view "$ISSUE_NUMBER" --json title,body --repo "$GITHUB_REPOSITORY") if [[ $? -ne 0 ]]; then echo "Error fetching issue details for #$ISSUE_NUMBER" else ISSUE_TITLE_VAL=$(jq -r '.title // ""' <<< "$ISSUE_DETAILS_JSON") ISSUE_BODY_VAL=$(jq -r '.body // ""' <<< "$ISSUE_DETAILS_JSON") fi fi echo "ISSUE_TITLE<> "$GITHUB_OUTPUT" echo "$ISSUE_TITLE_VAL" >> "$GITHUB_OUTPUT" echo "EOF_AIDER_TITLE" >> "$GITHUB_OUTPUT" echo "ISSUE_BODY<> "$GITHUB_OUTPUT" echo "$ISSUE_BODY_VAL" >> "$GITHUB_OUTPUT" echo "EOF_AIDER_BODY" >> "$GITHUB_OUTPUT" CLEAN_COMMENT="${COMMENT_BODY/\/aider/}" CLEAN_COMMENT="${CLEAN_COMMENT#"${CLEAN_COMMENT%%[![:space:]]*}"}" CLEAN_COMMENT="${CLEAN_COMMENT%"${CLEAN_COMMENT##*[![:space:]]}"}" echo "COMMENT_CONTENT<> "$GITHUB_OUTPUT" echo "$CLEAN_COMMENT" >> "$GITHUB_OUTPUT" echo "EOF_AIDER_COMMENT" >> "$GITHUB_OUTPUT" echo "Finished determining inputs." run-aider: needs: [check-membership, check-and-prepare] if: needs.check-membership.outputs.is_member == 'true' uses: ./.github/workflows/aider-common.yml with: issue_title: ${{ needs.check-and-prepare.outputs.issue_title }} issue_body: ${{ needs.check-and-prepare.outputs.issue_body }} instruction: ${{ needs.check-and-prepare.outputs.comment_content }} issue_id: ${{ github.event.issue.number }} rules_files: ".cursor/rules/rust-best-practices.mdc .cursor/rules/svelte5-best-practices.mdc .cursor/rules/windmill-overview.mdc" secrets: inherit