Skip to content

Commit a6f68bd

Browse files
committed
Add config-docs-generator tool for automated documentation generation
1 parent e84fb4e commit a6f68bd

File tree

10 files changed

+3543
-13
lines changed

10 files changed

+3543
-13
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ testnet/index.html
6161
/testnet/helium/target/
6262
/contrib/tools/puppet-chain/target/
6363
/contrib/core-contract-tests/.cache/
64+
/contrib/tools/config-docs-generator/target/
6465

6566
# These are backup files generated by rustfmt
6667
**/*.rs.bk

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ members = [
1010
"contrib/tools/relay-server",
1111
"libsigner",
1212
"stacks-signer",
13-
"testnet/stacks-node"]
13+
"testnet/stacks-node",
14+
"contrib/tools/config-docs-generator"]
1415

1516
# Dependencies we want to keep the same between workspace members
1617
[workspace.dependencies]

Dockerfile

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
1-
FROM rust:bookworm AS build
1+
# Use a specific nightly toolchain for reproducible builds
2+
FROM rustlang/rust@sha256:04690ffa09cddd358b349272173155319f384e57816614eea0840ec7f9422862
23

3-
ARG STACKS_NODE_VERSION="No Version Info"
4-
ARG GIT_BRANCH='No Branch Info'
5-
ARG GIT_COMMIT='No Commit Info'
4+
# Set the working directory for building
5+
WORKDIR /build
66

7-
WORKDIR /src
7+
# Copy the entire project to build the binaries
88
COPY . .
9-
RUN mkdir /out
10-
RUN rustup toolchain install stable
11-
RUN cargo build --features monitoring_prom,slog_json --release
12-
RUN cp -R target/release/. /out
139

14-
FROM debian:bookworm-slim
15-
COPY --from=build /out/stacks-node /out/stacks-signer /out/stacks-inspect /bin/
16-
CMD ["stacks-node", "mainnet"]
10+
# Pre-build the config-docs-generator binaries during image build
11+
RUN cargo build --package config-docs-generator --release
12+
13+
# Set the working directory where the project will be mounted at runtime
14+
WORKDIR /project_root
15+
16+
# Set environment variables for generate-config-docs.sh
17+
ENV PROJECT_ROOT=/project_root
18+
ENV BUILD_ROOT=/build
19+
ENV CARGO_HOME=/project_root/.cargo
20+
ENV EXTRACT_DOCS_BIN=/build/target/release/extract-docs
21+
ENV GENERATE_MARKDOWN_BIN=/build/target/release/generate-markdown
22+
ENV SKIP_BUILD=true
23+
24+
# Set the entrypoint to run the config docs generation script
25+
ENTRYPOINT ["/build/contrib/tools/config-docs-generator/generate-config-docs.sh"]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "config-docs-generator"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[[bin]]
7+
name = "extract-docs"
8+
path = "src/extract_docs.rs"
9+
10+
[[bin]]
11+
name = "generate-markdown"
12+
path = "src/generate_markdown.rs"
13+
14+
[dependencies]
15+
serde = { version = "1.0", features = ["derive"] }
16+
serde_json = "1.0"
17+
clap = { version = "4.0", features = ["derive"] }
18+
regex = "1.0"
19+
anyhow = "1.0"
20+
once_cell = "1.18"
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Configuration Documentation Generator
2+
3+
A tool that automatically generates comprehensive Markdown documentation for Stacks node TOML configuration options. The documentation is extracted directly from Rust source code comments and generates a complete configuration reference.
4+
5+
## Quick Start
6+
7+
### Using Docker (Recommended)
8+
9+
The easiest way to generate configuration documentation:
10+
11+
```bash
12+
# Build the Docker image (one-time setup)
13+
docker build -t config-docs-generator .
14+
15+
# Generate documentation
16+
docker run --rm -v "$(pwd):/project_root" --user "$(id -u):$(id -g)" config-docs-generator
17+
```
18+
19+
This approach:
20+
- Uses a consistent nightly Rust environment
21+
- Generates `docs/generated/configuration-reference.md`
22+
23+
### Using Local Setup (Alternative)
24+
25+
If you prefer to run without Docker:
26+
27+
```bash
28+
# Install nightly toolchain if needed
29+
rustup toolchain install nightly
30+
31+
# Generate documentation
32+
./contrib/tools/config-docs-generator/generate-config-docs.sh
33+
```
34+
35+
## What It Does
36+
37+
The tool processes these configuration structs from the Stacks codebase:
38+
- `BurnchainConfig``[burnchain]` section
39+
- `NodeConfig``[node]` section
40+
- `MinerConfig``[miner]` section
41+
- `ConnectionOptionsFile``[connection_options]` section
42+
- `FeeEstimationConfigFile``[fee_estimation]` section
43+
- `EventObserverConfigFile``[event_observer]` section
44+
- `InitialBalanceFile``[initial_balances]` section
45+
46+
For each configuration field, it extracts:
47+
- Field documentation from `///` comments
48+
- Default values (including constant references)
49+
- Usage notes and examples
50+
- Deprecation warnings
51+
52+
## Output Files
53+
54+
- **Primary**: `docs/generated/configuration-reference.md` - Complete configuration reference
55+
- **Intermediate**: `target/doc-generation/extracted-config-docs.json` - Raw extracted data
56+
57+
## Adding New Configuration Structs
58+
59+
### 1. Update the Target List
60+
61+
Edit `contrib/tools/config-docs-generator/generate-config-docs.sh`:
62+
63+
```bash
64+
TARGET_STRUCTS="BurnchainConfig,NodeConfig,MinerConfig,YourNewConfig"
65+
```
66+
67+
### 2. Document Your Struct
68+
69+
Add proper documentation to your Rust configuration struct:
70+
71+
```rust
72+
/// Configuration for your new feature.
73+
///
74+
/// This controls how the feature operates and integrates
75+
/// with the existing node functionality.
76+
#[derive(Debug, Clone, Serialize, Deserialize)]
77+
pub struct YourNewConfig {
78+
/// Enable or disable the new feature.
79+
/// ---
80+
/// @default: `false`
81+
/// @notes:
82+
/// - Requires restart to take effect
83+
/// - May impact performance when enabled
84+
/// @toml_example: |
85+
/// enabled = true
86+
pub enabled: bool,
87+
88+
/// Timeout for feature operations in milliseconds.
89+
/// ---
90+
/// @default: [`DEFAULT_TIMEOUT`]
91+
pub timeout: u64,
92+
}
93+
```
94+
95+
### Supported Annotations
96+
97+
- **@default**: Default value (supports constant references like `[`CONSTANT_NAME`]`)
98+
- **@notes**: Bullet-pointed usage notes
99+
- **@deprecated**: Deprecation message
100+
- **@toml_example**: Example TOML configuration
101+
102+
### 3. Add Section Mapping (Optional)
103+
104+
If you want a custom TOML section name, edit `src/generate_markdown.rs`:
105+
106+
```rust
107+
fn struct_to_section_name(struct_name: &str) -> String {
108+
match struct_name {
109+
"YourNewConfig" => "[your_custom_section]".to_string(),
110+
// ... existing mappings
111+
_ => format!("[{}]", struct_name.to_lowercase()),
112+
}
113+
}
114+
```
115+
116+
### 4. Generate and Verify
117+
118+
```bash
119+
# Using Docker (recommended)
120+
docker run --rm -v "$(pwd):/project_root" --user "$(id -u):$(id -g)" config-docs-generator
121+
122+
# OR using local setup
123+
./contrib/tools/config-docs-generator/generate-config-docs.sh
124+
125+
# Check that your struct appears
126+
grep -A 5 "your_custom_section" docs/generated/configuration-reference.md
127+
```
128+
129+
## How It Works
130+
131+
The tool uses a three-step process:
132+
133+
1. **Extract**: Uses `cargo +nightly rustdoc --output-format json` to generate documentation JSON
134+
2. **Parse**: Extracts field information, resolves constant references across crates
135+
3. **Generate**: Converts to Markdown with proper cross-references and formatting
136+
137+
The process is automated by the shell script which coordinates building the tools and running the extraction/generation pipeline.
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
# Colors for output
6+
RED='\033[0;31m'
7+
GREEN='\033[0;32m'
8+
YELLOW='\033[1;33m'
9+
NC='\033[0m' # No Color
10+
11+
# Configuration - Allow environment variable overrides
12+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13+
PROJECT_ROOT="${PROJECT_ROOT:-$(cd "$SCRIPT_DIR/../../../" && pwd)}"
14+
BUILD_ROOT="${BUILD_ROOT:-$PROJECT_ROOT}"
15+
OUTPUT_DIR="$PROJECT_ROOT/docs/generated"
16+
TEMP_DIR="$PROJECT_ROOT/target/doc-generation"
17+
CONFIG_SOURCE_FILE="$PROJECT_ROOT/stackslib/src/config/mod.rs"
18+
19+
# Paths to binaries - allow override via environment
20+
EXTRACT_DOCS_BIN="${EXTRACT_DOCS_BIN:-$BUILD_ROOT/target/release/extract-docs}"
21+
GENERATE_MARKDOWN_BIN="${GENERATE_MARKDOWN_BIN:-$BUILD_ROOT/target/release/generate-markdown}"
22+
23+
# Check if binaries are pre-built (skip build step)
24+
SKIP_BUILD="${SKIP_BUILD:-false}"
25+
if [[ -f "$EXTRACT_DOCS_BIN" && -f "$GENERATE_MARKDOWN_BIN" ]]; then
26+
SKIP_BUILD=true
27+
fi
28+
29+
log_info() {
30+
echo -e "${GREEN}[INFO]${NC} $1"
31+
}
32+
33+
log_warn() {
34+
echo -e "${YELLOW}[WARN]${NC} $1"
35+
}
36+
37+
log_error() {
38+
echo -e "${RED}[ERROR]${NC} $1"
39+
}
40+
41+
cleanup() {
42+
if [[ -d "$TEMP_DIR" ]]; then
43+
rm -rf "$TEMP_DIR"
44+
fi
45+
}
46+
47+
trap cleanup EXIT
48+
49+
main() {
50+
log_info "Starting config documentation generation..."
51+
52+
# Create necessary directories
53+
mkdir -p "$OUTPUT_DIR"
54+
mkdir -p "$TEMP_DIR"
55+
56+
cd "$PROJECT_ROOT"
57+
58+
# Verify source file exists
59+
if [[ ! -f "$CONFIG_SOURCE_FILE" ]]; then
60+
log_error "Config source file not found: $CONFIG_SOURCE_FILE"
61+
exit 1
62+
fi
63+
64+
# Step 1: Build the documentation generation tools (skip if pre-built)
65+
if [[ "$SKIP_BUILD" == "true" ]]; then
66+
log_info "Using pre-built documentation generation tools..."
67+
else
68+
log_info "Building documentation generation tools..."
69+
cargo build --package config-docs-generator --release
70+
fi
71+
72+
# Step 2: Extract documentation from source code using rustdoc
73+
log_info "Extracting configuration documentation using rustdoc..."
74+
EXTRACTED_JSON="$TEMP_DIR/extracted-config-docs.json"
75+
# List of specific Rust struct names to be documented
76+
# NOTE: This variable must be manually updated if this list changes
77+
# (e.g., new config structs are added or removed from the project)
78+
TARGET_STRUCTS="BurnchainConfig,NodeConfig,MinerConfig,ConnectionOptionsFile,FeeEstimationConfigFile,EventObserverConfigFile,InitialBalanceFile"
79+
"$EXTRACT_DOCS_BIN" \
80+
--package stackslib \
81+
--structs "$TARGET_STRUCTS" \
82+
--output "$EXTRACTED_JSON"
83+
84+
# Step 3: Generate Markdown
85+
log_info "Generating Markdown documentation..."
86+
MARKDOWN_OUTPUT="$OUTPUT_DIR/configuration-reference.md"
87+
"$GENERATE_MARKDOWN_BIN" \
88+
--input "$EXTRACTED_JSON" \
89+
--output "$MARKDOWN_OUTPUT"
90+
91+
log_info "Documentation generation complete!"
92+
log_info "Generated files:"
93+
log_info " - Configuration reference: $MARKDOWN_OUTPUT"
94+
log_info " - Intermediate JSON: $EXTRACTED_JSON"
95+
96+
# Verify output
97+
if [[ -f "$MARKDOWN_OUTPUT" ]]; then
98+
WORD_COUNT=$(wc -w < "$MARKDOWN_OUTPUT")
99+
log_info "Generated Markdown contains $WORD_COUNT words"
100+
else
101+
log_error "Expected output file not found: $MARKDOWN_OUTPUT"
102+
exit 1
103+
fi
104+
}
105+
106+
# Help function
107+
show_help() {
108+
cat << EOF
109+
generate-config-docs.sh - Generate configuration documentation for Stacks node
110+
111+
USAGE:
112+
$0 [OPTIONS]
113+
114+
OPTIONS:
115+
-h, --help Show this help message
116+
117+
DESCRIPTION:
118+
This script generates comprehensive Markdown documentation for all TOML
119+
configuration options available in the Stacks node. The documentation is
120+
automatically extracted from Rust source code comments.
121+
122+
The process involves:
123+
1. Building the documentation generation tools
124+
2. Extracting configuration struct documentation from source code
125+
3. Converting to Markdown format
126+
127+
Source file: stackslib/src/config/mod.rs
128+
129+
OUTPUT:
130+
docs/generated/configuration-reference.md
131+
132+
EOF
133+
}
134+
135+
# Parse command line arguments
136+
while [[ $# -gt 0 ]]; do
137+
case $1 in
138+
-h|--help)
139+
show_help
140+
exit 0
141+
;;
142+
*)
143+
log_error "Unknown option: $1"
144+
show_help
145+
exit 1
146+
;;
147+
esac
148+
done
149+
150+
main "$@"

0 commit comments

Comments
 (0)