diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 00000000..04dd0bbc --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,72 @@ +# CI/CD Workflows + +This directory contains GitHub Actions workflows for automated testing, building, and deployment. + +## ๐Ÿงช Test Workflow (`test.yml`) + +**Triggers**: Pull requests and pushes to `main`/`develop` + +### Jobs: + +1. **`test`** - Unit Tests + - Runs all Jest unit tests + - Ensures all tests pass + +2. **`lint`** - Code Quality + - Checks TypeScript compilation + - Validates code formatting (Prettier) + +3. **`build`** - Build Verification + - Ensures project builds successfully + - Uploads build artifacts + +4. **`all-checks-passed`** - Gate Keeper + - Only passes if ALL other jobs succeed + - **This is the required status check for branch protection** + +### Test Requirements: + +- All unit tests must pass +- No failing test cases + +## ๐Ÿš€ E2E Workflows + +- `pr-main-e2e.yml` - E2E tests against production +- `pr-prod-e2e.yml` - Production E2E validation +- `manual-e2e.yml` - Manual E2E trigger +- `publish-on-merge.yml` - Package publishing + +## ๐Ÿ”ง Local Development + +```bash +# Run tests +yarn test + +# Run tests in watch mode +yarn test:watch + +# Run tests in CI mode +yarn test:ci + +# Type checking +yarn type-check + +# Code formatting +yarn lint +yarn lint:fix + +# Full CI simulation +yarn ci:test +``` + +## ๐Ÿ“Š Artifacts + +Each workflow run produces: + +- **Build Artifacts** (3 days retention) +- **Test Results** (30 days retention for E2E) + +## ๐Ÿ” Monitoring + +- Test results visible in workflow logs +- Failed runs block PR merging automatically diff --git a/.github/workflows/manual-e2e.yml b/.github/workflows/manual-e2e.yml index ab14a93b..d940ee62 100644 --- a/.github/workflows/manual-e2e.yml +++ b/.github/workflows/manual-e2e.yml @@ -1,4 +1,6 @@ name: Manual E2E Validation +permissions: + contents: read on: workflow_dispatch: diff --git a/.github/workflows/pr-main-e2e.yml b/.github/workflows/pr-main-e2e.yml index 5867c17f..f2b91265 100644 --- a/.github/workflows/pr-main-e2e.yml +++ b/.github/workflows/pr-main-e2e.yml @@ -1,5 +1,8 @@ name: UI prod e2e with local sdk build +permissions: + contents: read + on: pull_request: branches: [main] diff --git a/.github/workflows/pr-prod-e2e.yml b/.github/workflows/pr-prod-e2e.yml index 39bb2635..a92d75b9 100644 --- a/.github/workflows/pr-prod-e2e.yml +++ b/.github/workflows/pr-prod-e2e.yml @@ -1,4 +1,6 @@ name: UI prod e2e with staging sdk build +permissions: + contents: read on: pull_request: diff --git a/.github/workflows/publish-on-merge.yml b/.github/workflows/publish-on-merge.yml index 32aa2b45..3912f10b 100644 --- a/.github/workflows/publish-on-merge.yml +++ b/.github/workflows/publish-on-merge.yml @@ -13,6 +13,9 @@ on: jobs: publish: + permissions: + contents: write + pull-requests: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..9f22ccb0 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,144 @@ +name: Unit Tests +permissions: + contents: read + +on: + pull_request: + branches: [main, prod] + types: [opened, synchronize, reopened] + push: + branches: [main, prod] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +jobs: + type-check: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'yarn' + cache-dependency-path: yarn.lock + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Run TypeScript type checking + run: yarn tsc --noEmit + + lint: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'yarn' + cache-dependency-path: yarn.lock + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Check code formatting + run: | + if command -v yarn prettier &> /dev/null; then + echo "Running Prettier check..." + yarn prettier --check "src/**/*.{ts,tsx,js,jsx}" || { + echo "โŒ Code formatting issues found. Please run 'yarn prettier --write .' to fix them." + exit 1 + } + else + echo "Prettier not configured, skipping format check" + fi + + test: + runs-on: ubuntu-latest + timeout-minutes: 15 + needs: [type-check, lint] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'yarn' + cache-dependency-path: yarn.lock + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Run unit tests with coverage + run: yarn test:ci --coverage + env: + CI: true + + build: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'yarn' + cache-dependency-path: yarn.lock + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build project + run: yarn build + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-artifacts-${{ github.run_id }} + path: | + dist/ + retention-days: 3 + + # This job will only run if all previous jobs succeed + # It serves as a single status check for branch protection + all-checks-passed: + runs-on: ubuntu-latest + needs: [type-check, lint, test, build] + if: always() + + steps: + - name: Check if all jobs succeeded + run: | + if [[ "${{ needs.type-check.result }}" == "success" && + "${{ needs.lint.result }}" == "success" && + "${{ needs.test.result }}" == "success" && + "${{ needs.build.result }}" == "success" ]]; then + echo "โœ… All checks passed!" + exit 0 + else + echo "โŒ Some checks failed:" + echo " Type Check: ${{ needs.type-check.result }}" + echo " Lint: ${{ needs.lint.result }}" + echo " Test: ${{ needs.test.result }}" + echo " Build: ${{ needs.build.result }}" + exit 1 + fi diff --git a/demo/app.tsx b/demo/app.tsx index 8fbe657f..585bb987 100644 --- a/demo/app.tsx +++ b/demo/app.tsx @@ -25,12 +25,7 @@ export function App() { mode, enableAnalytics: false, auth: { type: 'key', clientKey }, - streamOptions: { - streamWarmup: warmup, - sessionTimeout, - compatibilityMode, - fluent, - }, + streamOptions: { streamWarmup: warmup, sessionTimeout, compatibilityMode, fluent }, }); async function onClick() { @@ -52,7 +47,6 @@ export function App() {