diff --git a/.github/scripts/build-and-release-app-for-upgrade-testing.sh b/.github/scripts/build-and-release-app-for-upgrade-testing.sh new file mode 100644 index 000000000..7dae1ba3d --- /dev/null +++ b/.github/scripts/build-and-release-app-for-upgrade-testing.sh @@ -0,0 +1,204 @@ +# SPDX-FileCopyrightText: 2023-2024 Jankari Tech Pvt. Ltd. +# SPDX-FileCopyrightText: 2023 Bundesministerium des Innern und für Heimat, PG ZenDiS "Projektgruppe für Aufbau ZenDiS" +# SPDX-FileCopyrightText: 2023 Nextcloud GmbH +# SPDX-License-Identifier: AGPL-3.0-only +#!/usr/bin/env bash + +# This bash script is to register and publish the apps in self-hosted appstore. +# To run this script the self-hosted appstore instances must be up and running + +set -e + +# helper functions +log_error() { + echo -e "\e[31m$1\e[0m" +} + +log_info() { + echo -e "\e[37m$1\e[0m" +} + +log_success() { + echo -e "\e[32m$1\e[0m" +} + +# env required +# NEXCLOUD_PATH=/home/nabin/www/stable29 # path to nextcloud +# $TAG=2.11.3 # tag that we want to publish +# WORKING_DIRECTORY=/home/nabin/www/fork-integrationOpenproject # current working directory simply done by pwd command + +if [[ -z "$TAG" ]] || [[ -z "$NEXCLOUD_PATH" ]] || [[ -z "$WORKING_DIRECTORY" ]]; then + log_error "Environment variables TAG, NEXCLOUD_PATH, or WORKING_DIRECTORY are missing." + exit 1 +fi + +if [[ ! -d "$WORKING_DIRECTORY/integration_openproject" ]]; then + log_error "integration_openproject directory does not exist." + exit 1 +fi + +# build the apps +cd $WORKING_DIRECTORY +make -C integration_openproject + +mkdir -p publish + +# remove unnecessary app files +log_info "Copying necessary app files to publish directory..." +rsync -a \ +--exclude=server \ +--exclude=dev \ +--exclude=.git \ +--exclude=appinfo/signature.json \ +--exclude='*.swp' \ +--exclude=build \ +--exclude=.gitignore \ +--exclude=.travis.yml \ +--exclude=.scrutinizer.yml \ +--exclude=CONTRIBUTING.md \ +--exclude=composer.phar \ +--exclude=js/node_modules \ +--exclude=node_modules \ +--exclude=src \ +--exclude=translationfiles \ +--exclude='webpack.*' \ +--exclude=stylelint.config.js \ +--exclude=.eslintrc.js \ +--exclude=.github \ +--exclude=.gitlab-ci.yml \ +--exclude=crowdin.yml \ +--exclude=tools \ +--exclude=.tx \ +--exclude=.l10nignore \ +--exclude=l10n/.tx \ +--exclude=l10n/l10n.pl \ +--exclude=l10n/templates \ +--exclude='l10n/*.sh' \ +--exclude='l10n/[a-z][a-z]' \ +--exclude='l10n/[a-z][a-z]_[A-Z][A-Z]' \ +--exclude=l10n/no-php \ +--exclude=makefile \ +--exclude=screenshots \ +--exclude='phpunit*xml' \ +--exclude=tests \ +--exclude=ci \ +--exclude=vendor/bin \ +integration_openproject publish/ + +cd publish + +# update version in info.xml +sed -i "s|.*|$TAG|" "integration_openproject/appinfo/info.xml" + +# https://nextcloudappstore.readthedocs.io/en/latest/developer.html#obtaining-a-certificate +log_info "Generating app.key and app.crt..." +sudo openssl req -x509 -newkey rsa:4096 -sha256 -nodes \ + -keyout app.key \ + -out app.crt \ + -days 3650 \ + -subj "/CN=$APP_ID" \ + -addext "basicConstraints=CA:FALSE" \ + -addext "keyUsage=digitalSignature" \ + -addext "extendedKeyUsage=codeSigning" + +if [[ ! -s app.key || ! -s app.crt ]]; then + log_error "Failed to generate app signing certificate and key. app.key or app.crt not found." + exit 1 +fi + +log_info "Adding the generated certificate to nextcloud's root.crt..." +nextcloud_root_crt="${NEXCLOUD_PATH}/resources/codesigning/root.crt" +if [[ -f ${nextcloud_root_crt} ]]; then + echo "" >> ${nextcloud_root_crt} + cat app.crt >> ${nextcloud_root_crt} +else + log_error "Nextcloud's root.crt not found at ${nextcloud_root_crt}." + exit 1 +fi + +# fix permisions for signing +sudo chown $USER: app.key +sudo chown -R $USER: $APP_ID + +# Sign the app +# need full path for signing +log_info "Signing the app using occ integrity:sign-app command..." +php ${NEXCLOUD_PATH}/occ integrity:sign-app \ + --privateKey=${WORKING_DIRECTORY}/publish/app.key \ + --certificate=${WORKING_DIRECTORY}/publish/app.crt \ + --path=${WORKING_DIRECTORY}/publish/$APP_ID || { log_error "Failed to sign app."; exit 1; } + +# php /home/runner/html/nextcloud/occ integrity:sign-app \ +# --privateKey=/home/runner/work/integration_openproject/integration_openproject/publish/app.key \ +# --certificate=/home/runner/work/integration_openproject/integration_openproject/publish/app.crt \ +# --path=/home/runner/work/integration_openproject/integration_openproject/publish/integration_openproject + +# Archive the app +tar -czf $APP_ID-$TAG.tar.gz $APP_ID +if [[ ! -f $APP_ID-$TAG.tar.gz ]]; then + log_error "Failed to archive the app. Archive file $APP_ID-$TAG.tar.gz not found." + exit 1 +fi +log_success "Archived the app into $APP_ID-$TAG.tar.gz." + +# Sign the archive +sudo openssl dgst -sha512 -sign app.key $APP_ID-$TAG.tar.gz | openssl base64 | tee ${WORKING_DIRECTORY}/publish/sign.txt || { log_error "Failed to sign the archive."; exit 1; } +if [[ ! -s ${WORKING_DIRECTORY}/publish/sign.txt ]]; then + log_error "Failed to sign the archive. Signature file sign.txt is empty or not found." + exit 1 +else + log_success "Signed the app archive successfully." +fi + +log_success "App build and release process has been completed successfully." + +## copy archieve in nextcloud directory to download +cp $APP_ID-$TAG.tar.gz ${NEXCLOUD_PATH}/$APP_ID-$TAG.tar.gz +if [[ -f ${NEXCLOUD_PATH}/$APP_ID-$TAG.tar.gz ]]; then + log_success "App archive has been copied successfully." +else + log_error "Failed to copy app archive to ${NEXCLOUD_PATH}." + exit 1 +fi + +## Prepare apps.json file +if [[ ! -f ${WORKING_DIRECTORY}/publish/integration_openproject/appinfo/signature.json ]]; then + log_error "Signature file not found at ${WORKING_DIRECTORY}/publish/integration_openproject/appinfo/signature.json." + exit 1 +fi + +# Convert sign.txt content to one line by removing newlines +signature=$(tr -d '\n' < "${WORKING_DIRECTORY}/publish/sign.txt") +certificate=$(jq '.certificate' ${WORKING_DIRECTORY}/publish/integration_openproject/appinfo/signature.json) + +cat > apps.json <> $GITHUB_OUTPUT + outputs: + matrix: ${{ steps.create-matrix.outputs.matrix }} + + upgrade-test: + name: Upgrade Testing + needs: create-matrix + if: ${{ success() }} + strategy: + matrix: ${{ fromJson(needs.create-matrix.outputs.matrix) }} + runs-on: ubuntu-latest + services: + database-mysql: + image: ghcr.io/nextcloud/continuous-integration-mariadb-10.5:latest + env: + MYSQL_ROOT_PASSWORD: 'nextcloud' + MYSQL_PASSWORD: 'nextcloud' + MYSQL_USER: 'nextcloud' + MYSQL_DATABASE: 'nextcloud' + ports: + - 3306:3306 + + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + with: + path: integration_openproject + + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + with: + repository: nextcloud/activity + ref: ${{ matrix.nextcloudVersion }} + path: activity + + - name: Setup NodeJS + uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 + with: + node-version: 20 + + - name: Setup npm + run: npm i -g npm + + - name: Setup PHP + uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d + with: + php-version: ${{ format('{0}.{1}', matrix.phpVersionMajor,matrix.phpVersionMinor) }} + extensions: mbstring, intl, mysql, gd + ini-values: post_max_size=256M, max_execution_time=180 + + - name: Build nextcloud project + run: | + export DEBIAN_FRONTEND=noninteractive + echo "###### installing nextcloud" + mkdir ~/html + git clone https://github.com/nextcloud/server.git --recursive --depth 1 -b ${{ matrix.nextcloudVersion }} ~/html/nextcloud + cd ~/html/nextcloud + git submodule update --init + mkdir -p data + php occ maintenance:install \ + --database mysql \ + --database-name nextcloud \ + --database-host 127.0.0.1 \ + --database-user nextcloud \ + --database-pass nextcloud \ + --admin-user admin \ + --admin-pass admin + php occ maintenance:mode --off + sudo php -S localhost:80 -t ~/html/nextcloud & + + - name: Wait for Nextcloud server to be ready + run: | + if ! timeout 5m bash -c ' + until curl -s -f http://localhost/status.php | grep '"'"'"installed":true'"'"'; do + echo "[INFO] Waiting for server to be ready..." + sleep 10 + done + '; then + echo "[ERROR] Server not ready within 5 minutes." + exit 1 + fi + + - name: Enable other apps from official app store + run: | + cd ~/html/nextcloud + php occ app:enable oidc user_oidc groupfolders integration_openproject + + # activity app cannot be installed using occ command + - name: Setup and enable dependent apps + run: | + cp -R activity ~/html/nextcloud/apps + cd ~/html/nextcloud + php occ app:enable activity + + - name: Build integration_openproject app for upgrade testing + env: + APP_ID: integration_openproject + NEXCLOUD_PATH: /home/runner/html/nextcloud + WORKING_DIRECTORY: ${{ github.workspace }} + run: | + cd integration_openproject + bash .github/scripts/build-and-release-app-for-upgrade-testing.sh + + - name: Update integration_openproject app + run: | + # latest data didn't get fetched properly, so we need to clear the appstore cache + echo "" > ~/html/nextcloud/data/appdata_*/appstore/apps.json + cd ~/html/nextcloud + php occ config:system:set ratelimit.protection.enabled --value false --type bool + php occ config:system:set appstoreurl --value "http://localhost" + php occ config:system:set allow_local_remote_servers --value true + php occ app:update --allow-unstable integration_openproject + if php occ app:list | grep -q "integration_openproject.*$TAG"; then + echo "App updated successfully to version $TAG" + else + echo "App not updated to version $TAG" + exit 1 + fi + + - name: API Tests + env: + NEXTCLOUD_BASE_URL: http://localhost + run: | + cd integration_openproject + # Run API tests + make api-test \ No newline at end of file diff --git a/tests/acceptance/features/bootstrap/FeatureContext.php b/tests/acceptance/features/bootstrap/FeatureContext.php index 1c7f59258..103708279 100644 --- a/tests/acceptance/features/bootstrap/FeatureContext.php +++ b/tests/acceptance/features/bootstrap/FeatureContext.php @@ -270,6 +270,12 @@ private function deleteUserDataFromDocker(string $user): void { echo "'docker' command not found. Skipping user data deletion.\n"; return; } + + // Skip if Nextcloud Docker container does not exist + exec("docker ps --format \"{{.Names}}\"", $output); + if(!in_array('nextcloud', $output)) { + return; + } $firstChar = substr($user, 0, 1); $restChars = substr($user, 1);