diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b32987..ea4fc69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,93 +36,124 @@ jobs: echo "should_test=false" >> "$GITHUB_OUTPUT" fi - build-and-test: - name: Build & Test (Node ${{ matrix.node-version }}) + setup: + name: Install & Build needs: check-changes if: needs.check-changes.outputs.should_test == 'true' runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x, 20.x, 22.x] - steps: - uses: actions/checkout@v4 - - name: Setup Node.js ${{ matrix.node-version }} + - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} - cache: 'npm' + node-version: '20.x' + + - name: Cache node_modules + id: cache-nm + uses: actions/cache@v4 + with: + path: node_modules + key: node-modules-${{ runner.os }}-node20-${{ hashFiles('package-lock.json') }} - name: Install dependencies + if: steps.cache-nm.outputs.cache-hit != 'true' run: npm ci - - name: Type check - run: npm run type-check - - name: Build run: npm run build - - name: Unit & integration tests + - name: Upload workspace + uses: actions/upload-artifact@v4 + with: + name: workspace + path: | + node_modules/ + dist/ + retention-days: 1 + + test: + name: Unit & Integration Tests + needs: setup + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Download workspace + uses: actions/download-artifact@v4 + with: + name: workspace + + - name: Run tests run: npm test + lint: + name: Lint & Type Check + needs: setup + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Download workspace + uses: actions/download-artifact@v4 + with: + name: workspace + + - name: Type check + run: npm run type-check + + e2e: + name: E2E Tests + needs: setup + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Download workspace + uses: actions/download-artifact@v4 + with: + name: workspace + - name: Check build artifacts run: | test -f dist/index.js test -f dist/server.js test -d dist/frontend - - name: Upload build artifacts - if: matrix.node-version == '20.x' - uses: actions/upload-artifact@v4 + - name: Get Playwright version + id: pw-version + run: echo "version=$(node -e "console.log(require('./node_modules/@playwright/test/package.json').version)")" >> "$GITHUB_OUTPUT" + + - name: Cache Playwright browsers + id: cache-pw + uses: actions/cache@v4 with: - name: build-artifacts - path: dist/ - retention-days: 7 - - lint-check: - name: Lint Check - needs: check-changes - if: needs.check-changes.outputs.should_test == 'true' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20.x' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Check for TypeScript errors - run: npm run type-check - - e2e: - name: E2E Tests - needs: [check-changes, build-and-test] - if: needs.check-changes.outputs.should_test == 'true' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20.x' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Build - run: npm run build + path: ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }} - name: Install Playwright browsers + if: steps.cache-pw.outputs.cache-hit != 'true' run: ./node_modules/.bin/playwright install --with-deps chromium + - name: Install Playwright system deps + if: steps.cache-pw.outputs.cache-hit == 'true' + run: ./node_modules/.bin/playwright install-deps chromium + - name: Run E2E tests run: npm run test:e2e env: @@ -140,7 +171,7 @@ jobs: runs-on: ubuntu-latest continue-on-error: false name: CI Status Check - needs: [check-changes, build-and-test, lint-check, e2e] + needs: [check-changes, setup, test, lint, e2e] if: always() permissions: statuses: write diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8836df2..dc23399 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,6 +12,10 @@ on: type: boolean default: false +concurrency: + group: docker-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: IMAGE_NAME_MCP: sanjibdevnath/mcp-excalidraw-local IMAGE_NAME_CANVAS: sanjibdevnath/mcp-excalidraw-local-canvas diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3caf91b..5d0c25f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,10 @@ on: types: [completed] branches: [main] +concurrency: + group: release-main + cancel-in-progress: true + permissions: contents: write id-token: write @@ -185,9 +189,16 @@ jobs: with: node-version: '20.x' registry-url: 'https://registry.npmjs.org' - cache: 'npm' + + - name: Cache node_modules + id: cache-nm + uses: actions/cache@v4 + with: + path: node_modules + key: node-modules-${{ runner.os }}-node20.x-${{ hashFiles('package-lock.json') }} - name: Install dependencies + if: steps.cache-nm.outputs.cache-hit != 'true' run: npm ci - name: Build diff --git a/README.md b/README.md index 2d3337f..2172865 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # MCP Excalidraw Local [![CI](https://github.com/sanjibdevnathlabs/mcp-excalidraw-local/actions/workflows/ci.yml/badge.svg)](https://github.com/sanjibdevnathlabs/mcp-excalidraw-local/actions/workflows/ci.yml) -[![Docker Build & Push](https://github.com/sanjibdevnathlabs/mcp-excalidraw-local/actions/workflows/docker.yml/badge.svg)](https://github.com/sanjibdevnathlabs/mcp-excalidraw-local/actions/workflows/docker.yml) +[![Release & Publish](https://github.com/sanjibdevnathlabs/mcp-excalidraw-local/actions/workflows/release.yml/badge.svg)](https://github.com/sanjibdevnathlabs/mcp-excalidraw-local/actions/workflows/release.yml) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) A fully local, self-hosted Excalidraw MCP server with **SQLite persistence**, **multi-tenancy**, and **auto-sync** — designed to run entirely on your machine without depending on `excalidraw.com`.