mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-11-05 06:17:34 +00:00
The prompt runs the whole plan with the toolbar at the bottom and, at the top, only the checks the layouts render differently.
468 lines
17 KiB
YAML
468 lines
17 KiB
YAML
name: desktop-linux
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- f/ci-desktop
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
actions: read
|
|
|
|
concurrency:
|
|
group: desktop-linux-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
GHC_VER: 9.6.3
|
|
CABAL_VER: 3.10.2.0
|
|
JAVA_VER: 17
|
|
CORE_PKG: desktop-core-linux-x86_64.tar.gz
|
|
BACKEND_PKG: desktop-linux-backend.tar.gz
|
|
|
|
jobs:
|
|
plan:
|
|
name: find earlier builds
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 10
|
|
outputs:
|
|
backend: ${{ steps.names.outputs.backend }}
|
|
backend-run: ${{ steps.backend.outputs.run-id }}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
|
|
# artifacts are named after the sources they are built from, so a run uses one that an earlier run uploaded
|
|
- name: Artifact names
|
|
id: names
|
|
run: echo "backend=desktop-linux-backend-${{ hashFiles('src/**', 'apps/simplex-chat/**', 'apps/simplex-directory-service/Main.hs', 'apps/simplex-directory-service/src/**', 'cabal.project', 'simplex-chat.cabal', 'scripts/ci/desktop-linux/build-backend.sh') }}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Find backend
|
|
id: backend
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: scripts/ci/desktop-linux/earlier-run.sh "${{ steps.names.outputs.backend }}"
|
|
|
|
backend:
|
|
name: test backend for the app
|
|
needs: plan
|
|
if: needs.plan.outputs.backend-run == ''
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 150
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
|
|
- name: Show runner
|
|
run: |
|
|
lsb_release -ds
|
|
nproc
|
|
free -h
|
|
df -h /
|
|
|
|
- name: Setup Haskell
|
|
id: haskell
|
|
uses: simplex-chat/setup-haskell-action@v2
|
|
with:
|
|
ghc-version: ${{ env.GHC_VER }}
|
|
cabal-version: ${{ env.CABAL_VER }}
|
|
|
|
# before the first backend store exists, the core library's has most of the same Hackage dependencies
|
|
- name: Restore cabal store
|
|
id: cabal-cache
|
|
uses: actions/cache/restore@v5
|
|
with:
|
|
path: |
|
|
${{ steps.haskell.outputs.cabal-store }}
|
|
dist-newstyle
|
|
key: desktop-linux-backend-store-ghc${{ env.GHC_VER }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }}-${{ github.run_id }}
|
|
restore-keys: |
|
|
desktop-linux-backend-store-ghc${{ env.GHC_VER }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }}-
|
|
desktop-linux-backend-store-ghc${{ env.GHC_VER }}-
|
|
desktop-linux-core-store-ghc${{ env.GHC_VER }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }}-
|
|
|
|
- name: Install libraries
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y libffi-dev libgmp-dev libnuma-dev libssl-dev zlib1g-dev
|
|
|
|
- name: Build backend
|
|
run: scripts/ci/desktop-linux/build-backend.sh ~/backend/${{ env.BACKEND_PKG }}
|
|
|
|
- name: Save cabal store
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/cache/save@v5
|
|
with:
|
|
path: |
|
|
${{ steps.haskell.outputs.cabal-store }}
|
|
dist-newstyle
|
|
key: ${{ steps.cabal-cache.outputs.cache-primary-key }}
|
|
|
|
- name: Upload backend
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: ${{ needs.plan.outputs.backend }}
|
|
path: ~/backend/${{ env.BACKEND_PKG }}
|
|
compression-level: 0
|
|
retention-days: 30
|
|
if-no-files-found: error
|
|
|
|
core:
|
|
name: core library for Linux
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 150
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
|
|
- name: Show runner
|
|
run: |
|
|
lsb_release -ds
|
|
nproc
|
|
free -h
|
|
df -h /
|
|
|
|
- name: Restore core library
|
|
id: core-cache
|
|
uses: actions/cache/restore@v5
|
|
with:
|
|
path: ~/core/${{ env.CORE_PKG }}
|
|
key: desktop-linux-core-${{ hashFiles('src/**', 'cabal.project', 'simplex-chat.cabal', 'PRIVACY.md', 'scripts/desktop/build-lib-linux.sh', 'scripts/ci/desktop-linux/build-core.sh') }}
|
|
|
|
- name: Setup Haskell
|
|
id: haskell
|
|
if: steps.core-cache.outputs.cache-hit != 'true'
|
|
uses: simplex-chat/setup-haskell-action@v2
|
|
with:
|
|
ghc-version: ${{ env.GHC_VER }}
|
|
cabal-version: ${{ env.CABAL_VER }}
|
|
|
|
- name: Restore cabal store
|
|
id: cabal-cache
|
|
if: steps.core-cache.outputs.cache-hit != 'true'
|
|
uses: actions/cache/restore@v5
|
|
with:
|
|
path: |
|
|
${{ steps.haskell.outputs.cabal-store }}
|
|
dist-newstyle
|
|
key: desktop-linux-core-store-ghc${{ env.GHC_VER }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }}-${{ github.run_id }}
|
|
restore-keys: |
|
|
desktop-linux-core-store-ghc${{ env.GHC_VER }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }}-
|
|
desktop-linux-core-store-ghc${{ env.GHC_VER }}-
|
|
|
|
- name: Install libraries
|
|
if: steps.core-cache.outputs.cache-hit != 'true'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y libffi-dev libgmp-dev libnuma-dev libssl-dev zlib1g-dev patchelf
|
|
|
|
- name: Build core library
|
|
if: steps.core-cache.outputs.cache-hit != 'true'
|
|
run: scripts/ci/desktop-linux/build-core.sh ~/core/${{ env.CORE_PKG }}
|
|
|
|
- name: Save cabal store
|
|
if: ${{ !cancelled() && steps.core-cache.outputs.cache-hit != 'true' }}
|
|
uses: actions/cache/save@v5
|
|
with:
|
|
path: |
|
|
${{ steps.haskell.outputs.cabal-store }}
|
|
dist-newstyle
|
|
key: ${{ steps.cabal-cache.outputs.cache-primary-key }}
|
|
|
|
- name: Save core library
|
|
if: steps.core-cache.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v5
|
|
with:
|
|
path: ~/core/${{ env.CORE_PKG }}
|
|
key: ${{ steps.core-cache.outputs.cache-primary-key }}
|
|
|
|
- name: Upload core library
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: desktop-core-linux-x86_64
|
|
path: ~/core/${{ env.CORE_PKG }}
|
|
compression-level: 0
|
|
retention-days: 3
|
|
if-no-files-found: error
|
|
|
|
app:
|
|
name: desktop app under Xvfb
|
|
needs: [plan, core, backend]
|
|
# backend is skipped when an earlier run built it
|
|
if: ${{ !cancelled() && !failure() }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 60
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Show runner
|
|
run: |
|
|
lsb_release -ds
|
|
nproc
|
|
free -h
|
|
df -h /
|
|
echo "ANDROID_HOME=$ANDROID_HOME"
|
|
ls "$ANDROID_HOME/platforms" "$ANDROID_HOME/build-tools" || true
|
|
|
|
- name: Install tools
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y xvfb xdotool openbox imagemagick tesseract-ocr sqlite3 fonts-dejavu-core
|
|
dpkg-query -W xvfb xdotool openbox imagemagick tesseract-ocr sqlite3 fonts-dejavu-core
|
|
|
|
- name: Download core library
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: desktop-core-linux-x86_64
|
|
path: ~/core
|
|
|
|
- name: Install core library
|
|
id: core
|
|
run: scripts/ci/desktop-linux/install-core.sh ~/core/${{ env.CORE_PKG }}
|
|
|
|
- name: Download backend
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: ${{ needs.plan.outputs.backend }}
|
|
path: ~/backend
|
|
run-id: ${{ needs.plan.outputs.backend-run || github.run_id }}
|
|
github-token: ${{ github.token }}
|
|
|
|
- name: Start test backend
|
|
timeout-minutes: 30
|
|
run: scripts/ci/desktop-linux/backend.sh start ~/backend/${{ env.BACKEND_PKG }} "$RUNNER_TEMP/backend"
|
|
|
|
- name: Point the app at the test directory
|
|
id: link
|
|
run: |
|
|
link=$(cat "$RUNNER_TEMP/backend/directory-link")
|
|
file=apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/DirectorySearch.kt
|
|
sed -i "s|^const val DIRECTORY_SERVICE_LINK = \".*\"$|const val DIRECTORY_SERVICE_LINK = \"$link\"|" "$file"
|
|
grep -F "const val DIRECTORY_SERVICE_LINK = \"$link\"" "$file"
|
|
|
|
# the app and its tests are still built when the backend fails
|
|
- name: Setup Java
|
|
if: ${{ !cancelled() && steps.core.outcome == 'success' }}
|
|
uses: actions/setup-java@v5
|
|
with:
|
|
distribution: corretto
|
|
java-version: ${{ env.JAVA_VER }}
|
|
cache: gradle
|
|
|
|
- name: Build app
|
|
id: build
|
|
if: ${{ !cancelled() && steps.core.outcome == 'success' }}
|
|
working-directory: apps/multiplatform
|
|
run: |
|
|
./gradlew --no-daemon --console=plain -Psimplex.assets.dir=../../assets :desktop:createDistributable
|
|
app=release/main/app/simplex
|
|
ls -la "$app/bin" "$app/lib/app/resources"
|
|
du -sh "$app"
|
|
LD_LIBRARY_PATH="$app/lib/app/resources" ldd "$app/lib/app/resources/libapp-lib.so"
|
|
|
|
- name: Run desktop tests
|
|
if: ${{ !cancelled() && steps.build.outcome == 'success' }}
|
|
working-directory: apps/multiplatform
|
|
run: ./gradlew --no-daemon --console=plain -Psimplex.assets.dir=../../assets :common:desktopTest
|
|
|
|
- name: Report desktop tests
|
|
if: ${{ !cancelled() && steps.build.outcome == 'success' }}
|
|
run: scripts/ci/desktop-linux/test-summary.py apps/multiplatform/common/build/test-results/desktopTest
|
|
|
|
- name: Run smoke test
|
|
if: ${{ !cancelled() && steps.build.outcome == 'success' && steps.link.outcome == 'success' }}
|
|
run: |
|
|
export NAMES_SERVER=$(cat "$RUNNER_TEMP/backend/names-server")
|
|
scripts/ci/desktop-linux/smoke-test.sh apps/multiplatform/release/main/app/simplex "$RUNNER_TEMP/smoke-test"
|
|
|
|
- name: Stop test backend
|
|
if: ${{ !cancelled() }}
|
|
run: scripts/ci/desktop-linux/backend.sh stop "$RUNNER_TEMP/backend"
|
|
|
|
- name: Upload smoke test results
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: desktop-smoke-test
|
|
path: ${{ runner.temp }}/smoke-test
|
|
retention-days: 3
|
|
if-no-files-found: warn
|
|
|
|
- name: Upload desktop test report
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: desktop-test-report
|
|
path: |
|
|
apps/multiplatform/common/build/reports/tests/desktopTest
|
|
apps/multiplatform/common/build/test-results/desktopTest
|
|
retention-days: 3
|
|
if-no-files-found: warn
|
|
|
|
- name: Upload backend logs
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: desktop-backend-logs
|
|
path: ${{ runner.temp }}/backend/*.log
|
|
retention-days: 3
|
|
if-no-files-found: warn
|
|
|
|
# Claude Code repeats the smoke test's searches with the ui helper. Each run spends the Claude
|
|
# subscription's usage limits, so it runs only when dispatched or asked for in the head commit's message.
|
|
claude:
|
|
name: Claude searches in the desktop app
|
|
needs: [plan, core, backend]
|
|
if: ${{ !cancelled() && !failure() && (github.event_name == 'workflow_dispatch' || contains(github.event.head_commit.message, '[claude-test]')) }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 60
|
|
environment:
|
|
name: app-sim-claude
|
|
deployment: false
|
|
concurrency:
|
|
group: desktop-linux-claude-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
env:
|
|
# the first release with Haiku 5.5's token counts right (2.1.293 added the model, 2.1.296 fixed its counts)
|
|
CLAUDE_CODE_VERSION: 2.1.296
|
|
CLAUDE_MODEL: claude-haiku-5-5
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
with:
|
|
submodules: recursive
|
|
persist-credentials: false
|
|
|
|
- name: Install tools
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y xvfb xdotool openbox imagemagick tesseract-ocr sqlite3 fonts-dejavu-core
|
|
dpkg-query -W xvfb xdotool openbox imagemagick tesseract-ocr sqlite3 fonts-dejavu-core
|
|
|
|
- name: Download core library
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: desktop-core-linux-x86_64
|
|
path: ~/core
|
|
|
|
- name: Install core library
|
|
run: scripts/ci/desktop-linux/install-core.sh ~/core/${{ env.CORE_PKG }}
|
|
|
|
- name: Download backend
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: ${{ needs.plan.outputs.backend }}
|
|
path: ~/backend
|
|
run-id: ${{ needs.plan.outputs.backend-run || github.run_id }}
|
|
github-token: ${{ github.token }}
|
|
|
|
- name: Start test backend
|
|
timeout-minutes: 30
|
|
run: scripts/ci/desktop-linux/backend.sh start ~/backend/${{ env.BACKEND_PKG }} "$RUNNER_TEMP/backend"
|
|
|
|
- name: Point the app at the test directory
|
|
run: |
|
|
link=$(cat "$RUNNER_TEMP/backend/directory-link")
|
|
file=apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/DirectorySearch.kt
|
|
sed -i "s|^const val DIRECTORY_SERVICE_LINK = \".*\"$|const val DIRECTORY_SERVICE_LINK = \"$link\"|" "$file"
|
|
grep -F "const val DIRECTORY_SERVICE_LINK = \"$link\"" "$file"
|
|
|
|
- name: Setup Java
|
|
uses: actions/setup-java@v5
|
|
with:
|
|
distribution: corretto
|
|
java-version: ${{ env.JAVA_VER }}
|
|
cache: gradle
|
|
|
|
- name: Build app
|
|
working-directory: apps/multiplatform
|
|
run: ./gradlew --no-daemon --console=plain -Psimplex.assets.dir=../../assets :desktop:createDistributable
|
|
|
|
# ui goes on every shell's PATH, where Claude's Bash tool finds it whatever environment it builds
|
|
- name: Install Claude Code and the ui command
|
|
run: |
|
|
npm install --prefix "$RUNNER_TEMP/claude-code" "@anthropic-ai/claude-code@$CLAUDE_CODE_VERSION"
|
|
echo "$RUNNER_TEMP/claude-code/node_modules/.bin" >> "$GITHUB_PATH"
|
|
printf '#!/bin/sh\nexec %s/scripts/ci/desktop-linux/ui "$@"\n' "$PWD" | sudo tee /usr/local/bin/ui
|
|
sudo chmod +x /usr/local/bin/ui
|
|
|
|
- name: Set the app up at the chat list
|
|
run: |
|
|
export NAMES_SERVER=$(cat "$RUNNER_TEMP/backend/names-server")
|
|
scripts/ci/desktop-linux/smoke-test.sh apps/multiplatform/release/main/app/simplex "$RUNNER_TEMP/claude-test/screens" setup
|
|
|
|
# Claude's Bash is limited to single ui commands by the guard hook in claude-test.sh. Claude Code's credential
|
|
# scrub stays off: on Linux it forces its whole Bash sandbox (bubblewrap, socat), which ui isn't set up for.
|
|
- name: Run Claude
|
|
id: claude
|
|
env:
|
|
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: 1
|
|
run: scripts/ci/desktop-linux/claude-test.sh "$RUNNER_TEMP/claude-test" "$RUNNER_TEMP/claude-transcript.jsonl"
|
|
|
|
- name: Report Claude usage
|
|
if: ${{ !cancelled() && steps.claude.outcome != 'skipped' }}
|
|
run: scripts/ci/desktop-linux/claude-usage.py "$RUNNER_TEMP/claude-transcript.jsonl" "$RUNNER_TEMP/claude-usage.json"
|
|
|
|
- name: Stop test backend
|
|
if: ${{ !cancelled() }}
|
|
run: scripts/ci/desktop-linux/backend.sh stop "$RUNNER_TEMP/backend"
|
|
|
|
- name: Upload Claude test results
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: desktop-claude-test
|
|
path: |
|
|
${{ runner.temp }}/claude-test
|
|
${{ runner.temp }}/claude-transcript.jsonl
|
|
${{ runner.temp }}/claude-transcript.jsonl.guard.log
|
|
${{ runner.temp }}/claude-usage.json
|
|
retention-days: 7
|
|
if-no-files-found: warn
|
|
|
|
- name: Upload backend logs
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: desktop-claude-backend-logs
|
|
path: ${{ runner.temp }}/backend/*.log
|
|
retention-days: 3
|
|
if-no-files-found: warn
|
|
|
|
release:
|
|
name: released app under Xvfb
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 30
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
with:
|
|
fetch-depth: 0
|
|
filter: tree:0
|
|
|
|
- name: Download released app
|
|
run: scripts/ci/desktop-linux/release-app.sh "$RUNNER_TEMP/release"
|
|
|
|
- name: Install UI tools
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y xvfb xdotool openbox imagemagick tesseract-ocr
|
|
dpkg-query -W xvfb xdotool openbox imagemagick tesseract-ocr
|
|
|
|
- name: Run smoke test
|
|
run: scripts/ci/desktop-linux/smoke-test.sh "$RUNNER_TEMP/release/app/opt/simplex" "$RUNNER_TEMP/smoke-test" onboarding
|
|
|
|
- name: Upload smoke test results
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: desktop-release-smoke-test
|
|
path: ${{ runner.temp }}/smoke-test
|
|
retention-days: 3
|
|
if-no-files-found: warn
|