Release (build all + publish) #13
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release (build all + publish) | |
| on: | |
| push: | |
| branches: [ main ] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' | |
| jobs: | |
| build-android: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| release_base: ${{ steps.vars.outputs.release_base }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Install Android command-line tools and SDK components (API 29) | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y unzip wget | |
| ANDROID_SDK_ROOT=$HOME/Android/Sdk | |
| mkdir -p $ANDROID_SDK_ROOT | |
| wget -q https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip -O /tmp/cmdline-tools.zip | |
| unzip -q /tmp/cmdline-tools.zip -d /tmp/cmdline-tools | |
| mkdir -p $ANDROID_SDK_ROOT/cmdline-tools/latest | |
| mv /tmp/cmdline-tools/cmdline-tools/* $ANDROID_SDK_ROOT/cmdline-tools/latest/ | |
| echo "ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT" >> $GITHUB_ENV | |
| echo "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin" >> $GITHUB_PATH | |
| echo "$ANDROID_SDK_ROOT/platform-tools" >> $GITHUB_PATH | |
| export PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$PATH" | |
| yes | sdkmanager --sdk_root=$ANDROID_SDK_ROOT --licenses || true | |
| sdkmanager --sdk_root=$ANDROID_SDK_ROOT "platform-tools" "platforms;android-29" "build-tools;29.0.3" | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: 'stable' | |
| - name: Cache pub and Gradle | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.pub-cache | |
| ~/.gradle/caches | |
| key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.yaml') }}-${{ hashFiles('**/gradle-wrapper.properties') }} | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Accept Android SDK licenses | |
| run: | | |
| yes | sdkmanager --licenses || true | |
| - name: Build Android AAB, fetch/install core, and package | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| flutter pub run tools/fetch_core_local.dart --repo sipeed/picoclaw --tag latest --out-dir app/bin --platform android --arch arm64 --build-mode release --install-to-build | |
| - name: Build Android APK (debug) and fetch/install core | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| flutter pub run tools/fetch_core_local.dart --repo sipeed/picoclaw --tag latest --out-dir app/bin --platform android --arch arm64 --build-mode debug --install-to-build | |
| - name: Prepare release metadata | |
| id: vars | |
| run: | | |
| now=$(date -u +%y%m%d) | |
| short=$(git rev-parse --short=6 $GITHUB_SHA) | |
| base_no_prefix="$now-$short" | |
| release_tag="picoclaw_fui-$base_no_prefix" | |
| echo "release_base=$base_no_prefix" >> $GITHUB_OUTPUT | |
| echo "RELEASE_BASE=$base_no_prefix" >> $GITHUB_ENV | |
| echo "RELEASE_TAG=$release_tag" >> $GITHUB_ENV | |
| - name: Collect and rename Android artifacts | |
| run: | | |
| set -e | |
| PKG_NAME=picoclaw_fui | |
| TAG=${RELEASE_BASE} | |
| AAB_NAME=${PKG_NAME}-${TAG}-android-arm_arm64.aab | |
| APK_NAME=${PKG_NAME}-${TAG}-android-universal.apk | |
| rm -f "$AAB_NAME" "$APK_NAME" || true | |
| if ls build/app/outputs/bundle/release/*.aab 1> /dev/null 2>&1; then | |
| cp build/app/outputs/bundle/release/*.aab "$AAB_NAME" | |
| else | |
| echo "AAB not found"; exit 1 | |
| fi | |
| if [ -f build/app/outputs/flutter-apk/app-debug.apk ]; then | |
| cp build/app/outputs/flutter-apk/app-debug.apk "$APK_NAME" | |
| else | |
| echo "Debug APK not found"; exit 1 | |
| fi | |
| # core binaries are installed into build outputs; avoid uploading app/bin | |
| - name: Upload AAB artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: picoclaw_fui-${{ env.RELEASE_BASE }}-android-arm_arm64.aab | |
| path: picoclaw_fui-${{ env.RELEASE_BASE }}-android-arm_arm64.aab | |
| - name: Upload APK artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: picoclaw_fui-${{ env.RELEASE_BASE }}-android-universal.apk | |
| path: picoclaw_fui-${{ env.RELEASE_BASE }}-android-universal.apk | |
| build-macos: | |
| runs-on: macos-latest | |
| needs: [] | |
| outputs: | |
| release_base: ${{ steps.vars.outputs.release_base }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: 'stable' | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Build macOS release (build + fetch/install core) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| flutter pub run tools/fetch_core_local.dart --repo sipeed/picoclaw --tag latest --out-dir app/bin --platform macos --arch arm64 --build-mode release --install-to-build | |
| - name: Prepare release metadata | |
| id: vars | |
| run: | | |
| now=$(date -u +%y%m%d) | |
| short=$(git rev-parse --short=6 $GITHUB_SHA) | |
| base_no_prefix="$now-$short" | |
| release_tag="picoclaw_fui-$base_no_prefix" | |
| echo "release_base=$base_no_prefix" >> $GITHUB_OUTPUT | |
| echo "RELEASE_BASE=$base_no_prefix" >> $GITHUB_ENV | |
| echo "RELEASE_TAG=$release_tag" >> $GITHUB_ENV | |
| - name: Package Release (dmg) | |
| run: | | |
| dest="picoclaw_fui-${RELEASE_BASE}-macos-arm64.dmg" | |
| rm -f "$dest" || true | |
| out_dir="build/macos/Build/Products/Release" | |
| if [ ! -d "$out_dir" ]; then | |
| echo "Release output not found"; exit 1 | |
| fi | |
| app_path=$(find "$out_dir" -maxdepth 1 -name "*.app" -print -quit) | |
| if [ -z "$app_path" ]; then | |
| echo "No .app found in $out_dir"; ls -la "$out_dir" || true; exit 1 | |
| fi | |
| stage_dir=$(mktemp -d) | |
| cp -R "$app_path" "$stage_dir/" | |
| hdiutil create -volname "PicoClawFUI" -srcfolder "$stage_dir" -ov -format UDZO "$dest" | |
| - name: Upload macOS DMG artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: picoclaw_fui-${{ env.RELEASE_BASE }}-macos-arm64.dmg | |
| path: picoclaw_fui-${{ env.RELEASE_BASE }}-macos-arm64.dmg | |
| build-windows: | |
| runs-on: windows-latest | |
| needs: [] | |
| outputs: | |
| release_base: ${{ steps.vars.outputs.release_base }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: 'stable' | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Locate MSBuild and add to PATH | |
| shell: powershell | |
| run: | | |
| Write-Output "Locating MSBuild with vswhere and adding to PATH" | |
| $vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe' | |
| if (-not (Test-Path $vswhere)) { | |
| Write-Error "vswhere not found at $vswhere" | |
| exit 1 | |
| } | |
| $inst = & $vswhere -latest -requires Microsoft.Component.MSBuild -products * -property installationPath | |
| if (-not $inst) { | |
| Write-Error "Visual Studio with MSBuild not found" | |
| exit 1 | |
| } | |
| $msbuildDir = Join-Path $inst 'MSBuild\Current\Bin' | |
| Write-Output "Found MSBuild dir: $msbuildDir" | |
| Add-Content -Path $env:GITHUB_PATH -Value $msbuildDir | |
| - name: Verify VS toolchain | |
| shell: powershell | |
| run: | | |
| Write-Output "--- Verify MSVC / MSBuild / NuGet ---" | |
| msbuild -version | |
| if (Get-Command cl.exe -ErrorAction SilentlyContinue) { cl.exe /? } else { Write-Output 'cl.exe not found' } | |
| if (-not (Get-Command nuget -ErrorAction SilentlyContinue)) { choco install nuget.commandline -y } | |
| nuget help | |
| - name: Build Windows release (build + fetch/install core) | |
| shell: powershell | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| flutter pub run tools/fetch_core_local.dart --repo sipeed/picoclaw --tag latest --out-dir app/bin --platform windows --arch x86_64 --build-mode release --install-to-build | |
| - name: Prepare release metadata | |
| id: vars | |
| shell: powershell | |
| run: | | |
| $date = Get-Date -Format 'yyMMdd' | |
| $short = git rev-parse --short=6 $env:GITHUB_SHA | |
| $base_no_prefix = "$date-$short" | |
| $release_tag = "picoclaw_fui-$base_no_prefix" | |
| Add-Content -Path $env:GITHUB_OUTPUT -Value "release_base=$base_no_prefix" | |
| Add-Content -Path $env:GITHUB_ENV -Value "RELEASE_BASE=$base_no_prefix" | |
| Add-Content -Path $env:GITHUB_ENV -Value "RELEASE_TAG=$release_tag" | |
| - name: Zip Release | |
| shell: powershell | |
| run: | | |
| $dest = "picoclaw_fui-${env:RELEASE_BASE}-windows-x64.zip" | |
| Compress-Archive -Path 'build\\windows\\x64\\runner\\Release\\*' -DestinationPath $dest -Force | |
| # core binaries are installed into build outputs; avoid uploading app/bin | |
| - name: Upload Windows ZIP artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: picoclaw_fui-${{ env.RELEASE_BASE }}-windows-x64.zip | |
| path: picoclaw_fui-${{ env.RELEASE_BASE }}-windows-x64.zip | |
| build-linux: | |
| runs-on: ubuntu-22.04 | |
| outputs: | |
| release_base: ${{ steps.vars.outputs.release_base }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: 'stable' | |
| - name: Install Linux build dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends \ | |
| clang cmake ninja-build pkg-config pkgconf build-essential \ | |
| libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev \ | |
| lld binutils libstdc++-12-dev libglu1-mesa | |
| - name: Cache pub | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.pub-cache | |
| key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.yaml') }} | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Fetch core and build Linux release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| flutter pub run tools/fetch_core_local.dart --repo sipeed/picoclaw --tag latest --out-dir app/bin --platform linux --arch x64 --build-mode release --install-to-build || true | |
| flutter build linux --release | |
| - name: Prepare release metadata | |
| id: vars | |
| run: | | |
| now=$(date -u +%y%m%d) | |
| short=$(git rev-parse --short=6 $GITHUB_SHA) | |
| base_no_prefix="$now-$short" | |
| release_tag="picoclaw_fui-$base_no_prefix" | |
| echo "release_base=$base_no_prefix" >> $GITHUB_OUTPUT | |
| echo "RELEASE_BASE=$base_no_prefix" >> $GITHUB_ENV | |
| echo "RELEASE_TAG=$release_tag" >> $GITHUB_ENV | |
| - name: Package Linux as .deb | |
| run: | | |
| set -e | |
| PKG_NAME=picoclaw_fui | |
| TAG=${RELEASE_BASE} | |
| DEST=${PKG_NAME}-${TAG}-linux-x64.deb | |
| PKGROOT=$PWD/pkg_root | |
| rm -rf "$PKGROOT" "$DEST" | |
| BUNDLE_DIR=build/linux/x64/release/bundle | |
| if [ ! -d "$BUNDLE_DIR" ]; then echo "Bundle not found: $BUNDLE_DIR"; ls -la build/linux || true; exit 1; fi | |
| mkdir -p "$PKGROOT/opt/${PKG_NAME}/${TAG}" | |
| cp -r "$BUNDLE_DIR"/* "$PKGROOT/opt/${PKG_NAME}/${TAG}/" | |
| mkdir -p "$PKGROOT/usr/bin" | |
| printf '%s\n' \ | |
| '#!/bin/sh' \ | |
| 'set -e' \ | |
| 'BASE=/opt/picoclaw_fui' \ | |
| 'if [ -d "$BASE" ]; then' \ | |
| ' DIRNAME=$(ls -1 "$BASE" 2>/dev/null | sort -V | tail -n1)' \ | |
| ' if [ -n "$DIRNAME" ] && [ -d "$BASE/$DIRNAME" ]; then' \ | |
| ' DIR="$BASE/$DIRNAME"' \ | |
| ' else' \ | |
| ' DIR="$BASE"' \ | |
| ' fi' \ | |
| 'else' \ | |
| ' DIR="$BASE"' \ | |
| 'fi' \ | |
| 'EXEC=$(find "$DIR" -maxdepth 1 -type f -executable -print -quit)' \ | |
| 'if [ -z "$EXEC" ]; then' \ | |
| ' echo "Executable not found in $DIR" >&2' \ | |
| ' exit 1' \ | |
| 'fi' \ | |
| 'exec "$EXEC" "$@"' > "$PKGROOT/usr/bin/${PKG_NAME}" | |
| chmod 0755 "$PKGROOT/usr/bin/${PKG_NAME}" | |
| mkdir -p "$PKGROOT/DEBIAN" | |
| # Install icon and desktop entry | |
| mkdir -p "$PKGROOT/usr/share/icons/hicolor/128x128/apps" | |
| mkdir -p "$PKGROOT/usr/share/applications" | |
| if [ -f assets/app_icon.png ]; then | |
| cp assets/app_icon.png "$PKGROOT/usr/share/icons/hicolor/128x128/apps/picoclaw_fui.png" | |
| fi | |
| printf '%s\n' \ | |
| "[Desktop Entry]" \ | |
| "Name=PicoClaw FUI" \ | |
| "Exec=/usr/bin/picoclaw_fui %U" \ | |
| "Icon=picoclaw_fui" \ | |
| "Type=Application" \ | |
| "Categories=Utility;" \ | |
| "Terminal=false" > "$PKGROOT/usr/share/applications/picoclaw_fui.desktop" | |
| printf '%s\n' \ | |
| "Package: picoclaw-fui" \ | |
| "Version: ${TAG}" \ | |
| "Section: utils" \ | |
| "Priority: optional" \ | |
| "Architecture: amd64" \ | |
| "Maintainer: GitHub Actions <actions@github.com>" \ | |
| "Description: PicoClaw FUI" > "$PKGROOT/DEBIAN/control" | |
| # Update icon cache if available (ignore errors) | |
| if command -v gtk-update-icon-cache >/dev/null 2>&1; then | |
| gtk-update-icon-cache -f "$PKGROOT/usr/share/icons/hicolor" || true | |
| fi | |
| dpkg-deb --build "$PKGROOT" "$DEST" | |
| - name: Upload Linux .deb artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: picoclaw_fui-${{ env.RELEASE_BASE }}-linux-x64.deb | |
| path: picoclaw_fui-${{ env.RELEASE_BASE }}-linux-x64.deb | |
| publish: | |
| needs: [build-android, build-windows, build-macos, build-linux] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: downloaded_artifacts | |
| - name: List downloaded files | |
| run: ls -la downloaded_artifacts || true | |
| - name: Move downloaded artifacts to workspace root | |
| run: | | |
| shopt -s globstar || true | |
| find downloaded_artifacts -type f -exec mv -t . {} + || true | |
| - name: Set release vars from build outputs | |
| run: echo "RELEASE_BASE=${{ needs.build-android.outputs.release_base }}" >> $GITHUB_ENV | |
| - name: Publish Release and upload artifacts | |
| uses: ncipollo/release-action@v1 | |
| with: | |
| tag: picoclaw_fui-${{ env.RELEASE_BASE }} | |
| name: picoclaw_fui-${{ env.RELEASE_BASE }} | |
| allowUpdates: true | |
| artifacts: | | |
| picoclaw_fui-${{ env.RELEASE_BASE }}-android-arm_arm64.aab | |
| picoclaw_fui-${{ env.RELEASE_BASE }}-android-universal.apk | |
| picoclaw_fui-${{ env.RELEASE_BASE }}-windows-x64.zip | |
| picoclaw_fui-${{ env.RELEASE_BASE }}-macos-arm64.dmg | |
| picoclaw_fui-${{ env.RELEASE_BASE }}-linux-x64.deb | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |