mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-10 16:00:47 +00:00
* feat(magisk): add module WebUI configuration Reuse the existing config generator in KernelSU-compatible module managers. Validate and atomically persist TOML through a module helper before restarting EasyTier, and package the generated assets in CI. Closes #1915 * fix(magisk): preserve existing WebUI configuration Merge form-managed fields into the original TOML so advanced module settings remain intact. Resolve the running core by its exact executable path before restart.
380 lines
13 KiB
YAML
380 lines
13 KiB
YAML
name: EasyTier Core
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
push:
|
|
branches: [ "develop", "main", "releases/**" ]
|
|
pull_request:
|
|
branches: [ "develop", "main" ]
|
|
types: [ opened, synchronize, reopened, ready_for_review ]
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
|
|
defaults:
|
|
run:
|
|
# necessary for windows
|
|
shell: bash
|
|
|
|
jobs:
|
|
pre_job:
|
|
runs-on: ubuntu-latest
|
|
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
|
|
env:
|
|
RELEVANT_PATHS: >-
|
|
["Cargo.toml", "Cargo.lock", "rust-toolchain.toml", ".cargo/**",
|
|
"pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "easytier/**",
|
|
"easytier-core/**", "easytier-proto/**", "easytier-rpc-build/**",
|
|
"easytier-web/**", "easytier-contrib/easytier-magisk/**",
|
|
".github/workflows/core.yml", ".github/actions/**"]
|
|
outputs:
|
|
# Release builds must run even if they only change release metadata.
|
|
should_skip: >-
|
|
${{
|
|
(
|
|
steps.skip_check.outputs.should_skip == 'true' ||
|
|
(
|
|
github.event_name == 'pull_request' &&
|
|
steps.path_filter.outputs.relevant != 'true'
|
|
)
|
|
) &&
|
|
!startsWith(github.ref_name, 'releases/')
|
|
}}
|
|
steps:
|
|
- id: skip_check
|
|
uses: fkirc/skip-duplicate-actions@v5
|
|
with:
|
|
concurrent_skipping: 'same_content_newer'
|
|
skip_after_successful_duplicate: 'true'
|
|
cancel_others: 'true'
|
|
paths: ${{ env.RELEVANT_PATHS }}
|
|
|
|
- id: path_filter
|
|
if: >-
|
|
github.event_name == 'pull_request' &&
|
|
steps.skip_check.outputs.should_skip != 'true'
|
|
uses: dorny/paths-filter@v4
|
|
with:
|
|
filters: |
|
|
relevant: ${{ env.RELEVANT_PATHS }}
|
|
build_web:
|
|
runs-on: ubuntu-latest
|
|
needs: pre_job
|
|
if: needs.pre_job.outputs.should_skip != 'true'
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Setup Frontend Environment
|
|
uses: ./.github/actions/prepare-pnpm
|
|
with:
|
|
token: ${{ github.token }}
|
|
build-filter: './easytier-web/*'
|
|
|
|
- name: Archive artifact
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: easytier-web-dashboard
|
|
path: |
|
|
easytier-web/frontend/dist/*
|
|
build:
|
|
strategy:
|
|
fail-fast: true
|
|
matrix:
|
|
include:
|
|
- TARGET: x86_64-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-x86_64
|
|
- TARGET: aarch64-unknown-linux-musl
|
|
OS: ubuntu-24.04-arm
|
|
ARTIFACT_NAME: linux-aarch64
|
|
|
|
- TARGET: riscv64gc-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-riscv64
|
|
- TARGET: loongarch64-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-loongarch64
|
|
|
|
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-armv7hf
|
|
- TARGET: armv7-unknown-linux-musleabi # raspberry pi 2-3-4, not tested
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-armv7
|
|
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-armhf
|
|
- TARGET: arm-unknown-linux-musleabi # raspberry pi 0-1, not tested
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-arm
|
|
|
|
- TARGET: mips-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-mips
|
|
- TARGET: mipsel-unknown-linux-musl
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: linux-mipsel
|
|
|
|
- TARGET: x86_64-unknown-freebsd
|
|
OS: ubuntu-24.04
|
|
ARTIFACT_NAME: freebsd-13.2-x86_64
|
|
BSD_VERSION: 13.2
|
|
|
|
- TARGET: x86_64-apple-darwin
|
|
OS: macos-latest
|
|
ARTIFACT_NAME: macos-x86_64
|
|
- TARGET: aarch64-apple-darwin
|
|
OS: macos-latest
|
|
ARTIFACT_NAME: macos-aarch64
|
|
|
|
- TARGET: x86_64-pc-windows-msvc
|
|
OS: windows-latest
|
|
ARTIFACT_NAME: windows-x86_64
|
|
- TARGET: i686-pc-windows-msvc
|
|
OS: windows-latest
|
|
ARTIFACT_NAME: windows-i686
|
|
- TARGET: aarch64-pc-windows-msvc
|
|
OS: windows-11-arm
|
|
ARTIFACT_NAME: windows-arm64
|
|
|
|
runs-on: ${{ matrix.OS }}
|
|
env:
|
|
NAME: easytier
|
|
TARGET: ${{ matrix.TARGET }}
|
|
OS: ${{ matrix.OS }}
|
|
OSS_BUCKET: ${{ secrets.ALIYUN_OSS_BUCKET }}
|
|
needs:
|
|
- pre_job
|
|
- build_web
|
|
if: needs.pre_job.outputs.should_skip != 'true'
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Set current ref as env variable
|
|
run: |
|
|
echo "GIT_DESC=$(git log -1 --format=%cd.%h --date=format:%Y-%m-%d_%H:%M:%S)" >> $GITHUB_ENV
|
|
|
|
- name: Download web artifact
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: easytier-web-dashboard
|
|
path: easytier-web/frontend/dist/
|
|
|
|
- name: Prepare build environment
|
|
uses: ./.github/actions/prepare-build
|
|
with:
|
|
target: ${{ matrix.TARGET }}
|
|
gui: true
|
|
pnpm: true
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# The prefix cache key, this can be changed to start a new cache manually.
|
|
# default: "v0-rust"
|
|
prefix-key: ""
|
|
shared-key: "core-registry"
|
|
cache-targets: "false"
|
|
|
|
- uses: mlugg/setup-zig@v2
|
|
if: ${{ contains(matrix.OS, 'ubuntu') }}
|
|
with:
|
|
version: 0.16.0
|
|
use-cache: true
|
|
|
|
- uses: taiki-e/install-action@v2
|
|
if: ${{ contains(matrix.OS, 'ubuntu') }}
|
|
with:
|
|
# v0.23.3 emits -mcpu=generic+v6+strict_align for
|
|
# arm-unknown-linux-musleabi, which zig 0.16.0 rejects;
|
|
# unpin only together with a zig bump.
|
|
tool: cargo-zigbuild@0.23.2
|
|
|
|
- name: Build
|
|
if: ${{ !contains(matrix.TARGET, 'mips') }}
|
|
run: |
|
|
if [[ "$TARGET" == *windows* ]]; then
|
|
SUFFIX=.exe
|
|
else
|
|
SUFFIX=""
|
|
fi
|
|
|
|
if [[ "$TARGET" =~ (x86_64-unknown-linux-musl|aarch64-unknown-linux-musl|windows|darwin) ]]; then
|
|
BUILD=build
|
|
else
|
|
BUILD=zigbuild
|
|
fi
|
|
|
|
if [[ "$TARGET" =~ ^(riscv64|loongarch64|aarch64).*$ || "$TARGET" =~ (freebsd|windows) ]]; then
|
|
FEATURES="mimalloc"
|
|
else
|
|
FEATURES="jemalloc"
|
|
fi
|
|
|
|
cargo $BUILD --release --target $TARGET --package=easytier-web --features=embed
|
|
mv ./target/$TARGET/release/easytier-web"$SUFFIX" ./target/$TARGET/release/easytier-web-embed"$SUFFIX"
|
|
|
|
cargo $BUILD --release --target $TARGET --features=$FEATURES
|
|
|
|
- name: Build (MIPS)
|
|
if: ${{ contains(matrix.TARGET, 'mips') }}
|
|
env:
|
|
RUSTC_BOOTSTRAP: 1
|
|
run: |
|
|
cargo build -r --target $TARGET -Z build-std=std,panic_abort --package=easytier --features=jemalloc
|
|
|
|
- name: Compress
|
|
run: |
|
|
mkdir -p ./artifacts/objects/
|
|
|
|
# windows is the only OS using a different convention for executable file name
|
|
if [[ $OS =~ ^windows.*$ ]]; then
|
|
SUFFIX=.exe
|
|
case $TARGET in
|
|
x86_64*) ARCH_DIR=x86_64 ;;
|
|
i686*) ARCH_DIR=i686 ;;
|
|
aarch64*) ARCH_DIR=arm64 ;;
|
|
esac
|
|
if [[ -n "$ARCH_DIR" ]]; then
|
|
find "easytier/third_party/${ARCH_DIR}" -maxdepth 1 -type f \( -name "*.dll" -o -name "*.sys" \) -exec cp {} ./artifacts/objects/ \;
|
|
fi
|
|
fi
|
|
|
|
if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then
|
|
TAG=$GITHUB_REF_NAME
|
|
else
|
|
TAG=$GITHUB_SHA
|
|
fi
|
|
|
|
if [[ $OS =~ ^ubuntu.*$ && ! $TARGET =~ (loongarch|freebsd) ]]; then
|
|
HOST_ARCH=$(uname -m)
|
|
case $HOST_ARCH in
|
|
x86_64) UPX_ARCH="amd64" ;;
|
|
aarch64) UPX_ARCH="arm64" ;;
|
|
*) UPX_ARCH="amd64" ;;
|
|
esac
|
|
|
|
UPX_VERSION=4.2.4
|
|
UPX_PKG="upx-${UPX_VERSION}-${UPX_ARCH}_linux"
|
|
curl -L "https://github.com/upx/upx/releases/download/v${UPX_VERSION}/${UPX_PKG}.tar.xz" -s | tar xJvf -
|
|
cp "${UPX_PKG}/upx" .
|
|
UPX_BIN=./upx
|
|
fi
|
|
|
|
for BIN in ./target/$TARGET/release/easytier-{core,cli,web,web-embed}"$SUFFIX"; do
|
|
if [[ -f "$BIN" ]]; then
|
|
if [[ -n "$UPX_BIN" ]]; then
|
|
$UPX_BIN --lzma --best "$BIN" || true
|
|
fi
|
|
|
|
mv "$BIN" ./artifacts/objects/
|
|
fi
|
|
done
|
|
|
|
mv ./artifacts/objects/* ./artifacts/
|
|
rm -rf ./artifacts/objects/
|
|
|
|
- name: Archive artifact
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: easytier-${{ matrix.ARTIFACT_NAME }}
|
|
path: |
|
|
./artifacts/*
|
|
|
|
- name: Prepare SignPath test artifact
|
|
if: ${{ github.event_name == 'workflow_dispatch' && contains(matrix.TARGET, 'windows') }}
|
|
run: |
|
|
mkdir -p ./signpath-artifacts
|
|
cp \
|
|
./artifacts/easytier-core.exe \
|
|
./artifacts/easytier-cli.exe \
|
|
./artifacts/easytier-web.exe \
|
|
./artifacts/easytier-web-embed.exe \
|
|
./signpath-artifacts/
|
|
|
|
- name: Upload unsigned SignPath test artifact
|
|
if: ${{ github.event_name == 'workflow_dispatch' && contains(matrix.TARGET, 'windows') }}
|
|
id: signpath-upload
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: signpath-unsigned-${{ matrix.ARTIFACT_NAME }}
|
|
path: ./signpath-artifacts/*
|
|
if-no-files-found: error
|
|
|
|
- name: Submit SignPath test-signing request
|
|
if: ${{ github.event_name == 'workflow_dispatch' && contains(matrix.TARGET, 'windows') }}
|
|
uses: signpath/github-action-submit-signing-request@v2
|
|
with:
|
|
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
|
organization-id: 368cf38d-86d5-4bfe-a1fa-82a50dce7e9f
|
|
project-slug: EasyTier
|
|
signing-policy-slug: test-signing
|
|
artifact-configuration-slug: initial
|
|
github-artifact-id: ${{ steps.signpath-upload.outputs.artifact-id }}
|
|
wait-for-completion: true
|
|
output-artifact-directory: ./signpath-signed-artifacts
|
|
|
|
- name: Upload signed SignPath test artifact
|
|
if: ${{ github.event_name == 'workflow_dispatch' && contains(matrix.TARGET, 'windows') }}
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: signpath-signed-${{ matrix.ARTIFACT_NAME }}
|
|
path: ./signpath-signed-artifacts/*
|
|
if-no-files-found: error
|
|
|
|
build_magisk:
|
|
runs-on: ubuntu-latest
|
|
needs: [ pre_job, build_web, build ]
|
|
if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled()
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@v5 # 必须先检出代码才能获取模块配置
|
|
|
|
# 下载二进制文件到独立目录
|
|
- name: Download Linux aarch64 binaries
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: easytier-linux-aarch64
|
|
path: ./downloaded-binaries/ # 独立目录避免冲突
|
|
|
|
- name: Download Magisk WebUI
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: easytier-web-dashboard
|
|
path: ./downloaded-webui/
|
|
|
|
# 将二进制文件和 WebUI 复制到 Magisk 模块目录
|
|
- name: Prepare Magisk module
|
|
run: |
|
|
module_dir=./easytier-contrib/easytier-magisk
|
|
mkdir -p "$module_dir/webroot"
|
|
cp ./downloaded-binaries/easytier-core "$module_dir/"
|
|
cp ./downloaded-binaries/easytier-cli "$module_dir/"
|
|
cp ./downloaded-binaries/easytier-web "$module_dir/"
|
|
cp -R ./downloaded-webui/config-generator/. "$module_dir/webroot/"
|
|
test -f "$module_dir/webroot/index.html"
|
|
|
|
# 上传生成的模块
|
|
- name: Upload Magisk Module
|
|
uses: actions/upload-artifact@v5
|
|
with:
|
|
name: Easytier-Magisk
|
|
path: |
|
|
./easytier-contrib/easytier-magisk
|
|
!./easytier-contrib/easytier-magisk/build.sh
|
|
!./easytier-contrib/easytier-magisk/magisk_update.json
|
|
if-no-files-found: error
|
|
|
|
core-result:
|
|
runs-on: ubuntu-latest
|
|
needs: [ pre_job, build_web, build, build_magisk ]
|
|
if: needs.pre_job.result == 'success' && needs.pre_job.outputs.should_skip != 'true' && !cancelled()
|
|
steps:
|
|
- name: Mark result as failed
|
|
if: contains(needs.*.result, 'failure')
|
|
run: exit 1
|