Build fix/video/version/0.12.0 - 1 #162
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: Build AppFlowy Linux | |
| run-name: Build ${{ github.event.inputs.branch }}/${{ github.event.inputs.build_name }} - ${{ github.event.inputs.internal_build }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| repo: | |
| description: "Repo" | |
| required: true | |
| default: "AppFlowy-IO/AppFlowy-Premium" | |
| branch: | |
| description: "Branch" | |
| required: true | |
| default: "main" | |
| build_name: | |
| description: "Build Version (it should match the version in pubspec.yaml)" | |
| required: true | |
| default: "0.12.0" | |
| internal_build: | |
| type: choice | |
| description: "Internal Build Type (1 for internal, 0 for external)" | |
| required: true | |
| default: "1" | |
| options: | |
| - "0" | |
| - "1" | |
| workflow_call: | |
| inputs: | |
| repo: | |
| description: "Repo" | |
| required: true | |
| type: string | |
| branch: | |
| description: "Branch" | |
| required: true | |
| type: string | |
| build_name: | |
| description: "Build Version" | |
| required: true | |
| type: string | |
| internal_build: | |
| description: "Internal Build Type" | |
| required: true | |
| type: string | |
| upload_url: | |
| description: "Upload URL for release assets" | |
| required: false | |
| type: string | |
| env: | |
| FLUTTER_VERSION: "3.41.9" | |
| RUST_TOOLCHAIN: "1.92.0" | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| os: [ubuntu-22.04] | |
| include: | |
| - os: ubuntu-22.04 | |
| target: x86_64-unknown-linux-gnu | |
| runs-on: ${{ matrix.os }} | |
| env: | |
| LINUX_APP_RELEASE_PATH: frontend/appflowy_flutter/product/${{ inputs.build_name }}/linux/Release | |
| LINUX_ZIP_NAME: AppFlowy-${{ inputs.build_name }}-linux.tar.gz | |
| LINUX_PACKAGE_DEB_NAME: AppFlowy-${{ inputs.build_name }}-linux-x86_64.deb | |
| LINUX_PACKAGE_RPM_NAME: AppFlowy-${{ inputs.build_name }}-linux-x86_64.rpm | |
| LINUX_PACKAGE_TMP_RPM_NAME: AppFlowy-${{ inputs.build_name }}-2.x86_64.rpm | |
| LINUX_PACKAGE_APPIMAGE_NAME: AppFlowy-${{ inputs.build_name }}-linux-x86_64.AppImage | |
| steps: | |
| # the following step is required to avoid running out of space | |
| - name: Maximize build space | |
| run: | | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /opt/ghc | |
| sudo rm -rf "/usr/local/share/boost" | |
| sudo rm -rf "$AGENT_TOOLSDIRECTORY" | |
| - name: Checkout source code | |
| uses: actions/checkout@v2 | |
| with: | |
| repository: ${{ inputs.repo }} | |
| ref: ${{ inputs.branch }} | |
| token: ${{ secrets.PRIVATE_REPO_TOKEN }} | |
| - name: Install Rust toolchain | |
| id: rust_toolchain | |
| uses: actions-rs/toolchain@v1 | |
| with: | |
| toolchain: ${{ env.RUST_TOOLCHAIN }} | |
| target: ${{ matrix.target }} | |
| override: true | |
| profile: minimal | |
| - name: Install flutter | |
| id: flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: "stable" | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| prefix-key: ${{ matrix.os }} | |
| workspaces: | | |
| frontend/rust-lib | |
| - uses: davidB/rust-cargo-make@v1 | |
| with: | |
| version: "0.37.18" | |
| - name: Install prerequisites | |
| working-directory: frontend | |
| run: | | |
| sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub | |
| sudo apt-get update | |
| sudo apt-get install -y --fix-broken | |
| sudo apt-get install -y build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev libcurl4-openssl-dev libepoxy-dev | |
| sudo apt-get install keybinder-3.0 libnotify-dev libwayland-cursor0 libwayland-client0 libwayland-egl1 unzip | |
| sudo apt-get -y install alien | |
| sudo apt install libmpv-dev mpv | |
| sudo apt install libasound2-dev | |
| # Install GStreamer for audioplayers_linux | |
| # Install libunwind-dev first to resolve dependency issues | |
| sudo apt-get -y install libunwind-dev | |
| sudo apt-get -y install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev | |
| # Install FUSE for AppImage support | |
| sudo apt-get install -y fuse libfuse2 | |
| # dpkg-shlibdeps (dpkg-dev) computes the .deb runtime dependencies; | |
| # the rest are tools appimage-builder shells out to while assembling | |
| # the AppImage. | |
| sudo apt-get install -y dpkg-dev patchelf desktop-file-utils libgtk-3-bin squashfs-tools zsync gnupg fakeroot strace | |
| source $HOME/.cargo/env | |
| cargo install duckscript_cli --force --locked | |
| rustup target add ${{ matrix.target }} | |
| shell: bash | |
| - name: Generate env file | |
| working-directory: frontend/appflowy_flutter | |
| run: | | |
| echo "INTERNAL_BUILD=${{ github.env.inputs.internal_build }}" >> .env | |
| shell: bash | |
| - name: Configure Git credentials for Cargo | |
| run: | | |
| git config --global credential.helper store | |
| echo "https://${{ secrets.ADMIN_GITHUB_TOKEN }}:x-oauth-basic@github.com" > ~/.git-credentials | |
| - name: Build AppFlowy | |
| working-directory: frontend | |
| run: | | |
| flutter config --enable-linux-desktop | |
| cd appflowy_flutter | |
| flutter pub get | |
| dart run pdfrx:remove_wasm_modules | |
| trap 'cd "$GITHUB_WORKSPACE/frontend/appflowy_flutter" && dart run pdfrx:remove_wasm_modules --revert' EXIT | |
| cd .. | |
| dart ./scripts/flutter_release_build/build_flowy.dart run . ${{ inputs.build_name }} | |
| - name: Archive Asset | |
| working-directory: ${{ env.LINUX_APP_RELEASE_PATH }} | |
| run: tar -czf ${{ env.LINUX_ZIP_NAME }} * | |
| - name: Bundle libmpv into AppFlowy bundle | |
| run: | | |
| set -euo pipefail | |
| BUNDLE="appflowy_flutter/product/${{ inputs.build_name }}/linux/Release" | |
| mkdir -p "$BUNDLE/libmpv" | |
| # Download libmpv1 from Ubuntu jammy (22.04) for maximum compatibility | |
| # This ensures the .so file is bundled and doesn't rely on system packages | |
| wget -q -O /tmp/libmpv1.deb \ | |
| http://archive.ubuntu.com/ubuntu/pool/universe/m/mpv/libmpv1_0.34.1-1ubuntu3_amd64.deb | |
| dpkg-deb -x /tmp/libmpv1.deb /tmp/libmpv-extracted | |
| cp -r /tmp/libmpv-extracted/usr/lib/x86_64-linux-gnu/* "$BUNDLE/lib/" | |
| # Also copy to libmpv subfolder for backup | |
| cp /tmp/libmpv-extracted/usr/lib/x86_64-linux-gnu/libmpv.so.1* "$BUNDLE/libmpv/" 2>/dev/null || true | |
| echo "✅ libmpv bundled into $BUNDLE/lib/" | |
| - name: Compute .deb runtime dependencies | |
| working-directory: frontend | |
| run: | | |
| set -euo pipefail | |
| BUNDLE="appflowy_flutter/product/${{ inputs.build_name }}/linux/Release/AppFlowy" | |
| CONTROL="scripts/linux_distribution/deb/DEBIAN/control" | |
| if [ ! -x "$BUNDLE/AppFlowy" ]; then | |
| echo "::error::AppFlowy binary not found at $BUNDLE/AppFlowy" | |
| exit 1 | |
| fi | |
| ABS_BUNDLE="$(pwd)/$BUNDLE" | |
| # dpkg-shlibdeps maps every system shared library NEEDED by the | |
| # executable and the bundled Flutter plugins (incl. media_kit -> | |
| # libmpv.so.1) to its providing apt package. It expects a throwaway | |
| # debian/ tree; --ignore-missing-info skips Flutter's own bundled | |
| # .so files, which are not provided by any apt package. | |
| WORK="$(mktemp -d)" | |
| mkdir -p "$WORK/debian" | |
| printf 'Source: appflowy\nMaintainer: AppFlowy\n\nPackage: appflowy\nArchitecture: amd64\nDescription: AppFlowy\n' > "$WORK/debian/control" | |
| COMPUTED="" | |
| if ( cd "$WORK" && dpkg-shlibdeps -O --ignore-missing-info \ | |
| "$ABS_BUNDLE/AppFlowy" "$ABS_BUNDLE"/lib/*.so ) > "$WORK/out" 2> "$WORK/err"; then | |
| COMPUTED="$(sed -n 's/^shlibs:Depends=//p' "$WORK/out")" | |
| fi | |
| echo "---- dpkg-shlibdeps diagnostics ----" | |
| cat "$WORK/err" || true | |
| echo "computed Depends: ${COMPUTED:-<none>}" | |
| # Curated fallback covering the critical runtime libraries, used only | |
| # if shlibdeps fails outright. libmpv is NO LONGER listed here because | |
| # we now bundle it inside the .deb - no external dependency needed. | |
| ESSENTIAL="libgtk-3-0, libkeybinder-3.0-0, libnotify4, libgstreamer1.0-0, libgstreamer-plugins-base1.0-0, libasound2" | |
| if [ -n "$COMPUTED" ]; then | |
| DEPS="$COMPUTED" | |
| else | |
| echo "::warning::dpkg-shlibdeps produced no output; using curated dependency list" | |
| DEPS="$ESSENTIAL" | |
| fi | |
| # Remove any libmpv reference from computed deps since we bundle it | |
| DEPS="$(echo "$DEPS" | sed 's/libmpv1,//g' | sed 's/,libmpv1//g' | sed 's/libmpv2,//g' | sed 's/,libmpv2//g')" | |
| python3 - "$CONTROL" "$DEPS" <<'PY' | |
| import re, sys | |
| path, deps = sys.argv[1], sys.argv[2] | |
| text = open(path).read() | |
| text = re.sub(r'(?m)^Depends:.*$', 'Depends: ' + deps, text, count=1) | |
| open(path, 'w').write(text) | |
| print("patched control ->", "Depends: " + deps) | |
| PY | |
| - name: Build Linux package (.deb) | |
| working-directory: frontend | |
| run: | | |
| sh scripts/linux_distribution/deb/build_deb.sh appflowy_flutter/product/${{ inputs.build_name }}/linux/Release ${{ inputs.build_name }} ${{ env.LINUX_PACKAGE_DEB_NAME }} | |
| - name: Build Linux package (.rpm) | |
| working-directory: ${{ env.LINUX_APP_RELEASE_PATH }} | |
| run: | | |
| sudo alien -r ${{ env.LINUX_PACKAGE_DEB_NAME }} | |
| cp -r ${{ env.LINUX_PACKAGE_TMP_RPM_NAME }} ${{ env.LINUX_PACKAGE_RPM_NAME }} | |
| - name: Build Linux package (.AppImage) | |
| working-directory: frontend | |
| continue-on-error: true | |
| run: | | |
| set -euo pipefail | |
| echo "📦 Building AppImage with appimage-builder (auto-bundles libmpv & its deps)..." | |
| # Enable FUSE user space file systems | |
| echo 'user_allow_other' | sudo tee -a /etc/fuse.conf | |
| # Download and bundle libmpv from Ubuntu jammy BEFORE appimage-builder runs. | |
| # media_kit loads libmpv.so.1 at runtime via dlopen, which appimage-builder's | |
| # ELF scanner may miss. We pre-bundle it to guarantee it's in the AppImage. | |
| LIBMPV_DEB="/tmp/libmpv1.AppImage.bundle.deb" | |
| mkdir -p /tmp/libmpv-AppImage | |
| wget -q -O "$LIBMPV_DEB" \ | |
| http://archive.ubuntu.com/ubuntu/pool/universe/m/mpv/libmpv1_0.34.1-1ubuntu3_amd64.deb | |
| dpkg-deb -x "$LIBMPV_DEB" /tmp/libmpv-AppImage/extracted | |
| # Generate the appimage-builder recipe. appimage-builder scans every | |
| # ELF in the bundle, resolves each NEEDED library (incl. the media_kit | |
| # plugin's libmpv.so.1 and its ffmpeg/libass/... tree) to an apt | |
| # package, bundles them, and generates a runtime that wires up the | |
| # library path. This is the approach the public AppFlowy repo uses. | |
| # libmpv is also listed explicitly so the result is correct even if | |
| # auto-detection is skipped. ${{ inputs.build_name }} is the version. | |
| cat > AppImageBuilder.yml <<'YML' | |
| version: 1 | |
| script: | |
| - rm -rf AppDir || true | |
| - cp -r appflowy_flutter/build/linux/x64/release/bundle AppDir | |
| - mkdir -p AppDir/usr/share/icons/hicolor/scalable/apps | |
| - cp scripts/linux_distribution/packaging/appflowy.svg AppDir/usr/share/icons/hicolor/scalable/apps/ | |
| - mkdir -p AppDir/usr/lib/x86_64-linux-gnu | |
| - cp -r /tmp/libmpv-AppImage/extracted/usr/lib/x86_64-linux-gnu/* AppDir/usr/lib/x86_64-linux-gnu/ | |
| AppDir: | |
| path: ./AppDir | |
| app_info: | |
| id: io.appflowy.AppFlowy | |
| name: AppFlowy | |
| icon: appflowy.svg | |
| version: "APPFLOWY_VERSION" | |
| exec: AppFlowy | |
| exec_args: $@ | |
| apt: | |
| arch: | |
| - amd64 | |
| allow_unauthenticated: true | |
| sources: | |
| - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy main restricted universe multiverse | |
| - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted universe multiverse | |
| - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted universe multiverse | |
| include: | |
| - libc6:amd64 | |
| - libnotify4:amd64 | |
| - libkeybinder-3.0-0:amd64 | |
| - libwayland-cursor0:amd64 | |
| - libwayland-client0:amd64 | |
| - libwayland-egl1:amd64 | |
| - libmpv1:amd64 | |
| files: | |
| include: [] | |
| exclude: | |
| - usr/share/man | |
| - usr/share/doc/*/README.* | |
| - usr/share/doc/*/changelog.* | |
| - usr/share/doc/*/NEWS.* | |
| - usr/share/doc/*/TODO.* | |
| AppImage: | |
| arch: x86_64 | |
| YML | |
| sed -i "s/APPFLOWY_VERSION/${{ inputs.build_name }}/" AppImageBuilder.yml | |
| # Download appimage-builder (same version proven in the public AppFlowy repo). | |
| APPIMAGE_BUILDER="./appimage-builder-x86_64.AppImage" | |
| if [ ! -x "$APPIMAGE_BUILDER" ]; then | |
| wget -q -O "$APPIMAGE_BUILDER" \ | |
| https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage | |
| chmod +x "$APPIMAGE_BUILDER" | |
| fi | |
| # APPIMAGE_EXTRACT_AND_RUN lets the builder (itself an AppImage) run | |
| # where FUSE is unavailable (CI runners). | |
| if APPIMAGE_EXTRACT_AND_RUN=1 "$APPIMAGE_BUILDER" --recipe AppImageBuilder.yml --skip-tests; then | |
| # appimage-builder emits AppFlowy-<version>-x86_64.AppImage in CWD | |
| # (frontend), which is exactly where the upload step looks. | |
| ls -la AppFlowy-*-x86_64.AppImage | |
| else | |
| echo "⚠️ AppImage build failed, but continuing..." | |
| # Create a dummy AppImage file to prevent upload failures | |
| touch "${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_PACKAGE_APPIMAGE_NAME }}" | |
| touch "AppFlowy-${{ inputs.build_name }}-x86_64.AppImage" | |
| fi | |
| - name: Upload ZIP | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ env.LINUX_ZIP_NAME }} | |
| path: ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_ZIP_NAME }} | |
| - name: Upload ZIP to Release | |
| if: inputs.upload_url != '' | |
| run: | | |
| filename="${{ env.LINUX_ZIP_NAME }}" | |
| filepath="${{ env.LINUX_APP_RELEASE_PATH }}/$filename" | |
| # URL encode the filename | |
| encoded_filename=$(echo -n "$filename" | jq -sRr @uri) | |
| # Remove the {?name,label} template from upload URL if present | |
| upload_url=$(echo "${{ inputs.upload_url }}" | sed 's/{[^}]*}//g') | |
| echo "Uploading $filename to release..." | |
| curl -L \ | |
| -X POST \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "Content-Type: application/octet-stream" \ | |
| --data-binary @"$filepath" \ | |
| "${upload_url}?name=${encoded_filename}" \ | |
| --fail-with-body | |
| - name: Upload Linux package | |
| working-directory: frontend | |
| run: | | |
| ls -a | |
| - name: Upload AppImage | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ env.LINUX_PACKAGE_APPIMAGE_NAME}} | |
| path: frontend/AppFlowy-${{ inputs.build_name }}-x86_64.AppImage | |
| - name: Upload AppImage to Release | |
| continue-on-error: true | |
| if: inputs.upload_url != '' | |
| run: | | |
| filename="${{ env.LINUX_PACKAGE_APPIMAGE_NAME }}" | |
| filepath="frontend/AppFlowy-${{ inputs.build_name }}-x86_64.AppImage" | |
| # URL encode the filename | |
| encoded_filename=$(echo -n "$filename" | jq -sRr @uri) | |
| # Remove the {?name,label} template from upload URL if present | |
| upload_url=$(echo "${{ inputs.upload_url }}" | sed 's/{[^}]*}//g') | |
| echo "Uploading $filename to release..." | |
| curl -L \ | |
| -X POST \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "Content-Type: application/octet-stream" \ | |
| --data-binary @"$filepath" \ | |
| "${upload_url}?name=${encoded_filename}" \ | |
| --fail-with-body | |
| - name: Upload RPM | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ env.LINUX_PACKAGE_RPM_NAME }} | |
| path: ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_PACKAGE_RPM_NAME }} | |
| - name: Upload RPM to Release | |
| if: inputs.upload_url != '' | |
| run: | | |
| filename="${{ env.LINUX_PACKAGE_RPM_NAME }}" | |
| filepath="${{ env.LINUX_APP_RELEASE_PATH }}/$filename" | |
| # URL encode the filename | |
| encoded_filename=$(echo -n "$filename" | jq -sRr @uri) | |
| # Remove the {?name,label} template from upload URL if present | |
| upload_url=$(echo "${{ inputs.upload_url }}" | sed 's/{[^}]*}//g') | |
| echo "Uploading $filename to release..." | |
| curl -L \ | |
| -X POST \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "Content-Type: application/octet-stream" \ | |
| --data-binary @"$filepath" \ | |
| "${upload_url}?name=${encoded_filename}" \ | |
| --fail-with-body | |
| - name: Upload DEB | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ env.LINUX_PACKAGE_DEB_NAME }} | |
| path: ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_PACKAGE_DEB_NAME }} | |
| - name: Upload DEB to Release | |
| if: inputs.upload_url != '' | |
| run: | | |
| filename="${{ env.LINUX_PACKAGE_DEB_NAME }}" | |
| filepath="${{ env.LINUX_APP_RELEASE_PATH }}/$filename" | |
| # URL encode the filename | |
| encoded_filename=$(echo -n "$filename" | jq -sRr @uri) | |
| # Remove the {?name,label} template from upload URL if present | |
| upload_url=$(echo "${{ inputs.upload_url }}" | sed 's/{[^}]*}//g') | |
| echo "Uploading $filename to release..." | |
| curl -L \ | |
| -X POST \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "Content-Type: application/octet-stream" \ | |
| --data-binary @"$filepath" \ | |
| "${upload_url}?name=${encoded_filename}" \ | |
| --fail-with-body |