# Responds to `/gitnexus index` comments on pull requests. # # Gated to the same author_association roles (OWNER, MEMBER, COLLABORATOR) # as the automatic PR index trigger, but applied to the COMMENTER, not # the PR author. This intentionally lets a contributor index a PR from # a non-contributor / first-time fork author — the contributor takes # responsibility for the trust boundary by typing the command. # # When a matching comment lands on a PR, this workflow dispatches # `gitnexus-index.yml` with the PR number and the `refs/pull//head` # ref so indexing works for fork PRs too (GitHub mirrors every PR's # head ref into the base repo regardless of which fork it originated # from, so actions/checkout can always resolve it). # # Use cases: # - Re-index a PR after a rebase without pushing a new commit # - Index a docs-only PR that was skipped by paths-ignore # - Index a non-contributor (fork) PR that the auto-trigger skipped # - Re-run a failed index # # Supported commands: # /gitnexus index — index the PR with embeddings (default) # /gitnexus index embeddings — explicit form of the above; same effect # /gitnexus index fast — graph-only index (skip embeddings), for # a quick re-index without waiting ~5 min # of embedding generation name: GitNexus PR Command on: issue_comment: types: [created] permissions: contents: read pull-requests: write actions: write # needed to dispatch gitnexus-index.yml concurrency: group: gitnexus-pr-command-${{ github.event.issue.number }} cancel-in-progress: false jobs: dispatch: # Only run for PR comments that start with /gitnexus from trusted # commenters. Intentionally checks the COMMENTER's association so a # contributor can index a non-contributor's PR on demand. if: | github.event.issue.pull_request != null && startsWith(github.event.comment.body, '/gitnexus') && (github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR') runs-on: ubuntu-latest timeout-minutes: 5 steps: - name: Parse command and resolve PR head ref id: parse uses: actions/github-script@v7 with: script: | const body = context.payload.comment.body.trim(); const match = body.match(/^\/gitnexus\s+(\w+)(?:\s+(\w+))?/); if (!match) { core.setFailed(`Unrecognized command: ${body}. Try: /gitnexus index [fast]`); return; } const [, subcommand, modifier] = match; if (subcommand !== 'index') { core.setFailed(`Unknown subcommand: ${subcommand}. Only 'index' is supported.`); return; } // Default to embeddings on — a contributor typing the command // has already decided they want a full re-index. The `fast` // modifier is the explicit opt-out for graph-only runs. // `embeddings` is accepted as a no-op alias for backwards // compat with the previous command form. let embeddings = 'true'; if (modifier === 'fast' || modifier === 'graph-only' || modifier === 'no-embeddings') { embeddings = 'false'; } // Use refs/pull//head instead of the raw head SHA. GitHub // mirrors every PR's head into the base repo as this ref, so // actions/checkout can always resolve it — even for PRs from // forks whose raw SHAs don't exist in the base repo. const prNum = context.payload.issue.number; core.setOutput('pr_number', String(prNum)); core.setOutput('pr_ref', `refs/pull/${prNum}/head`); core.setOutput('embeddings', embeddings); core.info( `Dispatching index for PR #${prNum} at refs/pull/${prNum}/head (embeddings=${embeddings}, modifier=${modifier || '(none)'})`, ); - name: Dispatch gitnexus-index workflow uses: actions/github-script@v7 with: script: | await github.rest.actions.createWorkflowDispatch({ owner: context.repo.owner, repo: context.repo.repo, workflow_id: 'gitnexus-index.yml', ref: 'main', inputs: { pr_number: '${{ steps.parse.outputs.pr_number }}', pr_ref: '${{ steps.parse.outputs.pr_ref }}', embeddings: '${{ steps.parse.outputs.embeddings }}', force: 'false', }, }); - name: React to the comment uses: actions/github-script@v7 with: script: | await github.rest.reactions.createForIssueComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: context.payload.comment.id, content: 'rocket', });