|
| 1 | +# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors |
| 2 | +# SPDX-License-Identifier: AGPL-3.0-or-later |
| 3 | + |
| 4 | +name: Migration test |
| 5 | + |
| 6 | +on: |
| 7 | + pull_request: |
| 8 | + branches: |
| 9 | + - main |
| 10 | + - stable* |
| 11 | + |
| 12 | +env: |
| 13 | + APP_NAME: context_chat |
| 14 | + PHP_EXTENSIONS: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite, pgsql, pdo_pgsql, mysql, pdo_mysql, oci8 |
| 15 | + |
| 16 | +permissions: |
| 17 | + contents: read |
| 18 | + |
| 19 | +concurrency: |
| 20 | + group: migration-test-${{ github.head_ref || github.run_id }} |
| 21 | + cancel-in-progress: true |
| 22 | + |
| 23 | +jobs: |
| 24 | + changes: |
| 25 | + runs-on: ubuntu-latest-low |
| 26 | + permissions: |
| 27 | + contents: read |
| 28 | + pull-requests: read |
| 29 | + |
| 30 | + outputs: |
| 31 | + src: ${{ steps.changes.outputs.src }} |
| 32 | + |
| 33 | + steps: |
| 34 | + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 |
| 35 | + id: changes |
| 36 | + continue-on-error: true |
| 37 | + with: |
| 38 | + filters: | |
| 39 | + src: |
| 40 | + - '.github/workflows/migration-test.yml' |
| 41 | + - 'lib/Migration/**' |
| 42 | + - 'lib/Repair/**' |
| 43 | +
|
| 44 | + migration-test: |
| 45 | + runs-on: ubuntu-latest |
| 46 | + |
| 47 | + needs: changes |
| 48 | + if: needs.changes.outputs.src != 'false' |
| 49 | + |
| 50 | + strategy: |
| 51 | + fail-fast: false |
| 52 | + matrix: |
| 53 | + include: |
| 54 | + - db: sqlite |
| 55 | + db-type: sqlite |
| 56 | + db-port: '' |
| 57 | + - db: pgsql |
| 58 | + db-type: pgsql |
| 59 | + db-port: '4445' |
| 60 | + - db: mysql |
| 61 | + db-type: mysql |
| 62 | + db-port: '4444' |
| 63 | + - db: mariadb |
| 64 | + db-type: mysql |
| 65 | + db-port: '4446' |
| 66 | + - db: oci21 |
| 67 | + db-type: oci |
| 68 | + db-port: '1521' |
| 69 | + oci-version: '21' |
| 70 | + oci-flavour: xe |
| 71 | + oci-name: XE |
| 72 | + - db: oci23 |
| 73 | + db-type: oci |
| 74 | + db-port: '1521' |
| 75 | + oci-version: '23' |
| 76 | + oci-flavour: free |
| 77 | + oci-name: FREE |
| 78 | + |
| 79 | + name: Migration test ${{ matrix.db }} |
| 80 | + |
| 81 | + steps: |
| 82 | + - name: Start postgres |
| 83 | + if: matrix.db == 'pgsql' |
| 84 | + run: | |
| 85 | + docker run -d --name db \ |
| 86 | + -e POSTGRES_USER=root \ |
| 87 | + -e POSTGRES_PASSWORD=rootpassword \ |
| 88 | + -e POSTGRES_DB=nextcloud \ |
| 89 | + -p 4445:5432 \ |
| 90 | + postgres:17 # zizmor: ignore[unpinned-images] |
| 91 | + timeout 60 bash -c 'until docker exec db pg_isready -U root; do sleep 1; done' |
| 92 | +
|
| 93 | + - name: Start mysql |
| 94 | + if: matrix.db == 'mysql' |
| 95 | + run: | |
| 96 | + docker run -d --name db \ |
| 97 | + -e MYSQL_ROOT_PASSWORD=rootpassword \ |
| 98 | + -p 4444:3306 \ |
| 99 | + mysql:8.4 # zizmor: ignore[unpinned-images] |
| 100 | + timeout 60 bash -c 'until docker exec db mysqladmin ping -prootpassword --silent; do sleep 1; done' |
| 101 | +
|
| 102 | + - name: Start mariadb |
| 103 | + if: matrix.db == 'mariadb' |
| 104 | + run: | |
| 105 | + docker run -d --name db \ |
| 106 | + -e MARIADB_ROOT_PASSWORD=rootpassword \ |
| 107 | + -p 4446:3306 \ |
| 108 | + mariadb:11.4 # zizmor: ignore[unpinned-images] |
| 109 | + timeout 60 bash -c 'until docker exec db mariadb-admin ping -prootpassword --silent; do sleep 1; done' |
| 110 | +
|
| 111 | + - name: Start oracle |
| 112 | + if: startsWith(matrix.db, 'oci') |
| 113 | + run: | |
| 114 | + docker run -d --name db \ |
| 115 | + -e ORACLE_PASSWORD=oracle \ |
| 116 | + -p 1521:1521 \ |
| 117 | + ghcr.io/gvenzl/oracle-${{ matrix.oci-flavour }}:${{ matrix.oci-version }} # zizmor: ignore[unpinned-images] |
| 118 | + timeout 300 bash -c 'until docker exec db healthcheck.sh; do sleep 5; done' |
| 119 | +
|
| 120 | + - name: Checkout server |
| 121 | + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 |
| 122 | + with: |
| 123 | + repository: nextcloud/server |
| 124 | + ref: ${{ github.base_ref == 'main' && 'master' || github.base_ref }} |
| 125 | + submodules: recursive |
| 126 | + persist-credentials: false |
| 127 | + |
| 128 | + - name: Checkout viewer |
| 129 | + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 |
| 130 | + with: |
| 131 | + repository: nextcloud/viewer |
| 132 | + path: apps/viewer |
| 133 | + ref: ${{ github.base_ref == 'main' && 'master' || github.base_ref }} |
| 134 | + persist-credentials: false |
| 135 | + |
| 136 | + - name: Set up php 8.2 |
| 137 | + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 |
| 138 | + with: |
| 139 | + php-version: '8.2' |
| 140 | + extensions: ${{ env.PHP_EXTENSIONS }} |
| 141 | + coverage: none |
| 142 | + ini-file: development |
| 143 | + ini-values: disable_functions= |
| 144 | + env: |
| 145 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 146 | + |
| 147 | + - name: Checkout app and fetch all tags |
| 148 | + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 |
| 149 | + with: |
| 150 | + repository: nextcloud/${{ env.APP_NAME }} |
| 151 | + path: apps/${{ env.APP_NAME }} |
| 152 | + fetch-depth: 0 |
| 153 | + persist-credentials: false |
| 154 | + |
| 155 | + - name: Switch to previous release tag |
| 156 | + id: prev-tag |
| 157 | + working-directory: apps/${{ env.APP_NAME }} |
| 158 | + run: | |
| 159 | + PREV_TAG=$(git tag --sort=-version:refname | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | head -1) |
| 160 | + if [ -z "$PREV_TAG" ]; then |
| 161 | + echo "No previous release tag found" |
| 162 | + exit 1 |
| 163 | + fi |
| 164 | + echo "tag=${PREV_TAG}" >> $GITHUB_OUTPUT |
| 165 | + git checkout "$PREV_TAG" |
| 166 | +
|
| 167 | + - name: Set up Nextcloud (${{ matrix.db }}) |
| 168 | + run: | |
| 169 | + mkdir -p data |
| 170 | + if [ "${{ matrix.db }}" = "sqlite" ]; then |
| 171 | + ./occ maintenance:install --verbose \ |
| 172 | + --database=sqlite --database-name=nextcloud \ |
| 173 | + --admin-user admin --admin-pass admin |
| 174 | + elif [ "${{ matrix.db-type }}" = "oci" ]; then |
| 175 | + ./occ maintenance:install --verbose \ |
| 176 | + --database=oci \ |
| 177 | + --database-name=${{ matrix.oci-name }} \ |
| 178 | + --database-host=127.0.0.1 \ |
| 179 | + --database-port=${{ matrix.db-port }} \ |
| 180 | + --database-user=system \ |
| 181 | + --database-pass=oracle \ |
| 182 | + --admin-user admin --admin-pass admin |
| 183 | + else |
| 184 | + ./occ maintenance:install --verbose \ |
| 185 | + --database=${{ matrix.db-type }} \ |
| 186 | + --database-name=nextcloud \ |
| 187 | + --database-host=127.0.0.1 \ |
| 188 | + --database-port=${{ matrix.db-port }} \ |
| 189 | + --database-user=root \ |
| 190 | + --database-pass=rootpassword \ |
| 191 | + --admin-user admin --admin-pass admin |
| 192 | + fi |
| 193 | + ./occ config:system:set debug --value true |
| 194 | + ./occ config:system:set loglevel --value 1 |
| 195 | +
|
| 196 | + - name: Enable app (previous version ${{ steps.prev-tag.outputs.tag }}) |
| 197 | + run: ./occ app:enable --force ${{ env.APP_NAME }} |
| 198 | + |
| 199 | + - name: Check if the previous version installed correctly |
| 200 | + run: | |
| 201 | + ./occ status |
| 202 | + ./occ app:list --output json | jq -e '.enabled | has("${{ env.APP_NAME }}")' |
| 203 | + ./occ migrations:status ${{ env.APP_NAME }} |
| 204 | +
|
| 205 | + - name: Dump database before upgrade |
| 206 | + if: always() |
| 207 | + run: | |
| 208 | + if [ "${{ matrix.db }}" = "sqlite" ]; then |
| 209 | + cp data/nextcloud.db /tmp/${{ matrix.db }}_before.db |
| 210 | + elif [ "${{ matrix.db }}" = "pgsql" ]; then |
| 211 | + docker exec db pg_dump -U root nextcloud > /tmp/${{ matrix.db }}_before.sql |
| 212 | + elif [ "${{ matrix.db }}" = "mysql" ] || [ "${{ matrix.db }}" = "mariadb" ]; then |
| 213 | + docker exec db mariadb-dump -uroot -prootpassword nextcloud > /tmp/${{ matrix.db }}_before.sql |
| 214 | + elif [[ "${{ matrix.db }}" == oci* ]]; then |
| 215 | + docker exec db expdp system/oracle@${{ matrix.oci-name }} directory=DATA_PUMP_DIR dumpfile=${{ matrix.db }}_before.dmp logfile=${{ matrix.db }}_before_expdp.log schemas=NEXTCLOUD || true |
| 216 | + docker cp db:/opt/oracle/admin/${{ matrix.oci-name }}/dpdump/${{ matrix.db }}_before.dmp /tmp/ || true |
| 217 | + fi |
| 218 | +
|
| 219 | + - name: Checkout app at PR version |
| 220 | + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 |
| 221 | + with: |
| 222 | + path: apps/${{ env.APP_NAME }} |
| 223 | + persist-credentials: false |
| 224 | + |
| 225 | + - name: Run occ upgrade |
| 226 | + run: ./occ upgrade -vvv |
| 227 | + |
| 228 | + - name: Check if the PR version upgraded correctly |
| 229 | + run: | |
| 230 | + ./occ status |
| 231 | + ./occ app:list --output json | jq -e '.enabled | has("${{ env.APP_NAME }}")' |
| 232 | + ./occ migrations:status ${{ env.APP_NAME }} |
| 233 | +
|
| 234 | + - name: Dump database after upgrade |
| 235 | + if: always() |
| 236 | + run: | |
| 237 | + if [ "${{ matrix.db }}" = "sqlite" ]; then |
| 238 | + cp data/nextcloud.db /tmp/${{ matrix.db }}_after.db |
| 239 | + elif [ "${{ matrix.db }}" = "pgsql" ]; then |
| 240 | + docker exec db pg_dump -U root nextcloud > /tmp/${{ matrix.db }}_after.sql |
| 241 | + elif [ "${{ matrix.db }}" = "mysql" ] || [ "${{ matrix.db }}" = "mariadb" ]; then |
| 242 | + docker exec db mariadb-dump -uroot -prootpassword nextcloud > /tmp/${{ matrix.db }}_after.sql |
| 243 | + elif [[ "${{ matrix.db }}" == oci* ]]; then |
| 244 | + docker exec db expdp system/oracle@${{ matrix.oci-name }} directory=DATA_PUMP_DIR dumpfile=${{ matrix.db }}_after.dmp logfile=${{ matrix.db }}_after_expdp.log schemas=NEXTCLOUD || true |
| 245 | + docker cp db:/opt/oracle/admin/${{ matrix.oci-name }}/dpdump/${{ matrix.db }}_after.dmp /tmp/ || true |
| 246 | + fi |
| 247 | +
|
| 248 | + - name: Upload artifacts |
| 249 | + uses: actions/upload-artifact@v4 |
| 250 | + if: always() |
| 251 | + with: |
| 252 | + name: ${{ matrix.db }}-artifacts |
| 253 | + path: | |
| 254 | + /tmp/${{ matrix.db }}_before.* |
| 255 | + /tmp/${{ matrix.db }}_after.* |
| 256 | + data/nextcloud.log |
| 257 | + data/context_chat.log |
| 258 | + if-no-files-found: ignore |
| 259 | + |
| 260 | + |
| 261 | + summary: |
| 262 | + permissions: |
| 263 | + contents: none |
| 264 | + runs-on: ubuntu-latest-low |
| 265 | + needs: [changes, migration-test] |
| 266 | + |
| 267 | + if: always() |
| 268 | + |
| 269 | + name: migration-test-summary |
| 270 | + |
| 271 | + steps: |
| 272 | + - name: Summary status |
| 273 | + run: if ${{ needs.changes.outputs.src != 'false' && needs.migration-test.result != 'success' }}; then exit 1; fi |
0 commit comments