name: main on: push: branches: [ main ] pull_request: branches: [ main ] workflow_call: # required to call this workflow from another workflow like release.yml env: CARGO_TERM_COLOR: always FILE_ROOTSHELL: ../../rootshell/rootshell FILE_RAYHUNTER_DAEMON: ../../rayhunter-daemon/rayhunter-daemon RUSTFLAGS: "-Dwarnings" jobs: files_changed: name: Detect file changes runs-on: ubuntu-latest permissions: contents: read outputs: code_changed: ${{ steps.files_changed.outputs.code_count }} daemon_changed: ${{ steps.files_changed.outputs.daemon_count }} web_changed: ${{ steps.files_changed.outputs.web_count }} docs_changed: ${{ steps.files_changed.outputs.docs_count }} installer_changed: ${{ steps.files_changed.outputs.installer_count }} installer_gui_changed: ${{ steps.files_changed.outputs.installer_gui_count }} rootshell_changed: ${{ steps.files_changed.outputs.rootshell_count }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: detect file changes id: files_changed run: | lcommit=${{ github.event.pull_request.base.sha || 'origin/main' }} # If we are on main, or if these workflow files are being changed, run everything if [ ${{ github.ref }} = 'refs/heads/main' ] || git diff --name-only $lcommit..HEAD | grep -qe ^.github/workflows/ -e ^.cargo then echo "building everything" echo code_count=forced >> "$GITHUB_OUTPUT" echo daemon_count=forced >> "$GITHUB_OUTPUT" echo web_count=forced >> "$GITHUB_OUTPUT" echo docs_count=forced >> "$GITHUB_OUTPUT" echo installer_count=forced >> "$GITHUB_OUTPUT" echo installer_gui_count=forced >> "$GITHUB_OUTPUT" echo rootshell_count=forced >> "$GITHUB_OUTPUT" else echo "code_count=$(git diff --name-only $lcommit...HEAD | grep -e ^daemon -e ^installer -e ^check -e ^lib -e ^rootshell -e ^telcom-parser | wc -l)" >> "$GITHUB_OUTPUT" echo "daemon_count=$(git diff --name-only $lcommit...HEAD | grep -e ^daemon -e ^lib -e ^telcom-parser | wc -l)" >> "$GITHUB_OUTPUT" echo "web_count=$(git diff --name-only $lcommit...HEAD | grep -e ^daemon/web | wc -l)" >> "$GITHUB_OUTPUT" echo "docs_count=$(git diff --name-only $lcommit...HEAD | grep -e ^book.toml -e ^doc | wc -l)" >> "$GITHUB_OUTPUT" echo "installer_count=$(git diff --name-only $lcommit...HEAD | grep -e ^installer/ | wc -l)" >> "$GITHUB_OUTPUT" echo "installer_gui_count=$(git diff --name-only $lcommit...HEAD | grep -e ^installer-gui | wc -l)" >> "$GITHUB_OUTPUT" echo "rootshell_count=$(git diff --name-only $lcommit...HEAD | grep -e ^rootshell | wc -l)" >> "$GITHUB_OUTPUT" fi mdbook_test: name: Test mdBook Documentation builds needs: files_changed if: needs.files_changed.outputs.docs_changed != '0' runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@v4 - name: Install mdBook run: | cargo install mdbook --no-default-features --features search --vers "^0.4" --locked - name: Test mdBook run: mdbook test mdbook_publish: name: Publish mdBook to Github Pages needs: mdbook_test if: ${{ github.ref == 'refs/heads/main' }} permissions: pages: write contents: write id-token: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install mdBook run: | cargo install mdbook --no-default-features --features search --vers "^0.4" --locked - name: Build mdBook run: mdbook build - name: Setup Pages uses: actions/configure-pages@v4 - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: book - name: Deploy to Github Pages uses: actions/deploy-pages@v4 check_and_test: needs: files_changed if: needs.files_changed.outputs.code_changed != '0' runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 - name: Check formatting run: cargo fmt --all --check - name: Check run: | pushd daemon/web npm install npm run build popd NO_FIRMWARE_BIN=true cargo check --verbose - name: Run tests run: | NO_FIRMWARE_BIN=true cargo test --verbose - name: Run clippy run: | NO_FIRMWARE_BIN=true cargo clippy --verbose installer_gui_check: # we test the GUI installer separately to: # 1) mimic the default behavior of cargo commands for rayhunter devs where # installer-gui isn't one of the default workspace packages # 2) avoid slowing down development on changes unrelated to the GUI installer needs: files_changed if: needs.files_changed.outputs.installer_gui_changed != '0' # we run this on macos simply because no additional OS packages need to be # installed runs-on: macos-latest permissions: contents: read steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: clippy - uses: Swatinem/rust-cache@v2 # we don't need to run cargo fmt here because both cargo fmt and cargo # fmt --all runs on all workspace packages so this is handled by # check_and_test above - name: Check run: | SKIP_INSTALLER_COPY=true cargo check --package installer-gui --verbose - name: Run clippy run: | SKIP_INSTALLER_COPY=true cargo clippy --package installer-gui --verbose test_daemon_frontend: needs: files_changed if: needs.files_changed.outputs.web_changed != '0' runs-on: ubuntu-latest permissions: contents: read defaults: run: working-directory: daemon/web steps: - uses: actions/checkout@v4 - run: npm install - run: npm run lint - run: npm run check - run: npm run test test_installer_frontend: needs: files_changed if: needs.files_changed.outputs.installer_gui_changed != '0' runs-on: ubuntu-latest permissions: contents: read defaults: run: working-directory: installer-gui steps: - uses: actions/checkout@v4 - run: npm install - run: npm run lint - run: npm run check windows_installer_check_and_test: needs: files_changed if: needs.files_changed.outputs.installer_changed != '0' runs-on: windows-latest permissions: contents: read steps: - uses: actions/checkout@v4 - uses: Swatinem/rust-cache@v2 - name: cargo check shell: bash run: | cd installer NO_FIRMWARE_BIN=true cargo check --verbose - name: cargo test shell: bash run: | cd installer NO_FIRMWARE_BIN=true cargo test --verbose --no-default-features build_rayhunter_check: if: needs.files_changed.outputs.daemon_changed != '0' needs: - check_and_test - files_changed permissions: contents: read packages: write strategy: matrix: platform: - name: linux-x64 os: ubuntu-latest target: x86_64-unknown-linux-musl - name: linux-armv7 os: ubuntu-latest target: armv7-unknown-linux-musleabi - name: linux-aarch64 os: ubuntu-24.04-arm target: aarch64-unknown-linux-musl - name: macos-arm os: macos-latest target: aarch64-apple-darwin - name: macos-intel os: macos-latest target: x86_64-apple-darwin - name: windows-x86_64 os: windows-latest target: x86_64-pc-windows-gnu runs-on: ${{ matrix.platform.os }} steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.platform.target }} - uses: Swatinem/rust-cache@v2 - name: Build rayhunter-check run: cargo build --bin rayhunter-check --release --target ${{ matrix.platform.target }} - uses: actions/upload-artifact@v4 with: name: rayhunter-check-${{ matrix.platform.name }} path: target/${{ matrix.platform.target }}/release/rayhunter-check${{ matrix.platform.os == 'windows-latest' && '.exe' || '' }} if-no-files-found: error build_rootshell: if: needs.files_changed.outputs.rootshell_changed != '0' || needs.files_changed.outputs.installer_changed != '0' needs: - check_and_test - files_changed runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: armv7-unknown-linux-musleabihf - uses: Swatinem/rust-cache@v2 - name: Build rootshell (armv7) run: cargo build -p rootshell --bin rootshell --target armv7-unknown-linux-musleabihf --profile=firmware - uses: actions/upload-artifact@v4 with: name: rootshell path: target/armv7-unknown-linux-musleabihf/firmware/rootshell if-no-files-found: error build_rayhunter: # build_rust_installer needs this step. so when installer_changed, we need # to build this step too. if we skip this step because only the installer # changed, the build_rust_installer step will be skipped too. if: needs.files_changed.outputs.daemon_changed != '0' || needs.files_changed.outputs.installer_changed != '0' needs: - check_and_test - files_changed permissions: contents: read packages: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: armv7-unknown-linux-musleabihf - uses: Swatinem/rust-cache@v2 - name: Install ARM cross-compilation toolchain run: sudo apt-get update && sudo apt-get install -y gcc-arm-linux-gnueabihf - name: Build rayhunter-daemon (armv7) run: | pushd daemon/web npm install npm run build popd # Run with -p so that cargo will select the minimum feature set for this package. # # Otherwise, it will consider the union of all requested features # from all packages in the workspace. For example, if installer # requires tokio with "full" feature, it will be included no matter # what the feature selection in rayhunter-daemon is. # # https://github.com/rust-lang/cargo/issues/4463 CC_armv7_unknown_linux_musleabihf=arm-linux-gnueabihf-gcc cargo build-daemon-firmware - uses: actions/upload-artifact@v4 with: name: rayhunter-daemon path: target/armv7-unknown-linux-musleabihf/firmware/rayhunter-daemon if-no-files-found: error build_rust_installer: if: needs.files_changed.outputs.installer_changed != '0' permissions: contents: read packages: write needs: - build_rayhunter - build_rootshell - files_changed - windows_installer_check_and_test strategy: matrix: platform: - name: linux-x64 os: ubuntu-latest target: x86_64-unknown-linux-musl - name: linux-armv7 os: ubuntu-latest target: armv7-unknown-linux-musleabi - name: linux-aarch64 os: ubuntu-24.04-arm target: aarch64-unknown-linux-musl - name: macos-arm os: macos-latest target: aarch64-apple-darwin - name: macos-intel os: macos-latest target: x86_64-apple-darwin - name: windows-x86_64 os: windows-latest target: x86_64-pc-windows-gnu runs-on: ${{ matrix.platform.os }} steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.platform.target }} - uses: Swatinem/rust-cache@v2 - run: cargo build --package installer --bin installer --release --target ${{ matrix.platform.target }} - uses: actions/upload-artifact@v4 with: name: installer-${{ matrix.platform.name }} path: target/${{ matrix.platform.target }}/release/installer${{ matrix.platform.os == 'windows-latest' && '.exe' || '' }} if-no-files-found: error build_installer_gui_linux: if: needs.files_changed.outputs.installer_gui_changed != '0' permissions: contents: read packages: write needs: - build_rust_installer - files_changed - installer_gui_check - test_installer_frontend strategy: matrix: platform: # we want to use the oldest supported version of ubuntu here to # maximize compatibility with older versions of glibc - name: linux-x64 os: ubuntu-22.04 target: x86_64-unknown-linux-gnu - name: linux-aarch64 os: ubuntu-22.04-arm target: aarch64-unknown-linux-gnu runs-on: ${{ matrix.platform.os }} steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.platform.target }} - uses: Swatinem/rust-cache@v2 - name: Install tauri dependencies run: sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev xdg-utils - name: Build GUI installer env: INSTALLER_PATH: "${{ github.workspace }}/installer-${{ matrix.platform.name }}/installer" shell: bash run: | cd installer-gui npm install chmod +x "$INSTALLER_PATH" npm run tauri build -- --target ${{ matrix.platform.target }} - uses: actions/upload-artifact@v4 with: name: gui-installer-${{ matrix.platform.name }}-appimage path: target/${{ matrix.platform.target }}/release/bundle/appimage/*.AppImage if-no-files-found: error - uses: actions/upload-artifact@v4 with: name: gui-installer-${{ matrix.platform.name }}-deb path: target/${{ matrix.platform.target }}/release/bundle/deb/*.deb if-no-files-found: error - uses: actions/upload-artifact@v4 with: name: gui-installer-${{ matrix.platform.name }}-rpm path: target/${{ matrix.platform.target }}/release/bundle/rpm/*.rpm if-no-files-found: error build_installer_gui_macos: if: needs.files_changed.outputs.installer_gui_changed != '0' permissions: contents: read packages: write needs: - build_rust_installer - files_changed - installer_gui_check - test_installer_frontend strategy: matrix: platform: - name: macos-arm target: aarch64-apple-darwin - name: macos-intel target: x86_64-apple-darwin runs-on: macos-latest steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.platform.target }} - uses: Swatinem/rust-cache@v2 - name: Build GUI installer env: INSTALLER_PATH: "${{ github.workspace }}/installer-${{ matrix.platform.name }}/installer" shell: bash run: | cd installer-gui npm install chmod +x "$INSTALLER_PATH" npm run tauri build -- --target ${{ matrix.platform.target }} cd .. mv "target/${{ matrix.platform.target }}/release/bundle/macos/"*.app . zip -r "rayhunter-installer-${{ matrix.platform.name }}.app.zip" ./*.app - uses: actions/upload-artifact@v4 with: name: gui-installer-${{ matrix.platform.name }}-app path: ./*.app.zip if-no-files-found: error build_installer_gui_windows: if: needs.files_changed.outputs.installer_gui_changed != '0' permissions: contents: read packages: write needs: - build_rust_installer - files_changed - installer_gui_check - test_installer_frontend env: TARGET: x86_64-pc-windows-msvc runs-on: windows-latest steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ env.TARGET }} - uses: Swatinem/rust-cache@v2 - name: Build GUI installer shell: bash env: INSTALLER_PATH: "${{ github.workspace }}/installer-windows-x86_64/installer.exe" run: | cd installer-gui npm install chmod +x "$INSTALLER_PATH" npm run tauri build -- --target ${{ env.TARGET }} - uses: actions/upload-artifact@v4 with: name: gui-installer-msi path: target/${{ env.TARGET }}/release/bundle/msi/*.msi if-no-files-found: error - uses: actions/upload-artifact@v4 with: name: gui-installer-exe path: target/${{ env.TARGET }}/release/bundle/nsis/*.exe if-no-files-found: error build_release_zip: permissions: contents: read packages: write needs: - build_rayhunter_check - build_rootshell - build_rayhunter - build_rust_installer runs-on: ubuntu-latest strategy: matrix: platform: - linux-x64 - linux-aarch64 - linux-armv7 - macos-intel - macos-arm - windows-x86_64 steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 - name: Fix executable permissions on binaries run: chmod +x installer-*/installer rayhunter-check-*/rayhunter-check rayhunter-daemon/rayhunter-daemon - name: Get Rayhunter version id: get_version run: echo "VERSION=$(grep '^version' daemon/Cargo.toml | head -n 1 | cut -d'"' -f2)" >> $GITHUB_ENV - name: Setup versioned release directory run: | platform="${{ matrix.platform }}" dest="rayhunter-v${{ env.VERSION }}-${{ matrix.platform }}" mkdir "$dest" # Handle installer with proper extension for Windows if [ "$platform" = "windows-x86_64" ]; then mv installer-$platform/installer.exe "$dest"/installer.exe else mv installer-$platform/installer "$dest"/installer fi cp -r rayhunter-check-* rayhunter-daemon rootshell/rootshell dist/* installer/install.ps1 "$dest"/ zip -r "$dest.zip" "$dest" sha256sum "$dest.zip" > "$dest.zip.sha256" - name: Upload zip release and sha256 uses: actions/upload-artifact@v4 with: name: rayhunter-v${{ env.VERSION }}-${{ matrix.platform }} path: | rayhunter-v${{ env.VERSION }}-${{ matrix.platform }}.zip rayhunter-v${{ env.VERSION }}-${{ matrix.platform }}.zip.sha256 if-no-files-found: error