mirror of
https://github.com/strands-agents/harness-sdk.git
synced 2026-10-02 02:44:48 +08:00
feat: auto-setup SDKs and data store before dev/build/test (#614)
Co-authored-by: Mackenzie Zastrow <zastrowm@users.noreply.github.com>
This commit is contained in:
co-authored by
Mackenzie Zastrow
parent
495050c41b
commit
9e7ff59f3b
@@ -35,11 +35,5 @@ jobs:
|
||||
- name: Typecheck snippets
|
||||
run: npm run typecheck:snippets
|
||||
|
||||
# Astro 5's content layer only generates data-store.json when the dev server runs.
|
||||
# Without it, vitest tests using getCollection() fail with "collection does not exist".
|
||||
# See: https://github.com/withastro/astro/issues/12836
|
||||
- name: Prepare tests
|
||||
run: npm run test:prep
|
||||
|
||||
- name: Test
|
||||
run: npm test
|
||||
|
||||
@@ -3,6 +3,7 @@ import { defineConfig } from 'astro/config'
|
||||
import starlight from '@astrojs/starlight'
|
||||
import path from 'node:path'
|
||||
import remarkMkdocsSnippets from './src/plugins/remark-mkdocs-snippets.ts'
|
||||
import sdkSetupPlugin from './src/plugins/vite-plugin-sdk-setup.ts'
|
||||
|
||||
import { loadSidebarFromMkdocs } from "./src/sidebar.ts"
|
||||
import AutoImport from './src/plugins/astro-auto-import.ts'
|
||||
@@ -22,6 +23,7 @@ export default defineConfig({
|
||||
site: 'https://strandsagents.com',
|
||||
base: process.env.ASTRO_BASE_PATH || '/',
|
||||
vite: {
|
||||
plugins: [sdkSetupPlugin()],
|
||||
// TODO once we separate out CMS build from TS verification, fix this
|
||||
// https://github.com/withastro/astro/issues/14117
|
||||
ssr: {
|
||||
|
||||
+1
-2
@@ -7,12 +7,11 @@
|
||||
"build:all": "npm run sdk:clone && npm run sdk:generate && npm run build",
|
||||
"dev": "astro dev",
|
||||
"test": "vitest run",
|
||||
"test:prep": "timeout 10s npm run dev || true",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"typecheck:snippets": "npm run typecheck --prefix test-snippets",
|
||||
"format": "prettier --write docs",
|
||||
"format:check": "prettier --check docs",
|
||||
"clean": "rm -rf .build",
|
||||
"clean": "rm -rf .build && rm -rf .astro",
|
||||
"preview": "astro preview",
|
||||
"cms:build": "npm run build:all",
|
||||
"docs:update": "tsx scripts/update-docs.ts",
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Vite plugin that automatically runs `npm run sdk:clone` and `npm run sdk:generate`
|
||||
* if the SDK build artifacts are not present, simplifying the getting-started experience.
|
||||
*/
|
||||
import { execSync } from 'node:child_process'
|
||||
import { existsSync } from 'node:fs'
|
||||
import type { Plugin } from 'vite'
|
||||
|
||||
const SDK_PATHS = ['.build/sdk-typescript', '.build/sdk-python']
|
||||
|
||||
function areSdksPresent(): boolean {
|
||||
return SDK_PATHS.every((p) => existsSync(p))
|
||||
}
|
||||
|
||||
function run(command: string): void {
|
||||
console.log(`[sdk-setup] Running: ${command}`)
|
||||
execSync(command, { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
function setupSdks(): void {
|
||||
if (areSdksPresent()) return
|
||||
|
||||
console.log('[sdk-setup] SDK build artifacts not found — running sdk:clone and sdk:generate...')
|
||||
run('npm run sdk:clone')
|
||||
run('npm run sdk:generate')
|
||||
console.log('[sdk-setup] SDK setup complete.')
|
||||
}
|
||||
|
||||
export default function sdkSetupPlugin(): Plugin {
|
||||
return {
|
||||
name: 'vite-plugin-sdk-setup',
|
||||
enforce: 'pre',
|
||||
// Used during `astro build`
|
||||
buildStart() {
|
||||
setupSdks()
|
||||
},
|
||||
// Used during `astro dev` — buildStart fires before the file watcher is running,
|
||||
// so newly generated files would be missed by Astro's content layer. configureServer
|
||||
// runs after the watcher is set up, and we emit a change event to trigger a re-sync.
|
||||
configureServer(server) {
|
||||
setupSdks()
|
||||
server.watcher.emit('change', '.build/api-docs')
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import { spawn } from 'node:child_process'
|
||||
|
||||
const DATA_STORE_PATH = '.astro/data-store.json'
|
||||
const TIMEOUT_MS = 60_000
|
||||
const SYNCED_MARKER = 'Synced content'
|
||||
|
||||
function isDataStorePopulated(): boolean {
|
||||
if (!existsSync(DATA_STORE_PATH)) return false
|
||||
try {
|
||||
return readFileSync(DATA_STORE_PATH, 'utf-8').trim().length > 100
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export async function setup() {
|
||||
if (isDataStorePopulated()) return
|
||||
|
||||
console.log('[global-setup] Data store not populated — starting astro dev temporarily...')
|
||||
|
||||
const server = spawn('npx', ['astro', 'dev'], {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
detached: true,
|
||||
})
|
||||
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const timer = setTimeout(() => reject(new Error('Timed out waiting for "Synced content"')), TIMEOUT_MS)
|
||||
|
||||
const onData = (chunk: Buffer) => {
|
||||
process.stdout.write(chunk)
|
||||
if (chunk.toString().includes(SYNCED_MARKER)) {
|
||||
clearTimeout(timer)
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
|
||||
server.stdout.on('data', onData)
|
||||
server.stderr.on('data', onData)
|
||||
server.on('error', (err) => {
|
||||
clearTimeout(timer)
|
||||
reject(err)
|
||||
})
|
||||
server.on('close', (code) => {
|
||||
if (code !== null) {
|
||||
clearTimeout(timer)
|
||||
reject(new Error(`Astro dev server exited with code ${code}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
} finally {
|
||||
if (server.pid != null) {
|
||||
process.kill(-server.pid, 'SIGTERM')
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[global-setup] Data store ready.')
|
||||
}
|
||||
@@ -3,5 +3,6 @@ import { getViteConfig } from 'astro/config'
|
||||
export default getViteConfig({
|
||||
test: {
|
||||
include: ['test/**/*.test.ts'],
|
||||
globalSetup: ['test/global-setup.ts'],
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user