ci: release from actions, only test changed files

This commit introduces release automation triggered by button clicks in
Github Actions, guarded by a check on whether all the Cargo.toml files
contain the same version string.

On PRs, changes to documentation no longer trigger code tests.
Similarly, changes to code that don't update documentation do not
trigger documentation tests. Changes that fail at the `cargo check`
stage abort early to prevent lengthy CI builds of the installer and
firmware.

Commits on the `main` branch always run the full test suite regardless
of what changed.

Releases also run the full check, test, build and publish suite.
This commit is contained in:
oopsbagel
2025-06-05 16:46:19 -07:00
committed by Cooper Quintin
parent 1eea086199
commit bd2e0b4394
4 changed files with 207 additions and 104 deletions

318
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,318 @@
name: Check, test, build release zip, publish docs
on:
push:
pull_request:
workflow_call:
env:
CARGO_TERM_COLOR: always
FILE_ROOTSHELL: ../../rootshell/rootshell
FILE_RAYHUNTER_DAEMON_ORBIC: ../../rayhunter-daemon-orbic/rayhunter-daemon
FILE_RAYHUNTER_DAEMON_TPLINK: ../../rayhunter-daemon-tplink/rayhunter-daemon
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 }}
docs_changed: ${{ steps.files_changed.outputs.docs_count }}
installer_changed: ${{ steps.files_changed.outputs.installer_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 [ ${{ github.ref }} = 'refs/heads/main' ]
then
echo "building everything"
echo code_count=forced >> "$GITHUB_OUTPUT"
echo daemon_count=forced >> "$GITHUB_OUTPUT"
echo docs_count=forced >> "$GITHUB_OUTPUT"
echo installer_count=forced >> "$GITHUB_OUTPUT"
echo rootshell_count=forced >> "$GITHUB_OUTPUT"
else
echo "code_count=$(git diff --name-only $lcommit...HEAD | grep -e ^bin -e ^installer -e ^lib -e ^rootshell -e ^telcom-parser | wc -l)" >> "$GITHUB_OUTPUT"
echo "daemon_count=$(git diff --name-only $lcommit...HEAD | grep -e ^bin -e ^lib -e ^telcom-parser | 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 "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.event_name != 'pull_request' }}
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'
strategy:
matrix:
device:
- name: tplink
- name: orbic
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Check formatting
run: cargo fmt --all --check
- name: Check
run: |
pushd bin/web
npm install
npm run build
popd
NO_FIRMWARE_BIN=true cargo check --verbose --no-default-features --features=${{ matrix.device.name }}
- name: Run tests
run: |
NO_FIRMWARE_BIN=true cargo test --verbose --no-default-features --features=${{ matrix.device.name }}
- name: Run clippy
run: |
NO_FIRMWARE_BIN=true cargo clippy --verbose --no-default-features --features=${{ matrix.device.name }}
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
- 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: ubuntu-24
os: ubuntu-latest
target: x86_64-unknown-linux-musl
- name: ubuntu-24-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-13
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
- name: Build rayhunter-check
run: cargo build --bin rayhunter-check --release
- uses: actions/upload-artifact@v4
with:
name: rayhunter-check-${{ matrix.platform.name }}
path: 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:
- 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
- name: Build rootshell (arm32)
run: cargo build --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:
if: needs.files_changed.outputs.daemon_changed != '0'
needs:
- check_and_test
- files_changed
permissions:
contents: read
packages: write
strategy:
matrix:
device:
- name: tplink
- name: orbic
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: armv7-unknown-linux-musleabihf
- name: Build rayhunter-daemon (arm32)
run: |
pushd bin/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
cargo build -p rayhunter-daemon --bin rayhunter-daemon --target armv7-unknown-linux-musleabihf --profile=firmware --no-default-features --features ${{ matrix.device.name }}
- uses: actions/upload-artifact@v4
with:
name: rayhunter-daemon-${{ matrix.device.name }}
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
- files_changed
- windows_installer_check_and_test
strategy:
matrix:
platform:
- name: ubuntu-24
os: ubuntu-latest
target: x86_64-unknown-linux-musl
- name: ubuntu-24-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-13
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 }}
- run: cargo build --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_release_zip:
permissions:
contents: read
packages: write
needs:
- build_rayhunter_check
- build_rootshell
- build_rayhunter
- build_rust_installer
runs-on: ubuntu-latest
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' bin/Cargo.toml | head -n 1 | cut -d'"' -f2)" >> $GITHUB_ENV
- name: Setup versioned release directory
run: |
VERSIONED_DIR="rayhunter-v${{ env.VERSION }}"
mkdir "$VERSIONED_DIR"
mv rayhunter-daemon-* rootshell/rootshell installer-* dist/* installer/install.ps1 "$VERSIONED_DIR"/
- name: Archive release directory as zip
run: |
VERSIONED_DIR="rayhunter-v${{ env.VERSION }}"
zip -r "$VERSIONED_DIR.zip" "$VERSIONED_DIR"
- name: Compute SHA256 of zip
run: |
VERSIONED_DIR="rayhunter-v${{ env.VERSION }}"
sha256sum "$VERSIONED_DIR.zip" > "$VERSIONED_DIR.zip.sha256"
# TODO: have this create a release directly
- name: Upload zip release and sha256
uses: actions/upload-artifact@v4
with:
name: rayhunter-v${{ env.VERSION }}
path: |
rayhunter-v${{ env.VERSION }}.zip
rayhunter-v${{ env.VERSION }}.zip.sha256
if-no-files-found: error