test-r-package.sh 9.55 KB
Newer Older
1
2
#!/bin/bash

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

# defaults
6
7
ARCH=$(uname -m)

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

15
16
17
18
19
20
# 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

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

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

    if [[ $R_BUILD_TYPE == "cran" ]]; then
        sudo apt-get install \
            --no-install-recommends \
            -y \
72
                "autoconf=$(cat R-package/AUTOCONF_UBUNTU_VERSION)" \
73
                automake \
74
                || exit 1
75
    fi
76
77
78
79
fi

# Installing R precompiled for Mac OS 10.11 or higher
if [[ $OS_NAME == "macos" ]]; then
80
81
    brew update-reset --auto-update
    brew update --auto-update
82
    if [[ $R_BUILD_TYPE == "cran" ]]; then
83
        brew install automake || exit 1
84
    fi
85
86
    brew install \
        checkbashisms \
87
88
        qpdf || exit 1
    brew install basictex || exit 1
89
    export PATH="/Library/TeX/texbin:$PATH"
90
91
    sudo tlmgr --verify-repo=none update --self || exit 1
    sudo tlmgr --verify-repo=none install inconsolata helvetic rsfs || exit 1
92

93
    curl -sL "${R_MAC_PKG_URL}" -o R.pkg || exit 1
94
    sudo installer \
95
        -pkg "$(pwd)/R.pkg" \
96
        -target / || exit 1
97
98
99
100
101
102

    # install tidy v5.8.0
    # ref: https://groups.google.com/g/r-sig-mac/c/7u_ivEj4zhM
    TIDY_URL=https://github.com/htacg/tidy-html5/releases/download/5.8.0/tidy-5.8.0-macos-x86_64+arm64.pkg
    curl -sL ${TIDY_URL} -o tidy.pkg
    sudo installer \
103
        -pkg "$(pwd)/tidy.pkg" \
104
105
106
107
108
        -target /

    # ensure that this newer version of 'tidy' is used by 'R CMD check'
    # ref: https://cran.r-project.org/doc/manuals/R-exts.html#Checking-packages
    export R_TIDYCMD=/usr/local/bin/tidy
109
110
fi

111
# fix for issue where CRAN was not returning {lattice} and {evaluate} when using R 3.6
112
113
# "Warning: dependency ‘lattice’ is not available"
if [[ "${R_MAJOR_VERSION}" == "3" ]]; then
114
    Rscript --vanilla -e "install.packages(c('https://cran.r-project.org/src/contrib/Archive/lattice/lattice_0.20-41.tar.gz', 'https://cran.r-project.org/src/contrib/Archive/evaluate/evaluate_0.23.tar.gz'), repos = NULL, lib = '${R_LIB_PATH}')"
115
116
117
118
119
else
    # {Matrix} needs {lattice}, so this needs to run before manually installing {Matrix}.
    # This should be unnecessary on R >=4.4.0
    # ref: https://github.com/microsoft/LightGBM/issues/6433
    Rscript --vanilla -e "install.packages('lattice', repos = '${CRAN_MIRROR}', lib = '${R_LIB_PATH}')"
120
121
fi

122
123
124
125
# manually install {Matrix}, as {Matrix}=1.7-0 raised its R floor all the way to R 4.4.0
# ref: https://github.com/microsoft/LightGBM/issues/6433
Rscript --vanilla -e "install.packages('https://cran.r-project.org/src/contrib/Archive/Matrix/Matrix_1.6-5.tar.gz', repos = NULL, lib = '${R_LIB_PATH}')"

126
# Manually install Depends and Imports libraries + 'knitr', 'markdown', 'RhpcBLASctl', 'testthat'
127
# to avoid a CI-time dependency on devtools (for devtools::install_deps())
128
packages="c('data.table', 'jsonlite', 'knitr', 'markdown', 'R6', 'RhpcBLASctl', 'testthat')"
129
compile_from_source="both"
130
if [[ $OS_NAME == "macos" ]]; then
131
132
    packages+=", type = 'binary'"
    compile_from_source="never"
133
fi
134
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
135

136
cd "${BUILD_DIRECTORY}"
137
138
PKG_TARBALL="lightgbm_$(head -1 VERSION.txt).tar.gz"
BUILD_LOG_FILE="lightgbm.Rcheck/00install.out"
139
LOG_FILE_NAME="lightgbm.Rcheck/00check.log"
140
if [[ $R_BUILD_TYPE == "cmake" ]]; then
141
    Rscript build_r.R -j4 --skip-install || exit 1
142
143
144
145
146
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
147
        ./R-package/recreate-configure.sh
148
149
150
151
152

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

162
    ./build-cran-package.sh || exit 1
163
164
165
166
167
168

    # 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/"
169
170
171
    mkdir -p "${R_CMD_CHECK_DIR}"
    mv "${PKG_TARBALL}" "${R_CMD_CHECK_DIR}"
    cd "${R_CMD_CHECK_DIR}"
172
fi
173

174
175
176
177
declare -i allowed_notes=0
bash "${BUILD_DIRECTORY}/.ci/run-r-cmd-check.sh" \
    "${PKG_TARBALL}" \
    "${allowed_notes}"
178

179
180
181
# ensure 'grep --count' doesn't cause failures
set +e

182
183
184
185
186
187
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}'."
188
    exit 1
189
190
191
192
193
194
195
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}"
    )
196
    if [[ $passed_correct_r_version_to_cmake -ne 1 ]]; then
197
        echo "Unexpected R version was passed into cmake. Expected '${R_VERSION}'."
198
        exit 1
199
200
201
    fi
fi

202
# this check makes sure that CI builds of the package actually use OpenMP
203
204
205
if [[ $OS_NAME == "macos" ]] && [[ $R_BUILD_TYPE == "cran" ]]; then
    omp_working=$(
        cat $BUILD_LOG_FILE \
206
        | grep --count -E "checking whether OpenMP will work .*yes"
207
    )
208
209
210
211
212
213
214
215
216
217
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"
218
    exit 1
219
fi
220

221
# this check makes sure that CI builds of the package
222
# actually use MM_PREFETCH preprocessor definition
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#
# _mm_prefetch will not work on arm64 architecture
# ref: https://github.com/microsoft/LightGBM/issues/4124
if [[ $ARCH != "arm64" ]]; then
    if [[ $R_BUILD_TYPE == "cran" ]]; then
        mm_prefetch_working=$(
            cat $BUILD_LOG_FILE \
            | grep --count -E "checking whether MM_PREFETCH work.*yes"
        )
    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"
        exit 1
    fi
242
243
fi

244
# this check makes sure that CI builds of the package
245
246
247
248
249
250
# 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"
    )
251
252
253
254
255
256
257
258
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"
259
    exit 1
260
261
fi

262
263
264
265
266
# 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 \
267
        | grep --count -E "warning: unknown pragma ignored"
268
269
270
    )
    if [[ $pragma_warning_present -ne 0 ]]; then
        echo "Unknown pragma warning is present, pragmas should have been removed before build"
271
        exit 1
272
273
    fi
fi