Skip to content

Commit 2e55688

Browse files
Release v0.6.2
Published from ScheierVentures/emburden (private).
1 parent 55b89cd commit 2e55688

49 files changed

Lines changed: 3069 additions & 2857 deletions

Some content is hidden

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

.dev/hooks/pre-commit

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/bin/bash
2+
#
3+
# Pre-commit hook for quick validation checks
4+
# Runs before every commit to catch issues early
5+
#
6+
7+
set -e # Exit on error
8+
9+
echo "=========================================="
10+
echo " Pre-commit: Quick Validation"
11+
echo "=========================================="
12+
echo ""
13+
14+
# 1. Check for BREAKING CHANGE commitments without version bumps
15+
echo "📋 Checking commit message format..."
16+
COMMIT_MSG_FILE=".git/COMMIT_EDITMSG"
17+
if [ -f "$COMMIT_MSG_FILE" ]; then
18+
if grep -q "BREAKING CHANGE" "$COMMIT_MSG_FILE"; then
19+
echo "⚠️ BREAKING CHANGE detected in commit message"
20+
echo " Remember to bump major version in DESCRIPTION before release!"
21+
fi
22+
fi
23+
24+
# 2. Check version consistency (quick check only)
25+
echo ""
26+
echo "📋 Checking version consistency..."
27+
if [ -f ".dev/check-version-consistency.R" ]; then
28+
Rscript .dev/check-version-consistency.R > /dev/null 2>&1
29+
if [ $? -eq 0 ]; then
30+
echo "✅ Version consistency check passed"
31+
else
32+
echo "❌ Version inconsistency detected!"
33+
echo ""
34+
Rscript .dev/check-version-consistency.R
35+
echo ""
36+
echo "Commit cancelled."
37+
exit 1
38+
fi
39+
else
40+
echo "⚠️ Version consistency script not found"
41+
fi
42+
43+
# 3. Check for common issues in staged files
44+
echo ""
45+
echo "📋 Checking staged files..."
46+
47+
# Check for debugger statements in R code (exclude hook files)
48+
STAGED_R_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.R$' || true)
49+
if [ -n "$STAGED_R_FILES" ]; then
50+
# Only check the actual R files, not all staged content
51+
if git diff --cached -- $STAGED_R_FILES | grep -E '^\+.*browser\(\)' > /dev/null; then
52+
echo "❌ Found browser() debugger call in staged R code!"
53+
echo " Remove debugger statements before committing."
54+
exit 1
55+
fi
56+
fi
57+
58+
# Check for TODO/FIXME in committed code (warn only)
59+
if git diff --cached | grep -E '^\+.*(TODO|FIXME|XXX)' > /dev/null; then
60+
echo "⚠️ Found TODO/FIXME markers in staged code"
61+
echo " Consider addressing these before committing"
62+
echo " (commit will proceed)"
63+
fi
64+
65+
echo "✅ Staged files check passed"
66+
67+
# 4. Quick R syntax check for staged .R files (if any)
68+
if [ -n "$STAGED_R_FILES" ]; then
69+
echo ""
70+
echo "📋 Checking R syntax..."
71+
72+
# Separate package files from scripts
73+
PACKAGE_R_FILES=$(echo "$STAGED_R_FILES" | grep "^R/" || true)
74+
SCRIPT_R_FILES=$(echo "$STAGED_R_FILES" | grep -v "^R/" || true)
75+
76+
# Check package R files using parse() instead of source()
77+
if [ -n "$PACKAGE_R_FILES" ]; then
78+
for file in $PACKAGE_R_FILES; do
79+
Rscript -e "parse('$file')" > /dev/null 2>&1
80+
if [ $? -ne 0 ]; then
81+
echo "❌ Syntax error in $file"
82+
Rscript -e "parse('$file')"
83+
echo ""
84+
echo "Commit cancelled."
85+
exit 1
86+
fi
87+
done
88+
fi
89+
90+
# Check script R files using source()
91+
if [ -n "$SCRIPT_R_FILES" ]; then
92+
for file in $SCRIPT_R_FILES; do
93+
Rscript -e "source('$file', echo=FALSE)" > /dev/null 2>&1
94+
if [ $? -ne 0 ]; then
95+
echo "❌ Syntax error in $file"
96+
Rscript -e "source('$file', echo=FALSE)"
97+
echo ""
98+
echo "Commit cancelled."
99+
exit 1
100+
fi
101+
done
102+
fi
103+
104+
echo "✅ R syntax check passed"
105+
fi
106+
107+
echo ""
108+
echo "=========================================="
109+
echo " ✅ Pre-commit checks passed!"
110+
echo "=========================================="
111+
echo ""
112+
113+
exit 0

.dev/hooks/pre-push

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#!/bin/bash
2+
#
3+
# Pre-push hook to catch CI issues before pushing
4+
# Runs comprehensive CRAN-style R CMD check in temporary directory
5+
#
6+
7+
set -e # Exit on error
8+
9+
# First check version consistency across metadata files
10+
if [ -f ".dev/check-version-consistency.R" ]; then
11+
Rscript .dev/check-version-consistency.R
12+
VERSION_STATUS=$?
13+
echo ""
14+
15+
if [ $VERSION_STATUS -ne 0 ]; then
16+
echo "Push cancelled."
17+
exit 1
18+
fi
19+
fi
20+
21+
echo "=========================================="
22+
echo " Pre-push: Spelling Validation"
23+
echo "=========================================="
24+
echo ""
25+
26+
Rscript -e "
27+
if (requireNamespace('spelling', quietly = TRUE)) {
28+
cat('📝 Checking spelling...\n\n')
29+
results <- spelling::spell_check_package()
30+
31+
if (nrow(results) > 0) {
32+
cat('❌ Spelling errors found:\n\n')
33+
print(results)
34+
cat('\n')
35+
cat('Please fix spelling errors or add valid technical terms to inst/WORDLIST\n')
36+
cat('Push cancelled.\n')
37+
quit(status = 1)
38+
}
39+
40+
cat('✅ No spelling errors found\n')
41+
quit(status = 0)
42+
} else {
43+
cat('⚠️ spelling package not installed - skipping spell check\n')
44+
cat(' Install with: install.packages(\"spelling\")\n')
45+
quit(status = 0)
46+
}
47+
"
48+
49+
SPELL_STATUS=$?
50+
51+
echo ""
52+
if [ $SPELL_STATUS -ne 0 ]; then
53+
echo "Push cancelled."
54+
exit 1
55+
else
56+
echo "=========================================="
57+
echo " ✅ Spelling check passed!"
58+
echo "=========================================="
59+
fi
60+
61+
echo ""
62+
63+
echo "=========================================="
64+
echo " Pre-push: CRAN-style R CMD check"
65+
echo "=========================================="
66+
echo ""
67+
68+
# Check if we have LaTeX/TinyTeX for vignettes (non-interactive)
69+
if ! command -v pdflatex &> /dev/null; then
70+
echo "⚠️ WARNING: pdflatex not found - skipping vignette build"
71+
echo " Install TinyTeX with: Rscript .dev/install-tinytex.R"
72+
echo ""
73+
SKIP_VIGNETTES="TRUE"
74+
else
75+
SKIP_VIGNETTES="FALSE"
76+
fi
77+
78+
# Create temporary directory for CRAN check
79+
CHECK_DIR=$(mktemp -d -t emburden-check-XXXXXX)
80+
echo "📦 Building package in temporary directory: $CHECK_DIR"
81+
echo ""
82+
83+
# Ensure cleanup on exit
84+
cleanup() {
85+
if [ -d "$CHECK_DIR" ]; then
86+
echo ""
87+
echo "🧹 Cleaning up temporary directory..."
88+
rm -rf "$CHECK_DIR"
89+
fi
90+
}
91+
trap cleanup EXIT INT TERM
92+
93+
# Run comprehensive CRAN check
94+
echo "🔍 Running R CMD check --as-cran..."
95+
echo " (This may take 2-3 minutes for full vignette build)"
96+
echo ""
97+
98+
Rscript -e "
99+
# Set environment to simulate CRAN
100+
Sys.setenv(
101+
'_R_CHECK_CRAN_INCOMING_' = 'TRUE',
102+
'_R_CHECK_CRAN_INCOMING_REMOTE_' = 'FALSE', # Skip URL checks (slow)
103+
'_R_CHECK_DONTTEST_EXAMPLES_' = 'false', # Skip \donttest{} examples (matches CRAN)
104+
'NOT_CRAN' = 'false'
105+
)
106+
107+
# Run comprehensive check
108+
skip_vignettes <- as.logical('$SKIP_VIGNETTES')
109+
110+
check_args <- c('--as-cran')
111+
build_args <- c('--no-manual') # PDF manual requires pandoc
112+
113+
if (skip_vignettes) {
114+
cat('⚠️ Skipping vignette build (no pdflatex)\n\n')
115+
check_args <- c(check_args, '--no-build-vignettes', '--ignore-vignettes')
116+
build_args <- c(build_args, '--no-build-vignettes')
117+
} else {
118+
# Use 'both' to match GitHub Actions workflow (tries gs+qpdf, falls back to qpdf)
119+
build_args <- c(build_args, '--compact-vignettes=both')
120+
cat('ℹ️ Using --compact-vignettes=both (matches GitHub Actions workflow)\n\n')
121+
}
122+
123+
cat('Check arguments:', paste(check_args, collapse=' '), '\n')
124+
cat('Build arguments:', paste(build_args, collapse=' '), '\n\n')
125+
126+
# Run check with rcmdcheck (cleaner output)
127+
if (requireNamespace('rcmdcheck', quietly = TRUE)) {
128+
results <- rcmdcheck::rcmdcheck(
129+
path = '.',
130+
args = check_args,
131+
build_args = build_args,
132+
error_on = 'never', # Don't stop, show results
133+
check_dir = '$CHECK_DIR'
134+
)
135+
136+
# Print summary
137+
cat('\n')
138+
cat(strrep('=', 60), '\n')
139+
cat('R CMD check results:\n')
140+
cat(strrep('=', 60), '\n')
141+
print(results)
142+
143+
# Check for errors or warnings (fail on errors only, allow warnings)
144+
if (length(results\$errors) > 0) {
145+
cat('\n❌ ERRORS found:\n')
146+
cat(paste(results\$errors, collapse='\n'), '\n')
147+
quit(status = 1)
148+
}
149+
150+
if (length(results\$warnings) > 0) {
151+
cat('\n⚠️ WARNINGS found (allowed, push will continue):\n')
152+
cat(paste(results\$warnings, collapse='\n'), '\n')
153+
# Don't fail on warnings - CI will catch critical ones
154+
}
155+
156+
if (length(results\$notes) > 0) {
157+
cat('\nℹ️ NOTES:\n')
158+
cat(paste(results\$notes, collapse='\n'), '\n')
159+
# Notes are OK, don't fail
160+
}
161+
162+
cat('\n✅ R CMD check passed!\n')
163+
quit(status = 0)
164+
165+
} else {
166+
cat('Installing rcmdcheck package...\n')
167+
install.packages('rcmdcheck', repos = 'https://cran.rstudio.com')
168+
cat('❌ Please re-run push after rcmdcheck is installed.\n')
169+
quit(status = 1)
170+
}
171+
"
172+
173+
CHECK_STATUS=$?
174+
175+
echo ""
176+
if [ $CHECK_STATUS -ne 0 ]; then
177+
echo "❌ R CMD check --as-cran failed with errors!"
178+
echo " Fix errors before pushing. Push cancelled."
179+
exit 1
180+
else
181+
echo "=========================================="
182+
echo " ✅ CRAN check passed (or warnings only)!"
183+
echo "=========================================="
184+
fi
185+
186+
echo ""
187+
188+
# Optional: CRAN submission dry-run test
189+
if [ "$SKIP_CRAN_DRYRUN" != "true" ]; then
190+
echo "=========================================="
191+
echo " Pre-push: CRAN Submission Dry-Run"
192+
echo "=========================================="
193+
echo ""
194+
echo "Testing CRAN submission process (no actual submission)..."
195+
echo ""
196+
197+
Rscript -e "
198+
# Find the tarball from R CMD build
199+
tarball <- list.files(pattern = 'emburden_.*\\.tar\\.gz$', full.names = TRUE)
200+
if (length(tarball) == 0) {
201+
cat('⚠️ No tarball found - skipping CRAN submission test\n')
202+
quit(status = 0)
203+
}
204+
205+
tarball <- tarball[1]
206+
cat('Found tarball:', tarball, '\n\n')
207+
208+
# Test CRAN submission preparation (doesn't actually submit)
209+
if (requireNamespace('devtools', quietly = TRUE)) {
210+
cat('📋 Checking CRAN submission readiness...\n\n')
211+
212+
# Check if package can be submitted
213+
tryCatch({
214+
# This checks the package is ready but doesn't submit
215+
devtools::check_built(tarball, cran = TRUE, remote = FALSE, manual = FALSE)
216+
cat('\n✅ CRAN submission dry-run passed!\n')
217+
cat(' Package is ready for CRAN submission.\n')
218+
}, error = function(e) {
219+
cat('\n❌ CRAN submission test failed:\n')
220+
cat(' ', conditionMessage(e), '\n')
221+
cat('\nNote: This is just a dry-run test. Fix issues before actual submission.\n')
222+
# Don't fail the push on dry-run errors
223+
})
224+
} else {
225+
cat('ℹ️ devtools not installed - skipping CRAN submission test\n')
226+
}
227+
" || true # Don't fail push if dry-run has issues
228+
229+
echo ""
230+
echo "=========================================="
231+
else
232+
echo "ℹ️ Skipping CRAN submission dry-run (SKIP_CRAN_DRYRUN=true)"
233+
echo ""
234+
fi
235+
236+
echo "🚀 Proceeding with push..."
237+
exit 0

0 commit comments

Comments
 (0)