Claude-code-plugins-plus-skills webflow-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/webflow-pack/skills/webflow-ci-integration" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-webflow-ci-integration && rm -rf "$T"
manifest:
plugins/saas-packs/webflow-pack/skills/webflow-ci-integration/SKILL.mdsource content
Webflow CI Integration
Overview
Set up CI/CD pipelines for Webflow Data API v2 integrations with GitHub Actions. Includes unit tests with mocked SDK, integration tests with test tokens, CMS schema validation, and automated publish-on-merge workflows.
Prerequisites
- GitHub repository with Actions enabled
- Webflow API token (test environment) stored as GitHub secret
SDK with vitest test suitewebflow-api
Instructions
Step 1: Store Secrets
# Store Webflow test token as GitHub secret gh secret set WEBFLOW_API_TOKEN --body "your-test-token" gh secret set WEBFLOW_SITE_ID --body "your-test-site-id" # For production deployments gh secret set WEBFLOW_API_TOKEN_PROD --body "your-prod-token"
Step 2: Unit Test Workflow
Tests that mock the SDK — run on every PR, no API calls:
# .github/workflows/webflow-test.yml name: Webflow Integration Tests 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 -- --coverage - name: Upload coverage uses: actions/upload-artifact@v4 with: name: coverage path: coverage/ lint-and-typecheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - run: npm ci - run: npx tsc --noEmit - run: npm run lint
Step 3: Integration Test Workflow
Tests against the real Webflow API — run only on main branch with secrets:
# .github/workflows/webflow-integration.yml name: Webflow Integration Tests on: push: branches: [main] workflow_dispatch: # Manual trigger jobs: integration: runs-on: ubuntu-latest # Only run if secrets are available if: ${{ vars.WEBFLOW_TESTS_ENABLED == 'true' }} env: WEBFLOW_API_TOKEN: ${{ secrets.WEBFLOW_API_TOKEN }} WEBFLOW_SITE_ID: ${{ secrets.WEBFLOW_SITE_ID }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - run: npm ci - name: Verify Webflow connectivity run: | HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: Bearer $WEBFLOW_API_TOKEN" \ https://api.webflow.com/v2/sites) if [ "$HTTP_CODE" != "200" ]; then echo "Webflow API returned HTTP $HTTP_CODE" exit 1 fi - name: Run integration tests run: npm run test:integration timeout-minutes: 5
Step 4: Integration Test Example
// tests/integration/webflow.integration.test.ts import { describe, it, expect } from "vitest"; import { WebflowClient } from "webflow-api"; const SKIP = !process.env.WEBFLOW_API_TOKEN; describe.skipIf(SKIP)("Webflow API Integration", () => { const webflow = new WebflowClient({ accessToken: process.env.WEBFLOW_API_TOKEN!, }); const siteId = process.env.WEBFLOW_SITE_ID!; it("should list sites", async () => { const { sites } = await webflow.sites.list(); expect(sites).toBeDefined(); expect(sites!.length).toBeGreaterThan(0); }); it("should get site details", async () => { const site = await webflow.sites.get(siteId); expect(site.id).toBe(siteId); expect(site.displayName).toBeDefined(); }); it("should list collections", async () => { const { collections } = await webflow.collections.list(siteId); expect(collections).toBeDefined(); for (const col of collections!) { expect(col.id).toBeDefined(); expect(col.displayName).toBeDefined(); expect(col.fields).toBeDefined(); } }); it("should handle rate limits gracefully", async () => { // The SDK auto-retries on 429 — this should not throw const promises = Array.from({ length: 5 }, () => webflow.sites.list() ); const results = await Promise.all(promises); expect(results.every(r => r.sites!.length > 0)).toBe(true); }); });
Step 5: CMS Schema Validation
Ensure your code matches the live Webflow collection schema:
// tests/integration/schema-validation.test.ts import { describe, it, expect } from "vitest"; import { WebflowClient } from "webflow-api"; const SKIP = !process.env.WEBFLOW_API_TOKEN; describe.skipIf(SKIP)("CMS Schema Validation", () => { const webflow = new WebflowClient({ accessToken: process.env.WEBFLOW_API_TOKEN!, }); const siteId = process.env.WEBFLOW_SITE_ID!; // Define expected schema for your "Blog Posts" collection const EXPECTED_FIELDS = [ { slug: "name", type: "PlainText", required: true }, { slug: "slug", type: "PlainText", required: true }, { slug: "post-body", type: "RichText", required: false }, { slug: "author-name", type: "PlainText", required: false }, { slug: "publish-date", type: "DateTime", required: false }, ]; it("should match expected collection schema", async () => { const { collections } = await webflow.collections.list(siteId); const blogCollection = collections!.find(c => c.slug === "blog-posts"); expect(blogCollection).toBeDefined(); for (const expected of EXPECTED_FIELDS) { const field = blogCollection!.fields!.find(f => f.slug === expected.slug); expect(field, `Field "${expected.slug}" should exist`).toBeDefined(); expect(field!.type).toBe(expected.type); } }); });
Step 6: Publish-on-Merge Workflow
Automatically publish Webflow site when content changes merge to main:
# .github/workflows/webflow-publish.yml name: Publish Webflow Site on: push: branches: [main] paths: - "content/**" - "src/webflow/**" jobs: sync-and-publish: runs-on: ubuntu-latest env: WEBFLOW_API_TOKEN: ${{ secrets.WEBFLOW_API_TOKEN_PROD }} WEBFLOW_SITE_ID: ${{ secrets.WEBFLOW_SITE_ID_PROD }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - run: npm ci - name: Sync content to Webflow CMS run: npm run sync:webflow - name: Publish site run: | curl -X POST \ "https://api.webflow.com/v2/sites/$WEBFLOW_SITE_ID/publish" \ -H "Authorization: Bearer $WEBFLOW_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"publishToWebflowSubdomain": true}'
Output
- Unit test pipeline (mocked, runs on every PR)
- Integration test pipeline (real API, runs on main)
- CMS schema validation tests
- Automated publish-on-merge workflow
- GitHub secrets configured
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Secret not found | Missing | Add secret via GitHub CLI |
| Integration tests timeout | Rate limited or slow API | Increase timeout, reduce parallelism |
| Schema mismatch | Collection changed in Webflow | Update expected schema in tests |
| Publish fails in CI | Wrong production token | Verify secret |
Resources
Next Steps
For deployment patterns, see
webflow-deploy-integration.