diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f63e7d5..0cd4502 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -25,12 +25,13 @@ ## Commands Run (local verification) - -- [ ] `npm run verify` passed locally + +- [ ] `npm run presubmit` passed locally (or `npm run verify`) ``` - + ``` ## CI Status diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 512aa2f..4511300 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,7 +67,10 @@ npm run test:watch # Type-check without emitting files npm run lint -# Pre-PR verification (tests, build, docs/CI reminders, acceptance criteria checklist) +# Pre-submission verification (lint, tests, coverage, build — run before opening a PR) +npm run presubmit + +# Pre-PR verification (same checks + docs/CI reminders + acceptance criteria checklist) npm run verify:pr # Start the dev watcher @@ -130,8 +133,14 @@ reminders from your git diff, and prints issue acceptance criteria, run: npm run verify:pr ``` -See [Pre-PR Verification](./docs/pre-pr-verification.md) for checklist -generation and `--issue` / `--checklist` options. +Before that (or as the minimum CI-parity gate), always run: + +```bash +npm run presubmit +``` + +See [Pre-submission Verification](./docs/pre-submission-verification.md) and +[Pre-PR Verification](./docs/pre-pr-verification.md). All tests must pass. ✅ @@ -173,6 +182,7 @@ The PocketPay SDK handles sensitive cryptographic keys and financial transaction Before opening a PR, run through this list: +- [ ] `npm run presubmit` passes (lint, circular deps, tests, coverage, build) - [ ] `npm run verify:pr` passes (or `npm run lint` + `npm test` at minimum) - [ ] `npm run lint` passes with no errors - [ ] `npm test` passes with no failures diff --git a/README.md b/README.md index b047b3b..88df9fe 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ npm install @axionvera/pocketpay-sdk - [SDK Roadmap](./docs/roadmap.md) - Directional plans and contributor opportunities across the SDK - [Testing](./docs/testing.md) - Unit vs integration test lanes and the offline guarantee - [Pre-PR Verification](./docs/pre-pr-verification.md) - Run `npm run verify:pr` before opening a pull request to confirm tests, docs, CI, and issue acceptance criteria +- [Pre-submission Verification](./docs/pre-submission-verification.md) - Run `npm run presubmit` before submitting a PR (lint, tests, coverage, build) - [Contribution Quality Gate](./docs/contribution-quality-gate.md) - Maintainer checklist and examples of incomplete vs acceptable issue work before approval - [Getting Started](./docs/getting-started.md) - Step-by-step guide to install, create wallets, fund accounts, check balances, and send payments - [End-to-End App Integration Blueprint](./docs/app_integration_blueprint.md) - App-level flow combining config, diagnostics, wallet, account, payments, transactions, Soroban, vault, security, and typed error handling @@ -101,25 +102,31 @@ alternatives and their cleanup steps. ## Local Verification -Run the full pre-push gate locally so CI stays green: +Before submitting a pull request, run the pre-submission command: ```bash -npm run verify +npm run presubmit ``` -`npm run verify` runs, in order: **lint** (`tsc --noEmit`) → **circular-dependency -check** → **unit tests** (`vitest run`) → **coverage** (`vitest run --coverage`) -→ **build** (`tsc`). It stops at the first failure. See -[Local Verification Workflow](./docs/local-verification.md) for step details, -when to run it, and failure-handling guidance. This mirrors what the repo's -automation checks when a PR is opened. +This is the contributor-facing pre-submission command. It runs the same +CI-parity pipeline as `npm run verify`: **lint** → **circular-dependency check** +→ **unit tests** → **coverage** → **build**, stops at the first failure, and +prints fix guidance. + +See [Pre-submission Verification](./docs/pre-submission-verification.md) for +usage and failure guidance. Details of each pipeline step also live in +[Local Verification Workflow](./docs/local-verification.md). + +```bash +npm run verify # same checks without step banners +``` ## Pull Request Expectations Every PR uses the [PR template](./.github/PULL_REQUEST_TEMPLATE.md), which requires you to state the related issue, implementation scope, **tests added** (or why tests don't -apply), the **`npm run verify`** output you ran locally, CI status, and +apply), the **`npm run verify` / `npm run presubmit`** output you ran locally, CI status, and acceptance-criteria coverage. A merged PR is not automatically payment-approved; reward eligibility is assessed separately. See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full checklist. diff --git a/docs/local-verification.md b/docs/local-verification.md index 048a52e..3c711f5 100644 --- a/docs/local-verification.md +++ b/docs/local-verification.md @@ -21,6 +21,10 @@ npm run verify All steps must pass locally before opening or updating a PR. +> **Contributor shortcut:** `npm run presubmit` runs this same pipeline with +> labeled steps and failure hints. Prefer it before submitting a PR — see +> [Pre-submission Verification](./pre-submission-verification.md). + ## When to run it - After finishing a change, **before** `git push`. diff --git a/docs/pre-pr-verification.md b/docs/pre-pr-verification.md index 604ec5f..f35fc1b 100644 --- a/docs/pre-pr-verification.md +++ b/docs/pre-pr-verification.md @@ -130,6 +130,7 @@ PocketPay SDK — Pre-PR Acceptance Verification ## Related docs - [CONTRIBUTING.md](../CONTRIBUTING.md) — contributor setup and PR checklist +- [Pre-submission Verification](./pre-submission-verification.md) — `npm run presubmit` CI-parity gate before opening a PR - [Contribution Quality Gate](./contribution-quality-gate.md) — maintainer pass/hold checklist before approval - [testing.md](./testing.md) — unit vs integration test lanes - [release-checklist.md](./release-checklist.md) — maintainer release gates (`npm run verify`) diff --git a/docs/pre-submission-verification.md b/docs/pre-submission-verification.md new file mode 100644 index 0000000..cfb0ce6 --- /dev/null +++ b/docs/pre-submission-verification.md @@ -0,0 +1,96 @@ +# Pre-submission Verification + +Run **one command** before opening or updating an SDK pull request. It mirrors +the local CI-parity pipeline so lint, typecheck, tests, coverage, and build +failures are caught on your machine instead of in CI. + +```bash +npm run presubmit +``` + +Aliases (same behaviour): + +```bash +npm run verify:presubmit +npm run verify # same checks, quieter (no step banners) +``` + +## What it runs + +`npm run presubmit` executes these steps **in order** and **stops at the first failure**: + +| Step | Command | Purpose | +| :--- | :--- | :--- | +| Lint / typecheck | `npm run lint` | `tsc --noEmit` — no type errors | +| Circular deps | `npm run check:circular` | No illegal import cycles in `src/` | +| Unit tests | `npm test` | Offline Vitest suite | +| Coverage | `npm run test:coverage` | Coverage report (v8; thresholds informational) | +| Build | `npm run build` | Package compiles to `dist/` | + +This is the contributor-facing pre-submission command for issue work. Use it +after your change is complete and before `git push` / opening the PR. + +## When to run it + +- After finishing a feature or bugfix, **before** submitting a PR +- After rebasing onto `main` +- Before requesting review on an updated PR + +For acceptance-criteria reminders and git-based docs/CI hints, also run +`npm run verify:pr` (see [Pre-PR Verification](./pre-pr-verification.md)). + +## Failure guidance + +| Failed step | What it means | How to fix | +| :--- | :--- | :--- | +| Lint / typecheck | TypeScript errors under `tsc --noEmit` | Fix the reported types; do not hide them with `@ts-ignore` | +| Circular dependency check | A new import cycle was introduced | Break the cycle — move shared code to a leaf module ([dependency map](./dependency_direction_map.md)) | +| Unit tests | A unit test failed | Read Vitest output; fix the cause (or the assertion). Keep tests offline ([testing.md](./testing.md)) | +| Coverage | Coverage runner failed | Run `npm install` so `@vitest/coverage-v8` is present | +| Build | `tsc` cannot emit `dist/` | Usually the same root cause as lint — resolve types first | + +After fixing, re-run: + +```bash +npm run presubmit +``` + +A green local run does **not** replace watching GitHub CI on the PR, but it +prevents most avoidable red checks. + +## Example success output + +```text +PocketPay SDK — Pre-submission verification +========================================== +… + +→ [1/5] Lint / typecheck (`npm run lint`) +✓ Lint / typecheck (4120ms) + +… + +✓ Pre-submission verification passed. + You are ready to push and open/update your PR. +``` + +## Example failure output + +```text +→ [3/5] Unit tests (offline) (`npm run test`) +… + +✗ Failed: Unit tests (offline) (1850ms) + Fix: Read the Vitest failure output and fix the cause … + +See docs/pre-submission-verification.md#failure-guidance for the full table. +Re-run `npm run presubmit` after fixing. +``` + +## Related docs + +- [Local Verification Workflow](./local-verification.md) — details of the `npm run verify` pipeline +- [Pre-PR Verification](./pre-pr-verification.md) — `npm run verify:pr` checklist / acceptance criteria +- [Contribution Quality Gate](./contribution-quality-gate.md) — maintainer pass/hold before approval +- [CONTRIBUTING.md](../CONTRIBUTING.md) — contributor setup +- [testing.md](./testing.md) — unit vs integration lanes diff --git a/docs/testing.md b/docs/testing.md index a00ddb6..95aaf08 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -55,5 +55,6 @@ occasionally non-deterministic. Keep them out of the critical path: the default | `npm run test:unit` | Unit suite (explicit alias of `npm test`) | | `npm run test:watch` | Unit suite in watch mode | | `npm run test:integration` | Integration suite (opt-in, needs the env flag)| -| `npm run verify` | Lint, circular-deps check, unit tests, and build | +| `npm run verify` | Lint, circular-deps check, unit tests, coverage, and build | +| `npm run presubmit` | Pre-submission command (same checks + step banners / failure hints) | | `npm run verify:pr` | Pre-PR script: automated checks + docs/CI/criteria reminders | \ No newline at end of file diff --git a/package.json b/package.json index 0fa3851..6da23c2 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "lint": "tsc --noEmit", "check:circular": "tsx scripts/check-circular-deps.ts", "verify": "npm run lint && npm run check:circular && npm run test && npm run test:coverage && npm run build", + "presubmit": "tsx scripts/presubmit.ts", + "verify:presubmit": "tsx scripts/presubmit.ts", "verify:pr": "tsx scripts/verify-acceptance.ts", "prepack": "npm run build", "prepublishOnly": "npm run build", diff --git a/scripts/presubmit.ts b/scripts/presubmit.ts new file mode 100644 index 0000000..c65ae91 --- /dev/null +++ b/scripts/presubmit.ts @@ -0,0 +1,132 @@ +#!/usr/bin/env node +/** + * Pre-submission verification command (issue #392). + * + * One local command contributors run before opening or updating an SDK PR. + * Mirrors the `npm run verify` CI-parity pipeline with clear step output and + * failure guidance. + */ +import { spawnSync } from 'child_process'; +import path from 'path'; + +const ROOT = path.resolve(__dirname, '..'); + +interface CheckStep { + id: string; + label: string; + /** npm script name shown in logs (e.g. lint, test:coverage). */ + npmScript: string; + command: string; + args: string[]; + /** Short fix hint shown when this step fails. */ + failureHint: string; +} + +const STEPS: CheckStep[] = [ + { + id: 'lint', + label: 'Lint / typecheck', + npmScript: 'lint', + command: 'npm', + args: ['run', 'lint'], + failureHint: + 'Fix TypeScript errors reported by `tsc --noEmit`. Do not silence them with `@ts-ignore`.', + }, + { + id: 'circular', + label: 'Circular dependency check', + npmScript: 'check:circular', + command: 'npm', + args: ['run', 'check:circular'], + failureHint: + 'Break the import cycle (move shared types/helpers into a leaf module). See docs/dependency_direction_map.md.', + }, + { + id: 'test', + label: 'Unit tests (offline)', + npmScript: 'test', + command: 'npm', + args: ['test'], + failureHint: + 'Read the Vitest failure output and fix the cause (or the test if the assertion is wrong). Keep unit tests offline — see docs/testing.md.', + }, + { + id: 'coverage', + label: 'Coverage report', + npmScript: 'test:coverage', + command: 'npm', + args: ['run', 'test:coverage'], + failureHint: + 'Ensure `@vitest/coverage-v8` is installed (`npm install`). Thresholds are informational (0) unless raised in config.', + }, + { + id: 'build', + label: 'Package build', + npmScript: 'build', + command: 'npm', + args: ['run', 'build'], + failureHint: + 'Resolve `tsc` emit errors (usually the same root cause as lint). Confirm `dist/` is produced.', + }, +]; + +function printHelp(): void { + console.log(` +PocketPay SDK — Pre-submission verification + +Usage: + npm run presubmit + npm run verify:presubmit + +Runs the same local CI-parity checks as \`npm run verify\`: + lint → check:circular → test → test:coverage → build + +Stops at the first failure and prints fix guidance. + +Documentation: docs/pre-submission-verification.md +`); +} + +function runStep(step: CheckStep): { ok: boolean; durationMs: number } { + const started = Date.now(); + const result = spawnSync(step.command, step.args, { + cwd: ROOT, + stdio: 'inherit', + shell: process.platform === 'win32', + }); + return { ok: result.status === 0, durationMs: Date.now() - started }; +} + +function main(argv: string[]): number { + if (argv.includes('--help') || argv.includes('-h')) { + printHelp(); + return 0; + } + + console.log('PocketPay SDK — Pre-submission verification'); + console.log('=========================================='); + console.log('Run this before opening or updating a pull request.'); + console.log('Pipeline: lint → circular → test → coverage → build\n'); + + for (let i = 0; i < STEPS.length; i++) { + const step = STEPS[i]!; + console.log(`→ [${i + 1}/${STEPS.length}] ${step.label} (\`npm run ${step.npmScript}\`)`); + const result = runStep(step); + if (!result.ok) { + console.error(`\n✗ Failed: ${step.label} (${result.durationMs}ms)`); + console.error(` Fix: ${step.failureHint}`); + console.error('\nSee docs/pre-submission-verification.md#failure-guidance for the full table.'); + console.error('Re-run `npm run presubmit` after fixing.\n'); + return 1; + } + console.log(`✓ ${step.label} (${result.durationMs}ms)\n`); + } + + console.log('✓ Pre-submission verification passed.'); + console.log(' You are ready to push and open/update your PR.'); + console.log(' Optional next: `npm run verify:pr` for acceptance-criteria reminders.'); + console.log(' See docs/pre-submission-verification.md\n'); + return 0; +} + +process.exit(main(process.argv.slice(2)));