diff --git a/.github/workflows/autocheckers.yml b/.github/workflows/autocheckers.yml index 375ecf0d7dd62..6ebd87f3b6f20 100644 --- a/.github/workflows/autocheckers.yml +++ b/.github/workflows/autocheckers.yml @@ -74,6 +74,9 @@ jobs: autocheckers: runs-on: ubuntu-latest-low + needs: changes + if: needs.changes.outputs.src != 'false' + strategy: matrix: php-versions: ['8.2'] @@ -125,4 +128,4 @@ jobs: steps: - name: Summary status - run: if ${{ needs.autocheckers.result != 'success' || (needs.changes.outputs.src != 'false' && needs.autoloader.result != 'success') }}; then exit 1; fi + run: if ${{ needs.changes.outputs.src != 'false' && (needs.autocheckers.result != 'success' || needs.autoloader.result != 'success') }}; then exit 1; fi diff --git a/.github/workflows/command-pull-3rdparty.yml b/.github/workflows/command-pull-3rdparty.yml index 8a0e7fbc865bf..97ea974ea1a19 100644 --- a/.github/workflows/command-pull-3rdparty.yml +++ b/.github/workflows/command-pull-3rdparty.yml @@ -14,6 +14,7 @@ jobs: runs-on: ubuntu-latest permissions: contents: none + pull-requests: read # On pull requests and if the comment starts with `/update-3rdparty` if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/update-3rdparty') @@ -27,8 +28,25 @@ jobs: comment-id: ${{ github.event.comment.id }} reactions: '+1' + # issue_comment events carry no pull_request context in their payload, so we + # must fetch the PR via the API. This also gives us base.ref for free, avoiding + # a second API call. The GITHUB_TOKEN needs pull-requests:read (granted above). + - name: Get pull request metadata + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + id: get-pr + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const pull = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }); + core.setOutput('head_repo', pull.data.head.repo?.full_name ?? ''); + core.setOutput('base_ref', pull.data.base.ref); + - name: Disabled on forks - if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + if: steps.get-pr.outputs.head_repo != github.repository run: | echo 'Can not execute /update-3rdparty on forks' exit 1 @@ -46,24 +64,17 @@ jobs: ref: ${{ steps.comment-branch.outputs.head_ref }} - name: Register server reference to fallback to master branch - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - script: | - const baseRef = context.payload.pull_request.base.ref - if (baseRef === 'main' || baseRef === 'master') { - core.exportVariable('server_ref', 'master'); - console.log('Setting server_ref to master'); - } else { - const regex = /^stable(\d+)$/ - const match = baseRef.match(regex) - if (match) { - core.exportVariable('server_ref', match[0]); - console.log('Setting server_ref to ' + match[0]); - } else { - console.log('Not based on master/main/stable*, so skipping pull 3rdparty command'); - } - } + run: | + base_ref="${{ steps.get-pr.outputs.base_ref }}" + if [[ "$base_ref" == "main" || "$base_ref" == "master" ]]; then + echo "server_ref=master" >> "$GITHUB_ENV" + echo "Setting server_ref to master" + elif [[ "$base_ref" =~ ^stable[0-9]+$ ]]; then + echo "server_ref=$base_ref" >> "$GITHUB_ENV" + echo "Setting server_ref to $base_ref" + else + echo "Not based on master/main/stable*, so skipping pull 3rdparty command" + fi - name: Setup git run: | diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index dc1730f35a494..d62a121760cda 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -41,12 +41,6 @@ jobs: PUPPETEER_SKIP_DOWNLOAD: true steps: - - name: Disabled on forks - if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} - run: | - echo 'Can not run cypress on forks' - exit 1 - - name: Checkout server uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -176,10 +170,6 @@ jobs: # We already installed the dependencies in the init job install: false component: ${{ matrix.containers == 'component' }} - group: ${{ matrix.use-cypress-cloud && matrix.containers == 'component' && 'Run component' || matrix.use-cypress-cloud && 'Run E2E' || '' }} - # cypress env - ci-build-id: ${{ matrix.use-cypress-cloud && format('{0}-{1}', github.sha, github.run_number) || '' }} - tag: ${{ matrix.use-cypress-cloud && github.event_name || '' }} env: # Needs to be prefixed with CYPRESS_ CYPRESS_BRANCH: ${{ env.BRANCH }} @@ -188,7 +178,6 @@ jobs: # Needed for some specific code workarounds TESTING: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} SPLIT: ${{ matrix.total-containers }} SPLIT_INDEX: ${{ matrix.containers == 'component' && 0 || matrix.containers }} SPLIT_RANDOM_SEED: ${{ github.run_id }} diff --git a/.github/workflows/files-external-sftp.yml b/.github/workflows/files-external-sftp.yml index 9e86a08bfd7a3..97b5873ff4fef 100644 --- a/.github/workflows/files-external-sftp.yml +++ b/.github/workflows/files-external-sftp.yml @@ -73,7 +73,7 @@ jobs: - name: Set up sftpd run: | sudo mkdir /tmp/sftp - sudo chown -R 0777 /tmp/sftp + sudo chmod -R 0777 /tmp/sftp if [[ '${{ matrix.sftpd }}' == 'openssh' ]]; then docker run -p 2222:22 --name sftp -d -v /tmp/sftp:/home/test atmoz/sftp 'test:test:::data'; fi - name: Set up php ${{ matrix.php-versions }} diff --git a/.github/workflows/integration-dav.yml b/.github/workflows/integration-dav.yml index 4939d120487c4..05bacd8cef49c 100644 --- a/.github/workflows/integration-dav.yml +++ b/.github/workflows/integration-dav.yml @@ -52,69 +52,69 @@ jobs: name: ${{ matrix.service }} (${{ matrix.endpoint }} endpoint) php${{ matrix.php-versions }} steps: - - name: Checkout server - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - submodules: true - - - name: Set up php ${{ matrix.php-versions }} - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0 - timeout-minutes: 5 - with: - php-version: ${{ matrix.php-versions }} - # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation - extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite - coverage: 'none' - ini-file: development - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up Python - uses: LizardByte/actions/actions/setup_python@70bb8d394d1c92f6113aeec6ae9cc959a5763d15 # v2026.227.200013 - with: - python-version: '2.7' - - - name: Set up CalDAVTester - run: | - git clone --depth=1 https://github.com/apple/ccs-caldavtester.git CalDAVTester - git clone --depth=1 https://github.com/apple/ccs-pycalendar.git pycalendar - - - name: Set up Nextcloud - run: | - mkdir data - ./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin - # disable the trashbin, so recurrent deletion of the same object works - ./occ config:app:set dav calendarRetentionObligation --value=0 - # Prepare users - OC_PASS=user01 ./occ user:add --password-from-env user01 - OC_PASS=user02 ./occ user:add --password-from-env user02 - # Prepare calendars - ./occ dav:create-calendar user01 calendar - ./occ dav:create-calendar user01 shared - ./occ dav:create-calendar user02 calendar - # Prepare address books - ./occ dav:create-addressbook user01 addressbook - ./occ dav:create-addressbook user02 addressbook - - - name: Run Nextcloud - run: | - php -S localhost:8888 & - - - name: Run CalDAVTester - run: | - cp "apps/dav/tests/testsuits/caldavtest/serverinfo-${{ matrix.endpoint }}${{ matrix.endpoint == 'old' && (matrix.service == 'CardDAV' && '-carddav' || '-caldav') || '' }}-endpoint.xml" "apps/dav/tests/testsuits/caldavtest/serverinfo.xml" - pushd CalDAVTester - PYTHONPATH="../pycalendar/src" python testcaldav.py --print-details-onfail --basedir "../apps/dav/tests/testsuits/caldavtest" -o cdt.txt \ - "${{ matrix.service }}/current-user-principal.xml" \ - "${{ matrix.service }}/sync-report.xml" \ - ${{ matrix.endpoint == 'new' && format('{0}/sharing-{1}.xml', matrix.service, matrix.service == 'CalDAV' && 'calendars' || 'addressbooks') || ';' }} - popd - - - name: Print Nextcloud logs - if: always() - run: | - cat data/nextcloud.log + - name: Checkout server + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + submodules: true + + - name: Set up php ${{ matrix.php-versions }} + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0 + timeout-minutes: 5 + with: + php-version: ${{ matrix.php-versions }} + # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation + extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite + coverage: 'none' + ini-file: development + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: LizardByte/actions/actions/setup_python@70bb8d394d1c92f6113aeec6ae9cc959a5763d15 # v2026.227.200013 + with: + python-version: '2.7' + + - name: Set up CalDAVTester + run: | + git clone --depth=1 https://github.com/apple/ccs-caldavtester.git CalDAVTester + git clone --depth=1 https://github.com/apple/ccs-pycalendar.git pycalendar + + - name: Set up Nextcloud + run: | + mkdir data + ./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin + # disable the trashbin, so recurrent deletion of the same object works + ./occ config:app:set dav calendarRetentionObligation --value=0 + # Prepare users + OC_PASS=user01 ./occ user:add --password-from-env user01 + OC_PASS=user02 ./occ user:add --password-from-env user02 + # Prepare calendars + ./occ dav:create-calendar user01 calendar + ./occ dav:create-calendar user01 shared + ./occ dav:create-calendar user02 calendar + # Prepare address books + ./occ dav:create-addressbook user01 addressbook + ./occ dav:create-addressbook user02 addressbook + + - name: Run Nextcloud + run: | + php -S localhost:8888 & + + - name: Run CalDAVTester + run: | + cp "apps/dav/tests/testsuits/caldavtest/serverinfo-${{ matrix.endpoint }}${{ matrix.endpoint == 'old' && (matrix.service == 'CardDAV' && '-carddav' || '-caldav') || '' }}-endpoint.xml" "apps/dav/tests/testsuits/caldavtest/serverinfo.xml" + pushd CalDAVTester + PYTHONPATH="../pycalendar/src" python testcaldav.py --print-details-onfail --basedir "../apps/dav/tests/testsuits/caldavtest" -o cdt.txt \ + "${{ matrix.service }}/current-user-principal.xml" \ + "${{ matrix.service }}/sync-report.xml" \ + ${{ matrix.endpoint == 'new' && format('{0}/sharing-{1}.xml', matrix.service, matrix.service == 'CalDAV' && 'calendars' || 'addressbooks') || ';' }} + popd + + - name: Print Nextcloud logs + if: always() + run: | + cat data/nextcloud.log caldav-integration-summary: permissions: diff --git a/.github/workflows/integration-s3-primary.yml b/.github/workflows/integration-s3-primary.yml index 7fe880c488919..dac758be560ce 100644 --- a/.github/workflows/integration-s3-primary.yml +++ b/.github/workflows/integration-s3-primary.yml @@ -95,7 +95,6 @@ jobs: - name: Wait for S3 run: | - sleep 10 curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready - name: Set up Nextcloud diff --git a/.github/workflows/lint-php-cs.yml b/.github/workflows/lint-php-cs.yml index c5817919967b7..a3b8ed86b1152 100644 --- a/.github/workflows/lint-php-cs.yml +++ b/.github/workflows/lint-php-cs.yml @@ -44,6 +44,9 @@ jobs: lint: runs-on: ubuntu-latest + needs: changes + if: needs.changes.outputs.src != 'false' + name: php-cs steps: diff --git a/.github/workflows/lint-stylelint.yml b/.github/workflows/lint-stylelint.yml index ce4d6d74d1d9f..1beeba03d7e38 100644 --- a/.github/workflows/lint-stylelint.yml +++ b/.github/workflows/lint-stylelint.yml @@ -18,9 +18,37 @@ concurrency: cancel-in-progress: true jobs: + changes: + runs-on: ubuntu-latest-low + permissions: + contents: read + pull-requests: read + + outputs: + src: ${{ steps.changes.outputs.src }} + + steps: + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + id: changes + continue-on-error: true + with: + filters: | + src: + - '.github/workflows/**' + - '**/src/**' + - '**/appinfo/info.xml' + - 'package.json' + - 'package-lock.json' + - '**.css' + - '**.scss' + - '**.vue' + lint: runs-on: ubuntu-latest + needs: changes + if: needs.changes.outputs.src != 'false' + name: stylelint steps: @@ -51,3 +79,18 @@ jobs: - name: Lint run: npm run stylelint + + summary: + permissions: + contents: none + runs-on: ubuntu-latest-low + needs: [changes, lint] + + if: always() + + # This is the summary, we just avoid to rename it so that branch protection rules still match + name: stylelint + + steps: + - name: Summary status + run: if ${{ needs.changes.outputs.src != 'false' && needs.lint.result != 'success' }}; then exit 1; fi diff --git a/.github/workflows/node-test.yml b/.github/workflows/node-test.yml index bba874c2cf6f5..c8f2ce840cbd1 100644 --- a/.github/workflows/node-test.yml +++ b/.github/workflows/node-test.yml @@ -83,9 +83,6 @@ jobs: run: | npm ci -# - name: Test -# run: npm run test --if-present - - name: Test and process coverage run: npm run test:coverage diff --git a/.github/workflows/object-storage-s3.yml b/.github/workflows/object-storage-s3.yml index 8fb63b002074c..6cfd0e0a552e3 100644 --- a/.github/workflows/object-storage-s3.yml +++ b/.github/workflows/object-storage-s3.yml @@ -111,7 +111,6 @@ jobs: - name: Wait for S3 run: | - sleep 10 curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready - name: PHPUnit diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index abcc463f5d8fd..6d23e493712e9 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -15,7 +15,13 @@ jobs: performance-testing: runs-on: ubuntu-latest - if: ${{ github.repository_owner != 'nextcloud-gmbh' }} + # Skip entirely on fork PRs so the job result is 'skipped' rather than + # 'failure'. The profiler action uses github.event.pull_request.head.repo.clone_url + # and GITHUB_TOKEN in ways that do not work reliably from forks, and a + # clean skip is far less confusing for contributors than a mid-run error. + if: >- + github.repository_owner != 'nextcloud-gmbh' && + github.event.pull_request.head.repo.full_name == github.repository permissions: pull-requests: write @@ -28,11 +34,6 @@ jobs: name: performance-${{ matrix.php-versions }} steps: - - name: Disabled on forks - if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} - run: | - echo 'Can not run performance tests on forks' - exit 1 - name: Checkout server before PR uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.github/workflows/phpunit-object-store-primary.yml b/.github/workflows/phpunit-object-store-primary.yml index 0ea1fbcfba6eb..cffce0dd8ff50 100644 --- a/.github/workflows/phpunit-object-store-primary.yml +++ b/.github/workflows/phpunit-object-store-primary.yml @@ -104,7 +104,7 @@ jobs: curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready - name: PHPUnit - run: composer run test:db + run: composer run test:db -- --log-junit junit.xml - name: S3 logs if: always() diff --git a/.github/workflows/update-min-supported-desktop.yml b/.github/workflows/update-min-supported-desktop.yml index dd65b1af60edc..3413147a6496c 100644 --- a/.github/workflows/update-min-supported-desktop.yml +++ b/.github/workflows/update-min-supported-desktop.yml @@ -115,7 +115,7 @@ jobs: committer: GitHub author: nextcloud-command signoff: true - branch: "automated/noid/${{ matrix.branches }}-update-min-supported-desktop-version" + branch: "automated/noid/update-min-supported-desktop-version" title: "chore: Update minimum supported desktop version to ${{ steps.extract-version.outputs.VERSION }}" base: "master" body: |