Build & Push Frontend Docker Image / build-and-push (push) Canceled after 0s
Build Validation / validate (push) Canceled after 6s
Build & Push Backend Docker Image / build-and-push (push) Failing after 10m10s
Build & Push Gateway Docker Image / build-and-push (push) Failing after 10m9s
A professional workspace for AI coding agents with: - Real-time streaming chat with SSE - Session management (fork, clone, tree navigation) - MCP tools browser & metadata panel - Skills browser (global, project, package sources) - Voice input & STT provider configuration - Integrated terminal & file explorer - Model selector with capability metadata - Keyboard-first UI with command palette - 8 languages (en, pt-BR, es, ja, zh-CN, ar, bn, hi) - Tauri 2 desktop app - React 19 + TypeScript + Vite 8 + Tailwind CSS 4 - Pi Agent extension runtime Originally forked from OpenCodeUI, now an independent project. License: GPL-3.0-only
241 lines
7.9 KiB
YAML
241 lines
7.9 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
|
|
concurrency:
|
|
group: release-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# ============================================
|
|
# Desktop builds (Windows, macOS, Linux)
|
|
# ============================================
|
|
build-desktop:
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- platform: macos-latest
|
|
args: '--target aarch64-apple-darwin'
|
|
arch: aarch64
|
|
os: macos
|
|
- platform: macos-latest
|
|
args: '--target x86_64-apple-darwin'
|
|
arch: x86_64
|
|
os: macos
|
|
- platform: ubuntu-22.04
|
|
args: ''
|
|
arch: x86_64
|
|
os: linux
|
|
- platform: windows-latest
|
|
args: ''
|
|
arch: x86_64
|
|
os: windows
|
|
|
|
runs-on: ${{ matrix.platform }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: lts/*
|
|
cache: 'npm'
|
|
|
|
- name: Install Rust stable
|
|
uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
|
|
|
|
- name: Rust cache
|
|
uses: swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: './src-tauri -> target'
|
|
key: ${{ matrix.os }}-${{ matrix.arch }}
|
|
|
|
- name: Install Linux dependencies
|
|
if: matrix.platform == 'ubuntu-22.04'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
|
|
|
- run: npm ci
|
|
|
|
# tauri-action 自动执行 beforeBuildCommand (npm run build) + cargo build
|
|
- name: Build desktop app
|
|
uses: tauri-apps/tauri-action@v0
|
|
with:
|
|
args: ${{ matrix.args }}
|
|
|
|
- name: Prepare artifacts
|
|
shell: bash
|
|
run: |
|
|
mkdir -p release-artifacts
|
|
BUNDLE_DIR="src-tauri/target/release/bundle"
|
|
if [[ "${{ matrix.os }}" == "macos" ]]; then
|
|
BUNDLE_DIR="src-tauri/target/${{ matrix.arch }}-apple-darwin/release/bundle"
|
|
fi
|
|
|
|
if [[ "${{ matrix.os }}" == "windows" ]]; then
|
|
find "$BUNDLE_DIR/nsis" -name "*.exe" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
|
elif [[ "${{ matrix.os }}" == "macos" ]]; then
|
|
find "$BUNDLE_DIR/dmg" -name "*.dmg" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
|
elif [[ "${{ matrix.os }}" == "linux" ]]; then
|
|
find "$BUNDLE_DIR/deb" -name "*.deb" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
|
find "$BUNDLE_DIR/appimage" -name "*.AppImage" -exec cp {} release-artifacts/ \; 2>/dev/null || true
|
|
fi
|
|
|
|
echo "Artifacts:"
|
|
ls -R release-artifacts
|
|
|
|
- uses: actions/upload-artifact@v7
|
|
with:
|
|
name: artifacts-desktop-${{ matrix.os }}-${{ matrix.arch }}
|
|
path: release-artifacts
|
|
if-no-files-found: warn
|
|
retention-days: 1
|
|
|
|
# ============================================
|
|
# Android builds (arm64 + armv7 并行)
|
|
# ============================================
|
|
build-android:
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- target: aarch64
|
|
rust_target: aarch64-linux-android
|
|
label: arm64
|
|
- target: armv7
|
|
rust_target: armv7-linux-androideabi
|
|
label: armv7
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: lts/*
|
|
cache: 'npm'
|
|
|
|
- uses: actions/setup-java@v5
|
|
with:
|
|
distribution: 'temurin'
|
|
java-version: '17'
|
|
|
|
- uses: android-actions/setup-android@v3
|
|
|
|
- run: sdkmanager "ndk;29.0.14206865"
|
|
|
|
- name: Install Rust stable
|
|
uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
targets: ${{ matrix.rust_target }}
|
|
|
|
- name: Rust cache
|
|
uses: swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: './src-tauri -> target'
|
|
key: android-${{ matrix.target }}
|
|
|
|
- name: Gradle cache
|
|
uses: actions/cache@v5
|
|
with:
|
|
path: |
|
|
~/.gradle/caches
|
|
~/.gradle/wrapper
|
|
src-tauri/gen/android/.gradle
|
|
key: gradle-${{ matrix.target }}-${{ hashFiles('src-tauri/gen/android/**/*.gradle*', 'src-tauri/gen/android/**/gradle-wrapper.properties') }}
|
|
restore-keys: gradle-
|
|
|
|
- run: npm ci
|
|
|
|
- name: Setup Android signing
|
|
run: |
|
|
cd src-tauri/gen/android
|
|
echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" > keystore.properties
|
|
echo "password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> keystore.properties
|
|
base64 -d <<< "${{ secrets.ANDROID_KEY_BASE64 }}" > $RUNNER_TEMP/keystore.jks
|
|
echo "storeFile=$RUNNER_TEMP/keystore.jks" >> keystore.properties
|
|
|
|
- name: Build and sign APK
|
|
run: |
|
|
VERSION=${{ github.ref_name }}
|
|
BT="$ANDROID_HOME/build-tools/$(ls $ANDROID_HOME/build-tools/ | tail -1)"
|
|
|
|
npx tauri android build --apk --target ${{ matrix.target }}
|
|
|
|
SIGNED_APK=$(find src-tauri/gen/android/app/build/outputs/apk -path '*/release/*-signed*' -name '*.apk' -type f 2>/dev/null | head -1)
|
|
RELEASE_APK=$(find src-tauri/gen/android/app/build/outputs/apk -path '*/release/*.apk' -name '*.apk' -type f 2>/dev/null | head -1)
|
|
APK_PATH="${SIGNED_APK:-$RELEASE_APK}"
|
|
DEST="OpenCodeUI-${VERSION}-android-${{ matrix.label }}.apk"
|
|
|
|
if $BT/apksigner verify "$APK_PATH" 2>/dev/null; then
|
|
cp "$APK_PATH" "$DEST"
|
|
else
|
|
$BT/zipalign -v 4 "$APK_PATH" "${APK_PATH}.aligned"
|
|
$BT/apksigner sign \
|
|
--ks $RUNNER_TEMP/keystore.jks \
|
|
--ks-key-alias ${{ secrets.ANDROID_KEY_ALIAS }} \
|
|
--ks-pass pass:${{ secrets.ANDROID_KEY_PASSWORD }} \
|
|
--key-pass pass:${{ secrets.ANDROID_KEY_PASSWORD }} \
|
|
--out "$DEST" "${APK_PATH}.aligned"
|
|
fi
|
|
|
|
mkdir -p release-artifacts
|
|
mv "$DEST" release-artifacts/
|
|
env:
|
|
NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/29.0.14206865
|
|
|
|
- uses: actions/upload-artifact@v7
|
|
with:
|
|
name: artifacts-android-${{ matrix.label }}
|
|
path: release-artifacts/*
|
|
retention-days: 1
|
|
|
|
# ============================================
|
|
# Publish Release
|
|
# ============================================
|
|
publish-release:
|
|
permissions:
|
|
contents: write
|
|
runs-on: ubuntu-latest
|
|
needs: [build-desktop, build-android]
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
path: artifacts
|
|
pattern: artifacts-*
|
|
merge-multiple: true
|
|
|
|
- name: Display artifacts
|
|
run: ls -R artifacts
|
|
|
|
- name: Extract changelog
|
|
id: changelog
|
|
run: |
|
|
TAG="${{ github.ref_name }}"
|
|
BODY=$(sed -n "/^## \[${TAG}\]/,/^## \[/{ /^## \[${TAG}\]/d; /^## \[/d; p; }" CHANGELOG.md)
|
|
BODY=$(echo "$BODY" | sed -e '/./,$!d' -e :a -e '/^\n*$/{$d;N;ba;}')
|
|
if [ -z "$BODY" ]; then
|
|
BODY="No changelog entry found for ${TAG}."
|
|
fi
|
|
echo "$BODY" > /tmp/release-body.md
|
|
printf '\n---\n\n**Desktop:** Windows (.exe), macOS (.dmg), Linux (.deb, .AppImage)\n**Mobile:** Android (.apk) — arm64, armeabi-v7a\n' >> /tmp/release-body.md
|
|
|
|
- name: Create Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ github.ref_name }}
|
|
name: 'OpenCodeUI ${{ github.ref_name }}'
|
|
body_path: /tmp/release-body.md
|
|
files: artifacts/*
|
|
draft: false
|
|
prerelease: ${{ contains(github.ref_name, 'canary') || contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|