name: CI/CD Pipeline on: push: branches: [ main, develop ] pull_request: branches: [ main ] release: types: [ published ] permissions: contents: read security-events: write actions: read jobs: test: name: Test on Node.js ${{ matrix.node-version }} and ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: node-version: [16.x, 18.x, 20.x, 22.x] os: [ubuntu-latest, windows-latest, macos-latest] exclude: # Exclude older Node versions on macOS ARM64 to avoid compatibility issues - os: macos-latest node-version: 16.x steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: 'npm' - name: Install SQLite (Ubuntu) if: matrix.os == 'ubuntu-latest' run: sudo apt-get update && sudo apt-get install -y sqlite3 - name: Install SQLite (macOS) if: matrix.os == 'macos-latest' run: brew install sqlite - name: Install SQLite (Windows) if: matrix.os == 'windows-latest' run: | choco install sqlite --no-progress # Refresh environment and add SQLite to PATH $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") # Add SQLite to PATH for subsequent steps echo "C:\ProgramData\chocolatey\lib\SQLite\tools" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append shell: powershell - name: Install dependencies run: npm ci - name: Run tests run: npm test - name: Test CLI functionality run: | # Test CLI help node bin/cli.js help # Create test database with cross-platform commands mkdir -p test-ci # Create test database if [ "${{ matrix.os }}" = "windows-latest" ]; then sqlite3.exe test-ci/test.db "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT); INSERT INTO users (name) VALUES ('Test User');" else sqlite3 test-ci/test.db "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT); INSERT INTO users (name) VALUES ('Test User');" fi # Test backup creation node bin/cli.js create test-ci/test.db --backup-dir test-ci/backups # Test backup listing node bin/cli.js list test-ci/test.db --backup-dir test-ci/backups # Test backup verification BACKUP_FILE=$(find test-ci/backups -name "*.db" | head -1) if [ -n "$BACKUP_FILE" ]; then node bin/cli.js verify "$BACKUP_FILE" fi # Cleanup rm -rf test-ci shell: bash - name: Test examples run: | # Create sample database for examples mkdir -p data # Create test database if [ "${{ matrix.os }}" = "windows-latest" ]; then sqlite3.exe data/app.db "CREATE TABLE sample (id INTEGER PRIMARY KEY, name TEXT); INSERT INTO sample (name) VALUES ('Sample Data');" else sqlite3 data/app.db "CREATE TABLE sample (id INTEGER PRIMARY KEY, name TEXT); INSERT INTO sample (name) VALUES ('Sample Data');" fi # Run examples with timeout (cross-platform) if [ "${{ matrix.os }}" = "windows-latest" ]; then # Windows approach - run with a simple timeout mechanism node -e " const { spawn } = require('child_process'); const child = spawn('node', ['examples/basic-usage.js'], { stdio: 'inherit' }); const timeout = setTimeout(() => { console.log('Example timeout reached, terminating...'); child.kill(); }, 30000); child.on('exit', (code) => { clearTimeout(timeout); console.log('Example finished with code:', code); process.exit(0); }); " || true else timeout 30s node examples/basic-usage.js || true fi # Cleanup rm -rf data shell: bash lint: name: Lint and Code Quality runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Check package structure run: | # Verify main files exist test -f lib/index.js test -f lib/index.d.ts test -f bin/cli.js test -f README.md test -f package.json # Verify CLI is executable test -x bin/cli.js # Verify TypeScript definitions node -e "const pkg = require('./package.json'); console.log('Package structure OK:', pkg.name, pkg.version)" - name: Validate package.json run: npm pkg fix --dry-run - name: Check for vulnerabilities run: npm audit --audit-level=moderate publish: name: Publish to npm needs: [test, lint] runs-on: ubuntu-latest if: github.event_name == 'release' && github.event.action == 'published' steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm' registry-url: 'https://registry.npmjs.org' - name: Install SQLite run: sudo apt-get update && sudo apt-get install -y sqlite3 - name: Install dependencies run: npm ci - name: Run final tests run: npm test - name: Publish to npm run: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} update-version: name: Auto-increment version on main runs-on: ubuntu-latest needs: [test, lint] if: github.ref == 'refs/heads/main' && github.event_name == 'push' permissions: contents: write steps: - name: Checkout code uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm' - name: Configure git run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - name: Bump version run: | # Only bump version if not already a version commit if [[ ! "${{ github.event.head_commit.message }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then npm version patch --no-git-tag-version git add package.json git commit -m "$(node -p "require('./package.json').version")" || exit 0 git push fi security: name: Security Scan runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write steps: - name: Checkout code uses: actions/checkout@v4 - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: scan-type: 'fs' scan-ref: '.' format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: 'trivy-results.sarif'