1- name : Minimal Sanitizer Checks
1+ # R-hub's sanitizer checks with custom test integration
2+ # Skips vignette building to avoid pandoc-citeproc issues
3+
4+ name : R-hub Sanitizer Checks
5+ run-name : " ${{ github.event.inputs.id || 'Sanitizer checks' }}: ${{ github.event.inputs.name || github.event.head_commit.message || github.event.pull_request.title || format('triggered by {0}', github.triggering_actor) }}"
26
37on :
8+ workflow_dispatch :
9+ inputs :
10+ config :
11+ description : ' Sanitizer configurations'
12+ type : string
13+ default : ' clang-asan,clang-ubsan,valgrind'
14+ name :
15+ description : ' Custom run name'
16+ type : string
17+ id :
18+ description : ' Custom run ID'
19+ type : string
420 push :
521 branches : [main]
622 pull_request :
925permissions : read-all
1026
1127jobs :
28+ setup :
29+ runs-on : ubuntu-latest
30+ outputs :
31+ containers : ${{ steps.rhub-setup.outputs.containers }}
32+
33+ steps :
34+ - uses : r-hub/actions/setup@v1
35+ with :
36+ config : ${{ github.event.inputs.config || 'clang-asan,clang-ubsan,valgrind' }}
37+ id : rhub-setup
38+
1239 sanitizer-checks :
40+ needs : setup
41+ if : ${{ needs.setup.outputs.containers != '[]' }}
1342 runs-on : ubuntu-latest
14- name : " ${{ matrix.config.name }}"
43+ name : " ${{ matrix.config.label }}"
1544
1645 strategy :
1746 fail-fast : false
1847 matrix :
19- config :
20- - {name: 'Clang-ASAN', container: 'ghcr.io/r-hub/containers/clang-asan:latest', check_args: '--no-manual --no-vignettes --no-build-vignettes'}
21- - {name: 'Clang-UBSAN', container: 'ghcr.io/r-hub/containers/clang-ubsan:latest', check_args: '--no-manual --no-vignettes --no-build-vignettes'}
48+ config : ${{ fromJson(needs.setup.outputs.containers) }}
2249
2350 container :
2451 image : ${{ matrix.config.container }}
2552
2653 env :
2754 GITHUB_PAT : ${{ secrets.GITHUB_TOKEN }}
2855 R_KEEP_PKG_SOURCE : yes
29- _R_CHECK_CRAN_INCOMING_ : false
3056 _R_CHECK_FORCE_SUGGESTS_ : false
31- R_BUILD_ARGS : " --no-manual --no-vignettes"
32- R_CHECK_ARGS : " ${{ matrix.config.check_args }}"
57+ _R_CHECK_CRAN_INCOMING_ : false
58+ # Skip vignettes
59+ R_BUILD_ARGS : " --no-manual --no-build-vignettes"
60+ R_CHECK_ARGS : " --no-manual --no-vignettes --no-build-vignettes"
3361
3462 steps :
35- - uses : actions/checkout@v4
63+ - uses : r-hub/ actions/checkout@v1
3664
37- - name : Install system dependencies
65+ - uses : r-hub/actions/platform-info@v1
66+ with :
67+ token : ${{ secrets.RHUB_TOKEN }}
68+ job-config : ${{ matrix.config.job-config }}
69+
70+ # Setup dependencies but skip vignette-related packages
71+ - uses : r-hub/actions/setup-deps@v1
72+ with :
73+ token : ${{ secrets.RHUB_TOKEN }}
74+ job-config : ${{ matrix.config.job-config }}
75+ extra-packages : |
76+ any::testthat
77+ any::pak
78+ needs : |
79+ testthat
80+
81+ - name : Remove vignettes to prevent build issues
3882 run : |
39- # Update package list
40- apt-get update || true
41-
42- # Install minimal dependencies needed for R packages
43- apt-get install -y --no-install-recommends \
44- libcurl4-openssl-dev \
45- libssl-dev \
46- libxml2-dev \
47- libgit2-dev || true
83+ # Remove vignettes directory to ensure they're not built
84+ if [ -d "vignettes" ]; then
85+ echo "Removing vignettes directory"
86+ rm -rf vignettes
87+ fi
88+ if [ -d "cpp11armadillotest/vignettes" ]; then
89+ echo "Removing cpp11armadillotest/vignettes directory"
90+ rm -rf cpp11armadillotest/vignettes
91+ fi
92+ shell : bash
4893
49- - name : Install R dependencies
94+ - name : Install cpp11armadillotest with tests
5095 run : |
51- # Install essential packages
52- install.packages(c("remotes", "rcmdcheck", "testthat"))
53-
54- # Install package dependencies
55- remotes::install_deps(".", dependencies = TRUE, upgrade = "never")
56-
57- # Install cpp11armadillotest dependencies if it exists
5896 if (dir.exists("cpp11armadillotest")) {
59- remotes::install_deps("cpp11armadillotest", dependencies = TRUE, upgrade = "never")
97+ cat("Installing cpp11armadillotest dependencies\n")
98+ # Use pak which should be available from setup-deps
99+ if (requireNamespace("pak", quietly = TRUE)) {
100+ pak::local_install_deps("cpp11armadillotest", upgrade = FALSE)
101+ }
102+
103+ cat("Building and installing cpp11armadillotest with tests\n")
104+ # Build without vignettes
105+ system("R CMD build --no-build-vignettes --no-manual cpp11armadillotest")
106+
107+ # Find the built package
108+ tarball <- list.files(pattern = "^cpp11armadillotest.*\\.tar\\.gz$", full.names = TRUE)[1]
109+ if (!is.na(tarball) && file.exists(tarball)) {
110+ install.packages(tarball, repos = NULL, type = "source", INSTALL_opts = "--install-tests")
111+ cat("cpp11armadillotest installed successfully\n")
112+ } else {
113+ cat("Could not find cpp11armadillotest tarball\n")
114+ }
60115 }
61116 shell : Rscript {0}
62-
63- - name : Build and install main package (no vignettes)
64- run : |
65- R CMD build --no-build-vignettes --no-manual .
66- R CMD INSTALL *.tar.gz
67-
68- - name : Build and install cpp11armadillotest (no vignettes)
69- run : |
70- if [ -d "cpp11armadillotest" ]; then
71- R CMD build --no-build-vignettes --no-manual cpp11armadillotest
72- R CMD INSTALL --install-tests cpp11armadillotest*.tar.gz
73- fi
74-
75- - name : Run R CMD check (no vignettes)
76- run : |
77- # Get the package tarball name
78- PKG_TARBALL=$(ls -1 *.tar.gz | grep -v cpp11armadillotest | head -n 1)
79- echo "Checking package: $PKG_TARBALL"
117+
118+ # Run check without vignettes
119+ - uses : r-hub/actions/run-check@v1
120+ with :
121+ token : ${{ secrets.RHUB_TOKEN }}
122+ job-config : ${{ matrix.config.job-config }}
123+ args : ' c("--no-manual", "--no-vignettes", "--no-build-vignettes")'
124+ build_args : ' c("--no-manual", "--no-build-vignettes")'
80125
81- # Run R CMD check with sanitizers
82- R CMD check ${{ matrix.config.check_args }} "$PKG_TARBALL"
83-
84126 - name : Run cpp11armadillotest tests with sanitizers
85127 if : always()
86128 run : |
87- Rscript -e '
88- if (dir.exists("cpp11armadillotest/tests") && requireNamespace("cpp11armadillotest", quietly = TRUE)) {
89- cat("\n=== Running cpp11armadillotest tests with sanitizers ===\n")
90- library(testthat)
91- library(cpp11armadillotest)
92-
93- # Set working directory
94- old_wd <- getwd()
95- setwd("cpp11armadillotest/tests")
96-
97- # Run tests
98- tryCatch({
99- test_results <- test_check("cpp11armadillotest", reporter = "progress")
100- print(test_results)
101-
102- # Check for failures
103- if (any(as.data.frame(test_results)$failed > 0)) {
104- stop("Tests failed under sanitizers")
105- }
106- }, error = function(e) {
107- cat("Error: ", conditionMessage(e), "\n")
108- stop(e)
109- }, finally = {
110- setwd(old_wd)
111- })
112- } else {
113- cat("cpp11armadillotest not found or not installed\n")
129+ cat("\n=== Running cpp11armadillotest tests ===\n")
130+
131+ # Check if package and tests exist
132+ if (!requireNamespace("cpp11armadillotest", quietly = TRUE)) {
133+ cat("cpp11armadillotest package not installed\n")
134+ quit(status = 0)
135+ }
136+
137+ if (!dir.exists("cpp11armadillotest/tests")) {
138+ cat("cpp11armadillotest/tests directory not found\n")
139+ quit(status = 0)
140+ }
141+
142+ # Load required packages
143+ library(testthat)
144+ library(cpp11armadillotest)
145+
146+ # Run tests
147+ old_wd <- getwd()
148+ setwd("cpp11armadillotest/tests")
149+
150+ test_results <- tryCatch({
151+ test_check("cpp11armadillotest", reporter = "progress")
152+ }, error = function(e) {
153+ cat("Error running tests: ", conditionMessage(e), "\n")
154+ NULL
155+ })
156+
157+ setwd(old_wd)
158+
159+ # Check results
160+ if (!is.null(test_results)) {
161+ print(test_results)
162+ failures <- sum(as.data.frame(test_results)$failed)
163+ if (failures > 0) {
164+ cat(sprintf("\n%d test(s) failed under %s\n", failures, "${{ matrix.config.label }}"))
165+ quit(status = 1)
114166 }
115- '
167+ }
168+ shell : Rscript {0}
116169
117- - name : Show sanitizer output
170+ - name : Show sanitizer results
118171 if : always()
119172 run : |
120- # Find and display any sanitizer output
121- echo "=== Looking for sanitizer output ==="
122- find . -name "*.Rcheck" -type d -exec sh -c '
123- echo "=== Check directory: {} ==="
124- find {} -name "*.Rout" -o -name "*.Rout.fail" | while read f; do
125- if grep -E "(AddressSanitizer|UndefinedBehaviorSanitizer|ERROR: LeakSanitizer|valgrind)" "$f" >/dev/null 2>&1; then
126- echo "=== Sanitizer output in $f ==="
127- cat "$f"
173+ echo "=== Searching for sanitizer output ==="
174+
175+ # Function to check files for sanitizer output
176+ check_sanitizer_output() {
177+ local file="$1"
178+ if [ -f "$file" ]; then
179+ if grep -E "(AddressSanitizer|UndefinedBehaviorSanitizer|ERROR: LeakSanitizer|==ERROR==|runtime error:|attempting free on address|memcheck)" "$file" >/dev/null 2>&1; then
180+ echo "=== Sanitizer output found in $file ==="
181+ grep -E "(AddressSanitizer|UndefinedBehaviorSanitizer|ERROR: LeakSanitizer|==ERROR==|runtime error:|attempting free on address|memcheck)" "$file" -A 5 -B 5
128182 fi
129- done
130- ' \;
183+ fi
184+ }
131185
132- # Also check test output
133- if [ -f "cpp11armadillotest.Rcheck/tests/testthat.Rout" ]; then
134- echo "=== Test output ==="
135- cat "cpp11armadillotest.Rcheck/tests/testthat.Rout"
136- fi
186+ # Check R CMD check output
187+ find . -name "*.Rcheck" -type d | while read checkdir; do
188+ echo "Checking $checkdir"
189+ find "$checkdir" -name "*.Rout" -o -name "*.Rout.fail" -o -name "*.log" | while read f; do
190+ check_sanitizer_output "$f"
191+ done
192+ done
137193
138- # Check for core dumps
139- if ls core* 1> /dev/null 2>&1; then
140- echo "=== Core dumps found ==="
141- ls -la core*
142- fi
143-
144- - name : Upload check results
145- if : failure()
146- uses : actions/upload-artifact@v4
147- with :
148- name : ${{ matrix.config.name }}-results
149- path : |
150- *.Rcheck/
151- *.tar.gz
152-
194+ # Check test output specifically
195+ for f in cpp11armadillo.Rcheck/tests/testthat.Rout cpp11armadillotest.Rcheck/tests/testthat.Rout; do
196+ if [ -f "$f" ]; then
197+ echo "=== Test output from $f ==="
198+ cat "$f"
199+ fi
200+ done
201+
0 commit comments