Skip to content

Commit a53b0b5

Browse files
committed
feat: add GitHub Action for one-line CI setup
1 parent b8d073a commit a53b0b5

4 files changed

Lines changed: 308 additions & 1 deletion

File tree

.github/workflows/publish-release.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ jobs:
4949
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
5050
"
5151
52+
- name: Strip video URLs from README for npm
53+
if: steps.check.outputs.published == 'false'
54+
run: sed -i '/^https:\/\/github.com\/user-attachments\//d' README.md
55+
5256
- name: Build and publish
5357
if: steps.check.outputs.published == 'false'
5458
run: pnpm build && npm publish --access public

action.yml

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
name: "aimock"
2+
description: "Start an aimock server for AI application testing — LLM APIs, MCP, A2A, AG-UI, vector DBs"
3+
branding:
4+
icon: "server"
5+
color: "green"
6+
7+
inputs:
8+
fixtures:
9+
description: "Path to fixture files or directory"
10+
required: false
11+
default: "./fixtures"
12+
config:
13+
description: "Path to aimock JSON config file (overrides fixtures)"
14+
required: false
15+
port:
16+
description: "Port to listen on"
17+
required: false
18+
default: "4010"
19+
host:
20+
description: "Host to bind to"
21+
required: false
22+
default: "127.0.0.1"
23+
version:
24+
description: "aimock version to install (default: latest)"
25+
required: false
26+
default: "latest"
27+
args:
28+
description: "Additional CLI arguments (e.g., --strict --record --provider-openai https://api.openai.com)"
29+
required: false
30+
default: ""
31+
wait-timeout:
32+
description: "Max seconds to wait for health check (default: 30)"
33+
required: false
34+
default: "30"
35+
36+
outputs:
37+
url:
38+
description: "The aimock server URL (e.g., http://127.0.0.1:4010)"
39+
value: ${{ steps.start.outputs.url }}
40+
41+
runs:
42+
using: "composite"
43+
steps:
44+
- name: Install aimock
45+
shell: bash
46+
run: npm install -g @copilotkit/aimock@${{ inputs.version }}
47+
48+
- name: Start aimock
49+
id: start
50+
shell: bash
51+
run: |
52+
URL="http://${{ inputs.host }}:${{ inputs.port }}"
53+
echo "url=${URL}" >> $GITHUB_OUTPUT
54+
55+
if [ -n "${{ inputs.config }}" ]; then
56+
aimock --config "${{ inputs.config }}" \
57+
--port ${{ inputs.port }} \
58+
--host ${{ inputs.host }} \
59+
${{ inputs.args }} &
60+
else
61+
llmock --fixtures "${{ inputs.fixtures }}" \
62+
--port ${{ inputs.port }} \
63+
--host ${{ inputs.host }} \
64+
${{ inputs.args }} &
65+
fi
66+
67+
echo $! > /tmp/aimock.pid
68+
echo "Started aimock (PID: $(cat /tmp/aimock.pid))"
69+
70+
- name: Wait for health check
71+
shell: bash
72+
run: |
73+
URL="http://${{ inputs.host }}:${{ inputs.port }}/health"
74+
TIMEOUT=${{ inputs.wait-timeout }}
75+
ELAPSED=0
76+
77+
echo "Waiting for ${URL} ..."
78+
while [ $ELAPSED -lt $TIMEOUT ]; do
79+
if curl -sf "$URL" > /dev/null 2>&1; then
80+
echo "aimock is ready at http://${{ inputs.host }}:${{ inputs.port }}"
81+
exit 0
82+
fi
83+
sleep 1
84+
ELAPSED=$((ELAPSED + 1))
85+
done
86+
87+
echo "::error::aimock failed to start within ${TIMEOUT}s"
88+
if [ -f /tmp/aimock.pid ]; then
89+
kill "$(cat /tmp/aimock.pid)" 2>/dev/null || true
90+
fi
91+
exit 1

docs/github-action/index.html

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>GitHub Action — aimock</title>
7+
<link rel="icon" type="image/svg+xml" href="../favicon.svg" />
8+
<link rel="preconnect" href="https://fonts.googleapis.com" />
9+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10+
<link
11+
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Instrument+Sans:wght@400;500;600;700&display=swap"
12+
rel="stylesheet"
13+
/>
14+
<link rel="stylesheet" href="../style.css" />
15+
</head>
16+
<body>
17+
<nav class="top-nav">
18+
<div class="nav-inner">
19+
<div style="display: flex; align-items: center; gap: 1rem">
20+
<button
21+
class="sidebar-toggle"
22+
onclick="document.querySelector('.sidebar').classList.toggle('open')"
23+
aria-label="Toggle sidebar"
24+
>
25+
&#9776;
26+
</button>
27+
<a href="/" class="nav-brand"> <span class="prompt">$</span> aimock </a>
28+
</div>
29+
<ul class="nav-links">
30+
<li><a href="/">Home</a></li>
31+
<li><a href="/docs" style="color: var(--accent)">Docs</a></li>
32+
<li>
33+
<a href="https://github.com/CopilotKit/aimock" class="gh-link" target="_blank"
34+
><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
35+
<path
36+
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
37+
/>
38+
</svg>
39+
GitHub</a
40+
>
41+
</li>
42+
</ul>
43+
</div>
44+
</nav>
45+
46+
<div class="docs-layout">
47+
<aside class="sidebar" id="sidebar"></aside>
48+
49+
<main class="docs-content">
50+
<h1>GitHub Action</h1>
51+
<p class="lead">
52+
One-line CI setup. Start an aimock server in GitHub Actions with a single
53+
<code>uses:</code> step.
54+
</p>
55+
56+
<h2>Quick Start</h2>
57+
<div class="code-block">
58+
<div class="code-block-header">workflow.yml <span class="lang-tag">yaml</span></div>
59+
<pre><code>- <span class="prop">uses</span>: <span class="str">CopilotKit/aimock@v1</span>
60+
<span class="prop">with</span>:
61+
<span class="prop">fixtures</span>: <span class="str">./test/fixtures</span>
62+
63+
- <span class="prop">run</span>: <span class="str">pnpm test</span>
64+
<span class="prop">env</span>:
65+
<span class="prop">OPENAI_BASE_URL</span>: <span class="str">http://127.0.0.1:4010/v1</span></code></pre>
66+
</div>
67+
68+
<h2>Inputs</h2>
69+
<table class="endpoint-table">
70+
<thead>
71+
<tr>
72+
<th>Input</th>
73+
<th>Default</th>
74+
<th>Description</th>
75+
</tr>
76+
</thead>
77+
<tbody>
78+
<tr>
79+
<td><code>fixtures</code></td>
80+
<td><code>./fixtures</code></td>
81+
<td>Path to fixture files or directory</td>
82+
</tr>
83+
<tr>
84+
<td><code>config</code></td>
85+
<td>&mdash;</td>
86+
<td>Path to aimock JSON config file (overrides fixtures)</td>
87+
</tr>
88+
<tr>
89+
<td><code>port</code></td>
90+
<td><code>4010</code></td>
91+
<td>Port to listen on</td>
92+
</tr>
93+
<tr>
94+
<td><code>host</code></td>
95+
<td><code>127.0.0.1</code></td>
96+
<td>Host to bind to</td>
97+
</tr>
98+
<tr>
99+
<td><code>version</code></td>
100+
<td><code>latest</code></td>
101+
<td>aimock version to install</td>
102+
</tr>
103+
<tr>
104+
<td><code>args</code></td>
105+
<td>&mdash;</td>
106+
<td>Additional CLI arguments</td>
107+
</tr>
108+
<tr>
109+
<td><code>wait-timeout</code></td>
110+
<td><code>30</code></td>
111+
<td>Max seconds to wait for health check</td>
112+
</tr>
113+
</tbody>
114+
</table>
115+
116+
<h2>Outputs</h2>
117+
<table class="endpoint-table">
118+
<thead>
119+
<tr>
120+
<th>Output</th>
121+
<th>Description</th>
122+
</tr>
123+
</thead>
124+
<tbody>
125+
<tr>
126+
<td><code>url</code></td>
127+
<td>The aimock server URL (e.g., <code>http://127.0.0.1:4010</code>)</td>
128+
</tr>
129+
</tbody>
130+
</table>
131+
132+
<h2>Examples</h2>
133+
134+
<h3>Basic with fixtures</h3>
135+
<div class="code-block">
136+
<div class="code-block-header">workflow.yml <span class="lang-tag">yaml</span></div>
137+
<pre><code><span class="prop">steps</span>:
138+
- <span class="prop">uses</span>: <span class="str">actions/checkout@v4</span>
139+
- <span class="prop">uses</span>: <span class="str">CopilotKit/aimock@v1</span>
140+
<span class="prop">with</span>:
141+
<span class="prop">fixtures</span>: <span class="str">./fixtures</span>
142+
- <span class="prop">run</span>: <span class="str">npm test</span>
143+
<span class="prop">env</span>:
144+
<span class="prop">OPENAI_BASE_URL</span>: <span class="str">http://127.0.0.1:4010/v1</span></code></pre>
145+
</div>
146+
147+
<h3>Full suite with config</h3>
148+
<div class="code-block">
149+
<div class="code-block-header">workflow.yml <span class="lang-tag">yaml</span></div>
150+
<pre><code><span class="prop">steps</span>:
151+
- <span class="prop">uses</span>: <span class="str">actions/checkout@v4</span>
152+
- <span class="prop">uses</span>: <span class="str">CopilotKit/aimock@v1</span>
153+
<span class="prop">with</span>:
154+
<span class="prop">config</span>: <span class="str">./aimock.json</span>
155+
<span class="prop">args</span>: <span class="str">--strict</span>
156+
- <span class="prop">run</span>: <span class="str">npm test</span></code></pre>
157+
</div>
158+
159+
<h3>Record mode (proxy to real APIs)</h3>
160+
<div class="code-block">
161+
<div class="code-block-header">workflow.yml <span class="lang-tag">yaml</span></div>
162+
<pre><code><span class="prop">steps</span>:
163+
- <span class="prop">uses</span>: <span class="str">actions/checkout@v4</span>
164+
- <span class="prop">uses</span>: <span class="str">CopilotKit/aimock@v1</span>
165+
<span class="prop">with</span>:
166+
<span class="prop">fixtures</span>: <span class="str">./fixtures</span>
167+
<span class="prop">args</span>: <span class="str">--record --provider-openai https://api.openai.com</span>
168+
<span class="prop">env</span>:
169+
<span class="prop">OPENAI_API_KEY</span>: <span class="str">${{ secrets.OPENAI_API_KEY }}</span>
170+
- <span class="prop">run</span>: <span class="str">npm test</span></code></pre>
171+
</div>
172+
173+
<h3>Using the URL output</h3>
174+
<div class="code-block">
175+
<div class="code-block-header">workflow.yml <span class="lang-tag">yaml</span></div>
176+
<pre><code><span class="prop">steps</span>:
177+
- <span class="prop">uses</span>: <span class="str">CopilotKit/aimock@v1</span>
178+
<span class="prop">id</span>: <span class="str">mock</span>
179+
<span class="prop">with</span>:
180+
<span class="prop">fixtures</span>: <span class="str">./fixtures</span>
181+
- <span class="prop">run</span>: <span class="str">echo "Mock server at ${{ steps.mock.outputs.url }}"</span></code></pre>
182+
</div>
183+
184+
<h2>How It Works</h2>
185+
<ol>
186+
<li>Installs <code>@copilotkit/aimock</code> via npm</li>
187+
<li>Starts the server in the background</li>
188+
<li>
189+
Polls <code>/health</code> until the server is ready (up to
190+
<code>wait-timeout</code> seconds)
191+
</li>
192+
<li>Exports the URL as a step output</li>
193+
<li>The server runs for the duration of the job and is cleaned up automatically</li>
194+
</ol>
195+
</main>
196+
<aside class="page-toc" id="page-toc"></aside>
197+
</div>
198+
<footer class="docs-footer">
199+
<div class="footer-inner">
200+
<div class="footer-left"><span>$</span> aimock &middot; MIT License</div>
201+
<ul class="footer-links">
202+
<li><a href="https://github.com/CopilotKit/aimock" target="_blank">GitHub</a></li>
203+
<li>
204+
<a href="https://www.npmjs.com/package/@copilotkit/aimock" target="_blank">npm</a>
205+
</li>
206+
</ul>
207+
</div>
208+
</footer>
209+
<script src="../sidebar.js"></script>
210+
<script src="../cli-tabs.js"></script>
211+
</body>
212+
</html>

docs/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ body::before {
154154
top: 57px; /* nav height */
155155
left: 0;
156156
width: var(--sidebar-width);
157-
height: calc(100vh - 57px - 50px);
157+
height: calc(100vh - 57px);
158158
overflow-y: auto;
159159
background: var(--bg-surface);
160160
border-right: 1px solid var(--border);

0 commit comments

Comments
 (0)