Skip to content

Commit 56a9c26

Browse files
authored
Merge pull request #5 from grove-platform/DOCSP-56681
Add report testable-code command
2 parents 24ed0f4 + 652bb61 commit 56a9c26

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+7101
-498
lines changed

AGENTS.md

Lines changed: 125 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This document provides essential context for LLMs performing development tasks i
1313
- Analyze composable definitions and usage across projects
1414
- Compare files across documentation versions
1515
- Count documentation pages and tested code examples
16+
- Generate reports on testable code examples from analytics data
1617

1718
**Target Users**: MongoDB technical writers performing maintenance, scoping work, and reporting.
1819

@@ -36,29 +37,42 @@ audit-cli/
3637
│ │ └── composables/ # Analyze composable definitions and usage
3738
│ ├── compare/ # Compare files across versions
3839
│ │ └── file-contents/ # Compare file contents
39-
│ └── count/ # Count documentation content
40-
│ ├── tested-examples/ # Count tested code examples
41-
│ └── pages/ # Count documentation pages
40+
│ ├── count/ # Count documentation content
41+
│ │ ├── tested-examples/ # Count tested code examples
42+
│ │ └── pages/ # Count documentation pages
43+
│ └── report/ # Generate reports from documentation data
44+
│ └── testable-code/ # Analyze testable code examples from analytics
4245
├── internal/ # Internal packages (not importable externally)
4346
│ ├── config/ # Configuration management
4447
│ │ ├── config.go # Config loading from file/env/args
45-
│ │ └── config_test.go # Config tests
48+
│ │ ├── config_test.go # Config tests
49+
│ │ ├── url_mapping.go # URL-to-source-file mapping via Snooty Data API
50+
│ │ └── url_mapping_test.go # URL mapping tests
51+
│ ├── language/ # Programming language utilities
52+
│ │ ├── language.go # Language normalization, extensions, products
53+
│ │ └── language_test.go # Language tests
4654
│ ├── projectinfo/ # MongoDB docs project structure utilities
47-
│ │ ├── pathresolver.go # Path resolution
48-
│ │ ├── source_finder.go # Source directory detection
55+
│ │ ├── pathresolver.go # Path resolution
56+
│ │ ├── products.go # Content directory to product mapping
57+
│ │ ├── source_finder.go # Source directory detection
4958
│ │ └── version_resolver.go # Version path resolution
50-
│ └── rst/ # RST parsing utilities
51-
│ ├── parser.go # Generic parsing with includes
52-
│ ├── directive_parser.go # Directive parsing
53-
│ ├── directive_regex.go # Regex patterns for directives
54-
│ ├── parse_procedures.go # Procedure parsing (core logic)
55-
│ ├── get_procedure_variations.go # Variation extraction
56-
│ └── rstspec.go # Fetch and parse canonical rstspec.toml
59+
│ ├── rst/ # RST parsing utilities
60+
│ │ ├── parser.go # Generic parsing with includes
61+
│ │ ├── directive_parser.go # Directive parsing with language resolution
62+
│ │ ├── directive_regex.go # Regex patterns for directives
63+
│ │ ├── parse_procedures.go # Procedure parsing (core logic)
64+
│ │ ├── get_procedure_variations.go # Variation extraction
65+
│ │ ├── rstspec.go # Fetch and parse canonical rstspec.toml
66+
│ │ └── yaml_steps_parser.go # Parse YAML steps files for code examples
67+
│ └── snooty/ # Snooty.toml parsing utilities
68+
│ ├── snooty.go # Parse snooty.toml, find project config
69+
│ └── snooty_test.go # Snooty tests
5770
├── testdata/ # Test fixtures (auto-ignored by Go build)
5871
│ ├── input-files/source/ # Test RST files
5972
│ ├── expected-output/ # Expected extraction results
6073
│ ├── compare/ # Compare command test data
61-
│ └── count-test-monorepo/ # Count command test data
74+
│ ├── count-test-monorepo/ # Count command test data
75+
│ └── testable-code-test/ # Testable code report test data
6276
├── bin/ # Build output directory
6377
├── docs/ # Additional documentation
6478
│ └── PROCEDURE_PARSING.md # Detailed procedure parsing logic
@@ -393,6 +407,103 @@ func NewExtractCommand() *cobra.Command {
393407
- Support multiple output formats (text, JSON) where applicable
394408
- Use consistent formatting (headers with `=` separators, indentation)
395409

410+
### Network Request Caching
411+
412+
All network requests to external APIs should implement caching to avoid repeated requests and support offline usage. The caching pattern is implemented in `internal/config/url_mapping.go` (for Snooty Data API) and `internal/rst/rstspec.go` (for rstspec.toml).
413+
414+
**Cache Location**: `~/.audit-cli/` directory
415+
- URL mapping cache: `~/.audit-cli/url-mapping-cache.json`
416+
- Rstspec cache: `~/.audit-cli/rstspec-cache.json`
417+
418+
**Cache TTL**: 24 hours (configurable per cache type)
419+
420+
**Implementation Pattern**:
421+
422+
1. **Define cache constants**:
423+
```go
424+
const CacheTTL = 24 * time.Hour
425+
const CacheDir = ".audit-cli"
426+
const CacheFileName = "my-cache.json"
427+
```
428+
429+
2. **Create cache struct** with timestamp and data:
430+
```go
431+
type MyCache struct {
432+
Timestamp time.Time `json:"timestamp"`
433+
Data MyData `json:"data"`
434+
}
435+
```
436+
437+
3. **Implement cache functions**:
438+
```go
439+
// getCachePath returns the path to the cache file
440+
func getCachePath() (string, error) {
441+
homeDir, err := os.UserHomeDir()
442+
if err != nil {
443+
return "", fmt.Errorf("failed to get home directory: %w", err)
444+
}
445+
return filepath.Join(homeDir, CacheDir, CacheFileName), nil
446+
}
447+
448+
// loadCache loads from cache, returns error if missing or expired
449+
func loadCache() (*MyData, error) {
450+
// Read file, unmarshal JSON, check TTL
451+
}
452+
453+
// saveCache saves data to cache with current timestamp
454+
func saveCache(data *MyData) error {
455+
// Create directory if needed, marshal JSON, write file
456+
}
457+
458+
// fetchFromAPI fetches fresh data from the network
459+
func fetchFromAPI() (*MyData, error) {
460+
// HTTP request, parse response
461+
}
462+
```
463+
464+
4. **Main fetch function with fallback logic**:
465+
```go
466+
func FetchData() (*MyData, error) {
467+
// Try cache first
468+
data, err := loadCache()
469+
if err == nil {
470+
return data, nil
471+
}
472+
473+
// Cache miss or expired, try network
474+
data, fetchErr := fetchFromAPI()
475+
if fetchErr != nil {
476+
// Network failed - try expired cache as offline fallback
477+
// (read cache file without TTL check)
478+
if expiredData := loadExpiredCache(); expiredData != nil {
479+
fmt.Fprintf(os.Stderr, "Warning: Using expired cache\n")
480+
return expiredData, nil
481+
}
482+
return nil, fetchErr
483+
}
484+
485+
// Save to cache for next time
486+
if saveErr := saveCache(data); saveErr != nil {
487+
fmt.Fprintf(os.Stderr, "Warning: Could not save cache: %v\n", saveErr)
488+
}
489+
490+
return data, nil
491+
}
492+
```
493+
494+
**Key Behaviors**:
495+
- Cache is stored in user's home directory for persistence across sessions
496+
- Expired cache is used as fallback when network is unavailable (offline support)
497+
- Cache save failures are logged as warnings but don't fail the operation
498+
- JSON format for easy debugging and human readability
499+
500+
**When Adding New Network Calls**:
501+
1. Follow the pattern above
502+
2. Add cache file name constant
503+
3. Implement the four cache functions
504+
4. Use the same `~/.audit-cli/` directory for consistency
505+
5. Consider appropriate TTL (24 hours is default, adjust if data changes more/less frequently)
506+
396507
## Key Design Decisions
397508

398509
### RST Parsing Strategy

CHANGELOG.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,60 @@ All notable changes to audit-cli will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.3.0] - 2025-01-07
9+
10+
### Added
11+
12+
#### Report Commands
13+
- `report testable-code` - Analyze testable code examples on pages from analytics data
14+
- Takes a CSV file with page rankings and URLs from analytics
15+
- Resolves URLs to source files using the Snooty Data API
16+
- Collects code examples (literalinclude, code, code-block, io-code-block) from each page
17+
- Determines product context from tabs, composables, and content directories
18+
- Identifies tested vs testable vs "maybe testable" code examples
19+
- Supports multiple output formats: text, JSON, CSV
20+
- Flags:
21+
- `--format, -f` - Output format (text, json, csv)
22+
- `--output, -o` - Output file path (default: stdout)
23+
- `--details` - Show detailed per-product breakdown
24+
25+
#### Internal Packages
26+
- `internal/language` - Programming language utilities (refactored from code-examples)
27+
- Language normalization (e.g., "ts" → "typescript", "py" → "python")
28+
- File extension mapping for all supported languages
29+
- Language-to-product mapping for MongoDB drivers
30+
- Non-driver language detection (bash, json, yaml, etc.)
31+
- MongoDB Shell language detection
32+
- Language resolution with priority: argument > option > file extension
33+
- `internal/snooty` - Snooty.toml parsing utilities
34+
- Parse snooty.toml configuration files
35+
- Find project snooty.toml from source file paths
36+
- Build composable ID-to-title mappings
37+
- Extract project and version from snooty.toml paths
38+
- `internal/config/url_mapping.go` - URL-to-source-file mapping
39+
- Fetches project metadata from Snooty Data API
40+
- Resolves documentation URLs to source file paths
41+
- Caches API responses for 24 hours in `~/.audit-cli/`
42+
- Supports offline usage with expired cache fallback
43+
- `internal/projectinfo/products.go` - Content directory to product mapping
44+
- Maps driver content directories to display product names
45+
- Supports all MongoDB driver documentation projects
46+
- `internal/rst/yaml_steps_parser.go` - YAML steps file parsing
47+
- Parses legacy YAML-native code examples in steps files
48+
- Extracts code blocks with language and content
49+
- `internal/rst/directive_parser.go` - Enhanced directive parsing
50+
- Added `ResolveLanguage()` method to Directive type
51+
- Added `ResolveLanguage()` method to SubDirective type
52+
- Language resolution follows priority: argument > option > file extension
53+
54+
### Changed
55+
56+
- Refactored language handling from `commands/extract/code-examples/language.go` to `internal/language` package
57+
- All language-related utilities now centralized and reusable
58+
- Added product mapping and non-driver language detection
59+
- Enhanced `internal/rst` directive parsing with language resolution methods
60+
- Updated `analyze usage` to use new language package for file extension handling
61+
862
## [0.2.0] - 2025-12-12
963

1064
### Added

0 commit comments

Comments
 (0)