Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d0e3b10
ci: automate upgrade testing
nabim777 May 13, 2026
6175abe
ci: use the specific branch
nabim777 May 13, 2026
0aea303
ci: enabling other apps from officail appstore
nabim777 May 14, 2026
abf32a2
ci: add matrix
nabim777 May 14, 2026
0c0d306
ci: use env
nabim777 May 14, 2026
94093a4
ci: remove some env
nabim777 May 14, 2026
08aef28
ci: renaming the workflows
nabim777 May 14, 2026
7cde02f
ci: review addresses
nabim777 May 15, 2026
4241652
ci: use appstore alternatives
nabim777 May 18, 2026
63695bf
ci: enable activity apps in seperate steps
nabim777 May 18, 2026
d14d975
ci: make new tag dynamic
nabim777 May 19, 2026
be86d17
ci: rename bash script file
nabim777 May 19, 2026
a28622d
ci: remove success as not needed
nabim777 May 19, 2026
0995e71
ci: add comment in bash script
nabim777 May 19, 2026
ab3ee05
ci: remove npm install step
nabim777 May 19, 2026
e9d18ee
ci: updated the action full commit sha with latest one
nabim777 May 20, 2026
a53a056
ci: use nextcloud as container
nabim777 May 22, 2026
031c767
ci: rename workflow name
nabim777 May 25, 2026
86edbfd
ci: shifting apps.json prepare in script file
nabim777 May 25, 2026
893f6e6
test: rename added varaible name
nabim777 May 25, 2026
d7902f5
ci: add for checking the local appstore server
nabim777 May 26, 2026
20b1625
ci: make the shell scripts fails inside pipelines
nabim777 May 26, 2026
eaa305e
ci: improve comments and log message
nabim777 May 27, 2026
5d2a9cb
ci: configure workflow for nightly
nabim777 May 27, 2026
bca2c3c
ci: notify in matrix
nabim777 May 27, 2026
1aa5911
ci: replace workflow status check approach
nabim777 May 28, 2026
4eb1e88
ci: check the output of needs json
nabim777 May 28, 2026
bfa80f8
ci: make dynamic matrix noitfy
nabim777 May 28, 2026
e2981df
ci: notify
nabim777 May 29, 2026
48e0b3b
chore: revert the changes of matrix notification
nabim777 May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 207 additions & 0 deletions .github/scripts/build-upgradable-app.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#!/bin/bash
# SPDX-FileCopyrightText: 2026 Jankari Tech Pvt. Ltd.
# SPDX-License-Identifier: AGPL-3.0-or-later

# This script is used to build the upgradable integration_openproject app. It performs the following steps:
# 1. Copy the build files to a separate folder named publish, excluding unnecessary files and directories.
# 2. Get the current version of the app and update it to a new version by incrementing the major version number.
# 3. Sign the app files using self-signed certificate.
# 4. Archive the app into a .tar.gz file.
# 5. Sign the archive.
# NOTE: Before running this script, ensure that the Nextcloud instance is running and integration_openproject app is built.

# Required environment variables:
# 1. NEXTCLOUD_PATH (Absolute path to Nextcloud where occ command is available, e.g. /var/www/html)
# 2. INTEGRATION_OPENPROJECT_DIR (Absolute path to the directory containing the integration_openproject repository, e.g. /var/www/html/build-app-shared)

set -e -o pipefail

# 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"
}

if [[ -z "$NEXTCLOUD_PATH" ]] || [[ -z "$INTEGRATION_OPENPROJECT_DIR" ]]; then
log_error "Missing required environment variables: NEXTCLOUD_PATH, INTEGRATION_OPENPROJECT_DIR"
exit 1
fi

APP_ID=integration_openproject
cd "$INTEGRATION_OPENPROJECT_DIR"

if [[ ! -d "$INTEGRATION_OPENPROJECT_DIR/$APP_ID" ]]; then
log_error "Folder does not exist: $INTEGRATION_OPENPROJECT_DIR/$APP_ID"
exit 1
fi

mkdir -p publish
Comment thread
nabim777 marked this conversation as resolved.

# copy app files to a separate folder
log_info "Copying necessary app files to publish directory..."
rsync -a \
Comment thread
nabim777 marked this conversation as resolved.
--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 \
Comment thread
nabim777 marked this conversation as resolved.
$APP_ID publish/

cd publish

# get current version of integration_openproject and update to new version
current_version=$(php ${NEXTCLOUD_PATH}/occ app:list --output=json | jq -r ".enabled.$APP_ID") || { log_error "Failed to get current version of $APP_ID app."; exit 1; }
IFS=. read -r a b c <<< "$current_version"
NEXT_APP_VERSION="$((a+1)).$b.$c"

# Save the new tag to a file for later use in the workflow
echo "$NEXT_APP_VERSION" > "${APP_ID}_new_version.txt"

# update version in info.xml
sed -i "s|<version>.*</version>|<version>$NEXT_APP_VERSION</version>|" "integration_openproject/appinfo/info.xml"

#####################
# Signing the app #
#####################
# https://nextcloudappstore.readthedocs.io/en/latest/developer.html#obtaining-a-certificate
# Check if openssl exists, otherwise install it
if ! command -v openssl >/dev/null 2>&1; then
echo "OpenSSL not found. Installing..."
apt update && apt install -y openssl || {
echo "Failed to install OpenSSL."
exit 1
}
fi
log_info "Generating app.key and app.crt..."
Comment thread
nabim777 marked this conversation as resolved.
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="${NEXTCLOUD_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 permissions for signing
chown www-data app.key
chown www-data app.crt
chown -R www-data $APP_ID

# Sign the app
# need full path for signing
log_info "Signing the app files..."
php ${NEXTCLOUD_PATH}/occ integrity:sign-app \
--privateKey=${INTEGRATION_OPENPROJECT_DIR}/publish/app.key \
--certificate=${INTEGRATION_OPENPROJECT_DIR}/publish/app.crt \
--path=${INTEGRATION_OPENPROJECT_DIR}/publish/$APP_ID || { log_error "Failed to sign app."; exit 1; }

# Archive the app
tar -czf $APP_ID-$NEXT_APP_VERSION.tar.gz $APP_ID
if [[ ! -f $APP_ID-$NEXT_APP_VERSION.tar.gz ]]; then
log_error "Failed to archive the app. Archive file $APP_ID-$NEXT_APP_VERSION.tar.gz not found."
exit 1
fi
log_success "App archived into $APP_ID-$NEXT_APP_VERSION.tar.gz."

#####################
# Sign the archive #
#####################
log_info "Signing the app archive..."
openssl dgst -sha512 -sign app.key $APP_ID-$NEXT_APP_VERSION.tar.gz \
| openssl base64 \
| tee ${INTEGRATION_OPENPROJECT_DIR}/publish/sign.txt

if [[ ! -s ${INTEGRATION_OPENPROJECT_DIR}/publish/sign.txt ]]; then
log_error "Failed to sign the app archive. Signature file sign.txt is empty or not found."
exit 1
else
log_success "App archive signed successfully."
fi

log_success "Upgradable app built successfully."

# prepare apps.json file
if [[ ! -f ${INTEGRATION_OPENPROJECT_DIR}/publish/${APP_ID}/appinfo/signature.json ]]; then
echo "Signature file not found at ${INTEGRATION_OPENPROJECT_DIR}/publish/${APP_ID}/appinfo/signature.json."
exit 1
fi
certificate=$(jq '.certificate' "${INTEGRATION_OPENPROJECT_DIR}/publish/${APP_ID}/appinfo/signature.json")
signature=$(tr -d '\n' < "${INTEGRATION_OPENPROJECT_DIR}/publish/sign.txt")

# Create apps.json with the required structure
cat > apps.json <<EOF
[
{
"id": "$APP_ID",
"releases": [
{
"version": "$NEXT_APP_VERSION",
"minIntSize": 32,
"download": "http://localhost:8080/${APP_ID}-${NEXT_APP_VERSION}.tar.gz",
"licenses": [
"agpl"
],
"isNightly": false,
"rawPlatformVersionSpec": "\u003E=28",
"signature": "$signature",
"signatureDigest": "sha512"
}
],
"certificate": $certificate
}
]
EOF
175 changes: 175 additions & 0 deletions .github/workflows/app-upgrade.yml
Comment thread
nabim777 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# SPDX-FileCopyrightText: 2026 Jankari Tech Pvt. Ltd.
# SPDX-License-Identifier: AGPL-3.0-or-later

name: App Upgrade

on:
workflow_call:
inputs:
branch:
required: true
type: string
nextcloud_versions:
required: false
type: string
default: "31 32"
php_versions:
required: false
type: string
default: "8.3"

jobs:
create-matrix:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd

- name: Create matrix
id: create-matrix
env:
NEXTCLOUD_VERSIONS: ${{ inputs.nextcloud_versions }}
PHP_VERSIONS: ${{ inputs.php_versions }}
DEFAULT_PHP_VERSION: "8.3"
DEFAULT_DATABASE: "mysql"
run: |
MATRIX=$(./.github/scripts/generate-matrix.sh)
echo "matrix={\"include\": [$MATRIX]}" >> $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.create-matrix.outputs.matrix }}

upgrade-test:
name: Upgrade Testing
needs: create-matrix
runs-on: ubuntu-latest
strategy:
matrix: ${{ fromJson(needs.create-matrix.outputs.matrix) }}

services:
nextcloud:
image: ghcr.io/juliusknorr/nextcloud-dev-php${{ format('{0}{1}', matrix.phpVersionMajor,matrix.phpVersionMinor) }}:master
env:
SQL: ${{ matrix.database }}
SERVER_BRANCH: ${{ matrix.nextcloudVersion }}
NEXTCLOUD_AUTOINSTALL: "Yes"
NEXTCLOUD_AUTOINSTALL_APPS: oidc groupfolders user_oidc integration_openproject
NEXTCLOUD_AUTOINSTALL_APPS_WAIT_TIME: 60
WITH_REDIS: "YES"
ports:
- 80:80
options: --name=nextcloud
volumes:
- ${{ github.workspace }}/extra-apps:/var/www/html/apps-shared
- ${{ github.workspace }}/build-app:/var/www/html/build-app-shared

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'

redis:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
path: integration_openproject

- name: Setup PHP ${{ format('{0}.{1}', matrix.phpVersionMajor,matrix.phpVersionMinor) }}
uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d
with:
php-version: ${{ format('{0}.{1}', matrix.phpVersionMajor,matrix.phpVersionMinor) }}
tools: composer, phpunit
extensions: intl, gd, sqlite3

- 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

# activity app cannot be installed using occ command
Comment thread
nabim777 marked this conversation as resolved.
- name: Setup activity app
run: |
# fix permissions for folder extra-apps
sudo chown $USER:$USER extra-apps
cd extra-apps
git clone https://github.com/nextcloud/activity.git --depth 1 --branch ${{ matrix.nextcloudVersion }}
Comment thread
nabim777 marked this conversation as resolved.
# Enable activity apps
if [ "${{matrix.nextcloudVersion}}" == "master" ]; then
# enable app even if it is not compatible with the master branch
docker exec nextcloud /bin/bash -c 'occ a:e -f activity'
else
docker exec nextcloud /bin/bash -c 'occ a:e activity'
fi

- name: Build upgradable integration_openproject app
run: |
make -C integration_openproject
# fix permissions for build-app folder
sudo chown -R $USER:$USER build-app
cp -R integration_openproject build-app
# run the build script inside the nextcloud container
docker exec nextcloud /bin/bash -c "\
cd build-app-shared && \
INTEGRATION_OPENPROJECT_DIR=/var/www/html/build-app-shared \
NEXTCLOUD_PATH=/var/www/html \
source integration_openproject/.github/scripts/build-upgradable-app.sh"
Comment thread
nabim777 marked this conversation as resolved.
cd build-app/publish
echo "NEXT_APP_VERSION=$(cat integration_openproject_new_version.txt)" >> $GITHUB_ENV

- name: Update integration_openproject app
run: |
# Start local appstore server
docker exec nextcloud /bin/bash -c "cd build-app-shared && php -S localhost:8080 -t publish &"

# Wait for local appstore server to be ready
docker exec nextcloud /bin/bash -c '
for i in $(seq 1 5); do
if curl -sS http://localhost:8080 > /dev/null; then
exit 0
fi
sleep 2
done
echo "Failed to run local appstore at localhost:8080"
exit 1
'

# Clear appstore cache (force re-fetch)
docker exec nextcloud /bin/bash -c "echo '' > /var/www/html/data/appdata_*/appstore/apps.json"

# Disable share rate limit protection
docker exec nextcloud /bin/bash -c "php occ config:system:set ratelimit.protection.enabled --value false --type bool"

# Configure local appstore server
docker exec nextcloud /bin/bash -c "php occ config:system:set appstoreurl --value 'http://localhost:8080'"
docker exec nextcloud /bin/bash -c "php occ config:system:set allow_local_remote_servers --value true"

# Update app
docker exec nextcloud /bin/bash -c "php occ app:update --allow-unstable integration_openproject"

# Verify update
if docker exec nextcloud /bin/bash -c "php occ app:list | grep -q 'integration_openproject.*$NEXT_APP_VERSION'"; then
echo "App updated successfully to version $NEXT_APP_VERSION"
else
echo "App not updated to version $NEXT_APP_VERSION"
exit 1
fi

- name: API Tests
working-directory: integration_openproject
env:
NEXTCLOUD_BASE_URL: http://localhost
run: |
make api-test
5 changes: 5 additions & 0 deletions tests/acceptance/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ 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}}\"", $containers);
if (!in_array('nextcloud', $containers)) {
return;
}

$firstChar = substr($user, 0, 1);
$restChars = substr($user, 1);
Expand Down
Loading