Skip to content

Commit e7687eb

Browse files
committed
feat: linux cicd
1 parent 635262c commit e7687eb

File tree

10 files changed

+680
-8
lines changed

10 files changed

+680
-8
lines changed

.github/workflows/release.yml

Lines changed: 270 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,28 @@ jobs:
2828
- name: Setup Flutter
2929
uses: subosito/flutter-action@v2
3030
with:
31-
flutter-version: '3.32.5'
32-
channel: 'stable'
31+
flutter-versi ## 📱 Platform Support / 平台支持
32+
33+
### Android
34+
${{ needs.releaseAndroid.result == 'success' && '✅ APK available for download' || '❌ Android build failed' }}
35+
36+
### Linux
37+
${{ needs.releaseLinux.result == 'success' && '✅ AppImage available for download' || '❌ Linux build failed' }}
38+
39+
### iOS
40+
${{ needs.releaseiOS.result == 'success' && '✅ IPA available for download' || '❌ iOS build failed' }}
41+
42+
## 📝 Installation Notes / 安装说明
43+
44+
### Android
45+
- Direct installation from APK file
46+
- 直接从APK文件安装
47+
48+
### Linux
49+
- Download the AppImage file
50+
- Make it executable: `chmod +x lumma_*.AppImage`
51+
- Run directly: `./lumma_*.AppImage`
52+
- 下载AppImage文件,设置可执行权限后直接运行 channel: 'stable'
3353
cache: true
3454

3555
- name: Verify Flutter Installation
@@ -115,6 +135,235 @@ jobs:
115135
path: release-files/*.apk
116136
retention-days: 30
117137

138+
releaseLinux:
139+
name: Release Linux AppImage
140+
runs-on: ubuntu-22.04
141+
steps:
142+
- name: Checkout
143+
uses: actions/checkout@v4
144+
145+
- name: Setup Flutter
146+
uses: subosito/flutter-action@v2
147+
with:
148+
flutter-version: '3.32.5'
149+
channel: 'stable'
150+
cache: true
151+
152+
- name: Install Linux Dependencies
153+
run: |
154+
sudo apt-get update
155+
sudo apt-get install -y \
156+
clang \
157+
cmake \
158+
ninja-build \
159+
pkg-config \
160+
libgtk-3-dev \
161+
liblzma-dev \
162+
libstdc++-12-dev \
163+
wget \
164+
file \
165+
imagemagick \
166+
fuse
167+
168+
- name: Verify Flutter Installation
169+
run: |
170+
flutter config --no-analytics
171+
flutter doctor -v
172+
flutter --version
173+
flutter config --enable-linux-desktop
174+
175+
- name: Install Dependencies
176+
run: flutter pub get
177+
178+
- name: Extract Version Info
179+
id: version
180+
run: |
181+
TAG="${{ github.ref_name }}"
182+
VERSION=$(echo $TAG | sed 's/^v//')
183+
BUILD_NUM="${{ github.run_number }}"
184+
185+
echo "tag=$TAG" >> $GITHUB_OUTPUT
186+
echo "version=$VERSION" >> $GITHUB_OUTPUT
187+
echo "build_number=$BUILD_NUM" >> $GITHUB_OUTPUT
188+
189+
echo "=== Build Info ==="
190+
echo "Tag: $TAG"
191+
echo "Version: $VERSION"
192+
echo "Build Number: $BUILD_NUM"
193+
194+
- name: Create Environment File
195+
run: |
196+
cat > .env.release << EOF
197+
MODEL_PROVIDER=openrouter
198+
MODEL_BASE_URL=https://openrouter.ai/api/v1
199+
MODEL_API_KEY=sk-or-v1
200+
MODEL_NAME=deepseek/deepseek-chat-v3-0324:free
201+
USE_LOCAL_CONFIG=false
202+
EOF
203+
204+
- name: Build Linux Release
205+
run: |
206+
flutter build linux \
207+
--release \
208+
--build-name="${{ steps.version.outputs.version }}" \
209+
--build-number="${{ steps.version.outputs.build_number }}" \
210+
--verbose
211+
212+
- name: Verify Linux Build
213+
run: |
214+
echo "🔍 Verifying Linux build output..."
215+
if [ -d "build/linux/x64/release/bundle" ]; then
216+
echo "✅ Linux build directory exists"
217+
ls -la build/linux/x64/release/bundle/
218+
219+
if [ -f "build/linux/x64/release/bundle/lumma" ]; then
220+
echo "✅ Lumma executable found"
221+
file build/linux/x64/release/bundle/lumma
222+
else
223+
echo "❌ Lumma executable not found"
224+
exit 1
225+
fi
226+
else
227+
echo "❌ Linux build directory not found"
228+
exit 1
229+
fi
230+
231+
- name: Download AppImageTool
232+
run: |
233+
mkdir -p linux/build
234+
wget -O linux/build/appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
235+
chmod +x linux/build/appimagetool
236+
237+
- name: Create AppImage Structure
238+
run: |
239+
APP_NAME="${{ env.APP_NAME }}"
240+
APP_DIR="linux/build/${APP_NAME}.AppDir"
241+
242+
# Create AppDir structure
243+
mkdir -p $APP_DIR/usr/bin
244+
mkdir -p $APP_DIR/usr/lib
245+
mkdir -p $APP_DIR/usr/share/applications
246+
mkdir -p $APP_DIR/usr/share/icons/hicolor/256x256/apps
247+
248+
# Copy the built application
249+
cp -r build/linux/x64/release/bundle/* $APP_DIR/usr/bin/
250+
251+
# Copy required libraries
252+
echo "📚 Copying required libraries..."
253+
# Copy system libraries that might be needed
254+
mkdir -p $APP_DIR/usr/lib/x86_64-linux-gnu
255+
256+
# Find and copy Flutter engine libraries
257+
if [ -d "build/linux/x64/release/bundle/lib" ]; then
258+
cp -r build/linux/x64/release/bundle/lib/* $APP_DIR/usr/lib/ 2>/dev/null || true
259+
fi
260+
261+
# Create desktop file
262+
cat > $APP_DIR/usr/share/applications/$APP_NAME.desktop << EOF
263+
[Desktop Entry]
264+
Name=Lumma
265+
Comment=AI-powered Q&A Diary App
266+
Exec=$APP_NAME
267+
Icon=$APP_NAME
268+
Type=Application
269+
Categories=Office;
270+
StartupNotify=true
271+
EOF
272+
273+
# Create AppRun script
274+
cat > $APP_DIR/AppRun << 'EOF'
275+
#!/bin/bash
276+
277+
# Get the directory where this AppImage is located
278+
HERE="$(dirname "$(readlink -f "${0}")")"
279+
280+
# Set up library paths
281+
export LD_LIBRARY_PATH="${HERE}/usr/lib:${HERE}/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH}"
282+
283+
# Change to the application directory
284+
cd "${HERE}/usr/bin"
285+
286+
# Execute the application
287+
exec "${HERE}/usr/bin/lumma" "$@"
288+
EOF
289+
chmod +x $APP_DIR/AppRun
290+
291+
# Copy icon (use a default icon if app icon doesn't exist)
292+
if [ -f "assets/icon/icon.jpg" ]; then
293+
# Convert JPG to PNG for better AppImage support
294+
convert "assets/icon/icon.jpg" -resize 256x256 "$APP_DIR/usr/share/icons/hicolor/256x256/apps/$APP_NAME.png"
295+
echo "✅ Application icon converted and copied"
296+
else
297+
# Create a simple placeholder icon
298+
echo "⚠️ App icon not found, creating placeholder..."
299+
convert -size 256x256 xc:lightblue -pointsize 72 -fill darkblue -gravity center -annotate +0+0 "L" "$APP_DIR/usr/share/icons/hicolor/256x256/apps/$APP_NAME.png" || \
300+
wget -O "$APP_DIR/usr/share/icons/hicolor/256x256/apps/$APP_NAME.png" https://via.placeholder.com/256x256/lightblue/darkblue?text=L
301+
fi
302+
303+
# Create symlinks for desktop file and icon at root level
304+
ln -sf usr/share/applications/$APP_NAME.desktop $APP_DIR/
305+
ln -sf usr/share/icons/hicolor/256x256/apps/$APP_NAME.png $APP_DIR/
306+
307+
echo "AppDir structure created:"
308+
find $APP_DIR -type f | head -20
309+
310+
- name: Create AppImage
311+
run: |
312+
APP_NAME="${{ env.APP_NAME }}"
313+
VERSION="${{ steps.version.outputs.version }}"
314+
APP_DIR="linux/build/${APP_NAME}.AppDir"
315+
316+
# Create AppImage
317+
./linux/build/appimagetool "${APP_DIR}" "linux/build/${APP_NAME}-${VERSION}-x86_64.AppImage"
318+
319+
# Verify AppImage was created
320+
if [ -f "linux/build/${APP_NAME}-${VERSION}-x86_64.AppImage" ]; then
321+
echo "✅ AppImage created successfully"
322+
ls -la "linux/build/${APP_NAME}-${VERSION}-x86_64.AppImage"
323+
file "linux/build/${APP_NAME}-${VERSION}-x86_64.AppImage"
324+
325+
# Test AppImage structure
326+
echo "🔍 Testing AppImage structure..."
327+
./linux/build/appimagetool --appimage-extract-and-run "linux/build/${APP_NAME}-${VERSION}-x86_64.AppImage" --help 2>/dev/null || echo "AppImage help test completed"
328+
329+
# Make the AppImage executable
330+
chmod +x "linux/build/${APP_NAME}-${VERSION}-x86_64.AppImage"
331+
332+
echo "📊 AppImage size: $(du -h "linux/build/${APP_NAME}-${VERSION}-x86_64.AppImage" | cut -f1)"
333+
else
334+
echo "❌ AppImage creation failed"
335+
echo "Available files in linux/build/:"
336+
ls -la linux/build/ || echo "Build directory not found"
337+
exit 1
338+
fi
339+
340+
- name: Prepare Linux Release Files
341+
run: |
342+
mkdir -p release-files-linux
343+
344+
VERSION="${{ steps.version.outputs.version }}"
345+
APP_NAME="${{ env.APP_NAME }}"
346+
347+
# Copy AppImage
348+
if [ -f "linux/build/${APP_NAME}-${VERSION}-x86_64.AppImage" ]; then
349+
cp "linux/build/${APP_NAME}-${VERSION}-x86_64.AppImage" \
350+
"release-files-linux/${APP_NAME}_${VERSION}_linux_x86_64.AppImage"
351+
echo "✅ Linux AppImage ready"
352+
else
353+
echo "❌ Linux AppImage not found"
354+
exit 1
355+
fi
356+
357+
echo "📦 Linux Release files:"
358+
ls -la release-files-linux/
359+
360+
- name: Upload Linux Artifacts
361+
uses: actions/upload-artifact@v4
362+
with:
363+
name: linux-release
364+
path: release-files-linux/*.AppImage
365+
retention-days: 30
366+
118367
releaseiOS:
119368
name: Release iOS
120369
runs-on: macos-latest
@@ -266,8 +515,8 @@ jobs:
266515
createRelease:
267516
name: Create Unified Release
268517
runs-on: ubuntu-22.04
269-
needs: [releaseAndroid, releaseiOS]
270-
if: always() && (needs.releaseAndroid.result == 'success' || needs.releaseiOS.result == 'success')
518+
needs: [releaseAndroid, releaseLinux, releaseiOS]
519+
if: always() && (needs.releaseAndroid.result == 'success' || needs.releaseLinux.result == 'success' || needs.releaseiOS.result == 'success')
271520
steps:
272521
- name: Checkout
273522
uses: actions/checkout@v4
@@ -291,6 +540,14 @@ jobs:
291540
path: ./artifacts/android/
292541
continue-on-error: true
293542

543+
- name: Download Linux Artifacts
544+
if: needs.releaseLinux.result == 'success'
545+
uses: actions/download-artifact@v4
546+
with:
547+
name: linux-release
548+
path: ./artifacts/linux/
549+
continue-on-error: true
550+
294551
- name: Download iOS Artifacts
295552
if: needs.releaseiOS.result == 'success'
296553
uses: actions/download-artifact@v4
@@ -306,6 +563,7 @@ jobs:
306563
name: ${{ env.APP_NAME }} ${{ steps.version.outputs.tag }}
307564
files: |
308565
./artifacts/android/*.apk
566+
./artifacts/linux/*.AppImage
309567
./artifacts/ios/*.ipa
310568
body: |
311569
# 🌟 ${{ env.APP_NAME }} ${{ steps.version.outputs.tag }}
@@ -326,6 +584,9 @@ jobs:
326584
### iOS
327585
${{ needs.releaseiOS.result == 'success' && '✅ IPA available for download' || '❌ iOS build failed' }}
328586
587+
### Linux
588+
${{ needs.releaseLinux.result == 'success' && '✅ AppImage available for download' || '❌ Linux build failed' }}
589+
329590
## 📝 Installation Notes / 安装说明
330591
331592
### Android
@@ -336,6 +597,11 @@ jobs:
336597
> ⚠️ This is an unsigned development build. You may need to trust the developer certificate in iOS Settings > General > VPN & Device Management.
337598
> ⚠️ 这是未签名的开发版本,你可能需要在iOS设置 > 通用 > VPN与设备管理中信任开发者证书。
338599
600+
### Linux
601+
- Download the AppImage file
602+
- Make it executable: `chmod +x lumma_*.AppImage`
603+
- Run directly: `./lumma_*.AppImage`
604+
- 下载AppImage文件,设置可执行权限后直接运行
339605
---
340606
341607
> 💡 If you encounter installation or usage issues, please report them in Issues.

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ app.*.map.json
4545
/android/app/release
4646
.kotlin
4747

48+
# Linux AppImage build artifacts
49+
/linux/build/
50+
*.AppImage
51+
lumma.AppDir/
52+
4853
# Local model configuration
4954
test/sample_data
5055
.env.local

0 commit comments

Comments
 (0)