Claude-code-plugins-plus ideogram-ci-integration
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/ideogram-pack/skills/ideogram-ci-integration" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-ideogram-ci-integration && rm -rf "$T"
manifest:
plugins/saas-packs/ideogram-pack/skills/ideogram-ci-integration/SKILL.mdsource content
Ideogram CI Integration
Overview
Set up CI/CD pipelines for Ideogram integrations. Since Ideogram has no free tier for API testing, CI strategies focus on: mocked unit tests (free), optional integration tests gated behind secrets, and prompt validation without API calls.
Prerequisites
- GitHub repository with Actions enabled
- Ideogram API key for integration tests (optional)
- npm/pnpm project with vitest
Instructions
Step 1: GitHub Actions Workflow
# .github/workflows/ideogram-ci.yml name: Ideogram Integration CI on: push: branches: [main] pull_request: branches: [main] jobs: unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - run: npm ci - run: npm test -- --reporter=verbose - run: npm run lint # Optional: runs only when secret is configured integration-tests: runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' env: IDEOGRAM_API_KEY: ${{ secrets.IDEOGRAM_API_KEY }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - run: npm ci - name: Run integration tests if: env.IDEOGRAM_API_KEY != '' run: npm run test:integration timeout-minutes: 5
Step 2: Configure Secrets
set -euo pipefail # Store Ideogram API key in GitHub repository secrets gh secret set IDEOGRAM_API_KEY # Verify it was set gh secret list
Step 3: Unit Tests with Mocked API
// tests/ideogram-generate.test.ts import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; const mockGenerateResponse = { created: "2025-01-15T10:00:00Z", data: [{ url: "https://ideogram.ai/assets/image/mock-123.png", prompt: "test prompt", resolution: "1024x1024", is_image_safe: true, seed: 42, style_type: "DESIGN", }], }; describe("Ideogram Generate", () => { let fetchSpy: any; beforeEach(() => { fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValue( new Response(JSON.stringify(mockGenerateResponse), { status: 200, headers: { "Content-Type": "application/json" }, }) ); }); afterEach(() => fetchSpy.mockRestore()); it("sends correct headers", async () => { await fetch("https://api.ideogram.ai/generate", { method: "POST", headers: { "Api-Key": "test-key", "Content-Type": "application/json" }, body: JSON.stringify({ image_request: { prompt: "test" } }), }); expect(fetchSpy).toHaveBeenCalledWith( "https://api.ideogram.ai/generate", expect.objectContaining({ headers: expect.objectContaining({ "Api-Key": "test-key" }), }) ); }); it("parses response correctly", async () => { const response = await fetch("https://api.ideogram.ai/generate", { method: "POST", headers: { "Api-Key": "test-key", "Content-Type": "application/json" }, body: JSON.stringify({ image_request: { prompt: "test" } }), }); const result = await response.json(); expect(result.data[0].seed).toBe(42); expect(result.data[0].is_image_safe).toBe(true); }); it("handles 429 rate limit", async () => { fetchSpy.mockResolvedValueOnce(new Response("Rate limited", { status: 429 })); const response = await fetch("https://api.ideogram.ai/generate", { method: "POST", headers: { "Api-Key": "test-key", "Content-Type": "application/json" }, body: JSON.stringify({ image_request: { prompt: "test" } }), }); expect(response.status).toBe(429); }); });
Step 4: Prompt Validation in CI (No API Key Required)
// tests/prompt-validation.test.ts import { describe, it, expect } from "vitest"; const VALID_STYLES = ["AUTO", "GENERAL", "REALISTIC", "DESIGN", "RENDER_3D", "ANIME"]; const VALID_ASPECTS = [ "ASPECT_1_1", "ASPECT_16_9", "ASPECT_9_16", "ASPECT_3_2", "ASPECT_2_3", "ASPECT_4_3", "ASPECT_3_4", "ASPECT_10_16", "ASPECT_16_10", "ASPECT_1_3", "ASPECT_3_1", ]; function validateIdeogramRequest(req: any): string[] { const errors: string[] = []; if (!req.prompt || req.prompt.length === 0) errors.push("Prompt is required"); if (req.prompt?.length > 10000) errors.push("Prompt exceeds 10,000 char limit"); if (req.style_type && !VALID_STYLES.includes(req.style_type)) { errors.push(`Invalid style_type: ${req.style_type}`); } if (req.aspect_ratio && !VALID_ASPECTS.includes(req.aspect_ratio)) { errors.push(`Invalid aspect_ratio: ${req.aspect_ratio}`); } if (req.num_images && (req.num_images < 1 || req.num_images > 4)) { errors.push("num_images must be 1-4"); } return errors; } describe("Prompt Validation", () => { it("accepts valid request", () => { const errors = validateIdeogramRequest({ prompt: "A sunset over mountains", style_type: "REALISTIC", aspect_ratio: "ASPECT_16_9", }); expect(errors).toHaveLength(0); }); it("rejects empty prompt", () => { const errors = validateIdeogramRequest({ prompt: "" }); expect(errors).toContain("Prompt is required"); }); it("rejects invalid style", () => { const errors = validateIdeogramRequest({ prompt: "test", style_type: "INVALID" }); expect(errors[0]).toContain("Invalid style_type"); }); });
Step 5: Integration Test (API Key Required)
// tests/integration/ideogram-live.test.ts import { describe, it, expect } from "vitest"; describe.skipIf(!process.env.IDEOGRAM_API_KEY)("Ideogram Live API", () => { it("generates an image successfully", async () => { const response = await fetch("https://api.ideogram.ai/generate", { method: "POST", headers: { "Api-Key": process.env.IDEOGRAM_API_KEY!, "Content-Type": "application/json", }, body: JSON.stringify({ image_request: { prompt: "CI test: simple geometric shape", model: "V_2_TURBO", magic_prompt_option: "OFF", }, }), }); expect(response.status).toBe(200); const result = await response.json(); expect(result.data).toHaveLength(1); expect(result.data[0].url).toContain("http"); expect(result.data[0].is_image_safe).toBe(true); }, 30000); // 30s timeout for generation });
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Secret not found | Missing in GitHub settings | |
| Integration timeout | Generation takes 5-15s | Set |
| Flaky rate limits | Concurrent CI runs | Run integration tests on main only |
| Credits burned in CI | Too many integration tests | Mock in PRs, live tests on main only |
Output
- GitHub Actions workflow with unit + integration jobs
- Mocked unit tests that run without API key
- Prompt validation tests (zero API calls)
- Gated integration tests for main branch only
Resources
Next Steps
For deployment patterns, see
ideogram-deploy-integration.