@@ -1563,14 +1563,177 @@ jobs:
15631563 if : always()
15641564 run : tail -v -n +1 *container.json *.log data/nextcloud.log
15651565
1566+ nc-update-preserves-deploy-options :
1567+ runs-on : ubuntu-22.04
1568+ name : Update preserves deploy options (Docker)
1569+ # Regression test for https://github.com/nextcloud/app_api/issues/808
1570+ # When two or more ExApps have rows in `ex_deploy_options`, the update flow
1571+ # used to drop the target app's env vars because it read the unfiltered
1572+ # options table. This job seeds a stray second row, bumps the skeleton's
1573+ # version via a local info.xml, runs `app_api:app:update`, and asserts the
1574+ # user-provided env vars are still set on the new container.
1575+
1576+ services :
1577+ postgres :
1578+ image : ghcr.io/nextcloud/continuous-integration-postgres-14:latest # zizmor: ignore[unpinned-images]
1579+ ports :
1580+ - 4444:5432/tcp
1581+ env :
1582+ POSTGRES_USER : root
1583+ POSTGRES_PASSWORD : rootpassword
1584+ POSTGRES_DB : nextcloud
1585+ options : --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5
1586+
1587+ steps :
1588+ - name : Set app env
1589+ run : echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
1590+
1591+ - name : Checkout server
1592+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
1593+ with :
1594+ persist-credentials : false
1595+ submodules : true
1596+ repository : nextcloud/server
1597+ ref : master
1598+
1599+ - name : Checkout AppAPI
1600+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
1601+ with :
1602+ persist-credentials : false
1603+ path : apps/${{ env.APP_NAME }}
1604+
1605+ - name : Set up php
1606+ uses : shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
1607+ with :
1608+ php-version : ' 8.3'
1609+ extensions : bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, pgsql, pdo_pgsql
1610+ coverage : none
1611+ ini-file : development
1612+ ini-values :
1613+ apc.enabled=on, apc.enable_cli=on, disable_functions=
1614+ env :
1615+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
1616+
1617+ - name : Check composer file existence
1618+ id : check_composer
1619+ uses : andstor/file-existence-action@558493d6c74bf472d87c84eab196434afc2fa029 # v2
1620+ with :
1621+ files : apps/${{ env.APP_NAME }}/composer.json
1622+
1623+ - name : Set up dependencies
1624+ if : steps.check_composer.outputs.files_exists == 'true'
1625+ working-directory : apps/${{ env.APP_NAME }}
1626+ run : composer i
1627+
1628+ - name : Set up Nextcloud
1629+ env :
1630+ DB_PORT : 4444
1631+ run : |
1632+ mkdir data
1633+ ./occ maintenance:install --verbose --database=pgsql --database-name=nextcloud --database-host=127.0.0.1 \
1634+ --database-port=$DB_PORT --database-user=root --database-pass=rootpassword \
1635+ --admin-user admin --admin-pass admin
1636+ ./occ config:system:set loglevel --value=0 --type=integer
1637+ ./occ config:system:set debug --value=true --type=boolean
1638+ ./occ app:enable --force ${{ env.APP_NAME }}
1639+
1640+ - name : Register daemon & Skeleton v1 with user env vars
1641+ run : |
1642+ PHP_CLI_SERVER_WORKERS=2 php -S 127.0.0.1:8080 &
1643+ ./occ app_api:daemon:register docker_local_sock Docker docker-install http /var/run/docker.sock http://127.0.0.1:8080/index.php
1644+ ./occ app_api:app:register app-skeleton-python docker_local_sock \
1645+ --info-xml https://raw.githubusercontent.com/nextcloud/app-skeleton-python/main/appinfo/info.xml \
1646+ --env='TEST_ENV_2=user_provided_value'
1647+
1648+ - name : Verify env vars on the freshly registered container
1649+ run : |
1650+ docker inspect --format '{{ json .Config.Env }}' nc_app_app-skeleton-python | grep -q 'TEST_ENV_1=0' \
1651+ || { echo "TEST_ENV_1 default missing after register"; exit 1; }
1652+ docker inspect --format '{{ json .Config.Env }}' nc_app_app-skeleton-python | grep -q 'TEST_ENV_2=user_provided_value' \
1653+ || { echo "TEST_ENV_2 user value missing after register"; exit 1; }
1654+
1655+ - name : Seed stray ex_deploy_options row for a second app
1656+ # Without a second appid in the table, the Update.php bug from #808 is
1657+ # latent — formatDeployOptions() with no $appId filter still produces
1658+ # the single app's rows by luck. The `zz_` prefix ensures this stray row
1659+ # iterates AFTER `app-skeleton-python`, so the last-wins flattening
1660+ # actually clobbers the skeleton's env_vars entry.
1661+ run : |
1662+ php -r '
1663+ require "lib/base.php";
1664+ OCP\Server::get(OCP\App\IAppManager::class)->loadApp("app_api");
1665+ $svc = OCP\Server::get(OCA\AppAPI\Service\ExAppDeployOptionsService::class);
1666+ $svc->addExAppDeployOptions("zz_fake_second_app", [
1667+ "environment_variables" => ["UNRELATED_VAR" => ["name" => "UNRELATED_VAR", "value" => "x"]],
1668+ "mounts" => [],
1669+ ]);
1670+ '
1671+
1672+ - name : Build v2 info.xml with bumped version
1673+ # Update.php:153 short-circuits when versions match; bumping to 999.0.0
1674+ # forces the real update path to run without touching the image.
1675+ run : |
1676+ curl -sS https://raw.githubusercontent.com/nextcloud/app-skeleton-python/main/appinfo/info.xml \
1677+ | sed 's#<version>[^<]*</version>#<version>999.0.0</version>#' > /tmp/info-v2.xml
1678+ grep -q '<version>999.0.0</version>' /tmp/info-v2.xml || { echo "version bump failed"; exit 1; }
1679+
1680+ - name : Update ExApp
1681+ run : |
1682+ ./occ app_api:app:update app-skeleton-python --info-xml /tmp/info-v2.xml --wait-finish
1683+
1684+ - name : After update — TEST_ENV_1 default still present
1685+ run : |
1686+ docker inspect --format '{{ json .Config.Env }}' nc_app_app-skeleton-python | grep -q 'TEST_ENV_1=0' \
1687+ || { echo "#808 regression: TEST_ENV_1 lost on update"; exit 1; }
1688+
1689+ - name : After update — TEST_ENV_2 user value still present
1690+ run : |
1691+ docker inspect --format '{{ json .Config.Env }}' nc_app_app-skeleton-python | grep -q 'TEST_ENV_2=user_provided_value' \
1692+ || { echo "#808 regression: user-provided TEST_ENV_2 lost on update"; exit 1; }
1693+
1694+ - name : Save container info & logs
1695+ if : always()
1696+ run : |
1697+ docker inspect nc_app_app-skeleton-python | json_pp > container.json
1698+ docker logs nc_app_app-skeleton-python > container.log 2>&1
1699+
1700+ - name : Unregister Skeleton & Daemon
1701+ run : |
1702+ ./occ app_api:app:unregister app-skeleton-python
1703+ ./occ app_api:daemon:unregister docker_local_sock
1704+
1705+ - name : Upload Container info
1706+ if : always()
1707+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
1708+ with :
1709+ name : nc_update_preserves_deploy_options_container.json
1710+ path : container.json
1711+ if-no-files-found : warn
1712+
1713+ - name : Upload Container logs
1714+ if : always()
1715+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
1716+ with :
1717+ name : nc_update_preserves_deploy_options_container.log
1718+ path : container.log
1719+ if-no-files-found : warn
1720+
1721+ - name : Upload NC logs
1722+ if : always()
1723+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
1724+ with :
1725+ name : nc_update_preserves_deploy_options_nextcloud.log
1726+ path : data/nextcloud.log
1727+ if-no-files-found : warn
1728+
15661729 tests-deploy-success :
15671730 permissions :
15681731 contents : none
15691732 runs-on : ubuntu-22.04
15701733 needs : [nc-host-app-docker, nc-docker-app-docker, nc-docker-dsp-http,
15711734 nc-docker-dsp-https, nc-host-app-docker-redis, nc-host-network-host,
15721735 nc-docker-harp-bridge, nc-docker-harp-bridge-no-tls, nc-host-harp-host,
1573- nc-host-manual-harp-host]
1736+ nc-host-manual-harp-host, nc-update-preserves-deploy-options ]
15741737 name : Tests-Deploy-OK
15751738 steps :
15761739 - run : echo "Tests-Deploy passed successfully"
0 commit comments