feat(scripts): add tutorial code sync tool#135
Conversation
Adds a script to sync inline code blocks in tutorial docs with platform-tutorials source files, with check/diff modes for CI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe pull request introduces a tutorial code synchronization system that automatically syncs code blocks in documentation with source files from a platform-tutorials repository. It includes a GitHub Actions workflow for CI validation, a Python utility script with multiple discovery strategies, YAML configuration mapping, and supporting documentation. Changes
Sequence Diagram(s)sequenceDiagram
participant GHA as GitHub Actions
participant Script as sync_tutorial_code.py
participant YML as tutorial-code-map.yml
participant Src as platform-tutorials
participant Doc as Documentation
GHA->>Script: Execute with --check flag
Script->>YML: Load YAML configuration
YML-->>Script: Return source-to-doc mappings
loop For each mapping
Script->>Src: Read source file
Src-->>Script: Source code content
Script->>Doc: Locate code block (caption/sync/tab)
Doc-->>Script: Code block content
Script->>Script: Compare source vs doc block
Script-->>GHA: Report MATCH/DIFF/DRIFT
end
Script-->>GHA: Exit with status (0 if check passes)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
.github/workflows/check-tutorial-sync.yml (1)
24-24: Pinpyyamlversion to matchrequirements.txt.The workflow installs
pyyamlwithout a version constraint, whilerequirements.txtpinspyyaml==6.0. This creates potential inconsistency between CI and local development.Suggested fix
- - run: pip install pyyaml + - run: pip install pyyaml==6.0Or better yet, install from requirements.txt to ensure consistency:
- - run: pip install pyyaml + - run: pip install -r requirements.txt🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/check-tutorial-sync.yml at line 24, The workflow step that runs "pip install pyyaml" should be made deterministic: either pin the package to the same version used in requirements.txt by changing it to "pip install pyyaml==6.0" or (preferred) replace that step with installing from requirements.txt via "pip install -r requirements.txt" so CI uses the exact "pyyaml==6.0" specified in requirements.txt.scripts/tutorial-sync/sync_tutorial_code.py (2)
187-188: Consider extracting error message to a constant or custom exception.Static analysis (TRY003) flags the inline message. This is a minor style preference—you can optionally extract to a custom exception class for cleaner exception handling, but it's not critical.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/tutorial-sync/sync_tutorial_code.py` around lines 187 - 188, The inline error message raised by ValueError in the else branch that checks block_id (the raise ValueError(f"Unknown block_id type: {block_id}") in sync_tutorial_code.py) should be extracted for cleaner handling: either move the message string to a module-level constant (e.g., UNKNOWN_BLOCK_ID_MSG) and reference it in the ValueError, or define a small custom exception class (e.g., UnknownBlockIDError) and raise that with the formatted message; update any callers/tests to catch the new exception or the constant message as appropriate.
119-121: Potential off-by-one for empty code blocks.
code_start = fm.end() + 1assumes a newline immediately follows the fence opener (e.g.,```javascript\n). If the fence opener is at EOF or the code block is malformed without a trailing newline,code_startcould exceed the content length or produce incorrect offsets.This is likely an edge case given the controlled document format, but consider adding a bounds check:
Optional defensive fix
code_start = fm.end() + 1 # skip the newline after ```language + if code_start > len(content): + continue🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/tutorial-sync/sync_tutorial_code.py` around lines 119 - 121, The code computes code_start = fm.end() + 1 and can exceed the document length for malformed or EOF fence-openers; update the logic in the loop that uses fm and code_start (where you parse fenced code blocks) to check the bounds after computing code_start (compare code_start against len(content)) and skip/continue if it is out of range so you don't index past the end of content or produce incorrect offsets.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In @.github/workflows/check-tutorial-sync.yml:
- Line 24: The workflow step that runs "pip install pyyaml" should be made
deterministic: either pin the package to the same version used in
requirements.txt by changing it to "pip install pyyaml==6.0" or (preferred)
replace that step with installing from requirements.txt via "pip install -r
requirements.txt" so CI uses the exact "pyyaml==6.0" specified in
requirements.txt.
In `@scripts/tutorial-sync/sync_tutorial_code.py`:
- Around line 187-188: The inline error message raised by ValueError in the else
branch that checks block_id (the raise ValueError(f"Unknown block_id type:
{block_id}") in sync_tutorial_code.py) should be extracted for cleaner handling:
either move the message string to a module-level constant (e.g.,
UNKNOWN_BLOCK_ID_MSG) and reference it in the ValueError, or define a small
custom exception class (e.g., UnknownBlockIDError) and raise that with the
formatted message; update any callers/tests to catch the new exception or the
constant message as appropriate.
- Around line 119-121: The code computes code_start = fm.end() + 1 and can
exceed the document length for malformed or EOF fence-openers; update the logic
in the loop that uses fm and code_start (where you parse fenced code blocks) to
check the bounds after computing code_start (compare code_start against
len(content)) and skip/continue if it is out of range so you don't index past
the end of content or produce incorrect offsets.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fa82123d-da3d-4167-b82d-8af1154fedb6
📒 Files selected for processing (8)
.github/workflows/check-tutorial-sync.ymlCLAUDE.mdREADME.mdconf.pydocs/tutorials/create-and-fund-a-wallet.mdrequirements.txtscripts/tutorial-sync/sync_tutorial_code.pyscripts/tutorial-sync/tutorial-code-map.yml
Summary
scripts/tutorial-sync/sync_tutorial_code.py— a Python script that keeps inline code blocks in tutorial docs synchronized with the runnable source files indashpay/platform-tutorialsscripts/tutorial-sync/tutorial-code-map.yml— YAML config mapping 28 source files to their corresponding code blocks across 19 tutorial pagessync(update docs in-place),--check(CI drift detection),--diff(show unified diffs){code-block}with:caption:, tab-items with:sync:, and tab-items matched by titlepyyamldependency torequirements.txtContext
Tutorial code in
docs/tutorials/was manually duplicated fromdashpay/platform-tutorials. When the runnable code changed, both repos had to be updated independently, leading to drift. This script makesplatform-tutorialsthe single source of truth — run it to pull code into the docs, or use--checkin CI to catch when they diverge.Usage
Preview build: https://dash-docs-platform--135.org.readthedocs.build/en/135/
Summary by CodeRabbit
New Features
Documentation
Chores