diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c0785c..4a04e88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,6 +43,9 @@ jobs: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' && github.event_name == 'push' + outputs: + version_changed: ${{ steps.version.outputs.changed }} + new_version: ${{ steps.version.outputs.version }} steps: - name: Checkout repository @@ -68,6 +71,7 @@ jobs: NPM_VERSION=$(npm view supabase-sql-dev-runner version 2>/dev/null || echo "0.0.0") if [ "$PACKAGE_VERSION" != "$NPM_VERSION" ]; then echo "changed=true" >> $GITHUB_OUTPUT + echo "version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT echo "Version changed from $NPM_VERSION to $PACKAGE_VERSION" else echo "changed=false" >> $GITHUB_OUTPUT @@ -135,3 +139,33 @@ jobs: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + create-release: + needs: [test, publish-npm] + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.publish-npm.outputs.version_changed == 'true' + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Create git tag + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "v${{ needs.publish-npm.outputs.new_version }}" -m "Release v${{ needs.publish-npm.outputs.new_version }}" + git push origin "v${{ needs.publish-npm.outputs.new_version }}" + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ needs.publish-npm.outputs.new_version }} + name: v${{ needs.publish-npm.outputs.new_version }} + generate_release_notes: true + make_latest: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index fd5da8c..fb56d4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,27 +5,79 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.1] - 2025-12-11 + +### Changed + +- Updated README documentation with clearer examples and setup instructions + ## [1.0.0] - 2025-12-10 ### Added - Initial release -- Comprehensive test suite with 165 tests across 8 test files -- Test coverage for: CLI parsing, connection handling, logging, file scanning, SQL execution, and integration flows +- Comprehensive test suite with 352 tests across 13 test files +- Test coverage for: CLI parsing, connection handling, logging, file scanning, SQL execution, watcher, UI components, and integration flows + +#### Core Features - Sequential SQL file execution with alphabetical ordering - Transaction safety with automatic rollback on errors - Savepoint support for granular rollback per file - Human confirmation prompt before execution (configurable) -- CLI tool with extensive options (`sql-runner`, `supabase-sql-runner`) -- Programmatic API with `SqlRunner` class and `runSqlScripts` convenience function -- Dual module support (ESM and CommonJS) -- Full TypeScript type definitions -- SSL enabled by default for secure connections -- Password masking in logs -- Verbose mode for detailed output -- Dry run mode to preview execution +- Watch mode (`--watch`) for development - re-runs on file changes with 30-second countdown +- Dry run mode (`--dry-run`) to preview execution without making changes - File filtering with `--only` and `--skip` options -- Environment file loading (`.env` support) -- Execution logging to file +- Configuration file support (`.sqlrunnerrc`, `sql-runner.config.js`, etc.) + +#### CLI Tool +- CLI commands: `sql-runner`, `supabase-sql-runner`, `npx sql-runner` +- Extensive CLI options for all features +- Colored output with symbols for better readability +- Progress display during execution +- Argument combination validation (warns about conflicting options) + +#### Programmatic API +- `SqlRunner` class for full control +- `runSqlScripts` convenience function for simple usage - Progress callbacks (`onBeforeFile`, `onAfterFile`, `onComplete`, `onError`) - SQL NOTICE message handling via `onNotice` callback + +#### Error Handling +- 10 specialized error detectors for common connection issues: + - DNS resolution errors (direct connection vs pooler) + - Connection refused/timeout + - Authentication failures + - SSL/TLS errors + - Prepared statement conflicts (transaction pooler) + - Database not found + - Too many connections + - Invalid URL format +- Helpful error messages with actionable suggestions +- PostgreSQL error details: code, line number, column, and visual pointer to error location +- Graceful handling of connection termination after rollback + +#### Security +- SQL injection prevention with quoted identifiers for savepoints +- Password masking in logs +- SSL enabled by default for secure connections + +#### Logging +- Execution logging to file (`./logs/sql-runner.log`) +- Separate error log (`./logs/sql-runner-error.log`) +- Graceful handling of log file write failures +- Verbose mode for detailed output + +#### Build & Distribution +- Dual module support (ESM and CommonJS) +- Full TypeScript type definitions (`.d.ts` and `.d.cts`) +- Zero external dependencies except `pg` and `cosmiconfig` + +#### UI System +- Custom terminal UI components (box, banner, table, spinner) +- Theming support with configurable colors +- Cross-platform symbol support (Unicode with ASCII fallbacks) + +#### Developer Experience +- Environment file loading (`.env` support) +- CLAUDE.md documentation for AI assistants +- SOLID architecture throughout the codebase diff --git a/README.md b/README.md index e4f2274..95821df 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # supabase-sql-dev-runner [![npm version](https://img.shields.io/npm/v/supabase-sql-dev-runner.svg)](https://www.npmjs.com/package/supabase-sql-dev-runner) +[![GitHub](https://img.shields.io/github/stars/4riel/supabase-sql-dev-runner?style=social)](https://github.com/4riel/supabase-sql-dev-runner) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) Run SQL scripts on Supabase with transaction safety. No more copy-pasting into the dashboard. @@ -20,7 +21,27 @@ This tool fixes that. One command, all your SQL files run in order, wrapped in a ## Install ```bash +# npm npm install supabase-sql-dev-runner + +# yarn +yarn add supabase-sql-dev-runner + +# pnpm +pnpm add supabase-sql-dev-runner +``` + +Or run directly without installing: + +```bash +# npm +npx sql-runner + +# yarn +yarn dlx supabase-sql-dev-runner + +# pnpm +pnpm dlx supabase-sql-dev-runner ``` ## Setup @@ -295,6 +316,195 @@ const result = await runner.run({ }); ``` +### Advanced API + +The library exports additional utilities for advanced use cases: + +#### Connection utilities + +```typescript +import { + parseDatabaseUrl, + maskPassword, + validateDatabaseUrl, + getErrorMessage, +} from 'supabase-sql-dev-runner'; + +// Parse a database URL into its components +const config = parseDatabaseUrl('postgres://user:pass@host:5432/db'); +// { host, port, database, user, password, ssl } + +// Mask password for safe logging +const safeUrl = maskPassword('postgres://user:secret@host/db'); +// "postgres://user:****@host/db" + +// Validate URL format +const isValid = validateDatabaseUrl(url); // boolean +``` + +#### File scanner utilities + +```typescript +import { + scanSqlFiles, + readSqlFile, + createSavepointName, + DEFAULT_FILE_PATTERN, + DEFAULT_IGNORE_PATTERN, +} from 'supabase-sql-dev-runner'; + +// Scan directory for SQL files +const files = await scanSqlFiles('./sql', { + pattern: DEFAULT_FILE_PATTERN, // /\.sql$/ + ignorePattern: DEFAULT_IGNORE_PATTERN, // /^_ignored|README/ +}); + +// Read SQL file content +const sql = await readSqlFile('./sql/01_tables.sql'); + +// Generate savepoint name from filename +const savepoint = createSavepointName('01_tables.sql'); +// "sp_01_tables_sql" +``` + +#### Custom loggers + +```typescript +import { + ConsoleLogger, + SilentLogger, + createLogger, +} from 'supabase-sql-dev-runner'; + +// Console logger with file logging +const logger = new ConsoleLogger({ logDirectory: './logs' }); + +// Silent logger for tests/CI +const silent = new SilentLogger(); + +// Factory function +const auto = createLogger({ + logDirectory: './logs', // or null to disable + silent: false, // true for SilentLogger +}); + +// Use with SqlRunner +const runner = new SqlRunner({ + databaseUrl: process.env.DATABASE_URL, + sqlDirectory: './sql', + logger: silent, // No console output +}); +``` + +#### Watch mode programmatic + +```typescript +import { startWatcher } from 'supabase-sql-dev-runner'; + +const cleanup = startWatcher({ + directory: './sql', + pattern: /\.sql$/, + countdownSeconds: 30, + onExecute: async () => { + await runner.run({ skipConfirmation: true }); + }, + logger: { + info: (msg) => console.log(msg), + warning: (msg) => console.warn(msg), + }, +}); + +// Stop watching when done +process.on('SIGINT', cleanup); +``` + +#### Low-level SQL executor + +```typescript +import { SqlExecutor } from 'supabase-sql-dev-runner'; + +// For direct transaction control +const executor = new SqlExecutor(connectionConfig, logger); +await executor.connect(); +await executor.beginTransaction(); + +try { + await executor.executeSql('CREATE TABLE test (id INT)', 'setup'); + await executor.commit(); +} catch (error) { + await executor.rollback(); +} + +await executor.disconnect(); +``` + +#### Error handling extensibility + +The error system is built on SOLID principles and fully extensible: + +```typescript +import { + // Handler and helpers + ConnectionErrorHandler, + getConnectionErrorHelp, + formatConnectionErrorHelp, + + // Formatters (choose output format) + ConsoleErrorFormatter, // Styled terminal output + SimpleErrorFormatter, // Plain text + JsonErrorFormatter, // JSON (for logging systems) + MarkdownErrorFormatter, // Markdown (for docs/issues) + + // For custom detectors + BaseErrorDetector, + DefaultErrorDetectorRegistry, +} from 'supabase-sql-dev-runner'; + +// Quick usage +const help = getConnectionErrorHelp(error, databaseUrl); +console.error(formatConnectionErrorHelp(help)); + +// Custom formatter +const handler = new ConnectionErrorHandler({ + formatter: new JsonErrorFormatter({ pretty: true }), +}); +const jsonHelp = handler.format(handler.getHelp(error, { databaseUrl })); +``` + +### TypeScript types + +All types are exported for full TypeScript support: + +```typescript +import type { + // Core types + SqlRunnerConfig, + RunOptions, + Logger, + + // Results + FileExecutionResult, + ExecutionSummary, + SqlRunnerError, + + // Connection + ConnectionConfig, + + // Events + SqlRunnerEvent, + + // Error handling + ConnectionContext, + ErrorHelp, + ErrorDetector, + ErrorFormatter, + ErrorDetectorRegistry, + + // Watch mode + WatchOptions, +} from 'supabase-sql-dev-runner'; +``` + ## How It Works - Files execute in alphabetical order (`00_`, `01_`, `02_`...) @@ -303,6 +513,45 @@ const result = await runner.run({ - If any file fails, all changes roll back - Files starting with `_ignored` or `README` are skipped +## Watch Mode + +Watch mode (`--watch` or `-w`) provides a smooth development experience with smart execution timing: + +```bash +sql-runner --watch +``` + +### How it works + +1. **File change detected** - When you save a `.sql` file, a 30-second countdown starts +2. **Countdown display** - You'll see: `Running in 30s... (save again to reset)` +3. **Reset on save** - Saving again resets the countdown, so you can make multiple quick edits +4. **Auto-execute** - After 30 seconds of no changes, your SQL files run automatically +5. **Queued changes** - If you save during execution, the next run is queued + +### First run behavior + +On the first run, you'll need to confirm execution (unless using `-y`). After that, watch mode automatically skips confirmation for subsequent runs. + +### Typical workflow + +```bash +# Start watching with verbose output +sql-runner --watch --verbose + +# Now edit your SQL files... +# - Save 01_tables.sql → countdown starts (30s) +# - Save again with a fix → countdown resets (30s) +# - Wait for countdown → files execute +# - See results, make more changes → repeat +``` + +### Tips + +- Combine with `--verbose` to see detailed execution info +- Use `--skip "06_seed.sql"` to exclude slow seed files during development +- Press `Ctrl+C` to stop watching gracefully + ## Configuration | Option | Default | Description | @@ -376,10 +625,71 @@ interface ExecutionSummary { - Make sure they don't start with `_ignored` - Use `--verbose` to see which files are found +## Release Process + +### Changelog Format + +We follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format: + +```markdown +## [X.Y.Z] - YYYY-MM-DD + +### Added +- New features + +### Changed +- Changes to existing functionality + +### Deprecated +- Features to be removed in future + +### Removed +- Removed features + +### Fixed +- Bug fixes + +### Security +- Security fixes +``` + +### Version Bump Checklist + +1. **Update version** in `package.json` +2. **Run build** to sync version across files: + ```bash + npm run build + ``` +3. **Update CHANGELOG.md** with new version section +4. **Run tests** to ensure everything passes: + ```bash + npm test + ``` +5. **Verify version** shows correctly: + ```bash + npx sql-runner --version + ``` + +### Changelog Categories + +Use these categories to organize changes in each version: + +| Category | Use for | +|----------|---------| +| **Core Features** | Main functionality (execution, transactions, etc.) | +| **CLI Tool** | Command-line interface changes | +| **Programmatic API** | Library API changes | +| **Error Handling** | Error detection and messages | +| **Security** | Security-related changes | +| **Logging** | Logging and output changes | +| **Build & Distribution** | Build system, package format | +| **UI System** | Terminal UI components | +| **Developer Experience** | DX improvements, docs | + ## License MIT --- -Made with ❤️ by [4riel](https://github.com/4riel) +Made with ❤️ by [4riel](https://github.com/4riel) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index eac5c85..78a2559 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "supabase-sql-dev-runner", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "supabase-sql-dev-runner", - "version": "1.0.0", + "version": "1.0.1", "license": "MIT", "dependencies": { "cosmiconfig": "^9.0.0", diff --git a/package.json b/package.json index 5f4de81..74df7e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "supabase-sql-dev-runner", - "version": "1.0.0", + "version": "1.0.1", "description": "Execute SQL scripts sequentially on Supabase PostgreSQL with transaction safety, savepoints, and automatic rollback. Perfect for development database setup and AI agent integration.", "author": "4riel", "license": "MIT", diff --git a/src/cli/help.ts b/src/cli/help.ts index 882c4b1..0492cd1 100644 --- a/src/cli/help.ts +++ b/src/cli/help.ts @@ -33,7 +33,7 @@ interface PackageInfo { */ const DEFAULT_PACKAGE_INFO: PackageInfo = { name: 'sql-runner', - version: '1.0.0', + version: '1.0.1', }; /** diff --git a/src/ui/renderer.ts b/src/ui/renderer.ts index 1cde0b9..0c8011b 100644 --- a/src/ui/renderer.ts +++ b/src/ui/renderer.ts @@ -51,7 +51,7 @@ export class UIRenderer { constructor(options: UIRendererOptions = {}) { this.name = options.name ?? 'sql-runner'; - this.version = options.version ?? '1.0.0'; + this.version = options.version ?? '1.0.1'; this.stream = options.stream ?? process.stdout; this.silent = options.silent ?? false; }