diff --git a/.drone.yml b/.drone.yml
deleted file mode 100644
index 9123b04a06..0000000000
--- a/.drone.yml
+++ /dev/null
@@ -1,86 +0,0 @@
----
-kind: pipeline
-type: docker
-name: generic
-
-# SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-steps:
- - name: generic
- image: ghcr.io/nextcloud/continuous-integration-android8:4
- commands:
- - ./gradlew --console=plain assembleGeneric
-
-trigger:
- branch:
- - master
- - stable-*
- event:
- - pull_request
- - push
-
----
-kind: pipeline
-type: docker
-name: gplay
-
-steps:
- - name: gplay
- image: ghcr.io/nextcloud/continuous-integration-android8:4
- commands:
- - ./gradlew --console=plain assembleGplay
-
-trigger:
- branch:
- - master
- - stable-*
- event:
- - push
- - pull_request
-
----
-kind: pipeline
-type: docker
-name: tests
-
-steps:
- - name: all
- image: ghcr.io/nextcloud/continuous-integration-android8:4
- privileged: true
- commands:
- - emulator -avd android -no-snapshot -gpu swiftshader_indirect -no-window -no-audio -skin 500x833 &
- - scripts/wait_for_emulator.sh
- - ./gradlew --console=plain --stacktrace testGplayDebugUnitTest connectedGplayDebugAndroidTest
-
-services:
- - name: server
- image: nextcloudci/server:server-17
- environment:
- EVAL: "true"
- commands:
- - BRANCH='stable23' /usr/local/bin/initnc.sh
- - echo 127.0.0.1 server >> /etc/hosts
- - su www-data -c "OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1"
- - su www-data -c "OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2"
- - su www-data -c "OC_PASS=user3 php /var/www/html/occ user:add --password-from-env --display-name='User Three' user3"
- - su www-data -c "php /var/www/html/occ user:setting user2 files quota 1G"
- - su www-data -c "php /var/www/html/occ group:add users"
- - su www-data -c "php /var/www/html/occ group:adduser users user1"
- - su www-data -c "php /var/www/html/occ group:adduser users user2"
- - su www-data -c "git clone -b stable23 https://github.com/nextcloud/spreed.git /var/www/html/apps/spreed/"
- - su www-data -c "php /var/www/html/occ app:enable spreed"
- - /usr/local/bin/run.sh
-
-trigger:
- branch:
- - master
- - stable-*
- event:
- - push
- - pull_request
----
-kind: signature
-hmac: d3f0eb5c71a3a463a52789aa577b3ca742616a8d966ac90c187774179693f5ea
-
-...
diff --git a/.github/workflows/assembleFlavors.yml b/.github/workflows/assembleFlavors.yml
index df3161654a..ea8129f3b9 100644
--- a/.github/workflows/assembleFlavors.yml
+++ b/.github/workflows/assembleFlavors.yml
@@ -6,6 +6,8 @@ name: "Assemble"
on:
pull_request:
branches: [ master, stable-* ]
+ push:
+ branches: [ master, stable-* ]
# Declare default permissions as read only.
permissions: read-all
diff --git a/.github/workflows/configNC.sh b/.github/workflows/configNC.sh
new file mode 100644
index 0000000000..8446e69faa
--- /dev/null
+++ b/.github/workflows/configNC.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+
+# Nextcloud Android Library
+#
+# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: MIT
+#
+
+if [ $1 = "master" ]; then
+ SERVER_VERSION_MAIN="main"
+ SERVER_VERSION_MASTER="master"
+else
+ SERVER_VERSION_MAIN=$1
+ SERVER_VERSION_MASTER=$1
+fi
+
+curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
+export NVM_DIR="$HOME/.nvm"
+[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
+
+. ~/.bashrc; nvm install node
+
+php /var/www/html/occ log:manage --level warning
+
+OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1
+OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2
+OC_PASS=user3 php /var/www/html/occ user:add --password-from-env --display-name='User Three' user3
+OC_PASS=test php /var/www/html/occ user:add --password-from-env --display-name='Test@Test' test@test
+OC_PASS=test php /var/www/html/occ user:add --password-from-env --display-name='Test Spaces' 'test test'
+php /var/www/html/occ user:setting user2 files quota 1G
+php /var/www/html/occ group:add users
+php /var/www/html/occ group:adduser users user1
+php /var/www/html/occ group:adduser users user2
+php /var/www/html/occ group:adduser users test
+
+git clone --depth=1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/activity.git /var/www/html/apps/activity/
+php /var/www/html/occ app:enable -f activity
+
+git clone --depth=1 -b $SERVER_VERSION_MAIN https://github.com/nextcloud/text.git /var/www/html/apps/text/
+php /var/www/html/occ app:enable -f text
+
+git clone --depth=1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/end_to_end_encryption.git /var/www/html/apps/end_to_end_encryption/
+php /var/www/html/occ app:enable -f end_to_end_encryption
+
+git clone --depth=1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/password_policy.git /var/www/html/apps/password_policy/
+php /var/www/html/occ app:enable -f password_policy
+
+git clone --depth=1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/external.git /var/www/html/apps/external/
+cd /var/www/html/apps/external; composer install --no-dev
+php /var/www/html/occ app:enable -f external
+php /var/www/html/occ config:app:set external sites --value="{\"1\":{\"id\":1,\"name\":\"Nextcloud\",\"url\":\"https:\/\/www.nextcloud.com\",\"lang\":\"\",\"type\":\"link\",\"device\":\"\",\"icon\":\"external.svg\",\"groups\":[],\"redirect\":false},\"2\":{\"id\":2,\"name\":\"Forum\",\"url\":\"https:\/\/help.nextcloud.com\",\"lang\":\"\",\"type\":\"link\",\"device\":\"\",\"icon\":\"external.svg\",\"groups\":[],\"redirect\":false}}"
+
+git clone --depth=1 -b $SERVER_VERSION_MAIN https://github.com/nextcloud/files_lock.git /var/www/html/apps/files_lock/
+php /var/www/html/occ app:enable -f files_lock
+
+git clone --depth=1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/groupfolders.git /var/www/html/apps/groupfolders/
+php /var/www/html/occ app:enable -f groupfolders
+php /var/www/html/occ groupfolders:create groupfolder
+php /var/www/html/occ groupfolders:group 1 users
+
+git clone --depth=1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/notifications.git /var/www/html/apps/notifications/
+cd /var/www/html/apps/notifications; composer install --no-dev
+php /var/www/html/occ app:enable -f notifications
+
+if [ $1 = 'stable22' ]; then
+ php /var/www/html/occ notification:generate test test
+else
+ php /var/www/html/occ notification:generate test -d test
+fi
+
+git clone --depth=1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/photos.git /var/www/html/apps/photos/
+cd /var/www/html/apps/photos; composer install --no-dev
+php /var/www/html/occ app:enable -f photos
+
+git clone --depth=1 -b $SERVER_VERSION_MAIN https://github.com/nextcloud/assistant.git /var/www/html/apps/assistant/
+cd /var/www/html/apps/assistant; . ~/.bashrc; make
+php /var/www/html/occ app:enable -f assistant
+
+php /var/www/html/occ app:enable -f testing
+
+git clone --depth 1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/files_downloadlimit.git /var/www/html/apps/files_downloadlimit/
+php /var/www/html/occ app:enable -f files_downloadlimit
+
+git clone --depth 1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/recommendations.git /var/www/html/apps/recommendations/
+cd /var/www/html/apps/recommendations; composer install --no-dev
+php /var/www/html/occ app:enable -f recommendations
+
+git clone --depth 1 -b $SERVER_VERSION_MASTER https://github.com/nextcloud/viewer.git /var/www/html/apps/viewer/
+php /var/www/html/occ app:enable -f viewer
+
+php /var/www/html/occ config:system:set ratelimit.protection.enabled --value false --type bool
diff --git a/.github/workflows/configServer.sh b/.github/workflows/configServer.sh
new file mode 100644
index 0000000000..e87cbbf0f3
--- /dev/null
+++ b/.github/workflows/configServer.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Nextcloud Android Library
+#
+# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: MIT
+#
+
+wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
+apt-get update && apt-get install -y composer
+mkdir /var/www/.nvm /var/www/.npm
+mkdir /var/www/.cache/
+touch /var/www/.bashrc
+chown -R 33:33 /var/www/.nvm /var/www/.npm /var/www/.bashrc /var/www/.cache
+
+cd /var/www/html/
+rm data -rf
+rm config/config.php
+su www-data -c "git reset --hard"
+BRANCH="$1" /usr/local/bin/initnc.sh
diff --git a/.github/workflows/garm.yml b/.github/workflows/garm.yml
new file mode 100644
index 0000000000..a598d8ed5c
--- /dev/null
+++ b/.github/workflows/garm.yml
@@ -0,0 +1,122 @@
+# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
+# SPDX-License-Identifier: MIT
+
+name: "Garm"
+
+on:
+ pull_request:
+ branches: [ master, stable-* ]
+ push:
+ branches: [ master, stable-* ]
+
+permissions:
+ contents: read
+ pull-requests: write
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ test:
+ runs-on: ubuntu-24.04
+ services:
+ server:
+ image: ${{ matrix.server == 'stable22' && 'ghcr.io/nextcloud/continuous-integration-shallow-server-php8.0:1' || 'ghcr.io/nextcloud/continuous-integration-shallow-server-php8.2:1' }}
+ options: --name server
+ ports:
+ - 80:80
+ strategy:
+ fail-fast: false
+ matrix:
+ server: [ master ] # [ stable22, stable33, master ]
+ api-level: [ 29 ] # [ 21, 36 ]
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ - name: configure server
+ run: |
+ sudo apt-get update && sudo apt-get install unzip cpu-checker qemu-kvm --yes
+ sudo chmod 666 /dev/kvm
+ docker cp .github/workflows/configServer.sh server:/tmp/
+ docker exec server chmod +x /tmp/configServer.sh
+ docker exec server /tmp/configServer.sh ${{ matrix.server }}
+ docker cp .github/workflows/configNC.sh server:/tmp/
+ docker exec server chmod +x /tmp/configNC.sh
+ docker exec --user www-data server /tmp/configNC.sh ${{ matrix.server }}
+ docker exec server /usr/local/bin/run.sh
+
+ - name: set up JDK 21
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
+ with:
+ distribution: "temurin"
+ java-version: 21
+
+ - name: Enable KVM group perms
+ run: |
+ echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
+ sudo udevadm control --reload-rules
+ sudo udevadm trigger --name-match=kvm
+
+
+ - name: create AVD and generate snapshot for caching
+ uses: reactivecircus/android-emulator-runner@b530d96654c385303d652368551fb075bc2f0b6b # v2.35.0
+ with:
+ api-level: ${{ matrix.api-level }}
+ force-avd-creation: false
+ arch: x86_64
+ sdcard-path-or-size: 100M
+ target: google_apis
+ emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -skin 500x833
+ script: echo "Generated AVD snapshot for caching."
+
+ - name: Configure gradle daemon
+ run: |
+ mkdir -p $HOME/.gradle
+ echo "org.gradle.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g" >> $HOME/.gradle/gradle.properties
+ echo "org.gradle.caching=true" >> $HOME/.gradle/gradle.properties
+ echo "org.gradle.parallel=true" >> $HOME/.gradle/gradle.properties
+ echo "org.gradle.configureondemand=true" >> $HOME/.gradle/gradle.properties
+
+ - name: Build gplay
+ run: |
+ sdkmanager "cmake;4.1.2"
+ sed -i s#https://server#http://10.0.2.2# gradle.properties
+ sed -i s'#false#true#'g app/src/main/res/values/setup.xml
+ ./gradlew assembleGplayDebug
+
+ - name: wait and ping server
+ run: |
+ while ! curl http://localhost/status.php 2>&1 | grep installed; do
+ echo "wait…"
+ sleep 5
+ done
+
+ - name: gplay
+ env:
+ GITHUB_TOKEN: ${{ secrets.GIT_TOKEN }}
+ uses: reactivecircus/android-emulator-runner@b530d96654c385303d652368551fb075bc2f0b6b # v2.35.0
+ with:
+ api-level: ${{ matrix.api-level }}
+ force-avd-creation: false
+ arch: x86_64
+ sdcard-path-or-size: 100M
+ target: google_apis
+ emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -skin 500x833
+ script: ./gradlew --no-daemon --stacktrace connectedGplayDebugAndroidTest
+
+ - name: upload failing results
+ if: ${{ failure() }}
+ env:
+ LOG_USERNAME: ${{ secrets.LOG_USERNAME }}
+ LOG_PASSWORD: ${{ secrets.LOG_PASSWORD }}
+ GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
+ GITHUB_TOKEN: ${{ secrets.GIT_TOKEN }}
+ run: scripts/uploadReport.sh "${{ secrets.LOG_USERNAME }}" "${{ secrets.LOG_PASSWORD }}" ${{github.event.number}} ${{ matrix.server }} "IT" ${{github.event.number}}
+ - name: Archive Espresso results
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ if: ${{ always() }}
+ with:
+ name: Report-${{ matrix.server }}-${{ matrix.api-level }}
+ path: app/build/reports
+ retention-days: 4