Full CI #327
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Complete CI workflow | |
# Run by GitHub merge queues, and enforced before any PR is merged | |
# Includes unit and integration tests for all platforms, as well as optional nightly jobs | |
# See also: https://matklad.github.io/2021/09/04/fast-rust-builds.html | |
# Note: if workflow-wide fail-fast is needed, this step can be added at the end of *each* job. | |
# It will immediately cancel all outstanding jobs. This can be useful to free them up for other runs. | |
# - name: If job failed, cancel workflow... | |
# if: failure() | |
# uses: andymckay/cancel-action@0.2 | |
# Note: important points about Rust caching (Swatinem/rust-cache action), which contributes majorly to speedup: | |
# 1. It caches only dependencies. The own crates are always fully recompiled, and incremental compilation is disabled. | |
# 2. It takes the current job ID as a key, which means it CANNOT cache between jobs. | |
# Running a prior job to reuse build artifacts is thus pointless with this action. | |
# 3. The dependencies in Cargo.toml are hashed into the key, thus it cannot happen that removing a dependency will still work | |
# due to the dependency being cached. On the other hand, it means dependency changes come with full recompile. | |
# 4. As the effectivity of the cache depends on previous runs and available runners, workflow execution times | |
# can easily vary by 30%. | |
# Note: if CI becomes more complex, we might look into code-generation of the action and workflow files at some point. | |
# 300+ LOC for a few platform tests is still OK, but there's a lot of repetition, and quite some limitations that could be addressed. | |
name: Full CI | |
env: | |
# Local variables | |
# Note: using variables is limited at the moment, see https://github.com/actions/runner/issues/480 | |
GDRUST_FEATURES: "gdnative/async,gdnative/serde,gdnative_bindings_generator/debug" | |
CARGO_DENY_VERSION: "0.11.4" | |
CARGO_DINGHY_VERSION: "0.6.4" | |
CARGO_MACHETE_VERSION: "0.3" | |
on: | |
merge_group: | |
defaults: | |
run: | |
shell: bash | |
jobs: | |
rustfmt: | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v3 | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
with: | |
components: rustfmt | |
- name: "Check rustfmt" | |
run: cargo fmt --all -- --check | |
clippy: | |
name: clippy${{ matrix.rust.postfix }} | |
runs-on: ubuntu-latest | |
continue-on-error: ${{ matrix.rust.toolchain == 'nightly' }} | |
needs: rustfmt | |
strategy: | |
matrix: | |
rust: | |
- toolchain: stable | |
postfix: '' | |
- toolchain: nightly | |
postfix: ' (nightly)' | |
steps: | |
- uses: actions/checkout@v3 | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
with: | |
rust: ${{ matrix.rust.toolchain }} | |
components: clippy | |
- name: "Check clippy" | |
run: cargo clippy --workspace --features ${GDRUST_FEATURES} -- -D clippy::style -D clippy::complexity -D clippy::perf -D clippy::dbg_macro -D clippy::todo -D clippy::unimplemented -D warnings | |
cargo-deny-machete: | |
runs-on: ubuntu-latest | |
needs: rustfmt | |
steps: | |
- uses: actions/checkout@v3 | |
# Deny | |
# Note: manually downloading is ~30s faster than https://github.com/EmbarkStudios/cargo-deny-action | |
- name: "Install cargo-deny" | |
run: | | |
wget --no-verbose https://github.com/EmbarkStudios/cargo-deny/releases/download/$CARGO_DENY_VERSION/cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz -O cargo-deny.tar.gz | |
tar -zxvf cargo-deny.tar.gz | |
mkdir -p $HOME/.cargo/bin | |
mv cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl/cargo-deny $HOME/.cargo/bin | |
- name: "Deny non-conforming dependencies" | |
run: cargo deny check --config tools/deny.toml | |
# Machete | |
- name: "Install cargo-machete" | |
uses: baptiste0928/cargo-install@v1 | |
with: | |
crate: cargo-machete | |
version: ${{ env.CARGO_MACHETE_VERSION }} | |
- name: "Use machete to cut down dependencies" | |
run: cargo machete | |
test: | |
name: test-${{ matrix.os.name }}${{ matrix.rust.postfix }} | |
needs: rustfmt | |
continue-on-error: ${{ matrix.rust.toolchain == 'nightly' }} | |
strategy: | |
fail-fast: true # cancel all jobs as soon as one fails? | |
matrix: | |
# Order this way because MacOS typically has longest duration, followed by Windows, so it benefits total workflow execution time. | |
# Additionally, the 'linux (msrv *)' special case will then be listed next to the other 'linux' jobs. | |
# Note: Windows uses '--target x86_64-pc-windows-msvc' by default as Cargo argument. | |
os: | |
- id: macos-latest | |
name: macos | |
- id: windows-latest | |
name: windows | |
- id: ubuntu-latest | |
name: linux | |
rust: | |
- toolchain: stable | |
postfix: '' | |
- toolchain: nightly | |
postfix: ' (nightly)' | |
# All non-stable versions skip UI tests, as it's usually impossible to have them satisfy all possible compiler versions simultaneously | |
include: | |
- rust: { toolchain: 'nightly' } | |
testflags: '-- --skip ui_tests' | |
- os: { id: ubuntu-latest, name: linux } | |
rust: { toolchain: '1.67', postfix: ' (msrv 1.67)' } | |
testflags: '-- --skip ui_tests' | |
- os: { id: ubuntu-latest, name: linux } | |
rust: { toolchain: 'stable', postfix: ' (minimal-deps)', special: 'minimal-deps' } | |
testflags: '-- --skip ui_tests' | |
runs-on: ${{ matrix.os.id }} | |
steps: | |
- uses: actions/checkout@v3 | |
- name: "Install nightly Rust (minimal-deps only)" | |
uses: actions-rs/toolchain@v1 | |
with: | |
profile: minimal | |
toolchain: nightly | |
override: false # use selected toolchain for remainder of this step | |
components: cargo | |
if: ${{ matrix.rust.special == 'minimal-deps' }} | |
- name: "Install minimal dependency versions from Cargo" | |
run: cargo +nightly update -Z minimal-versions | |
if: ${{ matrix.rust.special == 'minimal-deps' }} | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
with: | |
rust: ${{ matrix.rust.toolchain }} | |
cache-key: ${{ matrix.rust.special }} # 'minimal-deps' or empty/not defined | |
- name: "Install LLVM" | |
uses: ./.github/composite/llvm | |
if: ${{ matrix.os.id == 'windows-latest' }} | |
- name: "Compile tests" | |
run: cargo test --workspace --features ${GDRUST_FEATURES} --no-run | |
- name: "Test" | |
run: cargo test --workspace --features ${GDRUST_FEATURES} ${{ matrix.testflags }} | |
build-release: | |
name: build-release-${{ matrix.os.name }} | |
needs: rustfmt | |
strategy: | |
fail-fast: true # cancel all jobs as soon as one fails? | |
matrix: | |
os: | |
- id: macos-latest | |
name: macos | |
- id: windows-latest | |
name: windows | |
- id: ubuntu-latest | |
name: linux | |
runs-on: ${{ matrix.os.id }} | |
steps: | |
- uses: actions/checkout@v3 | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
with: | |
rust: stable | |
- name: "Install LLVM" | |
uses: ./.github/composite/llvm | |
if: ${{ matrix.os.id == 'windows-latest' }} | |
- name: "Release build (check only)" | |
run: cargo check --release | |
build-ios: | |
needs: rustfmt | |
#continue-on-error: ${{ matrix.rust == 'nightly' }} | |
#strategy: | |
# matrix: | |
# rust: [stable] | |
runs-on: macos-latest | |
steps: | |
- uses: actions/checkout@v3 | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
#with: | |
# rust: ${{ matrix.rust.toolchain }} | |
- name: "Install cargo-dinghy" | |
run: | | |
rustup target add x86_64-apple-ios | |
curl -L https://github.com/sonos/dinghy/releases/download/$CARGO_DINGHY_VERSION/cargo-dinghy-macos-$CARGO_DINGHY_VERSION.tgz -o cargo-dinghy-macos.tar.gz | |
tar -zxvf cargo-dinghy-macos.tar.gz | |
mkdir -p $HOME/.cargo/bin | |
cp cargo-dinghy-$CARGO_DINGHY_VERSION/cargo-dinghy $HOME/.cargo/bin | |
- name: "Cross-compile to iOS" | |
run: | | |
RUNTIME_ID=$(xcrun simctl list runtimes | grep iOS | cut -d ' ' -f 7 | tail -1) | |
export SIM_ID=$(xcrun simctl create My-iphone11 com.apple.CoreSimulator.SimDeviceType.iPhone-11 $RUNTIME_ID) | |
xcrun simctl boot $SIM_ID | |
cd gdnative-core | |
cargo dinghy --platform auto-ios-x86_64 test | |
cd .. | |
cd gdnative-sys | |
cargo dinghy --platform auto-ios-x86_64 test | |
build-android: | |
# Note: even though Android builds for another architecture than Linux, it can reuse downloaded crates (source code, maybe 'cargo check'). | |
needs: rustfmt | |
#continue-on-error: ${{ matrix.rust == 'nightly' }} | |
#strategy: | |
# matrix: | |
# rust: [stable] | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v3 | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
#with: | |
# rust: ${{ matrix.rust.toolchain }} | |
- name: "Install Java + NDK" | |
run: | | |
# aarch64 and armv7 cover most Android phones & tablets. | |
rustup target add aarch64-linux-android armv7-linux-androideabi | |
sudo apt-get update | |
sudo apt-get install llvm-dev libclang-dev clang g++-multilib gcc-multilib libc6-dev libc6-dev-arm64-cross | |
# Relies on ls listing alphabetically, NDK versions having fixed | |
# digits, and the folder not containing any other files | |
- name: "Find highest Android NDK version" | |
run: | | |
highestNdk=$(ls $ANDROID_SDK_ROOT/ndk | tail -n1) | |
echo "Highest Android NDK: $highestNdk" | |
echo "ANDROID_NDK_VERSION=$highestNdk" >> $GITHUB_ENV | |
# See https://github.com/godot-rust/godot-rust/pull/920 | |
- name: "Found version ${{ env.ANDROID_NDK_VERSION }}. Workaround Rust bug..." | |
run: > | |
find -L $ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION -name libunwind.a | |
-execdir sh -c 'echo "INPUT(-lunwind)" > libgcc.a' \; | |
- name: "Build Rust for targets: aarch64-linux-android, armv7-linux-androideabi" | |
run: | | |
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++ | |
export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang++ | |
cargo build --target aarch64-linux-android --release | |
cargo build --target armv7-linux-androideabi --release | |
integration-test-godot: | |
name: itest-godot-${{ matrix.godot }}${{ matrix.postfix }} | |
needs: rustfmt | |
continue-on-error: ${{ matrix.rust.toolchain == 'nightly' }} | |
strategy: | |
fail-fast: false # cancel all jobs as soon as one fails? | |
matrix: | |
include: | |
# Latest Godot with different Rust versions | |
- rust: stable | |
godot: "3.5.1-stable" | |
postfix: '' | |
- rust: stable | |
godot: "3.5.1-stable" | |
postfix: ' (ptrcall)' | |
build_args: '--features ptrcall' | |
- rust: stable | |
godot: "3.5.1-stable" | |
postfix: ' (inventory)' | |
build_args: '--features inventory' | |
- rust: stable | |
godot: "3.5.1-stable" | |
postfix: ' (inventory)' | |
# Limiting no-manual-register tests to stable as to not slow down CI too far -- if inventory is | |
# working across all 3 Rust versions, this is likely to be as well. | |
build_args: '--features inventory,no-manual-register' | |
- rust: nightly | |
godot: "3.5.1-stable" | |
postfix: ' (nightly)' | |
- rust: nightly | |
godot: "3.5.1-stable" | |
postfix: ' (nightly, ptrcall)' | |
build_args: '--features ptrcall' | |
- rust: nightly | |
godot: "3.5.1-stable" | |
postfix: ' (nightly, inventory)' | |
build_args: '--features inventory' | |
- rust: '1.67' | |
godot: "3.5.1-stable" | |
postfix: ' (msrv 1.67)' | |
- rust: '1.67' | |
godot: "3.5.1-stable" | |
postfix: ' (msrv 1.67, ptrcall)' | |
build_args: '--features ptrcall' | |
- rust: '1.67' | |
godot: "3.5.1-stable" | |
postfix: ' (msrv 1.67, inventory)' | |
build_args: '--features inventory' | |
# Test with oldest supported engine version | |
- rust: stable | |
godot: "3.2-stable" | |
postfix: '' | |
build_args: '--features custom-godot' | |
- rust: stable | |
godot: "3.2-stable" | |
postfix: ' (ptrcall)' | |
build_args: '--features custom-godot,ptrcall' | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v3 | |
- name: "Run Godot integration test" | |
uses: ./.github/composite/godot | |
with: | |
rust_toolchain: ${{ matrix.rust }} | |
rust_extra_args: ${{ matrix.build_args }} | |
godot_ver: ${{ matrix.godot }} | |
# Job to notify merge queue about success/failure. Named the same as the one in minimal-ci. | |
# It is always run, even on failure, to not wait until timeouts happen. | |
# | |
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! | |
ci-status: | |
# Check for 'merge_group' not strictly necessary, but helpful when adding add-hoc `push:` trigger to `on:` for testing branch. | |
if: always() && github.event_name == 'merge_group' | |
needs: | |
- rustfmt | |
- clippy | |
- cargo-deny-machete | |
- test | |
- build-release | |
- build-ios | |
- build-android | |
- integration-test-godot | |
runs-on: ubuntu-latest | |
steps: | |
- name: "Success" | |
if: ${{ !(contains(needs.*.result, 'failure')) }} | |
run: exit 0 | |
- name: "Failure" | |
if: ${{ contains(needs.*.result, 'failure') }} | |
run: exit 1 |