-
Notifications
You must be signed in to change notification settings - Fork 3
143 lines (133 loc) · 5.94 KB
/
Copy pathsmoke.yml
File metadata and controls
143 lines (133 loc) · 5.94 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
name: Live-API smoke
# Runs the smoke test against real public APIs (DexScreener, GoPlus, OpenOcean,
# Across, Hyperliquid, Polymarket, Morpho, Pendle, Drift, etc.) on a schedule
# and on-demand. Unit tests mock these APIs; this catches drift between our
# wiring and what the upstream services actually return.
#
# This intentionally runs separately from the standard CI workflow so a
# transient upstream outage doesn't block PRs.
#
# Alerting model: ONE rolling issue (label: smoke-failure). A failing run
# creates it if absent, otherwise appends a comment. A green run closes it
# with a recovery comment. This keeps the signal at exactly one open issue
# instead of one new issue per day (issues #49–#68 taught us that an alert
# nobody can keep up with is the same as no alert).
on:
schedule:
# Daily at 09:00 UTC. Picks up endpoint shape changes within a day.
- cron: '0 9 * * *'
workflow_dispatch:
inputs:
ref:
description: 'Git ref to test (default: main)'
required: false
default: 'main'
jobs:
smoke:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.ref || 'main' }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: mcp-server/package-lock.json
- name: Install deps
run: cd mcp-server && npm ci
- name: Compile TypeScript
run: cd mcp-server && node node_modules/typescript/bin/tsc
- name: Run live-API smoke
id: smoke
env:
# CHAINGPT_API_KEY is required for the server to boot, but the
# read-only smoke cases never hit the ChainGPT plugin API itself.
CHAINGPT_API_KEY: ${{ secrets.CHAINGPT_API_KEY || 'smoke-test' }}
MORALIS_API_KEY: ${{ secrets.MORALIS_API_KEY }}
ONEINCH_API_KEY: ${{ secrets.ONEINCH_API_KEY }}
ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }}
run: |
cd mcp-server
set +e
node dist/smoke-test.js 2>&1 | tee smoke-output.txt
code=${PIPESTATUS[0]}
# Strip ANSI colors and keep the failure tail for the issue body
tail -c 4000 smoke-output.txt | sed 's/\x1b\[[0-9;]*m//g' > smoke-tail.txt
exit $code
- name: Update rolling issue (failure → create/comment, success → close)
if: ${{ always() && github.event_name == 'schedule' }}
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const failed = '${{ steps.smoke.outcome }}' === 'failure';
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const today = new Date().toISOString().slice(0, 10);
let tail = '';
try { tail = fs.readFileSync('mcp-server/smoke-tail.txt', 'utf8'); } catch {}
const { data: open } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'smoke-failure',
per_page: 50,
});
const rolling = open.find((i) => i.title.startsWith('[smoke] Live-API smoke failing'));
if (failed) {
const update = [
`**${today} — still failing.** [Run log](${runUrl})`,
'',
'```',
tail.slice(-3000),
'```',
].join('\n');
if (rolling) {
await github.rest.issues.createComment({
owner: context.repo.owner, repo: context.repo.repo,
issue_number: rolling.number, body: update,
});
core.info(`Commented on rolling issue #${rolling.number}.`);
} else {
await github.rest.issues.create({
owner: context.repo.owner, repo: context.repo.repo,
title: '[smoke] Live-API smoke failing',
body: [
'The scheduled live-API smoke is failing. This issue stays open (with one',
'comment per failing day) until the first green run auto-closes it.',
'',
'Likely causes: an upstream API changed shape, a rate limit, or a moved endpoint.',
'',
update,
].join('\n'),
labels: ['smoke-failure', 'live-api'],
});
core.info('Opened new rolling smoke-failure issue.');
}
} else if ('${{ steps.smoke.outcome }}' === 'success' && rolling) {
await github.rest.issues.createComment({
owner: context.repo.owner, repo: context.repo.repo,
issue_number: rolling.number,
body: `**${today} — recovered.** Smoke is green again: [run log](${runUrl}). Auto-closing.`,
});
await github.rest.issues.update({
owner: context.repo.owner, repo: context.repo.repo,
issue_number: rolling.number, state: 'closed',
});
core.info(`Closed rolling issue #${rolling.number} after green run.`);
} else if (rolling) {
// cancelled / skipped — inconclusive. Keep the issue open but
// don't let the timeline silently skip a day.
await github.rest.issues.createComment({
owner: context.repo.owner, repo: context.repo.repo,
issue_number: rolling.number,
body: `**${today} — inconclusive** (run outcome: ${{ toJSON(steps.smoke.outcome) }}). [Run log](${runUrl}). Issue stays open.`,
});
} else {
core.info('No open rolling issue — nothing to do.');
}