From 034e5ea3bcede41fed6dfdffe78f126532b38f61 Mon Sep 17 00:00:00 2001 From: li88iioo Date: Mon, 23 Mar 2026 01:02:22 +0800 Subject: [PATCH] ci(linux): enhance artifact verification and architecture handling - Added environment variables for npm configuration to specify architecture in CI jobs for both x64 and arm64 builds. - Implemented verification steps for downloaded Linux deb artifacts, ensuring both amd64 and arm64 versions are checked for integrity. - Updated the `ensure-node-pty-linux.sh` script to resolve and verify serialport prebuilds, ensuring compatibility with the specified architecture. - Enhanced the `verify-linux-deb-artifact.sh` script to allow optional deb file input and improved error handling for missing artifacts. These changes improve the reliability of the build process and ensure that the correct native modules are used for each architecture. --- .github/workflows/build.yml | 18 ++++++ scripts/ensure-node-pty-linux.sh | 54 ++++++++++++++++- scripts/verify-linux-deb-artifact.sh | 86 ++++++++++++++++++++++------ 3 files changed, 141 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 354ac8aa..2cf6d605 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -93,6 +93,8 @@ jobs: name: build-linux-x64 runs-on: ubuntu-22.04 env: + npm_config_arch: x64 + npm_config_target_arch: x64 VITE_SYNC_GITHUB_CLIENT_ID: ${{ secrets.VITE_SYNC_GITHUB_CLIENT_ID }} VITE_SYNC_GOOGLE_CLIENT_ID: ${{ secrets.VITE_SYNC_GOOGLE_CLIENT_ID }} VITE_SYNC_GOOGLE_CLIENT_SECRET: ${{ secrets.VITE_SYNC_GOOGLE_CLIENT_SECRET }} @@ -159,6 +161,8 @@ jobs: container: image: debian:bullseye env: + npm_config_arch: arm64 + npm_config_target_arch: arm64 VITE_SYNC_GITHUB_CLIENT_ID: ${{ secrets.VITE_SYNC_GITHUB_CLIENT_ID }} VITE_SYNC_GOOGLE_CLIENT_ID: ${{ secrets.VITE_SYNC_GOOGLE_CLIENT_ID }} VITE_SYNC_GOOGLE_CLIENT_SECRET: ${{ secrets.VITE_SYNC_GOOGLE_CLIENT_SECRET }} @@ -239,6 +243,20 @@ jobs: - name: List artifacts run: ls -la artifacts/ + - name: Verify downloaded Linux amd64 deb artifact + run: | + deb_file="$(find artifacts -maxdepth 1 -type f -name '*-linux-amd64.deb' -print | sort | head -n 1)" + test -n "${deb_file}" + bash scripts/verify-linux-deb-artifact.sh amd64 "${deb_file}" + + - name: Verify downloaded Linux arm64 deb artifact metadata + env: + VERIFY_LOAD: "0" + run: | + deb_file="$(find artifacts -maxdepth 1 -type f -name '*-linux-arm64.deb' -print | sort | head -n 1)" + test -n "${deb_file}" + bash scripts/verify-linux-deb-artifact.sh arm64 "${deb_file}" + - name: Generate Release Body run: node .github/scripts/generate-release-note.js env: diff --git a/scripts/ensure-node-pty-linux.sh b/scripts/ensure-node-pty-linux.sh index 08241455..3748f2b9 100644 --- a/scripts/ensure-node-pty-linux.sh +++ b/scripts/ensure-node-pty-linux.sh @@ -53,22 +53,43 @@ assert_loadable_native_module() { ' "${file}" } +resolve_serialport_prebuild() { + local root="$1" + local arch="$2" + local file + + file="$(find "${root}/prebuilds/linux-${arch}" -maxdepth 1 -type f -name '@serialport+bindings-cpp*.glibc.node' -print | sort | head -n 1)" + if [[ -z "${file}" ]]; then + echo "[node-pty] serialport glibc prebuild not found for linux-${arch}" >&2 + exit 1 + fi + + echo "${file}" +} + prepare() { local arch="$1" local root="node_modules/node-pty" local release_dir="${root}/build/Release" local prebuild_dir="${root}/prebuilds/linux-${arch}" + local serialport_root="node_modules/@serialport/bindings-cpp" + local serialport_release_dir="${serialport_root}/build/Release" + local serialport_prebuild echo "[node-pty] rebuilding native modules for Electron on linux-${arch}" log_electron_runtime_info - npx electron-rebuild --arch "${arch}" + rm -rf "${release_dir}" "${prebuild_dir}" "${serialport_release_dir}" + npx electron-rebuild --force --arch "${arch}" -w "node-pty,@serialport/bindings-cpp" test -f "${release_dir}/pty.node" + test -f "${serialport_release_dir}/bindings.node" echo "[node-pty] built Linux runtime artifacts:" log_file_info "${release_dir}/pty.node" log_optional_spawn_helper "${release_dir}/spawn-helper" assert_loadable_native_module "${release_dir}/pty.node" + log_file_info "${serialport_release_dir}/bindings.node" + assert_loadable_native_module "${serialport_release_dir}/bindings.node" mkdir -p "${prebuild_dir}" cp "${release_dir}/pty.node" "${prebuild_dir}/pty.node" @@ -79,17 +100,26 @@ prepare() { echo "[node-pty] mirrored Linux runtime artifacts into ${prebuild_dir}:" log_file_info "${prebuild_dir}/pty.node" log_optional_spawn_helper "${prebuild_dir}/spawn-helper" + + serialport_prebuild="$(resolve_serialport_prebuild "${serialport_root}" "${arch}")" + echo "[node-pty] serialport packaged prebuild candidate:" + log_file_info "${serialport_prebuild}" + assert_loadable_native_module "${serialport_prebuild}" } verify() { local arch="$1" local release_dir local prebuild_dir + local serialport_release_file + local serialport_prebuild_file log_electron_runtime_info release_dir="$(find release -type d -path "*/resources/app.asar.unpacked/node_modules/node-pty/build/Release" -print -quit)" prebuild_dir="$(find release -type d -path "*/resources/app.asar.unpacked/node_modules/node-pty/prebuilds/linux-${arch}" -print -quit)" + serialport_release_file="$(find release -type f -path "*/resources/app.asar.unpacked/node_modules/@serialport/bindings-cpp/build/Release/bindings.node" -print -quit)" + serialport_prebuild_file="$(find release -type f -path "*/resources/app.asar.unpacked/node_modules/@serialport/bindings-cpp/prebuilds/linux-${arch}/@serialport+bindings-cpp*.glibc.node" -print | sort | head -n 1)" if [[ -z "${release_dir}" ]]; then echo "[node-pty] packaged build/Release directory not found under release/" >&2 @@ -101,6 +131,16 @@ verify() { exit 1 fi + if [[ -z "${serialport_release_file}" ]]; then + echo "[node-pty] packaged serialport build/Release binding not found under release/" >&2 + exit 1 + fi + + if [[ -z "${serialport_prebuild_file}" ]]; then + echo "[node-pty] packaged serialport glibc prebuild not found for linux-${arch} under release/" >&2 + exit 1 + fi + test -f "${release_dir}/pty.node" test -f "${prebuild_dir}/pty.node" @@ -114,10 +154,22 @@ verify() { log_optional_spawn_helper "${prebuild_dir}/spawn-helper" assert_loadable_native_module "${prebuild_dir}/pty.node" + echo "[node-pty] packaged serialport build/Release artifact:" + log_file_info "${serialport_release_file}" + assert_loadable_native_module "${serialport_release_file}" + + echo "[node-pty] packaged serialport prebuild artifact:" + log_file_info "${serialport_prebuild_file}" + assert_loadable_native_module "${serialport_prebuild_file}" + echo "[node-pty] packaged artifact locations:" find release -path "*/resources/app.asar.unpacked/node_modules/node-pty/*" \ \( -name 'pty.node' -o -name 'spawn-helper' \) \ -print | sort + + find release -path "*/resources/app.asar.unpacked/node_modules/@serialport/bindings-cpp/*" \ + \( -name 'bindings.node' -o -name '@serialport+bindings-cpp*.node' \) \ + -print | sort } main() { diff --git a/scripts/verify-linux-deb-artifact.sh b/scripts/verify-linux-deb-artifact.sh index 6d65e724..6c649c19 100755 --- a/scripts/verify-linux-deb-artifact.sh +++ b/scripts/verify-linux-deb-artifact.sh @@ -5,7 +5,7 @@ set -euo pipefail TEMP_DIR="" usage() { - echo "Usage: $0 " >&2 + echo "Usage: $0 [deb-file]" >&2 exit 1 } @@ -67,6 +67,11 @@ assert_loadable_native_module() { local electron_bin="$1" local native_module="$2" + if [[ "${VERIFY_LOAD:-1}" != "1" ]]; then + echo "[deb-verify] skipping native module load check for ${native_module} (VERIFY_LOAD=${VERIFY_LOAD:-1})" + return + fi + echo "[deb-verify] loading native module with packaged Electron runtime: ${native_module}" ELECTRON_RUN_AS_NODE=1 "${electron_bin}" -e ' const path = require("node:path"); @@ -75,8 +80,56 @@ assert_loadable_native_module() { ' "${native_module}" } +resolve_file_from_glob() { + local search_dir="$1" + local pattern="$2" + find "${search_dir}" -maxdepth 1 -type f -name "${pattern}" -print | sort | head -n 1 +} + +resolve_single_file() { + local search_dir="$1" + local pattern="$2" + local file + + file="$(resolve_file_from_glob "${search_dir}" "${pattern}")" + if [[ -z "${file}" ]]; then + echo "[deb-verify] no file matched ${pattern} under ${search_dir}" >&2 + exit 1 + fi + + echo "${file}" +} + +resolve_serialport_prebuild() { + local root="$1" + local arch="$2" + local prebuild_dir="${root}/prebuilds/linux-${arch}" + local file + + file="$(find "${prebuild_dir}" -maxdepth 1 -type f -name '@serialport+bindings-cpp*.glibc.node' -print | sort | head -n 1)" + if [[ -z "${file}" ]]; then + echo "[deb-verify] serialport glibc prebuild not found under ${prebuild_dir}" >&2 + exit 1 + fi + + echo "${file}" +} + +verify_native_module() { + local label="$1" + local electron_bin="$2" + local file="$3" + local expected_machine="$4" + + assert_exists "${file}" + echo "[deb-verify] verifying ${label}" + log_file_info "${file}" + assert_file_arch "${file}" "${expected_machine}" + assert_loadable_native_module "${electron_bin}" "${file}" +} + main() { - if [[ $# -ne 1 ]]; then + if [[ $# -lt 1 || $# -gt 2 ]]; then usage fi @@ -89,6 +142,9 @@ main() { local main_binary local build_release_pty local prebuild_pty + local serialport_root + local build_release_serialport + local prebuild_serialport require_cmd dpkg-deb require_cmd file @@ -107,10 +163,11 @@ main() { ;; esac - deb_file="$(find release -maxdepth 1 -type f -name "*-linux-${deb_arch}.deb" -print | sort | head -n 1)" - if [[ -z "${deb_file}" ]]; then - echo "[deb-verify] no deb artifact found for ${deb_arch} under release/" >&2 - exit 1 + if [[ $# -eq 2 ]]; then + deb_file="$2" + assert_exists "${deb_file}" + else + deb_file="$(resolve_single_file "release" "*-linux-${deb_arch}.deb")" fi echo "[deb-verify] verifying deb artifact: ${deb_file}" @@ -131,22 +188,19 @@ main() { main_binary="${TEMP_DIR}/opt/Netcatty/netcatty" build_release_pty="${TEMP_DIR}/opt/Netcatty/resources/app.asar.unpacked/node_modules/node-pty/build/Release/pty.node" prebuild_pty="${TEMP_DIR}/opt/Netcatty/resources/app.asar.unpacked/node_modules/node-pty/prebuilds/linux-${prebuild_arch}/pty.node" + serialport_root="${TEMP_DIR}/opt/Netcatty/resources/app.asar.unpacked/node_modules/@serialport/bindings-cpp" + build_release_serialport="${serialport_root}/build/Release/bindings.node" + prebuild_serialport="$(resolve_serialport_prebuild "${serialport_root}" "${prebuild_arch}")" assert_executable "${electron_bin}" - assert_exists "${build_release_pty}" - assert_exists "${prebuild_pty}" echo "[deb-verify] verifying packaged binary architectures" log_file_info "${main_binary}" - log_file_info "${build_release_pty}" - log_file_info "${prebuild_pty}" - assert_file_arch "${main_binary}" "${expected_machine}" - assert_file_arch "${build_release_pty}" "${expected_machine}" - assert_file_arch "${prebuild_pty}" "${expected_machine}" - - assert_loadable_native_module "${electron_bin}" "${build_release_pty}" - assert_loadable_native_module "${electron_bin}" "${prebuild_pty}" + verify_native_module "node-pty build/Release" "${electron_bin}" "${build_release_pty}" "${expected_machine}" + verify_native_module "node-pty prebuild" "${electron_bin}" "${prebuild_pty}" "${expected_machine}" + verify_native_module "serialport build/Release" "${electron_bin}" "${build_release_serialport}" "${expected_machine}" + verify_native_module "serialport glibc prebuild" "${electron_bin}" "${prebuild_serialport}" "${expected_machine}" echo "[deb-verify] deb artifact verification passed for ${deb_file}" }