improve CTRL+Z shortcut #128
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: 'CI CD' | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: | |
| - master | |
| paths: | |
| - 'src/**' | |
| - 'e2e/**' | |
| - 'prisma-main/**' | |
| - 'prisma-e2e/**' | |
| - 'public/**' | |
| - 'scripts/**' | |
| - '*.css' | |
| - '*.ts' | |
| - '*.js' | |
| - '*.json' | |
| - '*.yml' | |
| - '*.yaml' | |
| - '.github/workflows/**' | |
| - '!**.md' | |
| - '!.ai/**' | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| paths: | |
| - 'src/**' | |
| - 'e2e/**' | |
| - 'prisma-main/**' | |
| - 'prisma-e2e/**' | |
| - 'public/**' | |
| - 'scripts/**' | |
| - '*.css' | |
| - '*.ts' | |
| - '*.js' | |
| - '*.json' | |
| - '*.yml' | |
| - '*.yaml' | |
| - '.github/workflows/**' | |
| - '!**.md' | |
| - '!.ai/**' | |
| jobs: | |
| lint: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run ESLint | |
| run: npm run lint | |
| prettier: | |
| runs-on: ubuntu-latest | |
| needs: [lint] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run Prettier check | |
| run: npx prettier --check . | |
| unit-integration-tests: | |
| runs-on: ubuntu-latest | |
| needs: [lint] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run tests | |
| run: npm run test:coverage | |
| - name: Upload unit coverage artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: unit-coverage | |
| path: coverage/unit/ | |
| retention-days: 1 | |
| e2e-tests: | |
| runs-on: ubuntu-latest | |
| needs: [lint] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Disable Next.js telemetry | |
| run: npx next telemetry disable | |
| - name: Get Playwright version | |
| id: playwright-version | |
| run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').dependencies['@playwright/test'].version)")" >> $GITHUB_OUTPUT | |
| - name: Cache Playwright browsers | |
| uses: actions/cache@v4 | |
| id: playwright-cache | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }} | |
| - name: Install Playwright browsers | |
| run: npx playwright install --with-deps chromium | |
| if: steps.playwright-cache.outputs.cache-hit != 'true' | |
| - name: Install Playwright system dependencies | |
| run: npx playwright install-deps chromium | |
| if: steps.playwright-cache.outputs.cache-hit == 'true' | |
| - name: Run tests | |
| run: npm run test:e2e:coverage | |
| env: | |
| CI: 'true' | |
| COVERAGE: 'true' | |
| BASE_URL: 'http://localhost:45678' | |
| BETTER_AUTH_SECRET: 'test-secret-key-at-least-32-characters-long-for-ci' | |
| BETTER_AUTH_URL: 'http://localhost:45678' | |
| - name: Check for E2E test artifacts | |
| if: always() | |
| id: check-artifacts | |
| run: | | |
| if [ -d e2e/results ] && [ "$(ls e2e/results)" ]; then | |
| echo "E2E test artifacts found" | |
| echo "has_artifacts=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "No E2E test artifacts found" | |
| echo "has_artifacts=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Upload E2E test artifacts | |
| if: always() && steps.check-artifacts.outputs.has_artifacts == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-test-results | |
| path: | | |
| test-results/ | |
| playwright-report/ | |
| e2e/results/ | |
| retention-days: 2 | |
| - name: Display E2E coverage report | |
| if: always() | |
| run: | | |
| if [ -d .nyc_output ] && [ "$(ls -A .nyc_output)" ]; then | |
| echo "E2E Coverage Report:" | |
| npx nyc report --reporter=text --temp-dir=.nyc_output --exclude '**/components/ui/**' | |
| else | |
| echo "No E2E coverage collected (requires webpack mode, not available in CI)" | |
| fi | |
| - name: Convert E2E coverage to lcov | |
| run: | | |
| mkdir -p coverage/e2e | |
| if [ -d .nyc_output ] && [ "$(ls -A .nyc_output)" ]; then | |
| echo "Converting E2E coverage to lcov format..." | |
| npx nyc report --reporter=lcov --report-dir=coverage/e2e --temp-dir=.nyc_output --exclude '**/components/ui/**' | |
| echo "E2E coverage converted" | |
| else | |
| echo "No E2E coverage found (webpack mode not used in CI)" | |
| touch coverage/e2e/lcov.info | |
| fi | |
| - name: Upload E2E coverage artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: e2e-coverage | |
| path: coverage/e2e/ | |
| retention-days: 1 | |
| deploy: | |
| if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'push' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| needs: [unit-integration-tests, e2e-tests] | |
| env: | |
| VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | |
| VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Vercel CLI | |
| run: npm install --global vercel@latest | |
| - name: Pull Vercel Environment Information (Production) | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
| run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} | |
| - name: Pull Vercel Environment Information (Preview) | |
| if: github.event_name == 'pull_request' | |
| run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} | |
| - name: Build Project Artifacts (Production) | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
| run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} | |
| - name: Build Project Artifacts (Preview) | |
| if: github.event_name == 'pull_request' | |
| run: vercel build --token=${{ secrets.VERCEL_TOKEN }} | |
| - name: Deploy Project Artifacts to Vercel (Production) | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
| run: | | |
| url="$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }})" | |
| vercel alias --scope jcubics-projects --token=${{ secrets.VERCEL_TOKEN }} set "$url" app.snapp.md | |
| - name: Deploy Project Artifacts to Vercel (Preview) | |
| if: github.event_name == 'pull_request' | |
| id: deploy-preview | |
| run: | | |
| url="$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})" | |
| echo "preview_url=$url" >> $GITHUB_OUTPUT | |
| - name: Comment PR with preview URL | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const previewUrl = '${{ steps.deploy-preview.outputs.preview_url }}'; | |
| const comment = `## 🚀 Preview Deployment | |
| Your preview deployment is ready! | |
| ✅ **Preview URL:** ${previewUrl} | |
| --- | |
| *This preview will be updated automatically when you push new commits to this PR.*`; | |
| // Find existing 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('Preview Deployment') | |
| ); | |
| // Update or create comment | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: comment | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: comment | |
| }); | |
| } | |
| merge-coverage: | |
| runs-on: ubuntu-latest | |
| needs: [unit-integration-tests, e2e-tests] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Download unit coverage artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: unit-coverage | |
| path: coverage/unit/ | |
| - name: Download E2E coverage artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: e2e-coverage | |
| path: coverage/e2e/ | |
| - name: Merge coverage reports | |
| run: | | |
| mkdir -p coverage/merged | |
| # Ensure coverage files exist | |
| if [ ! -f coverage/unit/lcov.info ]; then | |
| echo "Warning: No unit coverage found" | |
| touch coverage/unit/lcov.info | |
| fi | |
| if [ ! -f coverage/e2e/lcov.info ]; then | |
| echo "Warning: No E2E coverage found" | |
| touch coverage/e2e/lcov.info | |
| fi | |
| # Merge coverage files by concatenation | |
| echo "Merging coverage reports..." | |
| cat coverage/unit/lcov.info coverage/e2e/lcov.info > coverage/merged/lcov.info | |
| echo "Coverage merge complete" | |
| - name: Display merged coverage summary | |
| if: always() | |
| run: | | |
| if [ -f coverage/merged/lcov.info ] && [ -s coverage/merged/lcov.info ]; then | |
| echo "Merged Coverage Summary:" | |
| npx lcov-summary coverage/merged/lcov.info | |
| else | |
| echo "No merged coverage summary available" | |
| fi | |
| - name: Upload merged coverage to Coveralls | |
| if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'push' | |
| uses: coverallsapp/github-action@v2 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| path-to-lcov: ./coverage/merged/lcov.info | |
| - name: Purge README images | |
| if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'push' | |
| uses: kevincobain2000/action-camo-purge@v1 |