From f884bf5abb2d70fcf3e16d14f26d486ab0becd99 Mon Sep 17 00:00:00 2001 From: Dhirender Choudhary Date: Fri, 28 Aug 2026 21:18:21 +0530 Subject: [PATCH] ci: add GitHub Actions CI, release, and PR checks --- .github/PULL_REQUEST_TEMPLATE.md | 13 ++++++ .github/actions/setup/action.yml | 30 +++++++++++++ .github/dependabot.yml | 16 +++++++ .github/workflows/ci.yml | 77 ++++++++++++++++++++++++++++++++ .github/workflows/codeql.yml | 39 ++++++++++++++++ .github/workflows/pr-title.yml | 32 +++++++++++++ .github/workflows/release.yml | 30 +++++++++++++ .gitignore | 2 + CHANGELOG.md | 1 + CONTRIBUTING.md | 29 ++++++++---- README.md | 1 + 11 files changed, 261 insertions(+), 9 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/actions/setup/action.yml create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/pr-title.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..f035beb --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +## Summary + + + +## Test plan + +- [ ] `pnpm run format:check` passes +- [ ] `pnpm run lint` passes +- [ ] `pnpm run build` passes +- [ ] `pnpm test` passes +- [ ] Docs / `CHANGELOG.md` updated if this is user-facing + +Closes # diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 0000000..8e278c8 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,30 @@ +name: Setup +description: Install pnpm, Node.js, and dependencies from the lockfile. + +inputs: + node-version: + description: Node.js version to install + required: true + registry-url: + description: Optional npm registry URL (needed for publish) + required: false + default: "" + +runs: + using: composite + steps: + - uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + if: ${{ inputs.registry-url == '' }} + with: + node-version: ${{ inputs.node-version }} + cache: pnpm + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + if: ${{ inputs.registry-url != '' }} + with: + node-version: ${{ inputs.node-version }} + cache: pnpm + registry-url: ${{ inputs.registry-url }} + - name: Install dependencies + shell: bash + run: pnpm install --frozen-lockfile diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..05db778 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + github-actions: + patterns: + - "*" + + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..08dc31a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,77 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +concurrency: + group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +# Unit and mocked integration tests live under src/__tests__ and do not call +# provider APIs. A live Playwright job would need secrets that fork PRs never +# receive; add one when a real E2E suite exists, gated on push to main. + +jobs: + quality: + name: Lint, format, and typecheck + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: ./.github/actions/setup + with: + node-version: "22" + - name: Prettier + run: pnpm run format:check + - name: ESLint + run: pnpm run lint + - name: Typecheck + run: pnpm run build + + test: + name: Test (Node ${{ matrix.node-version }}) + runs-on: ubuntu-24.04 + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + node-version: [18, 20, 22, 24] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: ./.github/actions/setup + with: + node-version: ${{ matrix.node-version }} + - name: Test + run: pnpm test + - name: Coverage + if: matrix.node-version == 22 + run: pnpm run test:coverage + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + if: matrix.node-version == 22 + with: + name: coverage + path: coverage/ + if-no-files-found: error + + ci: + name: CI + needs: [quality, test] + if: always() + runs-on: ubuntu-24.04 + timeout-minutes: 2 + steps: + - name: Required jobs passed + run: | + test "${{ needs.quality.result }}" = "success" + test "${{ needs.test.result }}" = "success" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..23f3122 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,39 @@ +name: CodeQL + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: "27 3 * * 1" + workflow_dispatch: + +concurrency: + group: codeql-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-24.04 + timeout-minutes: 20 + permissions: + security-events: write + packages: read + actions: read + contents: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + with: + languages: javascript-typescript + build-mode: none + - uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + with: + category: "/language:javascript-typescript" diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 0000000..6f5d746 --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,32 @@ +name: PR title + +on: + pull_request: + types: [opened, edited, synchronize, reopened, ready_for_review] + +permissions: + pull-requests: read + +jobs: + lint: + name: Conventional title + runs-on: ubuntu-24.04 + timeout-minutes: 5 + steps: + - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + types: | + feat + fix + docs + style + refactor + perf + test + build + ci + chore + revert + requireScope: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e674caf --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,30 @@ +name: Release + +on: + release: + types: [published] + workflow_dispatch: + +permissions: + contents: read + id-token: write + +jobs: + publish: + name: Publish to npm + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: ./.github/actions/setup + with: + node-version: "22" + registry-url: https://registry.npmjs.org + - name: Build + run: pnpm run build + - name: Publish + run: pnpm publish --access public --no-git-checks --provenance + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 6ec6965..6bbdb09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ dist node_modules +coverage +.pnpm-store .DS_Store .env \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index bd857f9..30565a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- GitHub Actions CI/CD: Prettier, ESLint, typecheck, tests on Node 18–24, CodeQL, conventional PR titles, and npm publish (with provenance) on GitHub Release - **OpenAI Support**: Direct integration with OpenAI models via `@ai-sdk/openai` and `OPENAI_API_KEY` - `maxRetries` option to `AssertionOptions` (default: `1`) to control how many times a failed assertion is retried with a fresh page snapshot and screenshot. Setting it to `0` disables retries. - `onRetry` callback to `AssertionOptions` that fires before each retry, receiving the retry index and the full `AssertionResult` from the previous attempt for debugging flaky assertions. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c23028c..434fb22 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ Thank you for your interest in contributing to Passmark! This document provides 1. **Fork** the repository 2. **Clone** your fork locally -3. **Install dependencies**: `npm install` +3. **Install dependencies**: `pnpm install` (this repo is pinned to `pnpm@10.33.0` via `packageManager`) 4. **Create a branch** for your change: `git checkout -b feature/your-feature` ## Development Setup @@ -14,17 +14,23 @@ Thank you for your interest in contributing to Passmark! This document provides ### Prerequisites - Node.js >= 18.0.0 -- Redis instance (local or remote) -- API keys for Anthropic and Google Generative AI (for running tests) -- Playwright: `npx playwright install` +- pnpm 10 (`corepack enable` will use the version in `package.json`) +- Redis instance (local or remote) — only needed for live cache / `{{global.*}}` flows +- API keys for Anthropic and Google Generative AI — only needed for live AI runs, not for `pnpm test` +- Playwright: `npx playwright install` — only needed for running tests against a real browser -### Building +### Checks (same as CI) ```bash -npm run build +pnpm run format:check +pnpm run lint +pnpm run build +pnpm test ``` -This runs the TypeScript compiler (`tsc`). Fix any type errors before submitting. +`pnpm run build` runs the TypeScript compiler (`tsc`). Fix any type errors before submitting. + +CI runs these on every pull request to `main` (tests on Node 18, 20, 22, and 24). The unit suite is mocked and does not need API keys, Redis, or a browser. ## Code Style @@ -42,10 +48,11 @@ This runs the TypeScript compiler (`tsc`). Fix any type errors before submitting - `feature/description` for new features - `fix/description` for bug fixes - `docs/description` for documentation changes +- `ci/description` for CI/CD changes ### Commit Messages -Use clear, concise commit messages: +Use conventional commit messages. PR titles are checked the same way: ``` feat: add support for custom model providers @@ -53,14 +60,18 @@ fix: handle empty email extraction gracefully docs: update environment variables table ``` +Allowed prefixes: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`. + ### Pull Requests -1. Ensure `npm run build` passes with no errors +1. Ensure CI would pass locally (`pnpm run format:check`, `pnpm run lint`, `pnpm run build`, `pnpm test`) 2. Update documentation if your change affects the public API 3. Add entries to `CHANGELOG.md` under an `[Unreleased]` section 4. Keep PRs focused on a single change 5. Provide a clear description of what changed and why +Publishing to npm is automated: creating a GitHub Release on `main` runs `.github/workflows/release.yml`. That workflow needs an `NPM_TOKEN` repository secret with publish access to the `passmark` package. + ## Project Structure ``` diff --git a/README.md b/README.md index cc2d2c9..e2eba50 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Follow on X LinkedIn Website + CI npm package version License