Skip to content

Commit 7f86d88

Browse files
authored
Merge pull request #1525 from o1-labs/dw/doc-website-caml
Website + CI: add check to verify OCaml references
2 parents 55c55f7 + f3ab3e7 commit 7f86d88

File tree

9 files changed

+693
-33
lines changed

9 files changed

+693
-33
lines changed
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
#!/usr/bin/env bash
2+
# Script to validate OCaml reference comments in Rust code
3+
# Usage: ./.github/scripts/check-ocaml-refs.sh [--repo REPO_URL] [--branch BRANCH] [--update]
4+
5+
set -euo pipefail
6+
7+
# Default configuration
8+
OCAML_REPO="${OCAML_REPO:-https://github.com/MinaProtocol/mina.git}"
9+
OCAML_BRANCH="${OCAML_BRANCH:-compatible}"
10+
UPDATE_MODE="${UPDATE_MODE:-false}"
11+
RUST_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
12+
13+
# Parse arguments
14+
while [[ $# -gt 0 ]]; do
15+
case $1 in
16+
--repo)
17+
OCAML_REPO="$2"
18+
shift 2
19+
;;
20+
--branch)
21+
OCAML_BRANCH="$2"
22+
shift 2
23+
;;
24+
--update)
25+
UPDATE_MODE="true"
26+
shift
27+
;;
28+
*)
29+
echo "Unknown option: $1"
30+
echo "Usage: ./.github/scripts/check-ocaml-refs.sh [--repo REPO_URL] [--branch BRANCH] [--update]"
31+
exit 1
32+
;;
33+
esac
34+
done
35+
36+
echo "Checking OCaml references against ${OCAML_REPO} (branch: ${OCAML_BRANCH})"
37+
38+
# Create temporary directory
39+
TEMP_DIR=$(mktemp -d)
40+
trap 'rm -rf "$TEMP_DIR"' EXIT
41+
42+
# Extract GitHub owner and repo from URL (e.g., https://github.com/MinaProtocol/mina.git)
43+
GITHUB_URL_PATTERN="https://github.com/([^/]+)/(.+)"
44+
if [[ "$OCAML_REPO" =~ $GITHUB_URL_PATTERN ]]; then
45+
GITHUB_OWNER="${BASH_REMATCH[1]}"
46+
GITHUB_REPO="${BASH_REMATCH[2]%.git}" # Remove .git suffix if present
47+
else
48+
echo "Error: Repository URL must be a GitHub URL"
49+
exit 1
50+
fi
51+
52+
# Get current commit hash for the branch using GitHub API
53+
echo "Fetching current commit from ${OCAML_BRANCH}..."
54+
CURRENT_COMMIT=$(curl -s "https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/commits/${OCAML_BRANCH}" | grep -o '"sha": "[^"]*"' | head -1 | cut -d'"' -f4)
55+
56+
if [ -z "$CURRENT_COMMIT" ]; then
57+
echo "Error: Could not fetch current commit for branch ${OCAML_BRANCH}"
58+
exit 1
59+
fi
60+
61+
echo "Current OCaml commit: ${CURRENT_COMMIT}"
62+
63+
# Find all Rust files with OCaml references
64+
cd "${RUST_ROOT}"
65+
RUST_FILES=$(rg -l "^/// OCaml reference:" --type rust || true)
66+
67+
if [ -z "$RUST_FILES" ]; then
68+
echo "No OCaml references found in Rust code"
69+
exit 0
70+
fi
71+
72+
# Use temporary files to accumulate results
73+
RESULTS_FILE="${TEMP_DIR}/results.txt"
74+
touch "$RESULTS_FILE"
75+
76+
echo ""
77+
echo "Validating references..."
78+
echo "========================"
79+
80+
# Process each file
81+
echo "$RUST_FILES" | while IFS= read -r rust_file; do
82+
# Extract OCaml reference comments from the file
83+
awk '
84+
/^\/\/\/ OCaml reference:/ {
85+
ref = $0
86+
getline
87+
if ($0 ~ /^\/\/\/ Commit:/) {
88+
commit = $0
89+
getline
90+
if ($0 ~ /^\/\/\/ Last verified:/) {
91+
verified = $0
92+
print ref
93+
print commit
94+
print verified
95+
print "---"
96+
}
97+
}
98+
}
99+
' "$rust_file" | while IFS= read -r line; do
100+
if [[ "$line" == "/// OCaml reference:"* ]]; then
101+
# Extract file path and line range
102+
# Format: src/lib/mina_base/transaction_status.ml L:9-113
103+
FULL_REF="${line#/// OCaml reference: }"
104+
OCAML_PATH="${FULL_REF%% L:*}"
105+
LINE_RANGE=$(echo "$FULL_REF" | grep -o 'L:[0-9-]*' | sed 's/L://' || echo "")
106+
107+
# Read next two lines
108+
read -r commit_line
109+
read -r _verified_line
110+
read -r _separator
111+
112+
COMMIT="${commit_line#/// Commit: }"
113+
# LAST_VERIFIED could be extracted from _verified_line if needed for future validation
114+
115+
# Fetch the OCaml file from the current branch
116+
CURRENT_FILE="${TEMP_DIR}/current_${rust_file//\//_}_${OCAML_PATH//\//_}"
117+
CURRENT_URL="https://raw.githubusercontent.com/${GITHUB_OWNER}/${GITHUB_REPO}/${OCAML_BRANCH}/${OCAML_PATH}"
118+
119+
if ! curl -sf "$CURRENT_URL" -o "$CURRENT_FILE"; then
120+
echo "INVALID|${rust_file}|${OCAML_PATH}|FILE_NOT_FOUND" >> "$RESULTS_FILE"
121+
echo "❌ INVALID: ${rust_file}"
122+
echo " OCaml file not found: ${OCAML_PATH}"
123+
else
124+
# Validate line range if specified
125+
RANGE_VALID=true
126+
if [ -n "$LINE_RANGE" ]; then
127+
FILE_LINES=$(wc -l < "$CURRENT_FILE")
128+
# START_LINE is not currently used but could be useful for validation
129+
# START_LINE=$(echo "$LINE_RANGE" | cut -d'-' -f1)
130+
END_LINE=$(echo "$LINE_RANGE" | cut -d'-' -f2)
131+
132+
if [ "$END_LINE" -gt "$FILE_LINES" ]; then
133+
echo "INVALID|${rust_file}|${OCAML_PATH}|LINE_RANGE_EXCEEDED|L:${LINE_RANGE}|${FILE_LINES}" >> "$RESULTS_FILE"
134+
echo "❌ INVALID: ${rust_file}"
135+
echo " Line range L:${LINE_RANGE} exceeds file length (${FILE_LINES} lines): ${OCAML_PATH}"
136+
RANGE_VALID=false
137+
fi
138+
fi
139+
140+
if [ "$RANGE_VALID" = "true" ]; then
141+
# Verify that the code at the referenced commit matches the current branch
142+
CODE_MATCHES=true
143+
if [ -n "$LINE_RANGE" ]; then
144+
START_LINE=$(echo "$LINE_RANGE" | cut -d'-' -f1)
145+
END_LINE=$(echo "$LINE_RANGE" | cut -d'-' -f2)
146+
147+
# Fetch the file from the referenced commit
148+
COMMIT_FILE="${TEMP_DIR}/commit_${rust_file//\//_}_${OCAML_PATH//\//_}"
149+
COMMIT_URL="https://raw.githubusercontent.com/${GITHUB_OWNER}/${GITHUB_REPO}/${COMMIT}/${OCAML_PATH}"
150+
151+
if ! curl -sf "$COMMIT_URL" -o "$COMMIT_FILE"; then
152+
echo "INVALID|${rust_file}|${OCAML_PATH}|COMMIT_NOT_FOUND|${COMMIT}" >> "$RESULTS_FILE"
153+
echo "❌ INVALID: ${rust_file}"
154+
echo " Referenced commit does not exist: ${COMMIT}"
155+
CODE_MATCHES=false
156+
else
157+
# Extract the specific line ranges from both files and compare
158+
CURRENT_LINES=$(sed -n "${START_LINE},${END_LINE}p" "$CURRENT_FILE")
159+
COMMIT_LINES=$(sed -n "${START_LINE},${END_LINE}p" "$COMMIT_FILE")
160+
161+
if [ "$CURRENT_LINES" != "$COMMIT_LINES" ]; then
162+
echo "INVALID|${rust_file}|${OCAML_PATH}|CODE_MISMATCH|${COMMIT}" >> "$RESULTS_FILE"
163+
echo "❌ INVALID: ${rust_file}"
164+
echo " Code at L:${LINE_RANGE} differs between commit ${COMMIT} and current branch"
165+
echo " Referenced: https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/blob/${COMMIT}/${OCAML_PATH}#L${START_LINE}-L${END_LINE}"
166+
echo " Current: https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/blob/${OCAML_BRANCH}/${OCAML_PATH}#L${START_LINE}-L${END_LINE}"
167+
CODE_MATCHES=false
168+
fi
169+
fi
170+
fi
171+
172+
if [ "$CODE_MATCHES" = "true" ]; then
173+
# Check if commit is stale
174+
if [ "$COMMIT" != "$CURRENT_COMMIT" ]; then
175+
echo "STALE|${rust_file}|${OCAML_PATH}|${COMMIT}|${LINE_RANGE}" >> "$RESULTS_FILE"
176+
echo "✓ VALID: ${rust_file} -> ${OCAML_PATH} L:${LINE_RANGE}"
177+
echo " ⚠ STALE COMMIT: ${COMMIT} (current: ${CURRENT_COMMIT})"
178+
else
179+
echo "VALID|${rust_file}|${OCAML_PATH}|${LINE_RANGE}" >> "$RESULTS_FILE"
180+
echo "✓ VALID: ${rust_file} -> ${OCAML_PATH} L:${LINE_RANGE}"
181+
fi
182+
fi
183+
fi
184+
fi
185+
fi
186+
done
187+
done
188+
189+
# Count results
190+
TOTAL_REFS=$(wc -l < "$RESULTS_FILE")
191+
VALID_REFS=$(grep -c "^VALID|" "$RESULTS_FILE" || true)
192+
INVALID_REFS=$(grep -c "^INVALID|" "$RESULTS_FILE" || true)
193+
STALE_COMMITS=$(grep -c "^STALE|" "$RESULTS_FILE" || true)
194+
195+
echo ""
196+
echo "Summary"
197+
echo "======="
198+
echo "Total references found: ${TOTAL_REFS}"
199+
echo "Valid references: $((VALID_REFS + STALE_COMMITS))"
200+
echo "Invalid references: ${INVALID_REFS}"
201+
echo "Stale commits: ${STALE_COMMITS}"
202+
203+
if [ "$UPDATE_MODE" = "true" ] && [ "${STALE_COMMITS}" -gt 0 ]; then
204+
echo ""
205+
echo "Updating stale commit hashes and verification dates..."
206+
207+
CURRENT_DATE=$(date +%Y-%m-%d)
208+
209+
# Update each file with stale commits
210+
grep "^STALE|" "$RESULTS_FILE" | while IFS='|' read -r _status rust_file ocaml_path _old_commit _line_range; do
211+
echo "Updating ${rust_file}..."
212+
213+
# Find and replace the old commit with the new one
214+
sed -i.bak \
215+
-e "/^\/\/\/ OCaml reference: ${ocaml_path//\//\\/}/,/^\/\/\/ Last verified:/ {
216+
s/^\/\/\/ Commit: .*/\/\/\/ Commit: ${CURRENT_COMMIT}/
217+
s/^\/\/\/ Last verified: .*/\/\/\/ Last verified: ${CURRENT_DATE}/
218+
}" \
219+
"${RUST_ROOT}/${rust_file}"
220+
rm -f "${RUST_ROOT}/${rust_file}.bak"
221+
done
222+
223+
echo "Updated ${STALE_COMMITS} reference(s)"
224+
fi
225+
226+
# Exit with error if there are invalid references
227+
if [ "${INVALID_REFS}" -gt 0 ]; then
228+
echo ""
229+
echo "❌ Validation failed: ${INVALID_REFS} invalid reference(s) found"
230+
exit 1
231+
fi
232+
233+
if [ "${STALE_COMMITS}" -gt 0 ] && [ "$UPDATE_MODE" = "false" ]; then
234+
echo ""
235+
echo "⚠ Warning: ${STALE_COMMITS} reference(s) have stale commits"
236+
echo "Run with --update to update them automatically"
237+
exit 0
238+
fi
239+
240+
echo ""
241+
echo "✓ All OCaml references are valid!"

.github/scripts/verify-code-references.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ Please follow this workflow:
221221
2. Create a follow-up PR with the documentation updates that reference the merged code
222222
3. The verification will pass once the code is available on \`develop\`
223223
224-
See the [documentation guidelines](https://o1-labs.github.io/mina-rust/developers/documentation-guidelines) for more information about the two-PR workflow.
224+
See the [documentation guidelines](https://o1-labs.github.io/mina-rust/docs/developers/documentation-guidelines) for more information about the two-PR workflow.
225225
EOF
226226
echo ""
227227
echo "PR comment written to: ${COMMENT_FILE}"

0 commit comments

Comments
 (0)