diff --git a/.drone.yml b/.drone.yml_ similarity index 100% rename from .drone.yml rename to .drone.yml_ diff --git a/.github/workflows/configNC.sh b/.github/workflows/configNC.sh new file mode 100644 index 000000000000..8446e69faa16 --- /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 000000000000..e87cbbf0f35e --- /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 000000000000..ee08a7df01dd --- /dev/null +++ b/.github/workflows/garm.yml @@ -0,0 +1,107 @@ +# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: MIT + +name: "Garm" + +on: + pull_request: + 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.3:latest' }} + 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: 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: Config gplay + run: | + sed -i s#http://server#http://10.0.2.2# gradle.properties + sed -i s'#false#true#'g app/src/main/res/values/setup.xml + + - 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 }} + cmake: 4.1.2 + force-avd-creation: false + arch: x86_64 + sdcard-path-or-size: 100M + target: google_apis + emulator-options: -no-metrics -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -skin 500x833 + script: scripts/runCombinedTest.sh ${{github.event.number}} ${{ secrets.LOG_USERNAME }} ${{ secrets.LOG_PASSWORD }} ${{github.event.number}} ${{ matrix.server }} + + - 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 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 079d98774197..a659e78e0037 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -395,6 +395,7 @@ dependencies { androidTestImplementation(libs.rules) androidTestImplementation(libs.runner) androidTestUtil(libs.orchestrator) + androidTestImplementation(libs.test.core) androidTestImplementation(libs.core.ktx) androidTestImplementation(libs.core.testing) // endregion diff --git a/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt b/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt index 0805ef65e365..7c36aaefef49 100644 --- a/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt +++ b/app/src/androidTest/java/com/nextcloud/client/FileDisplayActivityIT.kt @@ -217,14 +217,19 @@ class FileDisplayActivityIT : AbstractOnServerIT() { @Suppress("DEPRECATION") @Test fun switchToGridView() { + val test1 = CreateFolderOperation("/test/", user, targetContext, storageManager) + .execute(client) + + assertTrue(test1.exception.message, test1.isSuccess) + launchActivity().use { scenario -> scenario.onActivity { sut -> onIdleSync { - assertTrue( - CreateFolderOperation("/test/", user, targetContext, storageManager) - .execute(client) - .isSuccess - ) + val test = CreateFolderOperation("/test/", user, targetContext, storageManager) + .execute(client) + + assertTrue(test.exception.message, test.isSuccess) + onView(withId(R.id.switch_grid_view_button)).perform(click()) } } diff --git a/app/src/androidTest/java/com/owncloud/android/AbstractIT.java b/app/src/androidTest/java/com/owncloud/android/AbstractIT.java index 519976ea9283..f1fbf772c377 100644 --- a/app/src/androidTest/java/com/owncloud/android/AbstractIT.java +++ b/app/src/androidTest/java/com/owncloud/android/AbstractIT.java @@ -6,7 +6,6 @@ */ package com.owncloud.android; -import android.Manifest; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorException; @@ -79,7 +78,6 @@ import androidx.test.espresso.contrib.DrawerActions; import androidx.test.espresso.intent.rule.IntentsTestRule; import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.rule.GrantPermissionRule; import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; import androidx.test.runner.lifecycle.Stage; @@ -97,8 +95,8 @@ public abstract class AbstractIT { @Rule public final TestRule storagePermissionRule = GrantStoragePermissionRule.grant(); - @Rule - public GrantPermissionRule notificationsPermissionRule = GrantPermissionRule.grant(Manifest.permission.POST_NOTIFICATIONS); +// @Rule +// public GrantPermissionRule notificationsPermissionRule = GrantPermissionRule.grant(Manifest.permission.POST_NOTIFICATIONS); protected ConnectivityService connectivityServiceMock = ConnectivityManagerFactory.INSTANCE.getMock(); diff --git a/scripts/runCombinedTest.sh b/scripts/runCombinedTest.sh index e588938f68df..da44d3e3d488 100755 --- a/scripts/runCombinedTest.sh +++ b/scripts/runCombinedTest.sh @@ -8,6 +8,7 @@ DRONE_PULL_REQUEST=$1 LOG_USERNAME=$2 LOG_PASSWORD=$3 DRONE_BUILD_NUMBER=$4 +BRANCH=$5 function upload_logcat() { log_filename="${DRONE_PULL_REQUEST}_logcat.txt.xz" @@ -19,14 +20,11 @@ function upload_logcat() { echo >&2 "Uploaded logcat to https://www.kaminsky.me/nc-dev/android-logcat/$log_filename" } -scripts/deleteOldComments.sh "master" "IT" "$DRONE_PULL_REQUEST" - -./gradlew assembleGplayDebugAndroidTest +scripts/deleteOldComments.sh "$BRANCH" "IT" "$DRONE_PULL_REQUEST" scripts/wait_for_emulator.sh || exit 1 ./gradlew installGplayDebugAndroidTest -scripts/wait_for_server.sh "server" || exit 1 # clear logcat and start saving it to file adb logcat -c @@ -42,7 +40,6 @@ kill $LOGCAT_PID if [ ! $stat -eq 0 ]; then upload_logcat - bash scripts/uploadReport.sh "$LOG_USERNAME" "$LOG_PASSWORD" "$DRONE_BUILD_NUMBER" "master" "IT" "$DRONE_PULL_REQUEST" fi curl -Os https://uploader.codecov.io/latest/linux/codecov diff --git a/scripts/uploadReport.sh b/scripts/uploadReport.sh index e3bb5eea5459..e8fa2eb5bec1 100755 --- a/scripts/uploadReport.sh +++ b/scripts/uploadReport.sh @@ -30,9 +30,9 @@ upload() { #5: TYPE (IT or Unit) #6: DRONE_PULL_REQUEST -ID=$3 USER=$1 PASS=$2 +ID=$3 BRANCH=$4 TYPE=$5 PR=$6