Files
VoiletMark/.github/workflows/packages.yml
T
liyepan 56ac3a89f2
安装包 / 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
feat: v0.12.5 —— Release 自动发布,Gitea 上所有 job 直接跳过
- 取消手动 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)
2026-10-23 15:20:31 +08:00

413 lines
14 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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