77 workflow_dispatch :
88 inputs :
99 build_windows :
10- description : ' Build Windows x64 executable'
10+ description : Build Windows x64 executable
1111 required : true
1212 default : true
1313 type : boolean
1414 build_linux :
15- description : ' Build Linux x64 deb package'
15+ description : Build Linux x64 deb package
1616 required : true
1717 default : true
1818 type : boolean
1919 create_release :
20- description : ' Create GitHub Release'
20+ description : Create GitHub Release
2121 required : true
2222 default : false
2323 type : boolean
24+ release_tag :
25+ description : Release tag for manual run (example: v1.3.1)
26+ required : false
27+ default : ' '
28+ type : string
29+
30+ permissions :
31+ contents : write
32+
33+ concurrency :
34+ group : build-release-${{ github.ref }}
35+ cancel-in-progress : false
2436
2537env :
2638 APP_NAME : assignsticker
27- APP_VERSION : " 1.3.0"
2839
2940jobs :
3041 build-windows :
@@ -33,38 +44,60 @@ jobs:
3344 steps :
3445 - uses : actions/checkout@v4
3546
47+ - name : Set up Python
48+ uses : actions/setup-python@v5
49+ with :
50+ python-version : ' 3.13'
51+
3652 - name : Install uv
3753 uses : astral-sh/setup-uv@v5
38-
39- - name : Set up Python
40- run : uv python install 3.13
54+ with :
55+ enable-cache : true
4156
4257 - name : Install dependencies
4358 run : |
44- uv sync
59+ uv sync --frozen
4560 uv pip install pyinstaller
4661
47- - name : Build
62+ - name : Build Windows executable
4863 run : uv run python build.py
4964
50- - name : Upload artifact
65+ - name : Upload Windows artifact
5166 uses : actions/upload-artifact@v4
5267 with :
5368 name : AssignSticker-windows-x64
5469 path : dist/AssignSticker.exe
70+ if-no-files-found : error
5571
5672 build-linux :
5773 runs-on : ubuntu-latest
5874 if : github.event_name != 'workflow_dispatch' || inputs.build_linux
5975 steps :
6076 - uses : actions/checkout@v4
6177
62- - name : Get version from tag
63- if : startsWith(github.ref, 'refs/tags/v')
64- run : echo "APP_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
78+ - name : Set up Python
79+ uses : actions/setup-python@v5
80+ with :
81+ python-version : ' 3.13'
6582
6683 - name : Install uv
6784 uses : astral-sh/setup-uv@v5
85+ with :
86+ enable-cache : true
87+
88+ - name : Resolve app version
89+ id : version
90+ shell : bash
91+ run : |
92+ if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
93+ VERSION="${GITHUB_REF#refs/tags/v}"
94+ elif [[ -n "${{ inputs.release_tag }}" ]]; then
95+ VERSION="${{ inputs.release_tag }}"
96+ VERSION="${VERSION#v}"
97+ else
98+ VERSION="0.0.0-dev"
99+ fi
100+ echo "app_version=${VERSION}" >> "$GITHUB_OUTPUT"
68101
69102 - name : Install system dependencies
70103 run : |
@@ -74,42 +107,39 @@ jobs:
74107 pkg-config \
75108 libcairo2-dev \
76109 libgirepository-2.0-dev \
77- gir1.2-girepository-2.0 \
78110 gir1.2-gtk-3.0 \
79111 gir1.2-webkit2-4.1 \
80- dpkg-dev \
81112 python3-gi \
82113 python3-gi-cairo \
83114 libwebkit2gtk-4.1-0 \
84115 libayatana-appindicator3-1 \
116+ dpkg-dev
85117
86118 - name : Build with PyInstaller
119+ shell : bash
87120 run : |
88- # 安装依赖和 pyinstaller
89- uv sync
90- uv add --dev pyinstaller
121+ uv sync --frozen
122+ uv pip install pyinstaller
91123
92- # 创建 pyinstaller spec 文件
93124 cat > assignsticker.spec << 'SPECEOF'
94125 # -*- mode: python ; coding: utf-8 -*-
95- import sys
96- from PyInstaller.building.build_main import Analysis, PYZ, EXE, COLLECT
126+ from PyInstaller.building.build_main import Analysis, PYZ, EXE
97127
98128 block_cipher = None
99129
100- # 数据文件
101130 datas = [
102131 ('htmls', 'htmls'),
103132 ('icons', 'icons'),
104133 ('saying', 'saying'),
105134 ('desktop_widgets', 'desktop_widgets'),
135+ ('homeworktemple', 'homeworktemple'),
106136 ('font.ttf', '.'),
107137 ('icon.ico', '.'),
108138 ('introduce', '.'),
109139 ('banner.png', '.'),
140+ ('作业模板YML格式标准.txt', '.'),
110141 ]
111142
112- # 隐藏导入(Linux 特有)
113143 hiddenimports = [
114144 'gi',
115145 'gi.repository',
@@ -169,33 +199,31 @@ jobs:
169199 )
170200 SPECEOF
171201
172- # 使用 pyinstaller 打包
173202 uv run pyinstaller assignsticker.spec
174203
175204 - name : Build DEB package
205+ shell : bash
206+ env :
207+ APP_VERSION : ${{ steps.version.outputs.app_version }}
176208 run : |
177- set -e
209+ set -euo pipefail
178210 PKG="build/deb/${APP_NAME}"
179211
180- # 创建 deb 包目录结构
181212 mkdir -p "${PKG}/opt/${APP_NAME}"
182213 mkdir -p "${PKG}/usr/bin"
183214 mkdir -p "${PKG}/usr/share/applications"
184215 mkdir -p "${PKG}/DEBIAN"
185216
186- # 复制 PyInstaller 输出
187217 cp -r dist/assignsticker/* "${PKG}/opt/${APP_NAME}/"
188218
189- # 创建启动脚本
190- cat > "${PKG}/usr/bin/${APP_NAME}" <<'EOF'
219+ cat > "${PKG}/usr/bin/${APP_NAME}" <<'LAUNCHEOF'
191220 #!/bin/bash
192221 export GI_TYPELIB_PATH=/usr/lib/x86_64-linux-gnu/girepository-1.0
193222 exec /opt/assignsticker/assignsticker "$@"
194- EOF
223+ LAUNCHEOF
195224 chmod +x "${PKG}/usr/bin/${APP_NAME}"
196225
197- # 创建 Desktop Entry
198- cat > "${PKG}/usr/share/applications/${APP_NAME}.desktop" <<EOF
226+ cat > "${PKG}/usr/share/applications/${APP_NAME}.desktop" <<DESKTOPEOF
199227 [Desktop Entry]
200228 Name=AssignSticker
201229 Comment=Homework Kanban Application
@@ -205,65 +233,83 @@ jobs:
205233 Categories=Education;Office;
206234 Terminal=false
207235 StartupWMClass=assignsticker
208- EOF
236+ DESKTOPEOF
209237
210- # 计算大小并创建 control 文件
211238 SIZE=$(du -sk "${PKG}" | cut -f1)
212- cat > "${PKG}/DEBIAN/control" <<EOF
239+ cat > "${PKG}/DEBIAN/control" <<CONTROLEOF
213240 Package: ${APP_NAME}
214241 Version: ${APP_VERSION}
215242 Section: education
216243 Priority: optional
217244 Architecture: amd64
218245 Installed-Size: ${SIZE}
219- Depends: gir1.2-gtk-3.0,
220- gir1.2-webkit2-4.1,
221- gir1.2-ayatanaappindicator3-0.1,
222- libcairo2,
223- libgtk-3-0,
224- libwebkit2gtk-4.1-0,
225- libgirepository-2.0-0
226- gir1.2-girepository-2.0-dev
246+ Depends: gir1.2-gtk-3.0, gir1.2-webkit2-4.1, libayatana-appindicator3-1, libcairo2, libgtk-3-0, libwebkit2gtk-4.1-0, libgirepository-2.0-0
227247 Maintainer: SECTL <sectl@example.com>
228- Homepage: https://github.com/sectl /AssignSticker
248+ Homepage: https://github.com/SECTL /AssignSticker
229249 Description: Homework Showboard Application
230- AssignSticker is a homework management and display
231- application for classroom use.
232- EOF
250+ AssignSticker is a homework management and display application for classroom use.
251+ CONTROLEOF
233252
234- # 打包
235253 dpkg-deb --root-owner-group --build "${PKG}"
236254 mv "build/deb/${APP_NAME}.deb" "AssignSticker-${APP_VERSION}-amd64.deb"
237255
238- - name : Upload artifact
256+ - name : Upload Linux artifact
239257 uses : actions/upload-artifact@v4
240258 with :
241259 name : AssignSticker-linux-amd64
242- path : " *.deb"
260+ path : AssignSticker-*-amd64.deb
261+ if-no-files-found : error
243262
244263 release :
245264 needs : [build-windows, build-linux]
246265 runs-on : ubuntu-latest
247266 if : |
248267 always() &&
249268 (startsWith(github.ref, 'refs/tags/v') ||
250- (github.event_name == 'workflow_dispatch' && inputs.create_release))
269+ (github.event_name == 'workflow_dispatch' && inputs.create_release)) &&
270+ (needs.build-windows.result == 'success' || needs.build-linux.result == 'success') &&
271+ (needs.build-windows.result != 'failure' && needs.build-linux.result != 'failure')
251272 steps :
252- - name : Download artifacts
273+ - name : Resolve release tag
274+ id : rel
275+ shell : bash
276+ run : |
277+ if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
278+ TAG="${GITHUB_REF#refs/tags/}"
279+ elif [[ -n "${{ inputs.release_tag }}" ]]; then
280+ TAG="${{ inputs.release_tag }}"
281+ else
282+ echo "Manual release must provide release_tag (example: v1.3.1)" >&2
283+ exit 1
284+ fi
285+ echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
286+
287+ - name : Download Windows artifact
288+ if : needs.build-windows.result == 'success'
253289 uses : actions/download-artifact@v4
254290 with :
255- path : artifacts
256- merge-multiple : true
291+ name : AssignSticker-windows-x64
292+ path : artifacts/windows
293+
294+ - name : Download Linux artifact
295+ if : needs.build-linux.result == 'success'
296+ uses : actions/download-artifact@v4
297+ with :
298+ name : AssignSticker-linux-amd64
299+ path : artifacts/linux
257300
258- - name : List files
259- run : find artifacts -type f
301+ - name : List release files
302+ run : find artifacts -type f || true
260303
261- - name : Create Release
304+ - name : Create GitHub Release
262305 uses : softprops/action-gh-release@v2
263306 with :
264- files : artifacts/*
307+ tag_name : ${{ steps.rel.outputs.tag }}
308+ files : |
309+ artifacts/windows/*
310+ artifacts/linux/*
265311 draft : false
266312 prerelease : false
267313 generate_release_notes : true
268314 env :
269- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
315+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
0 commit comments