Skip to main content
Glama
smart-ci.ymlβ€’12.5 kB
name: Smart CI Pipeline on: push: branches: [main, develop] pull_request: branches: [main, develop] workflow_dispatch: # Prevent concurrent runs for the same branch/PR concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: contents: read pull-requests: write issues: write env: NODE_VERSION_MATRIX: '["20.x", "22.x"]' jobs: # Job 1: Analyze Changes for Smart Execution change-analysis: name: Analyze Changes runs-on: ubuntu-latest timeout-minutes: 5 outputs: docs-only: ${{ steps.changes.outputs.docs-only }} tests-only: ${{ steps.changes.outputs.tests-only }} needs-integration: ${{ steps.changes.outputs.needs-integration }} test-strategy: ${{ steps.changes.outputs.test-strategy }} steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Analyze changed files id: changes run: | # Get changed files if [ "${{ github.event_name }}" = "pull_request" ]; then changed_files=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.number }}/files --jq '.[].filename') else changed_files=$(git diff --name-only HEAD~1 HEAD) fi echo "Changed files:" echo "$changed_files" # Analyze file types docs_only=true tests_only=true needs_integration=false while IFS= read -r file; do case "$file" in *.md|docs/*|README*|CHANGELOG*|LICENSE) # Documentation files don't affect other flags ;; test/*|*.test.*) docs_only=false ;; src/api/*|src/services/*|src/handlers/*) docs_only=false tests_only=false needs_integration=true ;; src/*) docs_only=false tests_only=false ;; *) docs_only=false tests_only=false ;; esac done <<< "$changed_files" # Determine test strategy if [ "$docs_only" = "true" ]; then test_strategy="smoke" elif [ "$tests_only" = "true" ]; then test_strategy="affected" else test_strategy="core" fi echo "docs-only=$docs_only" >> $GITHUB_OUTPUT echo "tests-only=$tests_only" >> $GITHUB_OUTPUT echo "needs-integration=$needs_integration" >> $GITHUB_OUTPUT echo "test-strategy=$test_strategy" >> $GITHUB_OUTPUT env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Job 2: Lint and Type Check (always runs) lint-and-typecheck: name: Lint & Type Check runs-on: ubuntu-latest timeout-minutes: 10 needs: change-analysis steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22.x' cache: 'npm' - name: Install dependencies run: npm ci - name: Run linter (src only) run: npm run lint:src - name: Enforce no new src warnings run: npm run lint:guard - name: Run type checker run: npm run typecheck - name: Check format run: npm run check:format # Optional: Lint tests (non-blocking) lint-tests: name: Lint Tests (non-blocking) runs-on: ubuntu-latest timeout-minutes: 10 needs: change-analysis if: always() continue-on-error: true steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22.x' cache: 'npm' - name: Install dependencies run: npm ci - name: Run linter (tests) run: npm run lint:test # Job 3: Smart Test Execution smart-tests: name: Smart Tests (${{ matrix.node-version }}) runs-on: ubuntu-latest timeout-minutes: 20 needs: [change-analysis, lint-and-typecheck] strategy: matrix: node-version: [20.x, 22.x] fail-fast: false steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: 'npm' - name: Clean npm cache and install dependencies run: | # Fix for npm optional dependencies bug with Rollup rm -rf node_modules package-lock.json npm cache clean --force npm install - name: Build project run: npm run build - name: Execute smart test strategy run: | strategy="${{ needs.change-analysis.outputs.test-strategy }}" echo "πŸ§ͺ Executing test strategy: $strategy" case "$strategy" in smoke) echo "πŸ“š Documentation changes detected - running smoke tests" npm run test:smoke ;; affected) echo "🎯 Test-only changes detected - running affected tests" npm run test:affected ;; core) echo "πŸ”§ Source changes detected - running core tests" npm run test:core ;; full) echo "πŸš€ API/Service changes detected - running extended tests" npm run test:extended ;; esac env: SKIP_INTEGRATION_TESTS: true - name: Performance budget check if: matrix.node-version == '22.x' run: | strategy="${{ needs.change-analysis.outputs.test-strategy }}" if [ "$strategy" != "smoke" ]; then npm run perf:budgets -- --tests-only fi # Job 4: Integration Tests (conditional) integration-tests: name: Integration Tests runs-on: ubuntu-latest timeout-minutes: 30 needs: [change-analysis] if: | needs.change-analysis.outputs.needs-integration == 'true' || contains(github.event.pull_request.labels.*.name, 'run-integration-tests') steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22.x' cache: 'npm' - name: Install dependencies run: npm ci - name: Build project run: npm run build - name: Run integration tests env: ATTIO_API_KEY: ${{ secrets.ATTIO_TEST_API_KEY }} ATTIO_WORKSPACE_ID: ${{ secrets.ATTIO_TEST_WORKSPACE_ID }} run: | if [ -z "$ATTIO_API_KEY" ]; then echo "⚠️ Integration tests skipped: ATTIO_TEST_API_KEY not available" exit 0 fi npm run test:integration # Job 5: Build Verification (skip for docs-only changes) build: name: Build Verification runs-on: ubuntu-latest timeout-minutes: 15 needs: [change-analysis] if: needs.change-analysis.outputs.docs-only != 'true' steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22.x' cache: 'npm' - name: Install dependencies run: npm ci - name: Build project run: npm run build - name: Verify build artifacts run: | test -d dist/ test -f dist/index.js test -f dist/cli/discover.js - name: Test CLI execution run: | chmod +x dist/index.js chmod +x dist/cli/discover.js node dist/index.js --help || echo "CLI help test completed" # Job 6: Performance Tests (main branch only) performance: name: Performance Tests runs-on: ubuntu-latest timeout-minutes: 20 needs: [change-analysis] if: | (github.event_name == 'push' && github.ref == 'refs/heads/main') || contains(github.event.pull_request.labels.*.name, 'run-performance-tests') steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22.x' cache: 'npm' - name: Install dependencies run: npm ci - name: Build project run: npm run build - name: Run performance budget checks run: npm run perf:budgets -- --report --regression - name: Upload performance results if: always() uses: actions/upload-artifact@v4 with: name: performance-results retention-days: 30 path: performance-results/ # Job 7: Smart Summary smart-summary: name: Smart CI Summary runs-on: ubuntu-latest needs: [change-analysis, lint-and-typecheck, smart-tests, build] if: always() && github.event_name == 'pull_request' steps: - name: Create smart summary uses: actions/github-script@v7 with: script: | const strategy = '${{ needs.change-analysis.outputs.test-strategy }}'; const docsOnly = '${{ needs.change-analysis.outputs.docs-only }}' === 'true'; let summary = '# 🧠 Smart CI Results\n\n'; summary += `**Strategy**: ${strategy.toUpperCase()}\n`; summary += `**Docs Only**: ${docsOnly ? 'βœ…' : '❌'}\n\n`; // Strategy explanation summary += '## πŸ“‹ Execution Strategy\n\n'; switch(strategy) { case 'smoke': summary += 'πŸ“š **Documentation Changes**: Only smoke tests executed for safety\n'; break; case 'affected': summary += '🎯 **Test Changes**: Affected tests executed based on impact analysis\n'; break; case 'core': summary += 'πŸ”§ **Source Changes**: Core test suite executed\n'; break; case 'full': summary += 'πŸš€ **API/Service Changes**: Extended test suite executed\n'; break; } // Job results const jobs = { 'Lint & Type Check': '${{ needs.lint-and-typecheck.result }}', 'Smart Tests': '${{ needs.smart-tests.result }}', 'Build Verification': '${{ needs.build.result || 'skipped' }}' }; summary += '\n## πŸ” Job Results\n\n'; for (const [job, result] of Object.entries(jobs)) { const emoji = result === 'success' ? 'βœ…' : result === 'failure' ? '❌' : result === 'skipped' ? '⏭️' : '⚠️'; summary += `${emoji} **${job}**: ${result}\n`; } // Time savings summary += '\n## ⚑ Efficiency Gains\n\n'; if (docsOnly) { summary += 'πŸš€ **Major time savings**: Skipped unnecessary builds and extended tests\n'; } else if (strategy === 'affected') { summary += '🎯 **Targeted execution**: Only affected tests run based on changes\n'; } else { summary += 'βš–οΈ **Balanced approach**: Full validation for significant changes\n'; } // Post comment const { data: comments } = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number }); const botComment = comments.find(comment => comment.user.type === 'Bot' && comment.body.includes('# 🧠 Smart CI Results') ); if (botComment) { await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: botComment.id, body: summary }); } else { await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body: summary }); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kesslerio/attio-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server