-
Notifications
You must be signed in to change notification settings - Fork 148
173 lines (166 loc) · 9.38 KB
/
Copy pathengineer-bot-followup.yml
File metadata and controls
173 lines (166 loc) · 9.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# Engineer Bot — follow-up.
#
# When someone replies to a review thread on a PR carrying the `engineer-bot`
# label (or the label is applied), the bot re-evaluates the open threads in
# catch-up mode, applies a fixup (or replies / marks blocked), and pushes to the
# PR branch. Driven by this repo's .bot/ prompts.
#
# Like the author, this builds/runs the product (setup-poetry). Shared setup
# (tokens + Node + engine install, PAT-free via an engine-scoped App token) is in
# the local ./.github/actions/bot-prelude composite; this file owns checkout,
# setup-poetry, and the followup run. Engine installed in REF mode pinned to a SHA.
#
# The gate below is the canonical label-gated form copied verbatim from the
# engine dogfood (the single source of truth). It ANDs with the engine-side
# floor; do not weaken it.
name: Engineer Bot — Follow-up
on:
pull_request_review_comment:
types: [created]
# `engineer-bot` label applied → catch-up over pre-existing review threads.
pull_request:
types: [labeled]
permissions:
contents: write # push fixup commits to the PR branch
pull-requests: write # post inline replies
id-token: write # JFrog OIDC exchange for the engine/SDK/CLI install
jobs:
followup:
# SECURITY + scope (CANONICAL label-gated model — verbatim from the engine):
# - skip fork PRs — keep the model + App token out of untrusted code's reach;
# - operate only on non-fork OPEN PRs carrying the `engineer-bot` label
# (maintainer-applied opt-in; label requires triage+);
# - comment path: trusted commenters only
# (OWNER/MEMBER/COLLABORATOR/CONTRIBUTOR, or a bot — reviewer-bot/Copilot),
# never the engineer-bot's own comments, and never a reviewer-bot reconcile
# loopback. CONTRIBUTOR is included because a maintainer with PRIVATE org
# membership is reported as `author_association: CONTRIBUTOR` in the webhook
# payload (even though REST shows MEMBER) — without it, such a maintainer's
# review comments SILENTLY fail this gate and the bot never engages. Low
# risk: this path already requires a non-fork, OPEN, `engineer-bot`-labeled
# PR (a maintainer-applied opt-in);
# - labeled path: the `engineer-bot` label was just applied by a human.
if: >-
github.event.pull_request.head.repo.fork == false
&& github.event.pull_request.state == 'open'
&& (
(
github.event_name == 'pull_request_review_comment'
&& contains(github.event.pull_request.labels.*.name, 'engineer-bot')
&& !startsWith(github.event.comment.user.login, 'peco-engineer-bot')
&& !contains(github.event.comment.body, '<!-- pr-review-bot:v1 reconcile -->')
&& (
contains(fromJson('["OWNER","MEMBER","COLLABORATOR","CONTRIBUTOR"]'), github.event.comment.author_association)
|| (
github.event.comment.user.type == 'Bot'
&& (
startsWith(github.event.comment.user.login, 'peco-review-bot')
|| startsWith(github.event.comment.user.login, 'Copilot')
|| startsWith(github.event.comment.user.login, 'copilot')
)
)
)
)
|| (
github.event_name == 'pull_request'
&& github.event.action == 'labeled'
&& github.event.label.name == 'engineer-bot'
&& github.event.sender.type != 'Bot'
&& !startsWith(github.event.sender.login, 'peco-engineer-bot')
)
)
environment: azure-prod # DATABRICKS_HOST / DATABRICKS_TOKEN live here
runs-on:
group: databricks-protected-runner-group
labels: [linux-ubuntu-latest]
timeout-minutes: 30
concurrency:
group: engineer-bot-followup-pr-${{ github.event.pull_request.number }}
cancel-in-progress: false
steps:
# Checkout FIRST (remote action) so the local `./` composites resolve.
# Check out the PR head BRANCH (not the merge ref) so fixups push back to
# it. persist-credentials:false; the run step below sets an authenticated
# push remote from the minted App token.
- name: Checkout PR head branch
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
persist-credentials: false
# Python + connector deps via the repo's OWN setup-poetry action (JFrog
# mirror + poetry lock + install) — egress-safe, tolerates a stale lock.
# The agent runs `poetry run python -m pytest tests/unit` to verify fixups.
- name: Setup Poetry + connector deps (for pytest self-verify)
uses: ./.github/actions/setup-poetry
with:
python-version: '3.11'
# Match code-coverage.yml's --all-extras install so the agent's mocked
# `tests/unit` self-verify runs against the same runtime as CI. The key
# extra here is the REAL `databricks-sql-kernel` wheel: with it present,
# broader unit selections must pass `-m "not realkernel"` (see the
# followup prompt, .bot/prompts/engineer-followup/system.md), otherwise
# the realkernel routing test fails loudly on the sys.modules fake that
# shadows the wheel. (Unlike engineer-bot.yml, this job runs NO e2e test
# — it wires no live-warehouse env, per the NOTE below — so the e2e
# repro is NOT the reason extras are installed here.)
install-args: "--all-extras"
# setup-poetry runs `poetry lock` (to reconcile the lock with the internal
# JFrog source it injects), which REWRITES tracked poetry.lock / pyproject.toml
# in the working tree. The venv is already built, so the tree no longer needs
# that churn — revert it, else the followup's fixup commit (or its leftover
# check) would sweep up these bot-untouched dirty files. Keep ONLY the
# agent's edits in the tree.
- name: Revert poetry lock/pyproject churn (keep only the agent's edits)
# No `|| true`: `git checkout -- <tracked-file>` exits 0 for both the
# clean and the reverted-churn cases, so a non-zero exit means the revert
# genuinely failed (e.g. the files went untracked/missing) and the dirty
# tree would otherwise be swept into the followup's fixup commit. Fail
# loudly here instead of masking it.
run: git checkout -- poetry.lock pyproject.toml
# Shared prelude: mint the engineer-bot token (pushes fixup commits, posts
# replies) + the engine-scoped token, set up Node, install the engine.
- name: Bot prelude (tokens + Node + engine install)
id: prelude
uses: ./.github/actions/bot-prelude
with:
app-id: ${{ secrets.ENGINEER_BOT_APP_ID }}
private-key: ${{ secrets.ENGINEER_BOT_APP_PRIVATE_KEY }}
# Engine pin lives in ONE place: bot-prelude's `engine-ref` default.
# Bump it there to move all four bots in lockstep; override here only
# to run this workflow against a different engine commit.
# Run the follow-up. Inlines the engine's bot-run env contract for
# engineer:followup, plus the authenticated push remote bot-run would set
# up (followup pushes fixup commits via a plain `git push`, which doesn't
# consult GH_TOKEN; the checkout is persist-credentials:false).
- name: Run engineer follow-up (catch-up over all unaddressed threads)
env:
GH_TOKEN: ${{ steps.prelude.outputs.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
HEAD_BRANCH: ${{ github.event.pull_request.head.ref }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_URL: ${{ github.event.pull_request.html_url }}
TRIGGER_COMMENT_ID: ${{ github.event.comment.id }}
MODEL_ENDPOINT: https://${{ secrets.DATABRICKS_HOST }}/serving-endpoints/databricks-claude-opus-4-8/invocations
DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }}
# NOTE: no live-warehouse connection env (DATABRICKS_SERVER_HOSTNAME /
# DATABRICKS_HTTP_PATH / DATABRICKS_CATALOG / DATABRICKS_USER) is wired
# here. The followup prompt (.bot/prompts/engineer-followup/system.md)
# runs only the mocked `tests/unit` suite and forbids tests/e2e, so the
# agent never consumes those vars — provisioning them would add live
# credentials to an LLM-driven step for no functional benefit. If
# followups should ever repair/run E2E repros, add them back here AND
# update that prompt.
RUNNER_TEMP: ${{ runner.temp }}
# The agent's working tree AND the .bot/ lookup root. run.py resolves
# the config at <REPO_ROOT>/.bot/config.yaml. The engine has NO path
# default — it fails with a clear error if this is unset — so it MUST be
# set (we check out at the workspace root, not the driver-repo layout's
# `internal-repo/`). (`TEST_REPO_ROOT` is the deprecated alias.)
REPO_ROOT: ${{ github.workspace }}
run: |
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
python -m databricks_bot_engine.engineer_bot.run --phase followup \
--system-prompt "$GITHUB_WORKSPACE/.bot/prompts/engineer-followup/system.md"