test_r_package.sh 10.3 KB
Newer Older
1
2
#!/bin/bash

3
4
5
set -e -E -u -o pipefail

# defaults
6
ARCH=$(uname -m)
7
INSTALL_CMAKE_FROM_RELEASES=${INSTALL_CMAKE_FROM_RELEASES:-"false"}
8

9
# set up R environment
10
CRAN_MIRROR="https://cran.rstudio.com"
11
12
R_LIB_PATH=~/Rlib
mkdir -p $R_LIB_PATH
13
export R_LIBS=$R_LIB_PATH
14
15
export PATH="$R_LIB_PATH/R/bin:$PATH"

16
17
18
19
20
21
# don't fail builds for long-running examples unless they're very long.
# See https://github.com/microsoft/LightGBM/issues/4049#issuecomment-793412254.
if [[ $R_BUILD_TYPE != "cran" ]]; then
    export _R_CHECK_EXAMPLE_TIMING_THRESHOLD_=30
fi

22
# Get details needed for installing R components
23
24
25
R_MAJOR_VERSION=( ${R_VERSION//./ } )
if [[ "${R_MAJOR_VERSION}" == "3" ]]; then
    export R_MAC_VERSION=3.6.3
26
    export R_MAC_PKG_URL=${CRAN_MIRROR}/bin/macosx/R-${R_MAC_VERSION}.nn.pkg
27
28
29
    export R_LINUX_VERSION="3.6.3-1bionic"
    export R_APT_REPO="bionic-cran35/"
elif [[ "${R_MAJOR_VERSION}" == "4" ]]; then
30
    export R_MAC_VERSION=4.3.1
31
    export R_MAC_PKG_URL=${CRAN_MIRROR}/bin/macosx/big-sur-${ARCH}/base/R-${R_MAC_VERSION}-${ARCH}.pkg
32
    export R_LINUX_VERSION="4.3.1-1.2204.0"
33
    export R_APT_REPO="jammy-cran40/"
34
35
else
    echo "Unrecognized R version: ${R_VERSION}"
36
    exit 1
37
38
fi

39
40
41
# installing precompiled R for Ubuntu
# https://cran.r-project.org/bin/linux/ubuntu/#installation
# adding steps from https://stackoverflow.com/a/56378217/3986677 to get latest version
42
43
#
# `devscripts` is required for 'checkbashisms' (https://github.com/r-lib/actions/issues/111)
44
if [[ $OS_NAME == "linux" ]]; then
45
46
    mkdir -p ~/.gnupg
    echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf
47
    sudo apt-key adv \
48
        --homedir ~/.gnupg \
49
        --keyserver keyserver.ubuntu.com \
50
        --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 || exit 1
51
    sudo add-apt-repository \
52
        "deb ${CRAN_MIRROR}/bin/linux/ubuntu ${R_APT_REPO}" || exit 1
53
54
55
    sudo apt-get update
    sudo apt-get install \
        --no-install-recommends \
56
        -y \
57
            devscripts \
58
            r-base-core=${R_LINUX_VERSION} \
59
            r-base-dev=${R_LINUX_VERSION} \
60
            texinfo \
61
            texlive-latex-extra \
62
63
64
            texlive-latex-recommended \
            texlive-fonts-recommended \
            texlive-fonts-extra \
65
            tidy \
66
            qpdf \
67
            || exit 1
68
69
70
71
72
73

    if [[ $R_BUILD_TYPE == "cran" ]]; then
        sudo apt-get install \
            --no-install-recommends \
            -y \
                autoconf=$(cat R-package/AUTOCONF_UBUNTU_VERSION) \
74
                automake \
75
                || exit 1
76
    fi
77
78
    if [[ $INSTALL_CMAKE_FROM_RELEASES == "true" ]]; then
        curl -O -L \
79
            https://github.com/Kitware/CMake/releases/download/v3.25.1/cmake-3.25.1-linux-${ARCH}.sh \
80
        || exit 1
81

82
        sudo mkdir /opt/cmake || exit 1
83
        sudo sh cmake-3.25.1-linux-${ARCH}.sh --skip-license --prefix=/opt/cmake || exit 1
84
        sudo ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake || exit 1
85
    fi
86
87
88
89
fi

# Installing R precompiled for Mac OS 10.11 or higher
if [[ $OS_NAME == "macos" ]]; then
90
91
    brew update-reset --auto-update
    brew update --auto-update
92
    if [[ $R_BUILD_TYPE == "cran" ]]; then
93
        brew install automake || exit 1
94
    fi
95
96
    brew install \
        checkbashisms \
97
98
        qpdf || exit 1
    brew install basictex || exit 1
99
    export PATH="/Library/TeX/texbin:$PATH"
100
101
    sudo tlmgr --verify-repo=none update --self || exit 1
    sudo tlmgr --verify-repo=none install inconsolata helvetic rsfs || exit 1
102

103
    curl -sL ${R_MAC_PKG_URL} -o R.pkg || exit 1
104
105
    sudo installer \
        -pkg $(pwd)/R.pkg \
106
        -target / || exit 1
107
108
fi

109
110
111
# fix for issue where CRAN was not returning {lattice} when using R 3.6
# "Warning: dependency ‘lattice’ is not available"
if [[ "${R_MAJOR_VERSION}" == "3" ]]; then
112
    Rscript --vanilla -e "install.packages('https://cran.r-project.org/src/contrib/Archive/lattice/lattice_0.20-41.tar.gz', repos = NULL, lib = '${R_LIB_PATH}')"
113
114
fi

115
# Manually install Depends and Imports libraries + 'knitr', 'markdown', 'RhpcBLASctl', 'testthat'
116
# to avoid a CI-time dependency on devtools (for devtools::install_deps())
117
118
# NOTE: testthat is not required when running rchk
if [[ "${TASK}" == "r-rchk" ]]; then
119
    packages="c('data.table', 'jsonlite', 'knitr', 'markdown', 'Matrix', 'R6', 'RhpcBLASctl')"
120
else
121
    packages="c('data.table', 'jsonlite', 'knitr', 'markdown', 'Matrix', 'R6', 'RhpcBLASctl', 'testthat')"
122
fi
123
compile_from_source="both"
124
if [[ $OS_NAME == "macos" ]]; then
125
126
    packages+=", type = 'binary'"
    compile_from_source="never"
127
fi
128
Rscript --vanilla -e "options(install.packages.compile.from.source = '${compile_from_source}'); install.packages(${packages}, repos = '${CRAN_MIRROR}', lib = '${R_LIB_PATH}', dependencies = c('Depends', 'Imports', 'LinkingTo'), Ncpus = parallel::detectCores())" || exit 1
129
130
131

cd ${BUILD_DIRECTORY}

Guolin Ke's avatar
Guolin Ke committed
132
PKG_TARBALL="lightgbm_*.tar.gz"
133
LOG_FILE_NAME="lightgbm.Rcheck/00check.log"
134
if [[ $R_BUILD_TYPE == "cmake" ]]; then
135
    Rscript build_r.R -j4 --skip-install || exit 1
136
137
138
139
140
elif [[ $R_BUILD_TYPE == "cran" ]]; then

    # on Linux, we recreate configure in CI to test if
    # a change in a PR has changed configure.ac
    if [[ $OS_NAME == "linux" ]]; then
141
        ${BUILD_DIRECTORY}/R-package/recreate-configure.sh
142
143
144
145
146
147
148
149
150
151

        num_files_changed=$(
            git diff --name-only | wc -l
        )
        if [[ ${num_files_changed} -gt 0 ]]; then
            echo "'configure' in the R package has changed. Please recreate it and commit the changes."
            echo "Changed files:"
            git diff --compact-summary
            echo "See R-package/README.md for details on how to recreate this script."
            echo ""
152
            exit 1
153
154
155
        fi
    fi

156
    ./build-cran-package.sh || exit 1
157

158
159
160
161
162
163
164
165
166
167
    if [[ "${TASK}" == "r-rchk" ]]; then
        echo "Checking R package with rchk"
        mkdir -p packages
        cp ${PKG_TARBALL} packages
        RCHK_LOG_FILE="rchk-logs.txt"
        docker run \
            -v $(pwd)/packages:/rchk/packages \
            kalibera/rchk:latest \
            "/rchk/packages/${PKG_TARBALL}" \
        2>&1 > ${RCHK_LOG_FILE} \
168
        || (cat ${RCHK_LOG_FILE} && exit 1)
169
170
        cat ${RCHK_LOG_FILE}

James Lamb's avatar
James Lamb committed
171
        # the exceptions below are from R itself and not LightGBM:
172
173
174
175
        # https://github.com/kalibera/rchk/issues/22#issuecomment-656036156
        exit $(
            cat ${RCHK_LOG_FILE} \
            | grep -v "in function strptime_internal" \
James Lamb's avatar
James Lamb committed
176
            | grep -v "in function RunGenCollect" \
177
178
179
180
            | grep --count -E '\[PB\]|ERROR'
        )
    fi

181
182
183
184
185
186
187
188
189
    # Test CRAN source .tar.gz in a directory that is not this repo or below it.
    # When people install.packages('lightgbm'), they won't have the LightGBM
    # git repo around. This is to protect against the use of relative paths
    # like ../../CMakeLists.txt that would only work if you are in the repo
    R_CMD_CHECK_DIR="${HOME}/tmp-r-cmd-check/"
    mkdir -p ${R_CMD_CHECK_DIR}
    mv ${PKG_TARBALL} ${R_CMD_CHECK_DIR}
    cd ${R_CMD_CHECK_DIR}
fi
190
191
192

# fails tests if either ERRORs or WARNINGs are thrown by
# R CMD CHECK
193
check_succeeded="yes"
194
195
196
(
    R CMD check ${PKG_TARBALL} \
        --as-cran \
197
        --run-donttest \
198
199
200
201
202
203
204
205
206
207
208
209
    || check_succeeded="no"
) &

# R CMD check suppresses output, some CIs kill builds after
# a few minutes with no output. This trick gives R CMD check more time
#     * https://github.com/travis-ci/travis-ci/issues/4190#issuecomment-169987525
#     * https://stackoverflow.com/a/29890106/3986677
CHECK_PID=$!
while kill -0 ${CHECK_PID} >/dev/null 2>&1; do
    echo -n -e " \b"
    sleep 5
done
210
211

echo "R CMD check build logs:"
212
213
BUILD_LOG_FILE=lightgbm.Rcheck/00install.out
cat ${BUILD_LOG_FILE}
214
215

if [[ $check_succeeded == "no" ]]; then
216
    exit 1
217
fi
218

219
220
221
# ensure 'grep --count' doesn't cause failures
set +e

222
223
224
225
226
227
used_correct_r_version=$(
    cat $LOG_FILE_NAME \
    | grep --count "using R version ${R_VERSION}"
)
if [[ $used_correct_r_version -ne 1 ]]; then
    echo "Unexpected R version was used. Expected '${R_VERSION}'."
228
    exit 1
229
230
231
232
233
234
235
236
237
fi

if [[ $R_BUILD_TYPE == "cmake" ]]; then
    passed_correct_r_version_to_cmake=$(
        cat $BUILD_LOG_FILE \
        | grep --count "R version passed into FindLibR.cmake: ${R_VERSION}"
    )
    if [[ $used_correct_r_version -ne 1 ]]; then
        echo "Unexpected R version was passed into cmake. Expected '${R_VERSION}'."
238
        exit 1
239
240
241
242
    fi
fi


243
244
if grep -q -E "NOTE|WARNING|ERROR" "$LOG_FILE_NAME"; then
    echo "NOTEs, WARNINGs, or ERRORs have been found by R CMD check"
245
    exit 1
246
fi
247

248
# this check makes sure that CI builds of the package actually use OpenMP
249
250
251
if [[ $OS_NAME == "macos" ]] && [[ $R_BUILD_TYPE == "cran" ]]; then
    omp_working=$(
        cat $BUILD_LOG_FILE \
252
        | grep --count -E "checking whether OpenMP will work .*yes"
253
    )
254
255
256
257
258
259
260
261
262
263
elif [[ $R_BUILD_TYPE == "cmake" ]]; then
    omp_working=$(
        cat $BUILD_LOG_FILE \
        | grep --count -E ".*Found OpenMP: TRUE.*"
    )
else
    omp_working=1
fi
if [[ $omp_working -ne 1 ]]; then
    echo "OpenMP was not found"
264
    exit 1
265
fi
266

267
# this check makes sure that CI builds of the package
268
269
270
271
272
273
# actually use MM_PREFETCH preprocessor definition
if [[ $R_BUILD_TYPE == "cran" ]]; then
    mm_prefetch_working=$(
        cat $BUILD_LOG_FILE \
        | grep --count -E "checking whether MM_PREFETCH work.*yes"
    )
274
275
276
277
278
279
280
281
else
    mm_prefetch_working=$(
        cat $BUILD_LOG_FILE \
        | grep --count -E ".*Performing Test MM_PREFETCH - Success"
    )
fi
if [[ $mm_prefetch_working -ne 1 ]]; then
    echo "MM_PREFETCH test was not passed"
282
    exit 1
283
284
fi

285
# this check makes sure that CI builds of the package
286
287
288
289
290
291
# actually use MM_MALLOC preprocessor definition
if [[ $R_BUILD_TYPE == "cran" ]]; then
    mm_malloc_working=$(
        cat $BUILD_LOG_FILE \
        | grep --count -E "checking whether MM_MALLOC work.*yes"
    )
292
293
294
295
296
297
298
299
else
    mm_malloc_working=$(
        cat $BUILD_LOG_FILE \
        | grep --count -E ".*Performing Test MM_MALLOC - Success"
    )
fi
if [[ $mm_malloc_working -ne 1 ]]; then
    echo "MM_MALLOC test was not passed"
300
    exit 1
301
302
fi

303
304
305
306
307
# this check makes sure that no "warning: unknown pragma ignored" logs
# reach the user leading them to believe that something went wrong
if [[ $R_BUILD_TYPE == "cran" ]]; then
    pragma_warning_present=$(
        cat $BUILD_LOG_FILE \
308
        | grep --count -E "warning: unknown pragma ignored"
309
310
311
    )
    if [[ $pragma_warning_present -ne 0 ]]; then
        echo "Unknown pragma warning is present, pragmas should have been removed before build"
312
        exit 1
313
314
    fi
fi