安装包 / Linux aarch64 (push) Canceled after 0s
安装包 / Linux x86_64 (push) Canceled after 0s
安装包 / Windows x86_64 (push) Canceled after 0s
安装包 / macOS arm64 (Apple Silicon) (push) Canceled after 0s
安装包 / macOS x86_64 (Intel) (push) Canceled after 0s
安装包 / 发布到 Release (push) Canceled after 0s
- 取消手动 publish 勾选:推 main / 打 tag / 手动 Run workflow 都会自动发 Release (PR 不发),仍然是 draft:false + Latest - 每个 job 加 github.server_url == 'https://github.com' 守卫: Gitea 里跑的 run 所有 job 都显示 skipped,不占 runner、不会发 Release - cancel-in-progress 改成 false,避免发布到一半被新 push 取消 - README 更新:自动发版说明 + Gitea 1.27 的三种关法(设置页/Actions 页/API)
413 lines
14 KiB
YAML
413 lines
14 KiB
YAML
name: 安装包
|
||
|
||
# 同步到 GitHub 后,这里编译并打出:
|
||
# 注意:Gitea Actions 也会读 .github/workflows,所以每个 job 都有
|
||
# if: github.server_url == 'https://github.com'
|
||
# 的守卫,在 Gitea 上只会显示成 skipped,不占 runner;要连 run 都不出现,
|
||
# 需要在 Gitea 仓库设置里禁用 Actions / 该工作流(详见 README)。
|
||
# Linux deb / rpm(x86_64、aarch64)
|
||
# Windows 安装包(关联 .md)+ 便携 zip
|
||
# macOS arm64 / x86_64 两个 dmg(未签名,不是公证版)
|
||
on:
|
||
push:
|
||
branches: [main, master]
|
||
tags: ["v*"]
|
||
pull_request:
|
||
workflow_dispatch:
|
||
|
||
permissions:
|
||
contents: write
|
||
|
||
concurrency:
|
||
group: packages-${{ github.ref }}
|
||
# 不要把正在发 Release 的 run 掐掉,否则可能留下半截草稿
|
||
cancel-in-progress: false
|
||
|
||
env:
|
||
QT_VERSION: "5.15.2"
|
||
|
||
jobs:
|
||
linux:
|
||
name: Linux ${{ matrix.arch }}
|
||
# Gitea 也会读这个文件;非 github.com 的 server 直接跳过,别占 Gitea 的 runner
|
||
if: ${{ github.server_url == 'https://github.com' }}
|
||
runs-on: ${{ matrix.runs-on }}
|
||
continue-on-error: ${{ matrix.optional }}
|
||
timeout-minutes: 30
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
include:
|
||
- arch: x86_64
|
||
runs-on: ubuntu-22.04
|
||
deb_arch: amd64
|
||
rpm_arch: x86_64
|
||
optional: false
|
||
- arch: aarch64
|
||
runs-on: ubuntu-24.04-arm
|
||
deb_arch: arm64
|
||
rpm_arch: aarch64
|
||
optional: true
|
||
steps:
|
||
- name: 检出代码
|
||
uses: actions/checkout@v4
|
||
|
||
- name: 安装构建依赖
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y --no-install-recommends \
|
||
build-essential file \
|
||
qtbase5-dev qtbase5-dev-tools qt5-qmake \
|
||
rpm dpkg-dev
|
||
|
||
- name: 读取版本号
|
||
id: meta
|
||
run: |
|
||
version=$(sed -n 's/^VERSION[[:space:]]*=[[:space:]]*//p' VoiletMark.pro | head -n1 | tr -d '[:space:]')
|
||
if [ -z "$version" ]; then
|
||
echo "VoiletMark.pro 里没有 VERSION" >&2
|
||
exit 1
|
||
fi
|
||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||
|
||
- name: 编译
|
||
run: |
|
||
qmake_bin=$(command -v qmake-qt5 || command -v qmake || true)
|
||
if [ -z "$qmake_bin" ]; then
|
||
echo "找不到 qmake(确认装了 qtbase5-dev / qt5-qmake)" >&2
|
||
exit 1
|
||
fi
|
||
"$qmake_bin" -v
|
||
mkdir -p build
|
||
cd build
|
||
"$qmake_bin" ../VoiletMark.pro PREFIX=/usr CONFIG+=release
|
||
make -j"$(nproc)"
|
||
make install INSTALL_ROOT="$PWD/stage"
|
||
find stage -type f | sort
|
||
|
||
- name: 打 .deb
|
||
run: ./packaging/build-deb.sh build/stage "${{ steps.meta.outputs.version }}" "${{ matrix.deb_arch }}" dist
|
||
|
||
- name: 打 .rpm
|
||
run: ./packaging/build-rpm.sh build/stage "${{ steps.meta.outputs.version }}" "${{ matrix.rpm_arch }}" dist
|
||
|
||
- name: 检查产物
|
||
run: |
|
||
ls -lh dist
|
||
dpkg-deb -I dist/*.deb
|
||
rpm -qpi dist/*.rpm
|
||
|
||
- name: 上传产物
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: voiletmark-linux-${{ matrix.arch }}
|
||
path: dist/*
|
||
if-no-files-found: error
|
||
|
||
windows:
|
||
name: Windows x86_64
|
||
if: ${{ github.server_url == 'https://github.com' }}
|
||
runs-on: windows-2022
|
||
timeout-minutes: 40
|
||
steps:
|
||
- name: 检出代码
|
||
uses: actions/checkout@v4
|
||
|
||
- name: 准备 MSVC 环境
|
||
uses: ilammy/msvc-dev-cmd@v1
|
||
with:
|
||
arch: x64
|
||
|
||
- name: 安装 Qt ${{ env.QT_VERSION }}
|
||
uses: jurplel/install-qt-action@v4
|
||
with:
|
||
version: ${{ env.QT_VERSION }}
|
||
arch: win64_msvc2019_64
|
||
cache: true
|
||
|
||
- name: 编译并收集 Qt 依赖
|
||
shell: bash
|
||
run: |
|
||
set -euo pipefail
|
||
version=$(sed -n 's/^VERSION[[:space:]]*=[[:space:]]*//p' VoiletMark.pro | head -n1 | tr -d '[:space:]')
|
||
if [ -z "$version" ]; then
|
||
echo "VoiletMark.pro 里没有 VERSION" >&2
|
||
exit 1
|
||
fi
|
||
echo "APP_VERSION=$version" >> "$GITHUB_ENV"
|
||
|
||
mkdir -p build
|
||
cd build
|
||
# Git Bash 的 /usr/bin 里也有个 link.exe(coreutils 的硬链接工具),
|
||
# 必须把 MSVC 的 bin 放到 PATH 最前面,nmake 才会用真正的 link.exe
|
||
cl_path=$(command -v cl.exe || command -v cl || true)
|
||
if [ -z "$cl_path" ]; then
|
||
echo "PATH 里找不到 cl.exe" >&2
|
||
exit 1
|
||
fi
|
||
msvc_bin=$(dirname "$cl_path")
|
||
export PATH="$msvc_bin:$PATH"
|
||
echo "cl: $(command -v cl)"
|
||
echo "link: $(command -v link)"
|
||
|
||
qmake ../VoiletMark.pro CONFIG+=release
|
||
nmake release || nmake
|
||
if [ -f release/VoiletMark.exe ]; then
|
||
exe=release/VoiletMark.exe
|
||
else
|
||
exe=$(find . -name VoiletMark.exe | head -n1)
|
||
fi
|
||
if [ -z "$exe" ]; then
|
||
echo "没找到 VoiletMark.exe" >&2
|
||
exit 1
|
||
fi
|
||
mkdir -p ../deploy
|
||
cp "$exe" ../deploy/VoiletMark.exe
|
||
cd ..
|
||
|
||
windeployqt --release --no-translations --compiler-runtime deploy/VoiletMark.exe
|
||
find deploy -maxdepth 1 -type f | sort
|
||
|
||
- name: 打 NSIS 安装包(关联 .md)
|
||
shell: bash
|
||
run: |
|
||
set -euo pipefail
|
||
mkdir -p dist
|
||
|
||
makensis='/c/Program Files (x86)/NSIS/makensis.exe'
|
||
if [ ! -x "$makensis" ]; then
|
||
makensis=$(find '/c/Program Files (x86)' '/c/Program Files' -maxdepth 3 -iname 'makensis.exe' 2>/dev/null | head -n1)
|
||
fi
|
||
if [ -z "$makensis" ]; then
|
||
choco install nsis -y --no-progress
|
||
makensis=$(find '/c/Program Files (x86)' '/c/Program Files' -maxdepth 3 -iname 'makensis.exe' 2>/dev/null | head -n1)
|
||
fi
|
||
if [ -z "$makensis" ]; then
|
||
echo "找不到 makensis(NSIS)" >&2
|
||
exit 1
|
||
fi
|
||
|
||
output=$(cygpath -w "$PWD/dist/VoiletMark-$APP_VERSION-win64-setup.exe")
|
||
deploy=$(cygpath -w "$PWD/deploy")
|
||
icon=$(cygpath -w "$PWD/packaging/voiletmark.ico")
|
||
script=$(cygpath -w "$PWD/packaging/windows/installer.nsi")
|
||
|
||
# Git Bash(MSYS)会把 /D... 当成 Unix 路径,转换成
|
||
# C:/Program Files/Git/DAPP_VERSION=...;这里关掉参数转换
|
||
MSYS2_ARG_CONV_EXCL='*' "$makensis" \
|
||
"/DAPP_VERSION=$APP_VERSION" \
|
||
"/DDEPLOY_DIR=$deploy" \
|
||
"/DICON_FILE=$icon" \
|
||
"/DOUTPUT_FILE=$output" \
|
||
"$script"
|
||
|
||
ls -lh dist
|
||
|
||
- name: 便携版 zip
|
||
shell: pwsh
|
||
run: |
|
||
Compress-Archive -Path deploy/* -DestinationPath "dist/VoiletMark-$env:APP_VERSION-win64-portable.zip"
|
||
Get-ChildItem dist | Select-Object Name, Length
|
||
|
||
- name: 上传产物
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: voiletmark-windows-x86_64
|
||
path: dist/*
|
||
if-no-files-found: error
|
||
|
||
macos-arm64:
|
||
name: macOS arm64 (Apple Silicon)
|
||
if: ${{ github.server_url == 'https://github.com' }}
|
||
runs-on: macos-15
|
||
timeout-minutes: 50
|
||
env:
|
||
HOMEBREW_NO_AUTO_UPDATE: "1"
|
||
steps:
|
||
- name: 检出代码
|
||
uses: actions/checkout@v4
|
||
|
||
- name: 安装 Qt 5(Homebrew,原生 arm64)
|
||
run: |
|
||
set -euo pipefail
|
||
brew install qt@5
|
||
qt_prefix=$(brew --prefix qt@5)
|
||
echo "QT_PREFIX=$qt_prefix" >> "$GITHUB_ENV"
|
||
"$qt_prefix/bin/qmake" -v
|
||
|
||
- name: 编译并打包 Qt 框架
|
||
run: |
|
||
set -euo pipefail
|
||
version=$(sed -n 's/^VERSION[[:space:]]*=[[:space:]]*//p' VoiletMark.pro | head -n1 | tr -d '[:space:]')
|
||
if [ -z "$version" ]; then
|
||
echo "VoiletMark.pro 里没有 VERSION" >&2
|
||
exit 1
|
||
fi
|
||
echo "APP_VERSION=$version" >> "$GITHUB_ENV"
|
||
|
||
mkdir -p build
|
||
cd build
|
||
"$QT_PREFIX/bin/qmake" ../VoiletMark.pro CONFIG+=release
|
||
make -j"$(sysctl -n hw.ncpu)"
|
||
|
||
file VoiletMark.app/Contents/MacOS/VoiletMark | tee /tmp/arch.txt
|
||
grep -q arm64 /tmp/arch.txt
|
||
|
||
"$QT_PREFIX/bin/macdeployqt" VoiletMark.app -always-overwrite
|
||
|
||
# 只留平台插件和样式插件;虚拟键盘 / 打印 / 图片格式这些用不到,
|
||
# 留着只会把 Homebrew 的 dylib 拖进来
|
||
rm -rf VoiletMark.app/Contents/PlugIns/virtualkeyboard \
|
||
VoiletMark.app/Contents/PlugIns/platforminputcontexts \
|
||
VoiletMark.app/Contents/PlugIns/printsupport \
|
||
VoiletMark.app/Contents/PlugIns/iconengines \
|
||
VoiletMark.app/Contents/PlugIns/imageformats \
|
||
VoiletMark.app/Contents/PlugIns/networkinformation \
|
||
VoiletMark.app/Contents/PlugIns/tls \
|
||
VoiletMark.app/Contents/PlugIns/bearer
|
||
|
||
otool -L VoiletMark.app/Contents/MacOS/VoiletMark | head -30
|
||
|
||
- name: 收 Homebrew 依赖 + ad-hoc 签名
|
||
run: |
|
||
set -euo pipefail
|
||
./packaging/macos/bundle-libs.sh build/VoiletMark.app
|
||
xattr -cr build/VoiletMark.app
|
||
codesign --force --deep --sign - build/VoiletMark.app
|
||
codesign --verify --deep --strict build/VoiletMark.app
|
||
|
||
- name: 打 dmg
|
||
run: ./packaging/macos/build-dmg.sh build/VoiletMark.app "$APP_VERSION" arm64 dist
|
||
|
||
- name: 上传产物
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: voiletmark-macos-arm64
|
||
path: dist/*
|
||
if-no-files-found: error
|
||
|
||
macos-x86_64:
|
||
name: macOS x86_64 (Intel)
|
||
# Intel 的 GitHub runner;拿不到这个 runner 时这一步会失败,不影响其它产物
|
||
if: ${{ github.server_url == 'https://github.com' }}
|
||
runs-on: macos-15-intel
|
||
timeout-minutes: 40
|
||
steps:
|
||
- name: 检出代码
|
||
uses: actions/checkout@v4
|
||
|
||
- name: 安装 Qt ${{ env.QT_VERSION }}
|
||
uses: jurplel/install-qt-action@v4
|
||
with:
|
||
version: ${{ env.QT_VERSION }}
|
||
arch: clang_64
|
||
cache: true
|
||
|
||
- name: 编译并打包 Qt 框架
|
||
run: |
|
||
set -euo pipefail
|
||
version=$(sed -n 's/^VERSION[[:space:]]*=[[:space:]]*//p' VoiletMark.pro | head -n1 | tr -d '[:space:]')
|
||
if [ -z "$version" ]; then
|
||
echo "VoiletMark.pro 里没有 VERSION" >&2
|
||
exit 1
|
||
fi
|
||
echo "APP_VERSION=$version" >> "$GITHUB_ENV"
|
||
|
||
mkdir -p build
|
||
cd build
|
||
qmake ../VoiletMark.pro CONFIG+=release
|
||
make -j"$(sysctl -n hw.ncpu)"
|
||
|
||
file VoiletMark.app/Contents/MacOS/VoiletMark | tee /tmp/arch.txt
|
||
grep -q x86_64 /tmp/arch.txt
|
||
|
||
macdeployqt VoiletMark.app -always-overwrite
|
||
|
||
rm -rf VoiletMark.app/Contents/PlugIns/virtualkeyboard \
|
||
VoiletMark.app/Contents/PlugIns/platforminputcontexts \
|
||
VoiletMark.app/Contents/PlugIns/printsupport \
|
||
VoiletMark.app/Contents/PlugIns/iconengines \
|
||
VoiletMark.app/Contents/PlugIns/imageformats \
|
||
VoiletMark.app/Contents/PlugIns/networkinformation \
|
||
VoiletMark.app/Contents/PlugIns/tls \
|
||
VoiletMark.app/Contents/PlugIns/bearer
|
||
|
||
- name: 收依赖 + ad-hoc 签名
|
||
run: |
|
||
set -euo pipefail
|
||
./packaging/macos/bundle-libs.sh build/VoiletMark.app
|
||
xattr -cr build/VoiletMark.app
|
||
codesign --force --deep --sign - build/VoiletMark.app
|
||
codesign --verify --deep --strict build/VoiletMark.app
|
||
|
||
- name: 打 dmg
|
||
run: ./packaging/macos/build-dmg.sh build/VoiletMark.app "$APP_VERSION" x86_64 dist
|
||
|
||
- name: 上传产物
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: voiletmark-macos-x86_64
|
||
path: dist/*
|
||
if-no-files-found: error
|
||
|
||
release:
|
||
name: 发布到 Release
|
||
needs: [linux, windows, macos-arm64, macos-x86_64]
|
||
# 打 tag 或手动勾 publish 才发;普通推送/PR 只留 artifact。
|
||
# always() 是为了某个平台失败时其它产物还能发出来。
|
||
# 推 main / 打 tag / 手动运行都自动发 Release(PR 不发);
|
||
# 非 github.com(比如 Gitea)直接跳过。always() 保证某个平台失败时其它产物还能发。
|
||
if: >-
|
||
always() && !cancelled() &&
|
||
github.server_url == 'https://github.com' &&
|
||
(github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||
runs-on: ubuntu-24.04
|
||
timeout-minutes: 10
|
||
steps:
|
||
- name: 检出代码
|
||
uses: actions/checkout@v4
|
||
|
||
- name: 读取版本号
|
||
id: meta
|
||
run: |
|
||
version=$(sed -n 's/^VERSION[[:space:]]*=[[:space:]]*//p' VoiletMark.pro | head -n1 | tr -d '[:space:]')
|
||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||
|
||
- name: 下载所有产物
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
path: dist
|
||
merge-multiple: true
|
||
|
||
- name: 检查产物
|
||
run: |
|
||
ls -lh dist
|
||
count=$(find dist -maxdepth 1 -type f | wc -l)
|
||
if [ "$count" -eq 0 ]; then
|
||
echo "一个安装包都没有,不发布" >&2
|
||
exit 1
|
||
fi
|
||
|
||
- name: 生成 SHA256SUMS
|
||
run: |
|
||
cd dist
|
||
find . -maxdepth 1 -type f ! -name SHA256SUMS -printf '%f\n' | sort > /tmp/files.txt
|
||
xargs sha256sum < /tmp/files.txt > SHA256SUMS
|
||
cat SHA256SUMS
|
||
|
||
- name: 挂到 Release
|
||
uses: softprops/action-gh-release@v2
|
||
with:
|
||
# 打 tag 时用那个 tag;手动发布时用 v<版本>(不存在就按当前提交新建)
|
||
tag_name: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || format('v{0}', steps.meta.outputs.version) }}
|
||
target_commitish: ${{ github.sha }}
|
||
name: VoiletMark ${{ steps.meta.outputs.version }}
|
||
files: dist/*
|
||
# 明确要求公开发布(不是草稿、不是预发布);
|
||
# 已存在同名草稿时,action 会更新它并把 draft 改回 false
|
||
draft: false
|
||
prerelease: false
|
||
make_latest: "true"
|
||
generate_release_notes: true
|
||
fail_on_unmatched_files: true
|