Full CI #1784
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
# Copyright (c) godot-rust; Bromeon and contributors. | |
# This Source Code Form is subject to the terms of the Mozilla Public | |
# License, v. 2.0. If a copy of the MPL was not distributed with this | |
# file, You can obtain one at https://mozilla.org/MPL/2.0/. | |
name: Full CI | |
# | |
# Runs before merging. Rebases on master to make sure CI passes for latest integration, not only for the PR at the time of creation. | |
on: | |
# Allow manually triggering the workflow: | |
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch | |
workflow_dispatch: | |
merge_group: | |
# push: | |
env: | |
# Applies to all 'register-docs' features across crates. | |
CLIPPY_FEATURES: '--features register-docs,godot/experimental-godot-api,godot/serde' | |
TEST_FEATURES: '' | |
RETRY: ${{ github.workspace }}/.github/other/retry.sh | |
# ASan options: https://github.com/google/sanitizers/wiki/AddressSanitizerFlags | |
# LSan options: https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer | |
# * report_objects: list individual leaked objects when running LeakSanitizer | |
LSAN_OPTIONS: report_objects=1 | |
CARGO_DENY_VERSION: "0.16.1" | |
CARGO_MACHETE_VERSION: "0.7.0" | |
defaults: | |
run: | |
shell: bash | |
# If a new commit is pushed before the old one's CI has completed (on the same branch), abort previous run | |
#concurrency: | |
# group: ${{ github.head_ref }} | |
# cancel-in-progress: true | |
jobs: | |
# Keep all in sync with minimal-ci and release-version. | |
rustfmt: | |
runs-on: ubuntu-22.04 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
with: | |
components: rustfmt | |
- name: "Check rustfmt" | |
run: cargo fmt --all -- --check | |
- name: "Run custom repo checks" | |
run: | | |
cargo run -p repo-tweak | |
git diff --quiet --exit-code || { | |
echo "::error::Godot versions out of sync; update with `cargo run -p repo-tweak`." | |
echo "Differences:" | |
echo "----------------------------------------------------" | |
git diff | |
echo "----------------------------------------------------" | |
exit 1 | |
} | |
# Needs to be its own job (apart from sync-doc), because lints don't work with --no-deps, and because it contributes to ci-status. | |
doc-lints: | |
runs-on: ubuntu-22.04 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Patch Cargo.toml to use nightly extension API" | |
run: .github/other/patch-prebuilt.sh nightly | |
# rustdoc is included as component. | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
- name: "Check rustdoc" | |
env: | |
RUSTDOCFLAGS: > | |
-D rustdoc::broken-intra-doc-links -D rustdoc::private-intra-doc-links -D rustdoc::invalid-codeblock-attributes | |
-D rustdoc::invalid-rust-codeblocks -D rustdoc::invalid-html-tags -D rustdoc::bare-urls -D rustdoc::unescaped-backticks | |
run: cargo doc -p godot --ignore-rust-version | |
clippy: | |
runs-on: ubuntu-22.04 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Patch Cargo.toml to use nightly extension API" | |
run: .github/other/patch-prebuilt.sh nightly | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
with: | |
components: clippy | |
# Note: could use `-- --no-deps` to not lint dependencies, however it doesn't really speed up and also skips deps in workspace. | |
- name: "Check clippy" | |
run: | | |
cargo clippy --all-targets $CLIPPY_FEATURES -- \ | |
-D clippy::suspicious \ | |
-D clippy::style \ | |
-D clippy::complexity \ | |
-D clippy::perf \ | |
-D clippy::dbg_macro \ | |
-D clippy::todo \ | |
-D clippy::unimplemented \ | |
-D warnings | |
unit-test: | |
name: unit-test (${{ matrix.name }}${{ matrix.rust-special }}) | |
runs-on: ${{ matrix.os }} | |
continue-on-error: false | |
strategy: | |
fail-fast: false # cancel all jobs as soon as one fails? | |
matrix: | |
# Order this way because macOS typically has the 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. | |
include: | |
- name: macos | |
os: macos-latest # arm64 | |
- name: windows | |
os: windows-latest | |
# Don't use latest Ubuntu (22.04) as it breaks lots of ecosystem compatibility. | |
# If ever moving to ubuntu-latest, need to manually install libtinfo5 for LLVM. | |
- name: linux | |
os: ubuntu-22.04 | |
- name: linux | |
os: ubuntu-22.04 | |
rust-toolchain: nightly | |
rust-special: -minimal-deps | |
rust-cache-key: minimal-deps | |
- name: linux | |
os: ubuntu-22.04 | |
rust-toolchain: "1.80" | |
rust-special: -msrv | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Patch Cargo.toml to use nightly extension API" | |
# Only on Linux because godot4-prebuilt/nightly branch doesn't have artifacts for other platforms. | |
if: matrix.name == 'linux' && matrix.rust-special == '' | |
run: .github/other/patch-prebuilt.sh nightly | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
with: | |
rust: ${{ matrix.rust-toolchain || 'stable' }} | |
cache-key: ${{ matrix.rust-cache-key }} # only needed when rustc version is possibly the same | |
- name: "Install minimal dependency versions from Cargo" | |
if: matrix.rust-special == '-minimal-deps' | |
run: cargo +nightly update -Z minimal-versions | |
- name: "Compile tests" | |
run: cargo test $TEST_FEATURES --no-run ${{ matrix.rust-extra-args }} | |
- name: "Test" | |
run: cargo test $TEST_FEATURES ${{ matrix.rust-extra-args }} | |
miri-test: | |
name: miri-test | |
runs-on: ubuntu-22.04 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
with: | |
rust: nightly | |
components: miri | |
- name: "Setup Miri" | |
run: cargo miri setup | |
- name: "Compile tests" | |
run: cargo miri test -p godot-cell --no-run | |
- name: "Test stacked borrows" | |
run: cargo miri test -p godot-cell | |
- name: "Test tree borrows" | |
run: MIRIFLAGS="-Zmiri-tree-borrows" cargo miri test -p godot-cell | |
proptest: | |
name: proptest | |
runs-on: ubuntu-22.04 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
- name: "Compile tests" | |
run: cargo test -p godot-cell --features="proptest" --no-run | |
- name: "Test" | |
run: cargo test -p godot-cell --features="proptest" | |
# For complex matrix workflow, see https://stackoverflow.com/a/65434401 | |
godot-itest: | |
name: godot-itest (${{ matrix.name }}) | |
runs-on: ${{ matrix.os }} | |
continue-on-error: false | |
timeout-minutes: 24 | |
strategy: | |
fail-fast: false # cancel all jobs as soon as one fails? | |
matrix: | |
# Naming: {os}[-{runtimeVersion}]-{apiVersion} | |
# runtimeVersion = version of Godot binary; apiVersion = version of GDExtension API against which gdext is compiled. | |
# Config overview (see job for details). | |
# | |
# Cross-platform: | |
# - Base version: Godot nightly, no custom | |
# - Double precision: Godot nightly, custom (bindgen), double | |
# - 4.2 compat: Godot 4.2 | |
# | |
# Linux-only: | |
# - Full: Godot nightly, full codegen | |
# - Double + lazy: Godot nightly, custom, double, lazy func tables | |
# - Features + exp: Godot nightly, custom, threads, serde, experimental API | |
# - Memcheck nightly: Godot mem nightly, custom, sanitizer | |
# - Memcheck 4.x: Godot mem 4.0/4.1, sanitizer | |
# Note: Windows uses '--target x86_64-pc-windows-msvc' by default as Cargo argument. | |
include: | |
# macOS -- for the unintuitive naming, see https://github.com/actions/runner-images?tab=readme-ov-file#available-images | |
- name: macos-x86 | |
os: macos-13 | |
artifact-name: macos-x86-nightly | |
godot-binary: godot.macos.editor.dev.x86_64 | |
with-hot-reload: true | |
- name: macos-double-x86 | |
os: macos-13 | |
artifact-name: macos-double-x86-nightly | |
godot-binary: godot.macos.editor.dev.double.x86_64 | |
rust-extra-args: --features godot/api-custom,godot/double-precision | |
- name: macos-x86-4.2 | |
os: macos-13 | |
artifact-name: macos-x86-4.2 | |
godot-binary: godot.macos.editor.dev.x86_64 | |
godot-prebuilt-patch: '4.2.2' | |
- name: macos-arm | |
os: macos-latest | |
artifact-name: macos-arm-nightly | |
godot-binary: godot.macos.editor.dev.arm64 | |
with-hot-reload: true | |
# api-custom on macOS arm64 not working, due to clang linker issues. | |
# - name: macos-double-arm | |
# os: macos-latest | |
# artifact-name: macos-double-arm-nightly | |
# godot-binary: godot.macos.editor.dev.double.arm64 | |
# rust-extra-args: --features godot/api-custom,godot/double-precision | |
- name: macos-arm-4.2 | |
os: macos-latest | |
artifact-name: macos-arm-4.2 | |
godot-binary: godot.macos.editor.dev.arm64 | |
godot-prebuilt-patch: '4.2.2' | |
# Windows | |
- name: windows | |
os: windows-latest | |
artifact-name: windows-nightly | |
godot-binary: godot.windows.editor.dev.x86_64.exe | |
with-hot-reload: true | |
- name: windows-double | |
os: windows-latest | |
artifact-name: windows-double-nightly | |
godot-binary: godot.windows.editor.dev.double.x86_64.exe | |
rust-extra-args: --features godot/api-custom,godot/double-precision | |
- name: windows-4.2 | |
os: windows-latest | |
artifact-name: windows-4.2 | |
godot-binary: godot.windows.editor.dev.x86_64.exe | |
godot-prebuilt-patch: '4.2.2' | |
# - name: windows-4.1 | |
# os: windows-latest | |
# artifact-name: windows-4.1 | |
# godot-binary: godot.windows.editor.dev.x86_64.exe | |
# godot-prebuilt-patch: '4.1.3' | |
# Linux | |
# Don't use latest Ubuntu (22.04) as it breaks lots of ecosystem compatibility. | |
# If ever moving to ubuntu-latest, need to manually install libtinfo5 for LLVM. | |
# Uses full+experimental codegen, so that compatibility breakage towards nightly is detected. | |
# If the experimental part causes problems, consider using only godot/__codegen-full. | |
- name: linux-full | |
os: ubuntu-22.04 | |
artifact-name: linux-nightly | |
godot-binary: godot.linuxbsd.editor.dev.x86_64 | |
rust-extra-args: --features itest/codegen-full | |
with-hot-reload: true | |
# Combines now a lot of features, but should be OK. lazy-function-tables doesn't work with experimental-threads. | |
- name: linux-double-lazy | |
os: ubuntu-22.04 | |
artifact-name: linux-double-nightly | |
godot-binary: godot.linuxbsd.editor.dev.double.x86_64 | |
rust-extra-args: --features godot/api-custom,godot/double-precision,itest/codegen-full,godot/lazy-function-tables | |
- name: linux-features-experimental | |
os: ubuntu-22.04 | |
artifact-name: linux-nightly | |
godot-binary: godot.linuxbsd.editor.dev.x86_64 | |
rust-extra-args: --features itest/experimental-threads,itest/codegen-full-experimental,godot/api-custom,godot/serde,itest/register-docs | |
- name: linux-release | |
os: ubuntu-22.04 | |
artifact-name: linux-release-nightly | |
godot-binary: godot.linuxbsd.template_release.x86_64 | |
rust-extra-args: --release | |
rust-cache-key: release | |
# Linux compat (4.1 disabled, already covered by memcheck) | |
- name: linux-4.3 | |
os: ubuntu-22.04 | |
artifact-name: linux-4.3 | |
godot-binary: godot.linuxbsd.editor.dev.x86_64 | |
#godot-prebuilt-patch: '4.3.x' | |
- name: linux-4.2 | |
os: ubuntu-22.04 | |
artifact-name: linux-4.2 | |
godot-binary: godot.linuxbsd.editor.dev.x86_64 | |
godot-prebuilt-patch: '4.2.2' | |
# Memory checks: special Godot binaries compiled with AddressSanitizer/LeakSanitizer to detect UB/leaks. | |
# See also https://rustc-dev-guide.rust-lang.org/sanitizers.html. | |
# | |
# Additionally, the Godot source is patched to make dlclose() a no-op, as unloading dynamic libraries loses stacktrace and | |
# cause false positives like println!. See https://github.com/google/sanitizers/issues/89. | |
# | |
# There is also a gcc variant besides clang, which is currently not used. | |
- name: linux-memcheck-nightly | |
os: ubuntu-22.04 | |
artifact-name: linux-memcheck-nightly | |
godot-binary: godot.linuxbsd.editor.dev.x86_64.llvm.san | |
rust-toolchain: nightly | |
rust-env-rustflags: -Zrandomize-layout -Zsanitizer=address | |
rust-extra-args: --features godot/api-custom | |
# Sanitizers can't build proc-macros and build scripts; with --target, cargo ignores RUSTFLAGS for those two. | |
rust-target: x86_64-unknown-linux-gnu | |
- name: linux-memcheck-4.1 | |
os: ubuntu-22.04 | |
artifact-name: linux-memcheck-4.1 | |
godot-binary: godot.linuxbsd.editor.dev.x86_64.llvm.san | |
godot-prebuilt-patch: '4.1' # check compat of API 4.1.0 with newer binaries. | |
rust-toolchain: nightly | |
rust-env-rustflags: -Zrandomize-layout -Zsanitizer=address | |
# Sanitizers can't build proc-macros and build scripts; with --target, cargo ignores RUSTFLAGS for those two. | |
rust-target: x86_64-unknown-linux-gnu | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Run Godot integration test" | |
uses: ./.github/composite/godot-itest | |
with: | |
artifact-name: godot-${{ matrix.artifact-name }} | |
godot-binary: ${{ matrix.godot-binary }} | |
godot-args: ${{ matrix.godot-args }} # currently unused | |
godot-prebuilt-patch: ${{ matrix.godot-prebuilt-patch }} | |
rust-extra-args: ${{ matrix.rust-extra-args }} | |
rust-toolchain: ${{ matrix.rust-toolchain || 'stable' }} | |
rust-env-rustflags: ${{ matrix.rust-env-rustflags }} | |
rust-target: ${{ matrix.rust-target }} | |
rust-cache-key: ${{ matrix.rust-cache-key }} | |
with-llvm: ${{ contains(matrix.name, 'macos') && contains(matrix.rust-extra-args, 'api-custom') }} | |
godot-check-header: ${{ matrix.godot-check-header }} | |
- name: "Build and test hot-reload" | |
if: ${{ matrix.with-hot-reload }} | |
working-directory: examples/hot-reload/godot/test | |
# Repeat a few times, our hot reload integration test can sometimes be a bit flaky. | |
run: $RETRY ./run-test.sh | |
shell: bash | |
run-examples: | |
runs-on: ubuntu-22.04 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Rust" | |
uses: ./.github/composite/rust | |
# First compile, to fail early in case of compilation errors. | |
- name: "Compile Rust examples (release mode)" | |
run: cargo build --release -p dodge-the-creeps | |
- name: "Install Godot" | |
uses: ./.github/composite/godot-install | |
with: | |
artifact-name: godot-linux-4.3 | |
godot-binary: godot.linuxbsd.editor.dev.x86_64 | |
- name: "Run examples for short time" | |
run: ./.github/other/check-example.sh dodge-the-creeps | |
cargo-deny-machete: | |
runs-on: ubuntu-22.04 | |
steps: | |
- uses: actions/checkout@v4 | |
# 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 .github/other/deny.toml | |
# Machete | |
- name: "Install cargo-machete" | |
uses: baptiste0928/cargo-install@v3 | |
with: | |
crate: cargo-machete | |
version: ${{ env.CARGO_MACHETE_VERSION }} | |
- name: "Use machete to cut down dependencies" | |
run: cargo machete | |
license-guard: | |
runs-on: ubuntu-22.04 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Check license headers" | |
uses: 'apache/skywalking-eyes/[email protected]' | |
with: | |
# log: debug # optional: set the log level. The default value is `info`. | |
config: .github/other/licenserc.yml | |
# token: # optional: the token that license eye uses when it needs to comment on the pull request. | |
# Set to empty ("") to disable commenting on pull request. The default value is ${{ github.token }} | |
# mode: # optional: Which mode License-Eye should be run in. Choices are `check` or `fix`. The default value is `check`. | |
mode: check | |
# --------------------------------------------------------------------------------------------------------------------------------------------- | |
# CI status report | |
# Job to notify merge queue about success/failure | |
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 | |
- doc-lints | |
- clippy | |
- unit-test | |
- miri-test | |
- proptest | |
- godot-itest | |
- run-examples | |
- cargo-deny-machete | |
- license-guard | |
runs-on: ubuntu-22.04 | |
steps: | |
# Deliberate choice to use bash script and not GitHub Action glob syntax, as that is not well-documented and hard to get right. | |
# For example: contains(needs.*.result, 'success') does NOT work because * is a logical OR, thus true if a single job succeeds. | |
- name: "Determine success or failure" | |
run: | | |
DEPENDENCIES='${{ toJson(needs) }}' | |
echo "Dependency jobs:" | |
all_success=true | |
for job in $(echo "$DEPENDENCIES" | jq -r 'keys[]'); do | |
status=$(echo "$DEPENDENCIES" | jq -r ".[\"$job\"].result") | |
echo "* $job -> $status" | |
if [[ "$status" != "success" ]]; then | |
all_success=false | |
fi | |
done | |
if [[ "$all_success" == "false" ]]; then | |
echo "One or more dependency jobs failed or were cancelled." | |
exit 1 | |
fi |