Claude-code-plugins-plus linktree-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/linktree-pack/skills/linktree-ci-integration" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-linktree-ci-integration && rm -rf "$T"
manifest:
plugins/saas-packs/linktree-pack/skills/linktree-ci-integration/SKILL.mdsource content
Linktree CI Integration
Overview
Configure CI pipelines that validate Linktree link-in-bio API integrations using a two-tier testing approach. Unit tests mock the Linktree REST API to verify profile retrieval, link CRUD operations, and click analytics aggregation without needing an API key. Integration tests authenticate with a real Bearer token on main-branch merges to confirm link ordering, analytics endpoints, and rate limit handling against the live Linktree API. This ensures every PR gets instant feedback while production-critical flows are verified before deploy.
GitHub Actions Workflow
# .github/workflows/linktree-tests.yml name: Linktree API Tests on: [push, pull_request] jobs: unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: npm run lint && npm run typecheck - run: npm test -- --testPathPattern=unit # No Bearer token needed integration-tests: runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' needs: unit-tests steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: npm test -- --testPathPattern=integration env: LINKTREE_API_KEY: ${{ secrets.LINKTREE_API_KEY }}
Mock-Based Unit Tests
// tests/unit/link-service.test.ts import { describe, it, expect, vi } from 'vitest'; import { reorderLinks } from '../../src/services/link-service'; import * as linktreeApi from '../../src/lib/linktree-api'; vi.mock('../../src/lib/linktree-api'); describe('LinkService', () => { it('reorders links and returns updated positions', async () => { vi.mocked(linktreeApi.patch).mockResolvedValue({ links: [ { id: 'lnk-1', title: 'Portfolio', position: 0 }, { id: 'lnk-2', title: 'GitHub', position: 1 }, ], }); const result = await reorderLinks(['lnk-1', 'lnk-2']); expect(result.links[0].position).toBe(0); expect(linktreeApi.patch).toHaveBeenCalledWith('/links/reorder', { link_ids: ['lnk-1', 'lnk-2'], }); }); });
Integration Tests
// tests/integration/profile-analytics.test.ts import { describe, it, expect } from 'vitest'; import { LinktreeClient } from '../../src/lib/linktree-api'; const canRun = !!process.env.LINKTREE_API_KEY; describe.skipIf(!canRun)('Linktree Analytics (live API)', () => { const client = new LinktreeClient({ apiKey: process.env.LINKTREE_API_KEY!, }); it('fetches click analytics for the authenticated profile', async () => { const analytics = await client.get('/analytics', { period: 'last_7_days', }); expect(analytics).toHaveProperty('total_clicks'); expect(typeof analytics.total_clicks).toBe('number'); }); });
CI Cost Management
// tests/helpers/api-budget.ts let callCount = 0; const MAX_CALLS_PER_RUN = 30; // Linktree API: 60 req/min for standard tier export function trackApiCall(): void { callCount++; if (callCount > MAX_CALLS_PER_RUN) { throw new Error( `CI API budget exceeded: ${callCount}/${MAX_CALLS_PER_RUN} calls. ` + 'Linktree standard tier allows 60 req/min — reduce test scope or add delays.' ); } } export function getCallCount(): number { return callCount; }
Error Handling
| CI Issue | Cause | Fix |
|---|---|---|
| 401 Unauthorized | Expired or revoked Bearer token | Regenerate in Linktree admin and update GitHub Secrets |
| 429 Rate Limited | Exceeded 60 req/min on standard tier | Add and insert small delays between integration tests |
| Empty analytics response | Profile has zero traffic in test period | Use a longer param or seed test clicks via the Links API |
| Link creation returns 409 | Duplicate URL already exists on profile | Add cleanup in to delete test links by ID |
| Integration job never runs | Branch name mismatch in workflow | Confirm default branch is , not |
Resources
Next Steps
See
linktree-deploy-integration.