Skip to content

feature: non-api adds non-API items to bindings #1363

feature: non-api adds non-API items to bindings

feature: non-api adds non-API items to bindings #1363

Workflow file for this run

name: Tests
on:
push:
branches:
- main
- master
pull_request:
branches:
- main
- master
issue_comment:
types:
- created
# Run this once per three days
schedule:
- cron: '29 17 */3 * *'
# This can also manually run
workflow_dispatch: {}
jobs:
test_with_bindgen:
# When the event is not issue_comment, always run the tests. When it is,
# check if (1) the comment is on pull request, (2) the comment author is the
# member of the organization, and (3) the comment starts with '/bindings'.
#
# ref.
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment
if: |
github.event_name != 'issue_comment'
|| (github.event.issue.pull_request && github.event.comment.author_association == 'MEMBER' && startsWith(github.event.comment.body, '/bindings'))
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (R-${{ matrix.config.r }} rust-${{ matrix.config.rust-version }}-${{ matrix.config.target || 'default' }})
strategy:
fail-fast: false
matrix:
config:
# On Windows,
#
# * for R >= 4.2, both the MSVC toolchain and the GNU toolchain should
# work. Since we primarily support MSVC, we focus on testing MSVC
# here. Also, at least one GNU case should be included so that we
# can detect when something gets broken.
# * for R < 4.2, the MSVC toolchain must be used to support
# cross-compilation to 32-bit.
#
# options:
# - targets: Targets to build and run tests against. If not
# specified, 'default' will be used.
# - no-test-targets: Targets to skip tests.
# - emit-bindings: If 'true', emit bindings. In principle, we choose
# only one stable Rust toolchain per combination of a platform and
# an R version (e.g. Windows and R-release) to emit bindings.
- {os: windows-latest, r: 'release', rust-version: 'stable-msvc', target: 'x86_64-pc-windows-gnu', emit-bindings: 'true'}
- {os: windows-latest, r: 'release', rust-version: 'nightly-msvc', target: 'x86_64-pc-windows-gnu'}
- {os: windows-latest, r: 'devel', rust-version: 'stable-msvc', target: 'x86_64-pc-windows-gnu', emit-bindings: 'true'}
- {os: windows-latest, r: 'release', rust-version: 'stable-gnu', target: 'x86_64-pc-windows-gnu'}
- {os: windows-latest, r: 'oldrel', rust-version: 'stable-msvc', target: 'x86_64-pc-windows-gnu', emit-bindings: 'true'}
- {os: macOS-latest, r: 'release', rust-version: 'nightly'}
- {os: macOS-latest, r: 'devel', rust-version: 'stable', emit-bindings: 'true'}
- {os: macOS-latest, r: 'oldrel', rust-version: 'stable', emit-bindings: 'true'}
- {os: macOS-latest, r: 'release', rust-version: 'stable', emit-bindings: 'true'}
- {os: macOS-latest, r: 'release', rust-version: 'stable', target: 'x86_64-apple-darwin', skip-tests: 'true', emit-bindings: 'true'}
- {os: ubuntu-latest, r: 'release', rust-version: 'nightly'}
- {os: ubuntu-latest, r: 'release', rust-version: 'stable', emit-bindings: 'true'}
- {os: ubuntu-latest, r: 'release', rust-version: 'stable', target: 'aarch64-unknown-linux-gnu', skip-tests: 'true', emit-bindings: 'true'}
- {os: ubuntu-latest, r: 'devel', rust-version: 'stable', emit-bindings: 'true'}
- {os: ubuntu-latest, r: 'devel', rust-version: 'stable', target: 'aarch64-unknown-linux-gnu', skip-tests: 'true', emit-bindings: 'true'}
- {os: ubuntu-latest, r: 'oldrel', rust-version: 'stable', emit-bindings: 'true'}
- {os: ubuntu-latest, r: 'oldrel', rust-version: 'stable', target: 'aarch64-unknown-linux-gnu', skip-tests: 'true', emit-bindings: 'true'}
env:
RSPM: ${{ matrix.config.rspm }}
# PowerShell core is available on all platforms and can be used to unify scripts
defaults:
run:
shell: pwsh
steps:
- uses: actions/checkout@v4
# When invoked by an issue comment event, the GitHub Actions runner runs
# on the default branch, so we need to switch the branch of the pull
# request. Since the branch name is not easily accessible via variables
# provided GitHub Actions, we use r-lib/actions, which is well-maintained.
- name: Switch branch (/bindings command)
if: github.event_name == 'issue_comment'
uses: r-lib/actions/pr-fetch@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up R
uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
use-public-rspm: true
- name: Set up Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.config.rust-version }}
components: rustfmt, clippy
targets: ${{ matrix.config.target }}
# All configurations for Windows go here
# 1. Configure linker
# 2. Create libgcc_eh mock
# 3. Add R bin path to PATH
# 4. Add Rtools' GCC to PATH (required to find linker)
# 5. Add include path (required to resolve standard headers like stdio.h)
- name: Configure Windows
if: runner.os == 'Windows'
run: |
# Configure linker
echo "RUSTFLAGS=-C linker=x86_64-w64-mingw32.static.posix-gcc.exe" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
# Create libgcc_eh mock
New-Item -Path libgcc_mock -Type Directory
New-Item -Path libgcc_mock\libgcc_eh.a -Type File
New-Item -Path libgcc_mock\libgcc_s.a -Type File
$pwd_slash = echo "${PWD}" | % {$_ -replace '\\','/'}
echo "LIBRARY_PATH=${pwd_slash}/libgcc_mock" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
# Add R bin path to PATH
echo "$(Rscript.exe --vanilla -e 'cat(normalizePath(R.home()))')\bin\x64" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append ;
# Add Rtools' GCC to PATH
# Source: https://github.com/r-lib/actions/blob/b7e68d63e51bdf225997973e2add36d551f60f02/setup-r/lib/installer.js#L471
$directories = @(
"C:\rtools44-aarch64\aarch64-w64-mingw32.static.posix",
"C:\rtools44\x86_64-w64-mingw32.static.posix",
"C:\rtools43\x86_64-w64-mingw32.static.posix",
"C:\rtools42\x86_64-w64-mingw32.static.posix",
"C:\rtools40\ucrt64",
"C:\Rtools\mingw_64"
)
$mingw_root = $null
foreach ($dir in $directories) {
if (Test-Path $dir) {
$mingw_root = $dir
Write-Host "Found Rtools directory at: $mingw_root"
break
}
}
echo "MINGW_ROOT=$mingw_root" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
if ($null -eq $mingw_root) {
Write-Host "No Rtools directory found."
} else {
Write-Host "Mingw root set to: $mingw_root"
}
echo "$mingw_root\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
# Add include path
echo "LIBRSYS_LIBCLANG_INCLUDE_PATH=$mingw_root\include" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
env:
RUST_TARGET: ${{ matrix.config.target }}
# macOS configurations, mainly llvm and path to libclang
# Because of this R installation issue on macOS-11.0
# https://github.com/r-lib/actions/issues/200
# Symlinks to R/Rscript are not properly set up, so we do it by hand, using this trick
# https://github.com/r-lib/ps/commit/a24f2c4d1bdba63be14e7729b9ab81d0ed9f719e
# Environment variables are required fir Mac-OS-11.0, see
# https://github.com/extendr/libR-sys/issues/35
- name: Configure macOS
if: runner.os == 'macOS'
run: |
brew install llvm
echo "LIBCLANG_PATH=$(brew --prefix llvm)/lib" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
$env:LLVM_CONFIG_PATH = "$(brew --prefix llvm)/bin/llvm-config"
echo "LLVM_CONFIG_PATH=$env:LLVM_CONFIG_PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "LIBRSYS_LIBCLANG_INCLUDE_PATH=$(. $env:LLVM_CONFIG_PATH --libdir)/clang/$(. $env:LLVM_CONFIG_PATH --version)/include" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
if ((Get-ChildItem -Path /usr/local/bin -Filter R | Measure-Object).Count -eq 0) {
echo "::warning:: Found no R symlink in /usr/local/bin, setting up manually..."
ln -s /Library/Frameworks/R.framework/Versions/Current/Resources/bin/R /usr/local/bin/
}
if ((Get-ChildItem -Path /usr/local/bin -Filter Rscript | Measure-Object).Count -eq 0) {
echo "::warning:: Found no Rscript symlink in /usr/local/bin, setting up manually..."
ln -s /Library/Frameworks/R.framework/Versions/Current/Resources/bin/Rscript /usr/local/bin/
}
# This is required for ubuntu r-devel
# 'Del alias:R' removes R alias which prevents running R
- name: Configure Linux
if: runner.os == 'linux'
run: |
Del alias:R
echo "LD_LIBRARY_PATH=$(R -s -e 'cat(normalizePath(R.home()))')/lib" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
if($env:RUST_TARGET -eq 'aarch64-unknown-linux-gnu') {
sudo apt-get update
sudo apt-get install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
# https://github.com/rust-lang/rust-bindgen/issues/1229
echo 'BINDGEN_EXTRA_CLANG_ARGS=--sysroot=/usr/aarch64-linux-gnu' >> $GITHUB_ENV
# https://github.com/rust-lang/rust/issues/28924
echo 'CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc' >> $GITHUB_ENV
}
env:
RUST_TARGET: ${{ matrix.config.target }}
# Build & run bindings with layout tests
- name: Run tests
id: test
if: matrix.config.skip-tests != 'true'
run: |
. ./ci-cargo.ps1
ci-cargo test -vv --features use-bindgen,layout_tests $(if ($env:RUST_TARGET -ne '') {"--target=$env:RUST_TARGET"} ) '--' --nocapture -ActionName "Running bindgen tests for target: $env:RUST_TARGET"
env:
RUST_TARGET: ${{ matrix.config.target }}
# Build and emit bindings to './generated_bindings'
- name: Build & Emit bindings
id: build
run: |
. ./ci-cargo.ps1
ci-cargo build -vv --features use-bindgen $(if ($env:RUST_TARGET -ne '') {"--target=$env:RUST_TARGET"} ) -ActionName "Building for target: $env:RUST_TARGET"
env:
LIBRSYS_BINDINGS_OUTPUT_PATH: generated_bindings
RUST_TARGET: ${{ matrix.config.target }}
- name: Upload generated bindings
if:
steps.build.outcome == 'success' &&
matrix.config.emit-bindings == 'true'
uses: actions/upload-artifact@v4
with:
name: generated_binding-${{ matrix.config.os }}-R-${{ matrix.config.r }}-rust-${{ matrix.config.rust-version }}-${{ matrix.config.target || 'default'}}
path: generated_bindings
check_generate_bindings_flag:
name: Check if [generate bindings] is in latest commit message
runs-on: ubuntu-latest
outputs:
head_commit_message: ${{ steps.get_head_commit_message.outputs.HEAD_COMMIT_MESSAGE }}
# generate_bindings: ${{ contains(steps.get_head_commit_message.outputs.HEAD_COMMIT_MESSAGE, '[generate bindings]') }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Get Head Commit Message
id: get_head_commit_message
run: echo "HEAD_COMMIT_MESSAGE=$(git show -s --format=%s)" >> "$GITHUB_OUTPUT"
- name: Show commit message
run: |
echo "${{ steps.get_head_commit_message.outputs.HEAD_COMMIT_MESSAGE }}"
echo "${{ contains(steps.get_head_commit_message.outputs.HEAD_COMMIT_MESSAGE, '[generate bindings]') }}"
pr_generated_bindings:
name: Make PR with generated bindings
needs: [test_with_bindgen, check_generate_bindings_flag]
if: ${{ contains(needs.check_generate_bindings_flag.outputs.head_commit_message, '[generate bindings]') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.ref }}
- uses: actions/download-artifact@v4
- name: Update bindings
run: |
# Update or add the bindings
cp generated_binding-*/*.rs bindings/
# Replace the default bindings
cd bindings
for x in linux-aarch64 linux-x86_64 macos-aarch64 macos-x86_64 windows-x86_64; do
# Choose the newest version except for devel
ln --force -s "$(ls -1 ./bindings-${x}-*.rs | grep -v devel | sort | tail -1)" ./bindings-${x}.rs
done
cd ..
- name: Add generated bindings
run: |
git add bindings/
git config --local user.name "${GITHUB_ACTOR}"
git config --local user.email "${GITHUB_ACTOR}@users.noreply.github.com"
git commit -m "Update bindings [skip ci]"
- name: Push to PR branch
run: git push
# Gather the generated bindings and push them to generated_bindings branch.
# If we need to update the bindings, create a pull request from that branch.
commit_generated_bindings:
needs: test_with_bindgen
runs-on: ubuntu-latest
# In the case of /bindings command, we don't need to check anything else
# because it should have checked in test_with_bindings job. In the other
# cases, we only want to invoke this on the master branch.
if: github.event_name == 'issue_comment' || github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
- name: Switch branch
if: github.event_name != 'issue_comment'
run: |
# 1) If there's already generated_bindings branch, checkout it.
# 2) If generated_binding branch is not created, create it from the default branch.
if git ls-remote --exit-code --heads origin generated_bindings 2>&1 >/dev/null; then
git fetch origin --no-tags --prune --depth=1 generated_bindings
git checkout generated_bindings
else
git switch -c generated_bindings
fi
- name: Switch branch (/bindings command)
if: github.event_name == 'issue_comment'
uses: r-lib/actions/pr-fetch@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Commit the generated bindings
run: |
# Update or add the bindings
cp generated_binding-*/*.rs bindings/
# Replace the default bindings
cd bindings
for x in linux-aarch64 linux-x86_64 macos-aarch64 macos-x86_64 windows-x86_64; do
# Choose the newest version except for devel
ln --force -s "$(ls -1 ./bindings-${x}-*.rs | grep -v devel | sort | tail -1)" ./bindings-${x}.rs
done
cd ..
# detect changes (the code is derived from https://stackoverflow.com/a/3879077)
git add bindings/
git update-index --refresh
if ! git diff-index --quiet HEAD -- bindings/; then
git config --local user.name "${GITHUB_ACTOR}"
git config --local user.email "${GITHUB_ACTOR}@users.noreply.github.com"
git commit -m "Update bindings [skip ci]"
else
echo "No changes"
fi
- name: Push
if: github.event_name != 'issue_comment'
run: git push origin generated_bindings
- name: Push (/bindings command)
if: github.event_name == 'issue_comment'
uses: r-lib/actions/pr-push@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}