Generate coverage gaps from API schema#95
Conversation
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
There was a problem hiding this comment.
Pull request overview
Adds internal tooling to compare this Go client’s implemented endpoints/models against the upstream Tailscale OpenAPI schema and generate markdown “coverage gap” reports.
Changes:
- Introduces an OpenAPI loader + fetcher, plus CLIs/Make targets to refresh the schema and generate reports.
- Adds repo analysis to extract implemented operations and JSON model fields from the Go client source.
- Generates and checks in initial coverage-gap markdown reports under
docs/coverage-gaps/.
Reviewed changes
Copilot reviewed 13 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tools/internal/repoanalysis/repo.go |
AST-based extraction of client operations and JSON leaf fields from structs. |
tools/internal/openapi/spec.go |
Loads YAML OpenAPI and extracts operations + reachable model leaf properties. |
tools/internal/openapi/fetch.go |
Downloads the OpenAPI schema and writes it to disk. |
tools/internal/openapi/fetch_test.go |
Unit test for schema fetching. |
tools/internal/coverage/report.go |
Builds endpoint/model coverage reports and renders markdown outputs. |
tools/internal/coverage/report_test.go |
Integration-style test for report generation on a synthetic repo/spec. |
tools/fetch-openapi/main.go |
CLI to fetch and write the upstream OpenAPI schema. |
tools/coverage-gaps/main.go |
CLI to analyze repo + schema and emit markdown coverage reports. |
README.md |
Documents the new tooling and Make targets. |
Makefile |
Adds openapi-refresh and coverage-gaps targets (and local .gocache). |
go.mod |
Adds gopkg.in/yaml.v3 as a direct dependency. |
docs/coverage-gaps/summary.md |
Generated summary report snapshot. |
docs/coverage-gaps/endpoint-coverage.md |
Generated endpoint coverage snapshot. |
docs/coverage-gaps/model-coverage.md |
Generated model coverage snapshot. |
docs/coverage-gaps/model-property-coverage.md |
Generated property-level coverage snapshot. |
.gitignore |
Ignores .gocache directory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if len(call.Args) < 3 { | ||
| return true | ||
| } | ||
|
|
||
| method := httpMethod(call.Args[1]) | ||
| path, ok := requestPath(call.Args[2]) | ||
| if method == "" || !ok { | ||
| return true | ||
| } |
There was a problem hiding this comment.
Operation extraction only handles buildRequest calls where the URL argument is an inline call to buildURL/buildTailnetURL. In this repo, several client methods build a URL into a local variable (often to add query params) and then pass that identifier to buildRequest (e.g., UsersResource.List, KeysResource.List, LoggingResource.GetNetworkFlowLogs). Those operations will be silently skipped here, causing false “missing endpoint” results in the coverage report. Consider extending requestPath/extractOperations to resolve *ast.Ident URL arguments back to their defining buildURL/buildTailnetURL call within the same function (a simple assignment/short-decl scan is usually enough) so these endpoints are counted.
| | POST | `/device/{deviceId}/expire` | `expireDeviceKey` | Devices | Expire a device's key | | ||
| | PATCH | `/tailnet/{tailnet}/device-attributes` | `batchUpdateCustomDevicePostureAttributes` | Devices | Batch update custom device posture attributes | | ||
| | GET | `/tailnet/{tailnet}/keys` | `listTailnetKeys` | Keys | List tailnet keys | | ||
| | GET | `/tailnet/{tailnet}/logging/configuration` | `listConfigurationAuditLogs` | Logging | List configuration audit logs | | ||
| | GET | `/tailnet/{tailnet}/logging/network` | `listNetworkFlowLogs` | Logging | List network flow logs | |
There was a problem hiding this comment.
This report marks several endpoints as “Missing From The Client” (e.g., GET /tailnet/{tailnet}/keys and GET /tailnet/{tailnet}/logging/network), but the repository does implement these operations (they build a tailnet URL into a local variable, mutate query params, then pass the identifier to buildRequest). This suggests the analyzer is under-detecting operations; after fixing repoanalysis to handle URL variables, this generated report should be regenerated.
| | DELETE | `/user-invites/{userInviteId}` | `deleteUserInvite` | UserInvites | Delete a user invite | | ||
| | GET | `/user-invites/{userInviteId}` | `getUserInvite` | UserInvites | Get a user invite | | ||
| | POST | `/user-invites/{userInviteId}/resend` | `resendUserInvite` | UserInvites | Resend a user invite | | ||
| | GET | `/tailnet/{tailnet}/users` | `listUsers` | Users | List users | |
There was a problem hiding this comment.
GET /tailnet/{tailnet}/users is listed here as missing, but the client has a UsersResource.List implementation that builds the URL in a variable (to add query params) and then calls buildRequest. This appears to be another false negative from the analyzer; once repoanalysis handles identifier URL arguments, this generated report should be regenerated.
| | GET | `/tailnet/{tailnet}/users` | `listUsers` | Users | List users | |
No description provided.