Skip to content

Commit cc75f63

Browse files
committed
chore: prettify agent instructions
1 parent 20ab979 commit cc75f63

2 files changed

Lines changed: 89 additions & 16 deletions

File tree

.github/AGENT_INSTRUCTIONS.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ pgcov/
3939
│ ├── database/ # PostgreSQL connection & temp DB management
4040
│ ├── discovery/ # Test/source file discovery
4141
│ ├── instrument/ # SQL/PL/pgSQL instrumentation
42-
│ ├── parser/ # SQL parsing (pg_query_go wrapper)
42+
│ ├── parser/ # SQL token scanning (pglex-based, not pg_query_go)
4343
│ ├── report/ # Report formatters (JSON, LCOV, HTML)
44-
── runner/ # Test execution & parallelization
45-
│ └── logger/ # Logging utilities
44+
── runner/ # Test execution & parallelization
45+
── internal/testutil/ # Shared test helpers (Docker-based Postgres)
4646
├── testdata/ # Integration test fixtures
4747
├── examples/ # Usage examples
4848
```
@@ -108,7 +108,7 @@ pgcov/
108108
### Key Technologies
109109

110110
- **CLI Framework**: `urfave/cli/v3` (subcommands, flags, env var binding)
111-
- **SQL Parser**: `pganalyze/pg_query_go/v6` (official PostgreSQL parser)
111+
- **SQL Parser**: `pashagolub/pglex` (token-level scanner — NOT pg_query_go/AST-based)
112112
- **PostgreSQL Driver**: `jackc/pgx/v5` (native protocol, LISTEN/NOTIFY)
113113

114114
### Core Workflows
@@ -118,8 +118,8 @@ pgcov/
118118
```
119119
1. Discovery: Find *_test.sql files recursively
120120
2. Source Discovery: Find co-located .sql files (same directory)
121-
3. Parsing: Parse source files with pg_query_go
122-
4. Instrumentation: Rewrite AST to inject NOTIFY calls
121+
3. Parsing: Token-split source files with pglex into `[]*Statement`
122+
4. Instrumentation: Rewrite function bodies to inject NOTIFY calls at statement boundaries
123123
5. Temp DB Creation: CREATE DATABASE pgcov_test_{timestamp}_{random}
124124
6. Deployment: Load instrumented sources into temp DB
125125
7. Execution: Run test file in temp DB
@@ -132,10 +132,12 @@ pgcov/
132132

133133
```
134134
Channel: coverage_signal
135-
Payload: file:line[:branch]
136-
Example: src/auth.sql:42 or src/auth.sql:42:branch_1
135+
Payload: file:startByteOffset:byteLength
136+
Example: src/auth.sql:128:42
137137
```
138138

139+
See `instrument.ParseSignalID` for the canonical parser. Positions are byte-offsets into the source file, not line numbers.
140+
139141
#### Temporary Database Naming
140142

141143
```
@@ -239,12 +241,12 @@ if err != nil {
239241

240242
### Logging
241243

244+
There is **no** `internal/logger` package. Use `fmt.Printf` guarded by a `verbose` flag:
245+
242246
```go
243-
// Use internal/logger package
244-
logger := logger.New(verbose)
245-
logger.Info("Discovering tests in %s", path)
246-
logger.Debug("Found test file: %s", filePath)
247-
logger.Error("Failed to parse: %v", err)
247+
if verbose {
248+
fmt.Printf("Discovering tests in %s\n", path)
249+
}
248250
```
249251

250252
### Naming Conventions
@@ -604,7 +606,7 @@ ALTER USER testuser CREATEDB;
604606

605607
**Solution**:
606608

607-
1. Check file with `pg_query_go` directly
609+
1. Check file syntax using pglex or a local PostgreSQL instance
608610
2. Verify PostgreSQL version compatibility
609611
3. Enable verbose logging: `pgcov run --verbose`
610612

@@ -622,7 +624,7 @@ pgcov run --timeout=60s ./tests/
622624

623625
### External Resources
624626

625-
- [pg_query_go Documentation](https://pkg.go.dev/github.com/pganalyze/pg_query_go/v6)
627+
- [pglex Documentation](https://github.com/pashagolub/pglex)
626628
- [pgx Driver Documentation](https://pkg.go.dev/github.com/jackc/pgx/v5)
627629
- [PostgreSQL SQL Syntax](https://www.postgresql.org/docs/current/sql.html)
628630
- [LCOV Format Specification](https://linux.die.net/man/1/geninfo)
@@ -634,7 +636,7 @@ pgcov run --timeout=60s ./tests/
634636
- `internal/database`: PostgreSQL connection management
635637
- `internal/discovery`: Test/source file discovery
636638
- `internal/instrument`: SQL instrumentation via AST rewriting
637-
- `internal/parser`: SQL parsing wrapper (pg_query_go)
639+
- `internal/parser`: SQL token scanner (pglex)
638640
- `internal/report`: Coverage report formatters
639641
- `internal/runner`: Test execution and parallelization
640642

.github/copilot-instructions.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# pgcov — Copilot Instructions
2+
3+
PostgreSQL test runner and coverage tool — pure Go (no CGO, no external CLI tools).
4+
5+
## Execution Pipeline
6+
7+
1. `internal/discovery` — walk dirs, classify `.sql` files as `Source` or `Test` (`*_test.sql`)
8+
2. `internal/parser` — token-split SQL into `[]*Statement` using `pashagolub/pglex` (pure Go lexer, not pg_query_go)
9+
3. `internal/instrument` — per-statement: PL/pgSQL/SQL function bodies get `PERFORM pg_notify('coverage_signal', '<relPath>:<startByteOffset>:<byteLength>')` injected; all other DDL/DML is marked implicitly covered
10+
4. `internal/database` — create isolated temp DB (`pgcov_test_<yyyymmdd_hhmmss>_<4-byte hex>`), deploy instrumented sources, execute the test `.sql` file, then `DROP DATABASE ... WITH (FORCE)`
11+
5. `internal/database.Listener` — dedicated `pgx.Conn` running `LISTEN coverage_signal`; forwards signals to a buffered channel (size 1000)
12+
6. `internal/coverage.Collector` — thread-safe (`sync.Mutex`) aggregation of signals into `Coverage.Positions[file]["startPos:length"]`
13+
7. `internal/report``Formatter` interface (`Format`, `FormatString`, `Name`); implementations `json.go`, `lcov.go`, `html.go`; factory `GetFormatter(FormatType)`
14+
15+
**Parallelism**: `runner.WorkerPool` fans out `*testJob` over a buffered channel; each worker owns its own temp DB — no shared state at all.
16+
17+
**Config flow**: `pkg/types.Config` is the canonical struct; aliased in `internal/cli`; CLI flags applied via `ApplyFlagsToConfig`; default coverage output path `.pgcov/coverage.json`.
18+
19+
## Key Files
20+
21+
| Path | Role |
22+
|---|---|
23+
| `cmd/pgcov/main.go` | `run` / `report` subcommands via `urfave/cli/v3`; wires flags → `ApplyFlagsToConfig` |
24+
| `internal/parser/parse.go` | `pglex` token scan → `[]*Statement` with `Type`, `Language`, `RawSQL`, byte offsets |
25+
| `internal/instrument/instrumenter.go` | `instrumentBody()` single-pass token scan; `instrumentStatement()` dispatch |
26+
| `internal/instrument/location.go` | `ParseSignalID(id) (file, start, length, err)` — canonical signal parser |
27+
| `internal/database/tempdb.go` | `CreateTempDatabase` / `DestroyTempDatabase` — preserves pool SSL config |
28+
| `internal/database/listener.go` | `NewListener` → goroutine `receiveLoop`; `Signals()` returns `<-chan CoverageSignal` |
29+
| `internal/runner/executor.go` | `Executor.Execute` orchestrates one test; `filterSourcesByDirectory` scopes sources |
30+
| `internal/runner/parallel.go` | `WorkerPool.ExecuteParallel` — falls back to sequential when `maxWorkers==1` |
31+
| `internal/coverage/collector.go` | `CollectFromRuns``AddPosition`; `Coverage()` returns snapshot |
32+
| `internal/report/formatter.go` | `GetFormatter(FormatType)` factory |
33+
| `pkg/types/types.go` | `Config`, `CoverageSignal` shared types |
34+
| `internal/testutil/postgres.go` | Docker-based Postgres setup for integration tests (`testcontainers-go`) |
35+
36+
## Build & Test
37+
38+
```bash
39+
# Build (no CGO required — pure Go)
40+
go build ./cmd/pgcov
41+
42+
# Unit tests
43+
go test ./...
44+
45+
# Integration tests (require Docker)
46+
go test ./... -run Integration
47+
```
48+
49+
VS Code tasks: **Build pgcov** (`Ctrl+Shift+B`), **Unit Test**, **Coverage Report**.
50+
51+
## Project-Specific Conventions
52+
53+
**Signal ID format**`"<relPath>:<startByteOffset>:<byteLength>"` (byte offsets, not line numbers). Always use `instrument.ParseSignalID` to parse, never split manually.
54+
55+
**Source scoping** — each test only sees sources from its own directory. `filterSourcesByDirectory` in `executor.go` enforces this. Never pass sources from sibling directories.
56+
57+
**Logging** — no logger package exists. Use `fmt.Printf(...)` guarded by `if verbose`. Do not add a logger dependency.
58+
59+
**Error wrapping** — always `fmt.Errorf("context: %w", err)`, never bare `return err`.
60+
61+
**Adding a report format** — implement `report.Formatter` (`Format`, `FormatString`, `Name`), add a `case` in `GetFormatter`, add `_test.go` alongside.
62+
63+
**Adding a config flag** — add field to `pkg/types.Config`, wire in `ApplyFlagsToConfig` in `internal/cli/config.go`, support `PGCOV_*` env var via `urfave/cli/v3` `EnvVars`.
64+
65+
## Hard Constraints
66+
67+
- Never use `psql` or shell exec — always `pgx` directly
68+
- Never require PostgreSQL extensions
69+
- Instrumentation must not change semantic behavior of tested SQL
70+
- Each test gets its own temp DB — no shared DB state, ever
71+
- Do not add CGO dependencies — the project is intentionally pure Go

0 commit comments

Comments
 (0)