-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmonthly_optimization_planner.yml
More file actions
297 lines (270 loc) · 13.2 KB
/
monthly_optimization_planner.yml
File metadata and controls
297 lines (270 loc) · 13.2 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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
name: Monthly Optimization Planner
"on":
workflow_dispatch:
inputs:
upstream_run_id:
description: "AI review run id from CryptoSnapshotPipelines"
required: true
downstream_run_id:
description: "AI review run id from BinancePlatform"
required: true
downstream_repo:
description: "Downstream execution repo"
required: true
default: "QuantStrategyLab/BinancePlatform"
jobs:
planner:
runs-on: ubuntu-latest
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
permissions:
actions: write
contents: read
issues: write
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Detect GitHub App credentials
id: cross_repo_credentials
env:
APP_ID: ${{ vars.CROSS_REPO_GITHUB_APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.CROSS_REPO_GITHUB_APP_PRIVATE_KEY }}
run: |
if [ -n "$APP_ID" ] && [ -n "$APP_PRIVATE_KEY" ]; then
echo "has_app_credentials=true" >> "$GITHUB_OUTPUT"
else
echo "has_app_credentials=false" >> "$GITHUB_OUTPUT"
fi
- name: Create GitHub App token for cross-repo access
id: cross_repo_app_token
if: steps.cross_repo_credentials.outputs.has_app_credentials == 'true'
uses: actions/create-github-app-token@v3
with:
app-id: ${{ vars.CROSS_REPO_GITHUB_APP_ID }}
private-key: ${{ secrets.CROSS_REPO_GITHUB_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: |
CryptoSnapshotPipelines
BinancePlatform
CryptoStrategies
permission-actions: write
permission-issues: write
- name: Resolve cross-repo access token
id: cross_repo_token
env:
APP_TOKEN: ${{ steps.cross_repo_app_token.outputs.token }}
FALLBACK_TOKEN: ${{ secrets.CROSS_REPO_GITHUB_TOKEN }}
run: |
if [ -n "$APP_TOKEN" ]; then
echo "token=$APP_TOKEN" >> "$GITHUB_OUTPUT"
echo "source=github_app" >> "$GITHUB_OUTPUT"
elif [ -n "$FALLBACK_TOKEN" ]; then
echo "token=$FALLBACK_TOKEN" >> "$GITHUB_OUTPUT"
echo "source=personal_access_token" >> "$GITHUB_OUTPUT"
else
echo "Missing cross-repo credentials. Configure GitHub App secrets or CROSS_REPO_GITHUB_TOKEN." >&2
exit 1
fi
- name: Download upstream AI review artifact
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p data/input/upstream
gh run download "${{ inputs.upstream_run_id }}" \
--repo "${GITHUB_REPOSITORY}" \
--dir data/input/upstream
- name: Download downstream AI review artifact
env:
GH_TOKEN: ${{ steps.cross_repo_token.outputs.token }}
run: |
mkdir -p data/input/downstream
gh run download "${{ inputs.downstream_run_id }}" \
--repo "${{ inputs.downstream_repo }}" \
--dir data/input/downstream
- name: Resolve downloaded artifact paths
id: artifact_paths
run: |
UPSTREAM_DIR=$(find data/input/upstream -mindepth 1 -maxdepth 1 -type d | head -1)
DOWNSTREAM_DIR=$(find data/input/downstream -mindepth 1 -maxdepth 1 -type d | head -1)
if [ -z "${UPSTREAM_DIR}" ] || [ -z "${DOWNSTREAM_DIR}" ]; then
echo "Failed to resolve downloaded artifact directories" >&2
exit 1
fi
{
echo "upstream_dir=${UPSTREAM_DIR}"
echo "downstream_dir=${DOWNSTREAM_DIR}"
} >> "${GITHUB_OUTPUT}"
- name: Prepare upstream review payload
run: |
python3 scripts/build_ai_review_payload.py \
--source-repo "${GITHUB_REPOSITORY}" \
--review-kind upstream_selector \
--issue-context-file "${{ steps.artifact_paths.outputs.upstream_dir }}/issue_context.json" \
--secondary-review-file "${{ steps.artifact_paths.outputs.upstream_dir }}/secondary_review.json" \
--run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${{ inputs.upstream_run_id }}" \
--output-file data/output/prepared/upstream_review_payload.json
- name: Prepare downstream review payload
run: |
python3 scripts/build_ai_review_payload.py \
--source-repo "${{ inputs.downstream_repo }}" \
--review-kind execution_runtime \
--issue-context-file "${{ steps.artifact_paths.outputs.downstream_dir }}/issue_context.json" \
--secondary-review-file "${{ steps.artifact_paths.outputs.downstream_dir }}/secondary_review.json" \
--run-url "${GITHUB_SERVER_URL}/${{ inputs.downstream_repo }}/actions/runs/${{ inputs.downstream_run_id }}" \
--output-file data/output/prepared/downstream_review_payload.json
- name: Build monthly optimization plan
run: |
python3 scripts/build_monthly_optimization_plan.py \
--upstream-review-file data/output/prepared/upstream_review_payload.json \
--downstream-review-file data/output/prepared/downstream_review_payload.json \
--output-dir data/output/monthly_optimization
- name: Append optimization summary
run: cat data/output/monthly_optimization/optimization_summary.md >> "$GITHUB_STEP_SUMMARY"
- name: Create monthly optimization issue
id: optimization_issue
run: |
issue_output=$(python3 scripts/post_monthly_optimization_issue.py \
--repo "${GITHUB_REPOSITORY}" \
--plan-file data/output/monthly_optimization/optimization_plan.json \
--summary-file data/output/monthly_optimization/optimization_summary.md)
echo "$issue_output"
issue_number=$(printf '%s\n' "$issue_output" | awk -F= '/^issue_number=/{print $2}' | tail -1)
if [ -z "$issue_number" ]; then
echo "Failed to capture optimization issue number" >&2
exit 1
fi
echo "issue_number=$issue_number" >> "$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Fan out CryptoSnapshotPipelines task issue
run: |
python3 scripts/fanout_monthly_optimization_tasks.py \
--plan-file data/output/monthly_optimization/optimization_plan.json \
--owner-repo CryptoSnapshotPipelines \
--repo "${GITHUB_REPOSITORY}" \
--planner-issue-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/issues/${{ steps.optimization_issue.outputs.issue_number }}" \
--output-file data/output/monthly_optimization/fanout/crypto_snapshot_pipelines.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Fan out CryptoStrategies task issue
run: |
python3 scripts/fanout_monthly_optimization_tasks.py \
--plan-file data/output/monthly_optimization/optimization_plan.json \
--owner-repo CryptoStrategies \
--repo "QuantStrategyLab/CryptoStrategies" \
--planner-issue-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/issues/${{ steps.optimization_issue.outputs.issue_number }}" \
--output-file data/output/monthly_optimization/fanout/crypto_strategies.json \
--allow-permission-skip
env:
GITHUB_TOKEN: ${{ steps.cross_repo_token.outputs.token }}
- name: Fan out BinancePlatform task issue
run: |
python3 scripts/fanout_monthly_optimization_tasks.py \
--plan-file data/output/monthly_optimization/optimization_plan.json \
--owner-repo BinancePlatform \
--repo "${{ inputs.downstream_repo }}" \
--planner-issue-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/issues/${{ steps.optimization_issue.outputs.issue_number }}" \
--output-file data/output/monthly_optimization/fanout/binance_platform.json \
--allow-permission-skip
env:
GITHUB_TOKEN: ${{ steps.cross_repo_token.outputs.token }}
- name: Append fanout summary
run: |
python3 - <<'PY' >> "$GITHUB_STEP_SUMMARY"
import json
from pathlib import Path
result_dir = Path("data/output/monthly_optimization/fanout")
print("\n## Repo Task Fanout")
for path in sorted(result_dir.glob("*.json")):
data = json.loads(path.read_text(encoding="utf-8"))
line = f"- **{data['owner_repo']}** `{data['status']}`"
if data.get("issue_url"):
line += f": {data['issue_url']}"
elif data.get("reason"):
line += f": {data['reason']}"
print(line)
PY
- name: Resolve upstream experiment validation target
id: upstream_experiment_target
run: |
python3 - <<'PY'
import json
import os
from pathlib import Path
fanout = json.loads(
Path("data/output/monthly_optimization/fanout/crypto_snapshot_pipelines.json").read_text(encoding="utf-8")
)
plan = json.loads(
Path("data/output/monthly_optimization/optimization_plan.json").read_text(encoding="utf-8")
)
actions = plan.get("repo_action_summary", {}).get("CryptoSnapshotPipelines", {}).get("actions", [])
should_dispatch = bool(fanout.get("issue_number")) and fanout.get("status") in {"created", "updated"} and any(
action.get("experiment_only") for action in actions
)
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
print(f"should_dispatch={'true' if should_dispatch else 'false'}", file=output)
print(f"issue_number={fanout.get('issue_number') or ''}", file=output)
PY
- name: Dispatch CryptoSnapshotPipelines experiment validation
if: steps.upstream_experiment_target.outputs.should_dispatch == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh workflow run experiment_validation.yml \
-f issue_number="${{ steps.upstream_experiment_target.outputs.issue_number }}"
- name: Resolve downstream experiment validation target
id: downstream_experiment_target
run: |
python3 - <<'PY'
import json
import os
from pathlib import Path
fanout = json.loads(
Path("data/output/monthly_optimization/fanout/binance_platform.json").read_text(encoding="utf-8")
)
plan = json.loads(
Path("data/output/monthly_optimization/optimization_plan.json").read_text(encoding="utf-8")
)
actions = plan.get("repo_action_summary", {}).get("BinancePlatform", {}).get("actions", [])
should_dispatch = bool(fanout.get("issue_number")) and fanout.get("status") in {"created", "updated"} and any(
action.get("experiment_only") for action in actions
)
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
print(f"should_dispatch={'true' if should_dispatch else 'false'}", file=output)
print(f"issue_number={fanout.get('issue_number') or ''}", file=output)
PY
- name: Best-effort label BinancePlatform issue for experiment validation
if: steps.downstream_experiment_target.outputs.should_dispatch == 'true'
env:
GH_TOKEN: ${{ steps.cross_repo_token.outputs.token }}
TARGET_REPO: ${{ inputs.downstream_repo }}
ISSUE_NUMBER: ${{ steps.downstream_experiment_target.outputs.issue_number }}
run: |
set +e
gh label create experiment-validation --repo "$TARGET_REPO" --color 1D76DB --description "Trigger experiment validation for monthly optimization tasks" --force
label_status=$?
gh issue edit "$ISSUE_NUMBER" --repo "$TARGET_REPO" --add-label experiment-validation
issue_status=$?
set -e
if [ "$label_status" -ne 0 ] || [ "$issue_status" -ne 0 ]; then
echo "Downstream experiment-validation label update skipped for $TARGET_REPO#$ISSUE_NUMBER." >> "$GITHUB_STEP_SUMMARY"
fi
- name: Dispatch BinancePlatform experiment validation
if: steps.downstream_experiment_target.outputs.should_dispatch == 'true'
env:
GH_TOKEN: ${{ steps.cross_repo_token.outputs.token }}
run: |
set +e
gh workflow run experiment_validation.yml \
-R "${{ inputs.downstream_repo }}" \
-f issue_number="${{ steps.downstream_experiment_target.outputs.issue_number }}"
status=$?
set -e
if [ "$status" -ne 0 ]; then
echo "Downstream experiment validation dispatch skipped: ${{ steps.cross_repo_token.outputs.source }} token likely needs Actions write on ${{ inputs.downstream_repo }}." >> "$GITHUB_STEP_SUMMARY"
fi
- name: Upload planner artifact
uses: actions/upload-artifact@v7
with:
name: monthly-optimization-plan-${{ inputs.upstream_run_id }}-${{ inputs.downstream_run_id }}
path: data/output/monthly_optimization/