> deepgram-ci-integration
Configure Deepgram CI/CD integration for automated testing and deployment. Use when setting up continuous integration pipelines, automated testing, or deployment workflows for Deepgram integrations. Trigger: "deepgram CI", "deepgram CD", "deepgram pipeline", "deepgram github actions", "deepgram automated testing".
curl "https://skillshub.wtf/jeremylongshore/claude-code-plugins-plus-skills/deepgram-ci-integration?format=md"Deepgram CI Integration
Overview
Set up CI/CD pipelines for Deepgram integrations with GitHub Actions. Includes unit tests with mocked SDK, integration tests against the real API, smoke tests, automated key rotation, and deployment gates.
Prerequisites
- GitHub repository with Actions enabled
DEEPGRAM_API_KEYstored as repository secret@deepgram/sdkandvitestinstalled- Test fixtures committed (or downloaded in CI)
Instructions
Step 1: GitHub Actions Workflow
# .github/workflows/deepgram-ci.yml
name: Deepgram CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm test -- --reporter=verbose
# Unit tests use mocked SDK — no API key needed
integration-tests:
runs-on: ubuntu-latest
needs: unit-tests
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
- run: npm ci
- run: npm run test:integration
env:
DEEPGRAM_API_KEY: ${{ secrets.DEEPGRAM_API_KEY }}
timeout-minutes: 5
smoke-test:
runs-on: ubuntu-latest
needs: integration-tests
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
- run: npm ci && npm run build
- name: Smoke test
run: npx tsx scripts/smoke-test.ts
env:
DEEPGRAM_API_KEY: ${{ secrets.DEEPGRAM_API_KEY }}
timeout-minutes: 2
Step 2: Integration Test Suite
// tests/integration/deepgram.test.ts
import { describe, it, expect, beforeAll } from 'vitest';
import { createClient, DeepgramClient } from '@deepgram/sdk';
const SAMPLE_URL = 'https://static.deepgram.com/examples/Bueller-Life-moves-702702706.wav';
describe('Deepgram Integration', () => {
let client: DeepgramClient;
beforeAll(() => {
const key = process.env.DEEPGRAM_API_KEY;
if (!key) throw new Error('DEEPGRAM_API_KEY required for integration tests');
client = createClient(key);
});
it('authenticates successfully', async () => {
const { result, error } = await client.manage.getProjects();
expect(error).toBeNull();
expect(result.projects.length).toBeGreaterThan(0);
});
it('transcribes pre-recorded audio with Nova-3', async () => {
const { result, error } = await client.listen.prerecorded.transcribeUrl(
{ url: SAMPLE_URL },
{ model: 'nova-3', smart_format: true }
);
expect(error).toBeNull();
const alt = result.results.channels[0].alternatives[0];
expect(alt.transcript).toContain('Life');
expect(alt.confidence).toBeGreaterThan(0.85);
}, 30000);
it('returns word-level timing', async () => {
const { result } = await client.listen.prerecorded.transcribeUrl(
{ url: SAMPLE_URL },
{ model: 'nova-3' }
);
const words = result.results.channels[0].alternatives[0].words;
expect(words).toBeDefined();
expect(words!.length).toBeGreaterThan(0);
expect(words![0]).toHaveProperty('start');
expect(words![0]).toHaveProperty('end');
expect(words![0]).toHaveProperty('confidence');
}, 30000);
it('speaker diarization identifies speakers', async () => {
const { result } = await client.listen.prerecorded.transcribeUrl(
{ url: SAMPLE_URL },
{ model: 'nova-3', diarize: true }
);
const words = result.results.channels[0].alternatives[0].words;
expect(words?.some((w: any) => w.speaker !== undefined)).toBe(true);
}, 30000);
it('TTS generates audio stream', async () => {
const response = await client.speak.request(
{ text: 'CI test.' },
{ model: 'aura-2-thalia-en', encoding: 'linear16', container: 'wav' }
);
const stream = await response.getStream();
expect(stream).toBeTruthy();
}, 15000);
});
Step 3: Smoke Test Script
// scripts/smoke-test.ts
import { createClient } from '@deepgram/sdk';
const SAMPLE_URL = 'https://static.deepgram.com/examples/Bueller-Life-moves-702702706.wav';
async function smokeTest() {
console.log('Deepgram Smoke Test');
console.log('='.repeat(40));
const client = createClient(process.env.DEEPGRAM_API_KEY!);
let passed = 0;
let failed = 0;
// Test 1: Authentication
try {
const { error } = await client.manage.getProjects();
if (error) throw error;
console.log('[PASS] Authentication');
passed++;
} catch (err: any) {
console.error(`[FAIL] Authentication: ${err.message}`);
failed++;
}
// Test 2: Pre-recorded transcription
try {
const { result, error } = await client.listen.prerecorded.transcribeUrl(
{ url: SAMPLE_URL },
{ model: 'nova-3', smart_format: true }
);
if (error) throw error;
if (!result.results.channels[0].alternatives[0].transcript) {
throw new Error('Empty transcript');
}
console.log('[PASS] Pre-recorded transcription');
passed++;
} catch (err: any) {
console.error(`[FAIL] Pre-recorded transcription: ${err.message}`);
failed++;
}
// Test 3: TTS
try {
const response = await client.speak.request(
{ text: 'Smoke test.' },
{ model: 'aura-2-thalia-en' }
);
const stream = await response.getStream();
if (!stream) throw new Error('No audio stream');
console.log('[PASS] Text-to-speech');
passed++;
} catch (err: any) {
console.error(`[FAIL] Text-to-speech: ${err.message}`);
failed++;
}
console.log(`\nResults: ${passed} passed, ${failed} failed`);
process.exit(failed > 0 ? 1 : 0);
}
smokeTest();
Step 4: Package.json Scripts
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest --watch",
"test:integration": "vitest run tests/integration/",
"test:smoke": "tsx scripts/smoke-test.ts",
"lint": "eslint src/ tests/",
"typecheck": "tsc --noEmit"
}
}
Step 5: Vitest Configuration
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'node',
include: ['tests/**/*.test.ts'],
exclude: ['tests/integration/**'], // Integration tests run separately
coverage: {
include: ['src/**'],
reporter: ['text', 'lcov'],
},
},
});
Step 6: Automated Key Rotation (Scheduled)
# .github/workflows/rotate-deepgram-key.yml
name: Rotate Deepgram API Key
on:
schedule:
- cron: '0 0 1 */3 *' # Quarterly (1st of every 3rd month)
workflow_dispatch:
jobs:
rotate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- name: Rotate key
run: |
NEW_KEY=$(npx tsx scripts/rotate-key.ts)
gh secret set DEEPGRAM_API_KEY --body "$NEW_KEY"
echo "Key rotated successfully"
env:
DEEPGRAM_ADMIN_KEY: ${{ secrets.DEEPGRAM_ADMIN_KEY }}
DEEPGRAM_PROJECT_ID: ${{ secrets.DEEPGRAM_PROJECT_ID }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Output
- GitHub Actions workflow (unit -> integration -> smoke)
- Integration test suite covering STT, diarization, TTS
- Smoke test script with pass/fail exit codes
- Vitest configuration with integration test separation
- Quarterly key rotation workflow
Error Handling
| Issue | Cause | Resolution |
|---|---|---|
| Integration tests 401 | Secret not set or expired | Rotate DEEPGRAM_API_KEY secret |
| Smoke test timeout | API latency | Increase timeout-minutes |
| Tests pass locally, fail in CI | Missing env var | Check secrets are set in repo settings |
| Fork PRs can't access secrets | GitHub security | Skip integration tests on fork PRs |
Resources
> related_skills --same-repo
> fathom-cost-tuning
Optimize Fathom API usage and plan selection. Trigger with phrases like "fathom cost", "fathom pricing", "fathom plan".
> fathom-core-workflow-b
Sync Fathom meeting data to CRM and build automated follow-up workflows. Use when integrating Fathom with Salesforce, HubSpot, or custom CRMs, or creating automated post-meeting email summaries. Trigger with phrases like "fathom crm sync", "fathom salesforce", "fathom follow-up", "fathom post-meeting workflow".
> fathom-core-workflow-a
Build a meeting analytics pipeline with Fathom transcripts and summaries. Use when extracting insights from meetings, building CRM sync, or creating automated meeting follow-up workflows. Trigger with phrases like "fathom analytics", "fathom meeting pipeline", "fathom transcript analysis", "fathom action items sync".
> fathom-common-errors
Diagnose and fix Fathom API errors including auth failures and missing data. Use when API calls fail, transcripts are empty, or webhooks are not firing. Trigger with phrases like "fathom error", "fathom not working", "fathom api failure", "fix fathom".