Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
runner = "qemu-aarch64-static"

[env]
CC_aarch64_unknown_linux_gnu = "aarch64-linux-gnu-gcc"
CXX_aarch64_unknown_linux_gnu = "aarch64-linux-gnu-g++"
AR_aarch64_unknown_linux_gnu = "aarch64-linux-gnu-ar"
26 changes: 26 additions & 0 deletions .github/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# podman build -t quay.io/jbride2000/rust:1.90.0-trixie-tools -f .github/Dockerfile .

FROM rust:1.90.0-trixie

# Install Rust components
RUN rustup component add rustfmt clippy

# Install ARM64 cross-compilation toolchain and system dependencies
RUN dpkg --add-architecture arm64 && \
apt-get update && apt-get install -y \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu \
libudev-dev \
libudev-dev:arm64 \
libssl-dev:arm64 \
pkg-config \
&& rm -rf /var/lib/apt/lists/*

# Add ARM64 target for Rust
RUN rustup target add aarch64-unknown-linux-gnu

# Set up cross-compilation environment
ENV CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
ENV CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++
ENV AR_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ar
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
161 changes: 161 additions & 0 deletions .github/ci-runner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/bin/bash

# CI runner script that can be used both locally and in GitHub Actions
# Supports hybrid approach: Podman containers + ARM SSH deployment
set -e

# Default values
WORKSPACE_DIR="${WORKSPACE_DIR:-$(pwd)}"
RUST_IMAGE="${RUST_IMAGE:-quay.io/jbride2000/rust:1.90.0-trixie-tools}"
CACHE_MOUNTS="${CACHE_MOUNTS:-true}"
TARGET_ARCH="${TARGET_ARCH:-}"
HYBRID_MODE="${HYBRID_MODE:-false}"
ARM_HOST="${ARM_HOST:-}"
ARM_USER="${ARM_USER:-}"
SKIP_CLIPPY="${SKIP_CLIPPY:-false}"

# Function to run a command in the container
run_in_container() {
local cmd="$1"
local description="$2"

echo "Running: $description"

# Add target architecture if specified
local target_cmd="$cmd"
if [ -n "$TARGET_ARCH" ]; then
# Set pkg-config for ARM64 cross-compilation
if [ "$TARGET_ARCH" = "aarch64-unknown-linux-gnu" ]; then
target_cmd="export PKG_CONFIG_ALLOW_CROSS=1 PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu/pkgconfig && rustup target add $TARGET_ARCH && $cmd --target $TARGET_ARCH"
else
target_cmd="rustup target add $TARGET_ARCH && $cmd --target $TARGET_ARCH"
fi
fi

if [ "$CACHE_MOUNTS" = "true" ]; then
podman run --rm \
-v "$WORKSPACE_DIR":/workspace:Z \
-w /workspace \
--mount=type=volume,source=cargo-registry,target=/usr/local/cargo/registry \
--mount=type=volume,source=cargo-git,target=/usr/local/cargo/git \
--mount=type=volume,source=cargo-target,target=/workspace/target \
"$RUST_IMAGE" \
bash -c "$target_cmd"
else
podman run --rm \
-v "$WORKSPACE_DIR":/workspace:Z \
-w /workspace \
"$RUST_IMAGE" \
bash -c "$target_cmd"
fi
}

# Function to deploy to ARM hardware
deploy_to_arm() {
local binary_path="$1"

if [ "$HYBRID_MODE" = "false" ] || [ -z "$ARM_HOST" ] || [ -z "$ARM_USER" ]; then
echo "Skipping ARM deployment (not in hybrid mode or missing ARM config)"
return 0
fi

echo "🚀 Deploying to ARM hardware..."

# Check if deployment script exists
if [ ! -f "scripts/local_ci/deploy-to-arm.sh" ]; then
echo "❌ ARM deployment script not found"
return 1
fi

# Run ARM deployment
chmod +x scripts/local_ci/deploy-to-arm.sh
./scripts/local_ci/deploy-to-arm.sh \
--host "$ARM_HOST" \
--user "$ARM_USER" \
--binary "$binary_path" \
--test-mode
}

# Parse command line arguments
case "${1:-all}" in
"fmt")
run_in_container "cargo fmt --all -- --check" "formatting check"
;;
"clippy")
if [ "$SKIP_CLIPPY" = "true" ]; then
echo "⏭️ Skipping clippy check (SKIP_CLIPPY=true)"
else
run_in_container "cargo clippy --all-targets --all-features -- -D warnings" "clippy check"
fi
;;
"build")
run_in_container "cargo build --verbose" "build"
;;
"build-release")
run_in_container "cargo build --release --verbose" "release build"
;;
"test")
run_in_container "cargo test --verbose" "tests"
;;
"test-release")
run_in_container "cargo test --release --verbose" "release tests"
;;
"all")
run_in_container "cargo fmt --all -- --check" "formatting check"
if [ "$SKIP_CLIPPY" = "true" ]; then
echo "⏭️ Skipping clippy check (SKIP_CLIPPY=true)"
else
run_in_container "cargo clippy --all-targets --all-features -- -D warnings" "clippy check"
fi
run_in_container "cargo build --verbose" "build"
run_in_container "cargo test --verbose" "tests"
;;
"hybrid")
echo "🔄 Running hybrid CI (containers + ARM deployment)..."

# Step 1: Container-based checks
run_in_container "cargo fmt --all -- --check" "formatting check"
if [ "$SKIP_CLIPPY" = "true" ]; then
echo "⏭️ Skipping clippy check (SKIP_CLIPPY=true)"
else
run_in_container "cargo clippy --all-targets --all-features -- -D warnings" "clippy check"
fi

# Step 2: Cross-compile for ARM64
TARGET_ARCH=aarch64-unknown-linux-gnu
run_in_container "cargo build --release --verbose" "ARM64 release build"

# Step 3: Deploy to ARM hardware
if [ -n "$TARGET_ARCH" ]; then
binary_path="$WORKSPACE_DIR/target/$TARGET_ARCH/release/mujina-minerd"
else
binary_path="$WORKSPACE_DIR/target/release/mujina-minerd"
fi

deploy_to_arm "$binary_path"
;;
*)
echo "Usage: $0 [fmt|clippy|build|build-release|test|test-release|all|hybrid]"
echo ""
echo "Commands:"
echo " fmt Check formatting"
echo " clippy Run clippy lints"
echo " build Build debug version"
echo " build-release Build release version"
echo " test Run tests"
echo " test-release Run release tests"
echo " all Run all checks"
echo " hybrid Run hybrid CI (containers + ARM deployment)"
echo ""
echo "Environment variables:"
echo " WORKSPACE_DIR: Directory to mount (default: current directory)"
echo " RUST_IMAGE: Rust container image (default: quay.io/jbride2000/rust:1.90.0-trixie-tools)"
echo " TARGET_ARCH: Target architecture (e.g., aarch64-unknown-linux-gnu)"
echo " CACHE_MOUNTS: Enable cache mounts (default: true)"
echo " SKIP_CLIPPY: Skip clippy lints (default: false)"
echo " HYBRID_MODE: Enable ARM deployment (default: false)"
echo " ARM_HOST: ARM64 host IP address"
echo " ARM_USER: SSH username for ARM host"
exit 1
;;
esac
111 changes: 111 additions & 0 deletions .github/workflows/hybrid-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: Hybrid CI (Podman + Native ARM64)

on:
push:
branches: [ main, master, preview, gh_actions]
pull_request:
branches: [ main, master, preview, gh_actions ]
workflow_dispatch:
inputs:
run_container_ci:
description: "Run container CI"
type: boolean
default: true
skip_clippy:
description: "Skip clippy lints"
type: boolean
default: false
run_arm64:
description: "Run ARM64 native test"
type: boolean
default: false

env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1

jobs:
# Fast checks using Podman containers on GitHub's x86_64 runners
container-ci:
name: Container CI (x86_64)
# https://github.com/actions/runner-images?tab=readme-ov-file#available-images
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install Podman
run: |
sudo apt-get update
sudo apt-get -y install podman

- name: Run CI checks in container
run: |
chmod +x .github/ci-runner.sh
./.github/ci-runner.sh all
env:
WORKSPACE_DIR: ${{ github.workspace }}
RUST_IMAGE: quay.io/jbride2000/rust:1.90.0-trixie-tools
CACHE_MOUNTS: "false"
SKIP_CLIPPY: ${{ github.event.inputs.skip_clippy || 'false' }}

- name: Cross-compile for ARM64
run: |
chmod +x .github/ci-runner.sh
TARGET_ARCH=aarch64-unknown-linux-gnu ./.github/ci-runner.sh build-release
env:
WORKSPACE_DIR: ${{ github.workspace }}
RUST_IMAGE: quay.io/jbride2000/rust:1.90.0-trixie-tools
TARGET_ARCH: aarch64-unknown-linux-gnu
CACHE_MOUNTS: "false"

- name: Upload ARM64 binary
uses: actions/upload-artifact@v4
with:
name: mujina-minerd-arm64
path: target/aarch64-unknown-linux-gnu/release/mujina-minerd

# Native ARM64 testing using GitHub's ARM64 runners
# https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/add-runners
arm64-self-hosted-runner:
name: ARM64 Self-Hosted Runner Test
if: ${{ github.event_name == 'workflow_dispatch' && inputs.run_arm64 }}
runs-on: self-hosted
needs: container-ci

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Download ARM64 binary
uses: actions/download-artifact@v4
with:
name: mujina-minerd-arm64
path: ./artifacts/

- name: Test ARM64 binary natively
run: |
# Test the ARM64 binary on native ARM64 hardware
chmod +x ./artifacts/mujina-minerd

echo "=== ARM64 Hardware Information ==="
uname -a
cat /proc/cpuinfo | grep -E "(processor|model name|cpu MHz|cache size)" | head -10
cat /proc/meminfo | head -5
echo ""

echo "=== Binary Information ==="
file ./artifacts/mujina-minerd
ldd ./artifacts/mujina-minerd || echo "Static binary or ldd not available"
echo ""

echo "=== Version Test ==="
./artifacts/mujina-minerd --version
echo ""

echo "=== Basic Functionality Test ==="
timeout 30 ./artifacts/mujina-minerd --help || echo "Help command completed"
echo ""

echo "✅ ARM64 native testing completed successfully!"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Cargo.lock
/target/
scripts/local_ci/arm-deployment.env
Loading