Merge branch 'master' into refactor/OC-Server-getRootFolder

Signed-off-by: John Molakvoæ <skjnldsv@users.noreply.github.com>
pull/40123/head
John Molakvoæ 3 months ago committed by GitHub
commit 3f560ae940
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

File diff suppressed because it is too large Load Diff

10
.github/CODEOWNERS vendored

@ -28,7 +28,15 @@
/apps/weather_status/appinfo/info.xml @julien-nc @juliushaertl /apps/weather_status/appinfo/info.xml @julien-nc @juliushaertl
/apps/workflowengine/appinfo/info.xml @blizzz @juliushaertl /apps/workflowengine/appinfo/info.xml @blizzz @juliushaertl
# Frontend expertise
/apps/files/src* @skjnldsv
/apps/files_external/src* @skjnldsv
/apps/files_reminders/src* @skjnldsv
/apps/files_sharing/src/actions* @skjnldsv
/apps/files_trashbin/src* @skjnldsv
# Security team # Security team
/resources/codesigning @mgallien @miaulalala @nickvergessen
/resources/config/ca-bundle.crt @ChristophWurst @miaulalala @nickvergessen /resources/config/ca-bundle.crt @ChristophWurst @miaulalala @nickvergessen
/.drone.yml @nickvergessen /.drone.yml @nickvergessen
@ -43,7 +51,7 @@
/core/routes.php @Altahrim /core/routes.php @Altahrim
# OpenAPI # OpenAPI
openapi.json @provokateurin openapi*.json @provokateurin
ResponseDefinitions.php @provokateurin ResponseDefinitions.php @provokateurin
# Talk team # Talk team

@ -29,6 +29,13 @@ Thanks for wanting to contribute source code to Nextcloud. That's great!
Please read the [Developer Manuals][devmanual] to learn how to create your first application or how to test the Nextcloud code with PHPUnit. Please read the [Developer Manuals][devmanual] to learn how to create your first application or how to test the Nextcloud code with PHPUnit.
### Conventional Commits
Please use [Conventional Commits](https://www.conventionalcommits.org) for your commit messages. This helps maintain clarity and consistency across the project, making it easier to understand changes and automate versioning.
```
feat(files_sharing): allow sharing with contacts
```
### Tests ### Tests
In order to constantly increase the quality of our software we can no longer accept pull request which submit un-tested code. In order to constantly increase the quality of our software we can no longer accept pull request which submit un-tested code.
@ -44,9 +51,9 @@ their contribution under the project's license.
Please read [contribute/developer-certificate-of-origin][dcofile]. Please read [contribute/developer-certificate-of-origin][dcofile].
If you can certify it, then just add a line to every git commit message: If you can certify it, then just add a line to every git commit message:
```` ```
Signed-off-by: Random J Developer <random@developer.example.org> Signed-off-by: Random J Developer <random@developer.example.org>
```` ```
Use your real name (sorry, no pseudonyms or anonymous contributions). Use your real name (sorry, no pseudonyms or anonymous contributions).
If you set your `user.name` and `user.email` git configs, you can sign your If you set your `user.name` and `user.email` git configs, you can sign your

@ -101,10 +101,10 @@ body:
Select PHP engine version serving Nextcloud Server. Select PHP engine version serving Nextcloud Server.
_Describe in the "Additional info" section if you chose "Other"._ _Describe in the "Additional info" section if you chose "Other"._
options: options:
- "PHP 7.4"
- "PHP 8.0" - "PHP 8.0"
- "PHP 8.1" - "PHP 8.1"
- "PHP 8.2" - "PHP 8.2"
- "PHP 8.3"
- "Other" - "Other"
- type: dropdown - type: dropdown
id: webserver id: webserver

@ -14,6 +14,49 @@ updates:
reviewers: reviewers:
- "nextcloud/server-dependabot" - "nextcloud/server-dependabot"
# cs-fixer
- package-ecosystem: composer
directory: "/vendor-bin/cs-fixer"
schedule:
interval: weekly
day: saturday
time: "04:10"
timezone: Europe/Copenhagen
labels:
- "3. to review"
- "feature: dependencies"
reviewers:
- "nextcloud/server-dependabot"
# openapi-extractor
- package-ecosystem: composer
directory: "/vendor-bin/openapi-extractor"
schedule:
interval: weekly
day: saturday
time: "04:20"
timezone: Europe/Brussels
labels:
- "3. to review"
- "feature: dependencies"
reviewers:
- "nextcloud/server-dependabot"
- "provokateurin"
# psalm
- package-ecosystem: composer
directory: "/vendor-bin/psalm"
schedule:
interval: weekly
day: saturday
time: "04:30"
timezone: Europe/Madrid
labels:
- "3. to review"
- "feature: dependencies"
reviewers:
- "nextcloud/server-dependabot"
# Main master npm # Main master npm
- package-ecosystem: npm - package-ecosystem: npm
directory: "/" directory: "/"
@ -64,7 +107,7 @@ updates:
day: saturday day: saturday
time: "03:00" time: "03:00"
timezone: Europe/Paris timezone: Europe/Paris
target-branch: stable25 target-branch: stable26
labels: labels:
- "3. to review" - "3. to review"
- "feature: dependencies" - "feature: dependencies"
@ -84,7 +127,7 @@ updates:
day: saturday day: saturday
time: "03:00" time: "03:00"
timezone: Europe/Paris timezone: Europe/Paris
target-branch: stable26 target-branch: stable27
labels: labels:
- "3. to review" - "3. to review"
- "feature: dependencies" - "feature: dependencies"
@ -104,7 +147,7 @@ updates:
day: saturday day: saturday
time: "03:00" time: "03:00"
timezone: Europe/Paris timezone: Europe/Paris
target-branch: stable27 target-branch: stable28
labels: labels:
- "3. to review" - "3. to review"
- "feature: dependencies" - "feature: dependencies"
@ -125,7 +168,7 @@ updates:
day: saturday day: saturday
time: "03:00" time: "03:00"
timezone: Europe/Paris timezone: Europe/Paris
target-branch: stable25 target-branch: stable26
labels: labels:
- "3. to review" - "3. to review"
- "feature: dependencies" - "feature: dependencies"
@ -143,7 +186,7 @@ updates:
day: saturday day: saturday
time: "03:00" time: "03:00"
timezone: Europe/Paris timezone: Europe/Paris
target-branch: stable26 target-branch: stable27
labels: labels:
- "3. to review" - "3. to review"
- "feature: dependencies" - "feature: dependencies"
@ -161,7 +204,7 @@ updates:
day: saturday day: saturday
time: "03:00" time: "03:00"
timezone: Europe/Paris timezone: Europe/Paris
target-branch: stable27 target-branch: stable28
labels: labels:
- "3. to review" - "3. to review"
- "feature: dependencies" - "feature: dependencies"
@ -176,7 +219,15 @@ updates:
- package-ecosystem: "github-actions" - package-ecosystem: "github-actions"
directory: "/" directory: "/"
schedule: schedule:
interval: weekly interval: monthly
day: saturday
time: "03:00"
timezone: Europe/Paris timezone: Europe/Paris
groups:
github-actions:
patterns:
- "*"
labels:
- "3. to review"
- "feature: dependencies"
reviewers:
- "nextcloud/server-dependabot"

@ -0,0 +1,96 @@
name: Code checkers
on:
pull_request:
permissions:
contents: read
concurrency:
group: autocheckers-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
autocheckers:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.3']
name: PHP checkers
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2
with:
php-version: ${{ matrix.php-versions }}
extensions: ctype, json, mbstring
coverage: none
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Check auto loaders
run: bash ./build/autoloaderchecker.sh
- name: Check translations are JSON decodeable
run: php ./build/translation-checker.php
- name: Check translations do not contain triple dot but ellipsis
run: php ./build/triple-dot-checker.php
- name: Check .htaccess does not contain invalid changes
run: php ./build/htaccess-checker.php
- name: Check that all and only expected files are included
run: php ./build/files-checker.php
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, autocheckers]
if: always()
name: autocheckers-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.autocheckers.result != 'success' }}; then exit 1; fi

@ -20,7 +20,7 @@ jobs:
# Only run on stableXX branches # Only run on stableXX branches
if: startsWith( github.base_ref, 'stable') if: startsWith( github.base_ref, 'stable')
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
steps: steps:
- name: Download updater config - name: Download updater config

@ -22,7 +22,7 @@ jobs:
if: github.event.pull_request.draft == false if: github.event.pull_request.draft == false
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
steps: steps:
- name: Download version.php from ${{ github.base_ref }} - name: Download version.php from ${{ github.base_ref }}

@ -0,0 +1,31 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: Block unconventional commits
on:
pull_request:
types: [opened, ready_for_review, reopened, synchronize]
permissions:
contents: read
concurrency:
group: block-unconventional-commits-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
block-unconventional-commits:
name: Block unconventional commits
runs-on: ubuntu-latest-low
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: webiny/action-conventional-commits@8bc41ff4e7d423d56fa4905f6ff79209a78776c7 # v1.3.0
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -15,15 +15,16 @@ jobs:
arg1: ${{ steps.command.outputs.arg1 }} arg1: ${{ steps.command.outputs.arg1 }}
arg2: ${{ steps.command.outputs.arg2 }} arg2: ${{ steps.command.outputs.arg2 }}
head_ref: ${{ steps.comment-branch.outputs.head_ref }} head_ref: ${{ steps.comment-branch.outputs.head_ref }}
base_ref: ${{ steps.comment-branch.outputs.base_ref }}
steps: steps:
- name: Check actor permission - name: Check actor permission
uses: skjnldsv/check-actor-permission@e591dbfe838300c007028e1219ca82cc26e8d7c5 # v2 uses: skjnldsv/check-actor-permission@69e92a3c4711150929bca9fcf34448c5bf5526e7 # v2
with: with:
require: write require: write
- name: Add reaction on start - name: Add reaction on start
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.1.0 uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}
repository: ${{ github.event.repository.full_name }} repository: ${{ github.event.repository.full_name }}
@ -31,7 +32,7 @@ jobs:
reactions: "+1" reactions: "+1"
- name: Parse command - name: Parse command
uses: skjnldsv/parse-command-comment@7cef1df370a99dfd5bf896d50121390c96785db8 # v2 uses: skjnldsv/parse-command-comment@5c955203c52424151e6d0e58fb9de8a9f6a605a1 # v2
id: command id: command
# Init path depending on which command is run # Init path depending on which command is run
@ -39,9 +40,9 @@ jobs:
id: git-path id: git-path
run: | run: |
if ${{ startsWith(steps.command.outputs.arg1, '/') }}; then if ${{ startsWith(steps.command.outputs.arg1, '/') }}; then
echo "path=${{ github.workspace }}${{steps.command.outputs.arg1}}" >> $GITHUB_OUTPUT echo "path=${{steps.command.outputs.arg1}}" >> $GITHUB_OUTPUT
else else
echo "path=${{ github.workspace }}${{steps.command.outputs.arg2}}" >> $GITHUB_OUTPUT echo "path=${{steps.command.outputs.arg2}}" >> $GITHUB_OUTPUT
fi fi
- name: Init branch - name: Init branch
@ -54,13 +55,13 @@ jobs:
steps: steps:
- name: Restore cached git repository - name: Restore cached git repository
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 uses: buildjet/cache@e376f15c6ec6dc595375c78633174c7e5f92dc0e # v3
with: with:
path: .git path: .git
key: git-repo key: git-repo
- name: Checkout ${{ needs.init.outputs.head_ref }} - name: Checkout ${{ needs.init.outputs.head_ref }}
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3.6.0 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}
fetch-depth: 0 fetch-depth: 0
@ -76,16 +77,22 @@ jobs:
id: package-engines-versions id: package-engines-versions
with: with:
fallbackNode: '^20' fallbackNode: '^20'
fallbackNpm: '^9' fallbackNpm: '^10'
- name: Set up node ${{ steps.package-engines-versions.outputs.nodeVersion }} - name: Set up node ${{ steps.package-engines-versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v3
with: with:
node-version: ${{ steps.package-engines-versions.outputs.nodeVersion }} node-version: ${{ steps.package-engines-versions.outputs.nodeVersion }}
cache: npm cache: npm
- name: Set up npm ${{ steps.package-engines-versions.outputs.npmVersion }} - name: Set up npm ${{ steps.package-engines-versions.outputs.npmVersion }}
run: npm i -g npm@"${{ steps.package-engines-versions.outputs.npmVersion }}" run: npm i -g npm@"${{ steps.package-engines-versions.outputs.npmVersion }}"
- name: Rebase to ${{ needs.init.outputs.base_ref }}
if: ${{ contains(needs.init.outputs.arg1, 'rebase') }}
run: |
git fetch origin ${{ needs.init.outputs.base_ref }}:${{ needs.init.outputs.base_ref }}
git rebase origin/${{ needs.init.outputs.base_ref }}
- name: Install dependencies & build - name: Install dependencies & build
env: env:
@ -95,29 +102,36 @@ jobs:
npm ci npm ci
npm run build --if-present npm run build --if-present
- name: Commit and push default - name: Commit default
if: ${{ needs.init.outputs.arg1 != 'fixup' && needs.init.outputs.arg1 != 'amend' }} if: ${{ !contains(needs.init.outputs.arg1, 'fixup') && !contains(needs.init.outputs.arg1, 'amend') }}
run: | run: |
git add ${{ needs.init.outputs.git_path }} git add ${{ github.workspace }}${{ needs.init.outputs.git_path }}
git commit --signoff -m 'chore(assets): Recompile assets' git commit --signoff -m 'chore(assets): Recompile assets'
git push origin ${{ needs.init.outputs.head_ref }}
- name: Commit fixup
- name: Commit and push fixup if: ${{ contains(needs.init.outputs.arg1, 'fixup') }}
if: ${{ needs.init.outputs.arg1 == 'fixup' }}
run: | run: |
git add ${{ needs.init.outputs.git_path }} git add ${{ github.workspace }}${{ needs.init.outputs.git_path }}
git commit --fixup=HEAD --signoff git commit --fixup=HEAD --signoff
git push origin ${{ needs.init.outputs.head_ref }}
- name: Commit and push amend - name: Commit amend
if: ${{ needs.init.outputs.arg1 == 'amend' }} if: ${{ contains(needs.init.outputs.arg1, 'amend') }}
run: | run: |
git add ${{ needs.init.outputs.git_path }} git add ${{ github.workspace }}${{ needs.init.outputs.git_path }}
git commit --amend --no-edit --signoff git commit --amend --no-edit --signoff
git push --force origin ${{ needs.init.outputs.head_ref }} # Remove any [skip ci] from the amended commit
git commit --amend -m "$(git log -1 --format='%B' | sed '/\[skip ci\]/d')"
- name: Push normally
if: ${{ !contains(needs.init.outputs.arg1, 'rebase') && !contains(needs.init.outputs.arg1, 'amend') }}
run: git push origin ${{ needs.init.outputs.head_ref }}
- name: Force push
if: ${{ contains(needs.init.outputs.arg1, 'rebase') || contains(needs.init.outputs.arg1, 'amend') }}
run: git push --force origin ${{ needs.init.outputs.head_ref }}
- name: Add reaction on failure - name: Add reaction on failure
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.1.0 uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
if: failure() if: failure()
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}

@ -18,7 +18,7 @@ jobs:
steps: steps:
- name: Add reaction on start - name: Add reaction on start
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.0.1 uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v3.0.1
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}
repository: ${{ github.event.repository.full_name }} repository: ${{ github.event.repository.full_name }}
@ -51,7 +51,7 @@ jobs:
git push git push
- name: Add reaction on failure - name: Add reaction on failure
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.0.1 uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v3.0.1
if: failure() if: failure()
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}

@ -23,7 +23,7 @@ jobs:
steps: steps:
- name: Add reaction on start - name: Add reaction on start
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.0.1 uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v3.0.1
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}
repository: ${{ github.event.repository.full_name }} repository: ${{ github.event.repository.full_name }}
@ -42,7 +42,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }} GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }}
- name: Add reaction on failure - name: Add reaction on failure
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3.0.1 uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v3.0.1
if: failure() if: failure()
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}

@ -31,7 +31,7 @@ jobs:
- name: Check composer.json - name: Check composer.json
id: check_composer id: check_composer
uses: andstor/file-existence-action@20b4d2e596410855db8f9ca21e96fbe18e12930b # v2 uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v2
with: with:
files: "composer.json" files: "composer.json"
@ -47,7 +47,7 @@ jobs:
fallbackNpm: "^9" fallbackNpm: "^9"
- name: Set up node ${{ steps.versions.outputs.nodeVersion }} - name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with: with:
node-version: ${{ steps.versions.outputs.nodeVersion }} node-version: ${{ steps.versions.outputs.nodeVersion }}
@ -77,10 +77,10 @@ jobs:
matrix: matrix:
# Run multiple copies of the current job in parallel # Run multiple copies of the current job in parallel
# Please increase the number or runners as your tests suite grows (0 based index for e2e tests) # Please increase the number or runners as your tests suite grows (0 based index for e2e tests)
containers: ["component", 0, 1, 2] containers: ["component", 0, 1, 2, 3, 4, 5]
# Hack as strategy.job-total includes the component and GitHub does not allow math expressions # Hack as strategy.job-total includes the component and GitHub does not allow math expressions
# Always aling this number with the total of e2e runners (max. index + 1) # Always aling this number with the total of e2e runners (max. index + 1)
total-containers: [3] total-containers: [6]
name: runner ${{ matrix.containers }} name: runner ${{ matrix.containers }}
@ -93,7 +93,7 @@ jobs:
path: ./ path: ./
- name: Set up node ${{ needs.init.outputs.nodeVersion }} - name: Set up node ${{ needs.init.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with: with:
node-version: ${{ needs.init.outputs.nodeVersion }} node-version: ${{ needs.init.outputs.nodeVersion }}
@ -101,7 +101,7 @@ jobs:
run: npm i -g npm@"${{ needs.init.outputs.npmVersion }}" run: npm i -g npm@"${{ needs.init.outputs.npmVersion }}"
- name: Run ${{ matrix.containers == 'component' && 'component' || 'E2E' }} cypress tests - name: Run ${{ matrix.containers == 'component' && 'component' || 'E2E' }} cypress tests
uses: cypress-io/github-action@ebe8b24c4428922d0f793a5c4c96853a633180e3 # v6.6.0 uses: cypress-io/github-action@1b70233146622b69e789ccdd4f9452adc638d25a # v6.6.1
with: with:
component: ${{ matrix.containers == 'component' }} component: ${{ matrix.containers == 'component' }}
group: ${{ matrix.use-cypress-cloud && matrix.containers == 'component' && 'Run component' || matrix.use-cypress-cloud && 'Run E2E' || '' }} group: ${{ matrix.use-cypress-cloud && matrix.containers == 'component' && 'Run component' || matrix.use-cypress-cloud && 'Run E2E' || '' }}
@ -121,7 +121,7 @@ jobs:
SPLIT_INDEX: ${{ matrix.containers == 'component' && 0 || matrix.containers }} SPLIT_INDEX: ${{ matrix.containers == 'component' && 0 || matrix.containers }}
- name: Upload snapshots - name: Upload snapshots
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
if: always() if: always()
with: with:
name: snapshots_${{ matrix.containers }} name: snapshots_${{ matrix.containers }}
@ -132,7 +132,7 @@ jobs:
run: docker logs nextcloud-cypress-tests-${{ env.APP_NAME }} > nextcloud.log run: docker logs nextcloud-cypress-tests-${{ env.APP_NAME }} > nextcloud.log
- name: Upload NC logs - name: Upload NC logs
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
if: failure() && matrix.containers != 'component' if: failure() && matrix.containers != 'component'
with: with:
name: nc_logs_${{ matrix.containers }} name: nc_logs_${{ matrix.containers }}
@ -143,14 +143,14 @@ jobs:
run: docker exec nextcloud-cypress-tests-server tar -cvjf - data > data.tar run: docker exec nextcloud-cypress-tests-server tar -cvjf - data > data.tar
- name: Upload data dir archive - name: Upload data dir archive
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
if: failure() && matrix.containers != 'component' if: failure() && matrix.containers != 'component'
with: with:
name: nc_data_${{ matrix.containers }} name: nc_data_${{ matrix.containers }}
path: data.tar path: data.tar
summary: summary:
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
needs: [init, cypress] needs: [init, cypress]
if: always() if: always()

@ -22,7 +22,7 @@ concurrency:
jobs: jobs:
auto-approve-merge: auto-approve-merge:
if: github.actor == 'dependabot[bot]' if: github.actor == 'dependabot[bot]'
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
permissions: permissions:
# for hmarr/auto-approve-action to approve PRs # for hmarr/auto-approve-action to approve PRs
pull-requests: write pull-requests: write

@ -1,29 +1,51 @@
name: FTP unit tests name: PHPUnit files_external FTP
on: on:
pull_request: pull_request:
paths: schedule:
- '.github/**' - cron: "5 2 * * *"
- 'apps/files_external/**'
concurrency: concurrency:
group: ftp-${{ github.head_ref || github.run_id }} group: files-external-ftp-${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
env:
APP_NAME: files_external
jobs: jobs:
ftp-tests: changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-ftp:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' }} if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy: strategy:
# do not stop on another job's failure # do not stop on another job's failure
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: ['8.0'] php-versions: ['8.0', '8.3']
ftpd: ['proftpd', 'vsftpd', 'pure-ftpd'] ftpd: ['proftpd', 'vsftpd', 'pure-ftpd']
include:
- php-versions: '8.0'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-${{ matrix.ftpd }} name: php${{ matrix.php-versions }}-${{ matrix.ftpd }}
@ -42,11 +64,14 @@ jobs:
if [[ "${{ matrix.ftpd }}" == 'proftpd' ]]; then docker run --name ftp -d --net host -e PASV_ADDRESS=127.0.0.1 -e FTPUSER_NAME=test -v /tmp/secret.txt:/run/secrets/ftp-user-password-secret -v /tmp/ftp:/home/test instantlinux/proftpd; fi if [[ "${{ matrix.ftpd }}" == 'proftpd' ]]; then docker run --name ftp -d --net host -e PASV_ADDRESS=127.0.0.1 -e FTPUSER_NAME=test -v /tmp/secret.txt:/run/secrets/ftp-user-password-secret -v /tmp/ftp:/home/test instantlinux/proftpd; fi
if [[ "${{ matrix.ftpd }}" == 'vsftpd' ]]; then docker run --name ftp -d --net host -e FTP_USER=test -e FTP_PASS=test -e PASV_ADDRESS=127.0.0.1 -v /tmp/ftp:/home/vsftpd/test fauria/vsftpd; fi if [[ "${{ matrix.ftpd }}" == 'vsftpd' ]]; then docker run --name ftp -d --net host -e FTP_USER=test -e FTP_PASS=test -e PASV_ADDRESS=127.0.0.1 -v /tmp/ftp:/home/vsftpd/test fauria/vsftpd; fi
if [[ "${{ matrix.ftpd }}" == 'pure-ftpd' ]]; then docker run --name ftp -d --net host -e "PUBLICHOST=localhost" -e FTP_USER_NAME=test -e FTP_USER_PASS=test -e FTP_USER_HOME=/home/test -v /tmp/ftp:/home/test -v /tmp/ftp:/etc/pure-ftpd/passwd stilliard/pure-ftpd; fi if [[ "${{ matrix.ftpd }}" == 'pure-ftpd' ]]; then docker run --name ftp -d --net host -e "PUBLICHOST=localhost" -e FTP_USER_NAME=test -e FTP_USER_PASS=test -e FTP_USER_HOME=/home/test -v /tmp/ftp:/home/test -v /tmp/ftp:/etc/pure-ftpd/passwd stilliard/pure-ftpd; fi
- name: Set up php ${{ matrix.php-versions }} - name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2 uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with: with:
php-version: ${{ matrix.php-versions }} php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -55,8 +80,9 @@ jobs:
composer install composer install
mkdir data 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 password ./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 password
./occ app:enable --force ${{ env.APP_NAME }} ./occ app:enable --force files_external
php -S localhost:8080 & echo "<?php return ['run' => true,'host' => 'localhost','user' => 'test','password' => 'test', 'root' => '${{ env.FTP_ROOT }}'];" > apps/files_external/tests/config.ftp.php
- name: smoketest ftp - name: smoketest ftp
run: | run: |
php -r 'var_dump(file_put_contents("ftp://test:test@localhost${{ env.FTP_ROOT }}/ftp.txt", "asd"));' php -r 'var_dump(file_put_contents("ftp://test:test@localhost${{ env.FTP_ROOT }}/ftp.txt", "asd"));'
@ -64,21 +90,30 @@ jobs:
php -r 'var_dump(mkdir("ftp://test:test@localhost${{ env.FTP_ROOT }}/asdads"));' php -r 'var_dump(mkdir("ftp://test:test@localhost${{ env.FTP_ROOT }}/asdads"));'
ls -l /tmp/ftp ls -l /tmp/ftp
[ -f /tmp/ftp/ftp.txt ] [ -f /tmp/ftp/ftp.txt ]
- name: PHPUnit - name: PHPUnit
run: | run: composer run test:files_external -- \
echo "<?php return ['run' => true,'host' => 'localhost','user' => 'test','password' => 'test', 'root' => '${{ env.FTP_ROOT }}'];" > apps/${{ env.APP_NAME }}/tests/config.ftp.php apps/files_external/tests/Storage/FtpTest.php \
composer run test:files_external apps/files_external/tests/Storage/FtpTest.php ${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.xml
flags: phpunit-files-external-ftp
- name: ftpd logs - name: ftpd logs
if: always() if: always()
run: | run: |
docker logs ftp docker logs ftp
ftp-summary: ftp-summary:
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
needs: ftp-tests needs: [changes, files-external-ftp]
if: always() if: always()
steps: steps:
- name: Summary status - name: Summary status
run: if ${{ needs.ftp-tests.result != 'success' }}; then exit 1; fi run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-ftp.result != 'success' }}; then exit 1; fi

@ -0,0 +1,185 @@
name: PHPUnit files_external S3
on:
pull_request:
schedule:
- cron: "5 2 * * *"
concurrency:
group: files-external-s3-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-s3-minio:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-s3
services:
minio:
image: bitnami/minio
env:
MINIO_ROOT_USER: nextcloud
MINIO_ROOT_PASSWORD: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
MINIO_DEFAULT_BUCKETS: nextcloud
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
run: |
composer install
./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 password
./occ app:enable --force files_external
echo "<?php return ['run' => true, 'secret' => 'actually-not-secret', 'passwordsalt' => 'actually-not-secret', 'hostname' => 'localhost','key' => '$OBJECT_STORE_KEY','secret' => '$OBJECT_STORE_SECRET', 'bucket' => 'bucket', 'port' => 9000, 'use_ssl' => false, 'autocreate' => true, 'use_path_style' => true];" > apps/files_external/tests/config.amazons3.php
- 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
run: composer run test:files_external -- \
apps/files_external/tests/Storage/Amazons3Test.php \
apps/files_external/tests/Storage/VersionedAmazonS3Test.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.xml
flags: phpunit-files-external-s3
- name: S3 logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
files-external-s3-localstack:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: true
name: php${{ matrix.php-versions }}-s3
services:
localstack:
env:
SERVICES: s3
DEBUG: 1
image: localstack/localstack
ports:
- "4566:4566"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
./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 password
./occ app:enable --force files_external
echo "<?php return ['run' => true,'hostname' => 'localhost','key' => 'ignored','secret' => 'ignored', 'bucket' => 'bucket', 'port' => 4566, 'use_ssl' => false, 'autocreate' => true, 'use_path_style' => true];" > apps/files_external/tests/config.amazons3.php
- name: PHPUnit
run: composer run test:files_external -- \
apps/files_external/tests/Storage/Amazons3Test.php \
apps/files_external/tests/Storage/VersionedAmazonS3Test.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.xml
flags: phpunit-files-external-s3
- name: S3 logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
s3-external-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-s3-minio, files-external-s3-localstack]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-s3-minio.result != 'success' && needs.files-external-s3-localstack.result != 'success' }}; then exit 1; fi

@ -0,0 +1,109 @@
name: PHPUnit files_external sFTP
on:
pull_request:
schedule:
- cron: "5 2 * * *"
concurrency:
group: files-external-sftp-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-sftp:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0', '8.3']
sftpd: ['openssh']
include:
- php-versions: '8.0'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-${{ matrix.sftpd }}
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up sftpd
run: |
sudo mkdir /tmp/sftp
sudo chown -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 }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
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 password
./occ app:enable --force files_external
echo "<?php return ['run' => true, 'host' => 'localhost:2222','user' => 'test','password' => 'test', 'root' => 'data'];" > apps/files_external/tests/config.sftp.php
- name: PHPUnit
run: composer run test:files_external -- \
apps/files_external/tests/Storage/SftpTest.php \
apps/files_external/tests/Storage/SFTP_KeyTest.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.xml
flags: phpunit-files-external-sftp
- name: sftpd logs
if: always()
run: |
ls -l /tmp/sftp
docker logs sftp
sftp-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-sftp]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-sftp.result != 'success' }}; then exit 1; fi

@ -1,19 +1,41 @@
name: Samba Kerberos SSO name: Samba Kerberos SSO
on: on:
pull_request: pull_request:
paths: schedule:
- 'apps/files_external/**' - cron: "5 2 * * *"
- '.github/workflows/smb-kerberos.yml'
concurrency: concurrency:
group: smb-kerberos-${{ github.head_ref || github.run_id }} group: files-external-smb-kerberos-${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
smb-kerberos-tests: changes:
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
if: ${{ github.repository_owner != 'nextcloud-gmbh' }} outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-smb-kerberos:
runs-on: ubuntu-22.04
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
name: smb-kerberos-sso name: smb-kerberos-sso
@ -22,11 +44,13 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with: with:
submodules: true submodules: true
- name: Checkout user_saml - name: Checkout user_saml
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with: with:
repository: nextcloud/user_saml repository: nextcloud/user_saml
path: apps/user_saml path: apps/user_saml
- name: Pull images - name: Pull images
run: | run: |
docker pull ghcr.io/icewind1991/samba-krb-test-dc docker pull ghcr.io/icewind1991/samba-krb-test-dc
@ -35,21 +59,35 @@ jobs:
docker tag ghcr.io/icewind1991/samba-krb-test-dc icewind1991/samba-krb-test-dc docker tag ghcr.io/icewind1991/samba-krb-test-dc icewind1991/samba-krb-test-dc
docker tag ghcr.io/icewind1991/samba-krb-test-apache icewind1991/samba-krb-test-apache docker tag ghcr.io/icewind1991/samba-krb-test-apache icewind1991/samba-krb-test-apache
docker tag ghcr.io/icewind1991/samba-krb-test-client icewind1991/samba-krb-test-client docker tag ghcr.io/icewind1991/samba-krb-test-client icewind1991/samba-krb-test-client
- name: Setup AD-DC - name: Setup AD-DC
run: | run: |
DC_IP=$(apps/files_external/tests/sso-setup/start-dc.sh) DC_IP=$(apps/files_external/tests/sso-setup/start-dc.sh)
sleep 1 sleep 1
apps/files_external/tests/sso-setup/start-apache.sh $DC_IP $PWD apps/files_external/tests/sso-setup/start-apache.sh $DC_IP $PWD
echo "DC_IP=$DC_IP" >> $GITHUB_ENV echo "DC_IP=$DC_IP" >> $GITHUB_ENV
- name: Set up Nextcloud - name: Set up Nextcloud
run: | run: |
apps/files_external/tests/sso-setup/setup-sso-nc.sh apps/files_external/tests/sso-setup/setup-sso-nc.sh
- name: Test SSO - name: Test SSO
run: | run: |
apps/files_external/tests/sso-setup/test-sso-smb.sh ${{ env.DC_IP }} apps/files_external/tests/sso-setup/test-sso-smb.sh ${{ env.DC_IP }}
- name: Show logs - name: Show logs
if: failure() if: always()
run: | run: |
FILEPATH=$(docker exec --user 33 apache ./occ log:file | grep "Log file:" | cut -d' ' -f3) FILEPATH=$(docker exec --user 33 apache ./occ log:file | grep "Log file:" | cut -d' ' -f3)
echo "$FILEPATH:" echo "$FILEPATH:"
docker exec --user 33 apache cat $FILEPATH docker exec --user 33 apache cat $FILEPATH
sftp-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-smb-kerberos]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-smb-kerberos.result != 'success' }}; then exit 1; fi

@ -0,0 +1,108 @@
name: PHPUnit files_external SMB
on:
pull_request:
schedule:
- cron: "5 2 * * *"
concurrency:
group: files-external-smb-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-smb:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.3']
include:
- php-versions: '8.0'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-smb
services:
samba:
image: ghcr.io/nextcloud/continuous-integration-samba:latest
ports:
- 445:445
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, smbclient, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up smbclient
# This is needed as icewind/smb php library for notify
run: sudo apt-get install -y smbclient
- name: Set up Nextcloud
run: |
composer install
./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 password
./occ config:system:set --value true --type boolean allow_local_remote_servers
./occ app:enable --force files_external
echo "<?php return ['run'=>true, 'host'=>'localhost', 'user'=>'test', 'password'=>'test', 'root'=>'', 'share'=>'public'];" > apps/files_external/tests/config.smb.php
- name: Wait for smb
run: |
apps/files_external/tests/env/wait-for-connection 127.0.0.1 445 60
- name: PHPUnit
run: composer run test:files_external -- --verbose \
apps/files_external/tests/Storage/SmbTest.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@4fe8c5f003fae66aa5ebb77cfd3e7bfbbda0b6b0 # v3.1.5
with:
files: ./clover.xml
flags: phpunit-files-external-smb
files-external-smb-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-smb]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-smb.result != 'success' }}; then exit 1; fi

@ -0,0 +1,105 @@
name: PHPUnit files_external WebDAV
on:
pull_request:
schedule:
- cron: "5 2 * * *"
concurrency:
group: files-external-webdav-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
files-external-webdav-apache:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-webdav
services:
apache:
image: ghcr.io/nextcloud/continuous-integration-webdav-apache:latest
ports:
- 8081:80
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
./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 password
./occ config:system:set --value true --type boolean allow_local_remote_servers
./occ app:enable --force files_external
echo "<?php return ['run' => true, 'host' => 'localhost:8081/webdav/', 'user' => 'test', 'password'=>'pass', 'root' => '', 'wait' => 0];" > apps/files_external/tests/config.webdav.php
- name: Wait for WebDAV
run: |
sleep 5
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://test:pass@localhost:8081/webdav/
- name: PHPUnit
run: composer run test:files_external -- --verbose \
apps/files_external/tests/Storage/WebdavTest.php \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@ab904c41d6ece82784817410c45d8b8c02684457 # v3.1.6
with:
files: ./clover.xml
flags: phpunit-files-external-webdav
files-external-webdav-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-webdav-apache]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-webdav-apache.result != 'success' }}; then exit 1; fi

@ -0,0 +1,93 @@
name: PHPUnit files_external generic
on:
pull_request:
schedule:
- cron: "5 2 * * *"
concurrency:
group: files-external-generic-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- 'apps/files_external/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
files-external-generic:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
name: php${{ matrix.php-versions }}-generic
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
run: |
composer install
./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 password
./occ app:enable --force files_external
- name: PHPUnit
run: composer run test:files_external \
${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.xml
flags: phpunit-files-external-generic
files-external-summary:
runs-on: ubuntu-latest-low
needs: [changes, files-external-generic ]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.files-external-generic.result != 'success' }}; then exit 1; fi

@ -24,7 +24,7 @@ jobs:
pull-requests: write pull-requests: write
name: Block fixup and squash commits name: Block fixup and squash commits
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
steps: steps:
- name: Run check - name: Run check

@ -0,0 +1,117 @@
name: S3 primary storage integration tests
on:
pull_request:
concurrency:
group: integration-s3-primary-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/*.php'
- '**/lib/**'
- '**/tests/**'
- '**/vendor-bin/**'
- 'build/integration/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
integration-s3-primary:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false' && github.repository_owner != 'nextcloud-gmbh'
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
key: ['objectstore', 'objectstore_multibucket']
name: php${{ matrix.php-versions }}-${{ matrix.key }}-minio
services:
redis:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
ports:
- 6379:6379/tcp
minio:
image: bitnami/minio
env:
MINIO_ROOT_USER: nextcloud
MINIO_ROOT_PASSWORD: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
MINIO_DEFAULT_BUCKETS: nextcloud
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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: 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
run: |
mkdir data
echo '<?php $CONFIG=["${{ matrix.key }}" => ["class" => "OC\Files\ObjectStore\S3", "arguments" => ["bucket" => "nextcloud", "autocreate" => true, "key" => "nextcloud", "secret" => "bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=", "hostname" => "localhost", "port" => 9000, "use_ssl" => false, "use_path_style" => true, "uploadPartSize" => 52428800]]];' > config/config.php
echo '<?php $CONFIG=["redis" => ["host" => "localhost", "port" => 6379], "memcache.local" => "\OC\Memcache\Redis", "memcache.distributed" => "\OC\Memcache\Redis"];' > config/redis.config.php
./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
php -f index.php
- name: Integration
run: |
cd build/integration
bash run.sh --tags "~@failure-s3" dav_features/webdav-related.feature
- name: S3 logs
if: always()
run: |
cat data/nextcloud.log
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
s3-primary-integration-summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, integration-s3-primary]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.integration-s3-primary.result != 'success' }}; then exit 1; fi

@ -0,0 +1,166 @@
name: Integration sqlite
on:
pull_request:
push:
branches:
- main
- master
- stable*
permissions:
contents: read
concurrency:
group: integration-sqlite-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/*.php'
- '**/lib/**'
- '**/tests/**'
- '**/vendor-bin/**'
- 'build/integration/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
integration-sqlite:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
fail-fast: false
matrix:
test-suite:
- 'capabilities_features'
- 'collaboration_features'
- 'comments_features'
- 'dav_features'
- 'features'
- 'federation_features'
- '--tags ~@large files_features'
- 'filesdrop_features'
- 'openldap_features'
- 'openldap_numerical_features'
- 'ldap_features'
- 'remoteapi_features'
- 'setup_features'
- 'sharees_features'
- 'sharing_features'
- 'videoverification_features'
php-versions: ['8.2']
spreed-versions: ['main']
services:
redis:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
ports:
- 6379:6379/tcp
openldap:
image: ghcr.io/nextcloud/continuous-integration-openldap:openldap-7
ports:
- 389:389
env:
SLAPD_DOMAIN: nextcloud.ci
SLAPD_ORGANIZATION: Nextcloud
SLAPD_PASSWORD: admin
SLAPD_ADDITIONAL_MODULES: memberof
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
submodules: true
- name: Checkout Talk app
if: ${{ matrix.test-suite == 'videoverification_features' }}
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
repository: nextcloud/spreed
path: apps/spreed
ref: ${{ matrix.spreed-versions }}
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d # v2
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, imagick, intl, json, ldap, 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 production dependencies
run: composer i --no-dev
- name: Set up behat dependencies
working-directory: build/integration
run: composer i
- name: Set up Talk dependencies
if: ${{ matrix.test-suite == 'videoverification_features' }}
working-directory: apps/spreed
run: composer i --no-dev
- name: Set up Nextcloud
run: |
mkdir data
./occ maintenance:install --verbose ${{ contains(matrix.test-suite,'ldap') && '--data-dir=/dev/shm/nc_int' || '' }} --database=sqlite --database-name=nextcloud --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
./occ config:system:set hashing_default_password --value=true --type=boolean
- name: Configure caching
if: ${{ contains(matrix.test-suite,'ldap') }}
run: |
./occ config:system:set redis host --value=localhost
./occ config:system:set redis port --value=6379 --type=integer
./occ config:system:set redis timeout --value=0 --type=integer
./occ config:system:set memcache.local --value='\OC\Memcache\Redis'
./occ config:system:set memcache.distributed --value='\OC\Memcache\Redis'
- name: Run integration
working-directory: build/integration
env:
LDAP_HOST: localhost
run: bash run.sh ${{ matrix.test-suite }} no-tail-log
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, integration-sqlite]
if: always()
name: integration-sqlite-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.integration-sqlite.result != 'success' }}; then exit 1; fi

@ -20,13 +20,13 @@ concurrency:
jobs: jobs:
changes: changes:
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
outputs: outputs:
src: ${{ steps.changes.outputs.src}} src: ${{ steps.changes.outputs.src}}
steps: steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 - uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes id: changes
continue-on-error: true continue-on-error: true
with: with:
@ -64,7 +64,7 @@ jobs:
fallbackNpm: '^9' fallbackNpm: '^9'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }} - name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with: with:
node-version: ${{ steps.versions.outputs.nodeVersion }} node-version: ${{ steps.versions.outputs.nodeVersion }}
@ -83,7 +83,7 @@ jobs:
summary: summary:
permissions: permissions:
contents: none contents: none
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
needs: [changes, lint] needs: [changes, lint]
if: always() if: always()

@ -16,13 +16,13 @@ concurrency:
jobs: jobs:
changes: changes:
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
outputs: outputs:
src: ${{ steps.changes.outputs.src}} src: ${{ steps.changes.outputs.src}}
steps: steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 - uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes id: changes
continue-on-error: true continue-on-error: true
with: with:
@ -65,7 +65,7 @@ jobs:
summary: summary:
permissions: permissions:
contents: none contents: none
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
needs: [changes, lint] needs: [changes, lint]
if: always() if: always()

@ -17,13 +17,13 @@ concurrency:
jobs: jobs:
changes: changes:
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
outputs: outputs:
src: ${{ steps.changes.outputs.src}} src: ${{ steps.changes.outputs.src}}
steps: steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 - uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes id: changes
continue-on-error: true continue-on-error: true
with: with:
@ -70,7 +70,7 @@ jobs:
summary: summary:
permissions: permissions:
contents: none contents: none
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
needs: [changes, lint] needs: [changes, lint]
if: always() if: always()

@ -11,13 +11,13 @@ concurrency:
jobs: jobs:
changes: changes:
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
outputs: outputs:
src: ${{ steps.changes.outputs.src}} src: ${{ steps.changes.outputs.src}}
steps: steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 - uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes id: changes
continue-on-error: true continue-on-error: true
with: with:
@ -72,7 +72,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Set up node ${{ needs.versions.outputs.nodeVersion }} - name: Set up node ${{ needs.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
with: with:
node-version: ${{ needs.versions.outputs.nodeVersion }} node-version: ${{ needs.versions.outputs.nodeVersion }}
@ -89,7 +89,7 @@ jobs:
run: npm run test:coverage run: npm run test:coverage
- name: Collect coverage - name: Collect coverage
uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 uses: codecov/codecov-action@ab904c41d6ece82784817410c45d8b8c02684457 # v3.1.6
with: with:
files: ./coverage/lcov.info files: ./coverage/lcov.info
@ -107,7 +107,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Set up node ${{ needs.versions.outputs.nodeVersion }} - name: Set up node ${{ needs.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
with: with:
node-version: ${{ needs.versions.outputs.nodeVersion }} node-version: ${{ needs.versions.outputs.nodeVersion }}
@ -138,7 +138,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- name: Set up node ${{ needs.versions.outputs.nodeVersion }} - name: Set up node ${{ needs.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
with: with:
node-version: ${{ needs.versions.outputs.nodeVersion }} node-version: ${{ needs.versions.outputs.nodeVersion }}
@ -157,7 +157,7 @@ jobs:
summary: summary:
permissions: permissions:
contents: none contents: none
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
needs: [changes, test, jsunit, handlebars] needs: [changes, test, jsunit, handlebars]
if: always() if: always()

@ -17,13 +17,13 @@ concurrency:
jobs: jobs:
changes: changes:
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
outputs: outputs:
src: ${{ steps.changes.outputs.src}} src: ${{ steps.changes.outputs.src}}
steps: steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 - uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes id: changes
continue-on-error: true continue-on-error: true
with: with:
@ -58,7 +58,7 @@ jobs:
fallbackNpm: '^9' fallbackNpm: '^9'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }} - name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with: with:
node-version: ${{ steps.versions.outputs.nodeVersion }} node-version: ${{ steps.versions.outputs.nodeVersion }}
@ -87,7 +87,7 @@ jobs:
summary: summary:
permissions: permissions:
contents: none contents: none
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
needs: [changes, build] needs: [changes, build]
if: always() if: always()

@ -18,7 +18,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
branches: ["main", "master", "stable27", "stable26", "stable25", "stable24"] branches: ["main", "master", "stable28", "stable27", "stable26"]
name: npm-audit-fix-${{ matrix.branches }} name: npm-audit-fix-${{ matrix.branches }}
@ -36,7 +36,7 @@ jobs:
fallbackNpm: '^9' fallbackNpm: '^9'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }} - name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with: with:
node-version: ${{ steps.versions.outputs.nodeVersion }} node-version: ${{ steps.versions.outputs.nodeVersion }}
@ -58,7 +58,7 @@ jobs:
- name: Create Pull Request - name: Create Pull Request
if: always() if: always()
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5 uses: peter-evans/create-pull-request@a4f52f8033a6168103c2538976c07b467e8163bc # v5
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}
commit-message: "chore(deps): fix npm audit" commit-message: "chore(deps): fix npm audit"

@ -0,0 +1,125 @@
name: Object storage azure
on:
pull_request:
schedule:
- cron: "15 2 * * *"
concurrency:
group: object-storage-azure-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
azure-primary-tests:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: true
name: php${{ matrix.php-versions }}-azure
services:
azurite:
image: mcr.microsoft.com/azure-storage/azurite
env:
AZURITE_ACCOUNTS: nextcloud:bmV4dGNsb3Vk
ports:
- 10000:10000
options: --health-cmd="nc 127.0.0.1 10000 -z" --health-interval=1s --health-retries=30
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
OBJECT_STORE: azure
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bmV4dGNsb3Vk
run: |
composer install
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./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 password
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit
env:
OBJECT_STORE: azure
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bmV4dGNsb3Vk
run: composer run test -- --group PRIMARY-azure ${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.xml
flags: phpunit-azure
- name: Azurite logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
azure-primary-summary:
runs-on: ubuntu-latest-low
needs: [changes, azure-primary-tests]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.azure-primary-tests.result != 'success' }}; then exit 1; fi

@ -0,0 +1,131 @@
name: Object storage S3
on:
pull_request:
schedule:
- cron: "15 2 * * *"
concurrency:
group: object-storage-s3-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
s3-primary-tests-minio:
runs-on: ubuntu-22.04
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: true
name: php${{ matrix.php-versions }}-s3
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
minio:
image: bitnami/minio
env:
MINIO_ROOT_USER: nextcloud
MINIO_ROOT_PASSWORD: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
MINIO_DEFAULT_BUCKETS: nextcloud
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
OBJECT_STORE: s3
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
run: |
composer install
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./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 password
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- 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
env:
OBJECT_STORE: s3
OBJECT_STORE_KEY: nextcloud
OBJECT_STORE_SECRET: bWluaW8tc2VjcmV0LWtleS1uZXh0Y2xvdWQ=
run: composer run test -- --group PRIMARY-s3 ${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.xml
flags: phpunit-s3
- name: S3 logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
s3-primary-summary:
runs-on: ubuntu-latest-low
needs: [changes,s3-primary-tests-minio]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.s3-primary-tests-minio.result != 'success' }}; then exit 1; fi

@ -0,0 +1,121 @@
name: Object storage Swift
on:
pull_request:
schedule:
- cron: "15 2 * * *"
concurrency:
group: object-storage-swift-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
swift-primary-tests:
runs-on: ubuntu-latest
needs: changes
if: ${{ github.repository_owner != 'nextcloud-gmbh' && needs.changes.outputs.src != 'false' }}
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: true
name: php${{ matrix.php-versions }}-swift
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
swift:
image: ghcr.io/cscfi/docker-keystone-swift
ports:
- 5000:5000
- 8080:8080
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
OBJECT_STORE: swift
OBJECT_STORE_SECRET: veryfast
run: |
composer install
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./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 password
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit
env:
OBJECT_STORE: swift
OBJECT_STORE_SECRET: veryfast
run: composer run test -- --group PRIMARY-swift ${{ matrix.coverage && ' --coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.xml
flags: phpunit-swift
- name: Swift logs
if: always()
run: |
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
swift-primary-summary:
runs-on: ubuntu-latest-low
needs: [changes,swift-primary-tests]
if: always()
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.swift-primary-tests.result != 'success' }}; then exit 1; fi

@ -45,8 +45,9 @@ jobs:
with: with:
blueprint: tests/blueprints/basic.toml blueprint: tests/blueprints/basic.toml
ref: ${{ github.event.pull_request.head.ref }} ref: ${{ github.event.pull_request.head.ref }}
- name: Run before measurements - name: Run before measurements
uses: nextcloud/profiler@1e66a9de5f76a01e9d1db4f0153bcc1cbf989b3d uses: nextcloud/profiler@6801ee10fc80f10b444388fb6ca9b36ad8a2ea83
with: with:
run: | run: |
curl -s -X PROPFIND -u test:test http://localhost:8080/remote.php/dav/files/test curl -s -X PROPFIND -u test:test http://localhost:8080/remote.php/dav/files/test
@ -68,7 +69,7 @@ jobs:
- name: Run after measurements - name: Run after measurements
id: compare id: compare
uses: nextcloud/profiler@1e66a9de5f76a01e9d1db4f0153bcc1cbf989b3d uses: nextcloud/profiler@6801ee10fc80f10b444388fb6ca9b36ad8a2ea83
with: with:
run: | run: |
curl -s -X PROPFIND -u test:test http://localhost:8080/remote.php/dav/files/test curl -s -X PROPFIND -u test:test http://localhost:8080/remote.php/dav/files/test
@ -82,14 +83,14 @@ jobs:
- name: Upload profiles - name: Upload profiles
if: always() if: always()
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
with: with:
name: profiles name: profiles
path: | path: |
before.json before.json
after.json after.json
- uses: actions/github-script@v6 - uses: actions/github-script@v7
if: failure() && steps.compare.outcome == 'failure' if: failure() && steps.compare.outcome == 'failure'
with: with:
github-token: ${{secrets.GITHUB_TOKEN}} github-token: ${{secrets.GITHUB_TOKEN}}

@ -0,0 +1,144 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit mariadb
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-mariadb-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-mariadb:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0']
mariadb-versions: ['10.3', '10.4', '10.5', '10.6', '10.11']
include:
- php-versions: '8.3'
mariadb-versions: '10.6'
coverage: ${{ github.event_name != 'pull_request' }}
name: MariaDB ${{ matrix.mariadb-versions }} (PHP ${{ matrix.php-versions }}) - database tests
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
mariadb:
image: mariadb:${{ matrix.mariadb-versions }}
ports:
- 4444:3306/tcp
env:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_USER: oc_autotest
MYSQL_PASSWORD: nextcloud
MYSQL_DATABASE: oc_autotest
options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 5
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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, mysql, pdo_mysql
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Enable ONLY_FULL_GROUP_BY MySQL option
run: |
echo "SET GLOBAL sql_mode=(SELECT CONCAT(@@sql_mode,',ONLY_FULL_GROUP_BY'));" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
echo "SELECT @@sql_mode;" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
- name: Set up Nextcloud
env:
DB_PORT: 4444
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=mysql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit
run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.db.xml
flags: phpunit-mariadb
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-mariadb]
if: always()
name: phpunit-mariadb-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-mariadb.result != 'success' }}; then exit 1; fi

@ -0,0 +1,123 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit memcached
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-memcached-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-memcached:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
name: Memcached (PHP ${{ matrix.php-versions }})
services:
memcached:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 11212:11212/tcp
- 11212:11212/udp
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2
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, memcached, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud
run: |
mkdir data
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit memcached tests
run: composer run test -- --group Memcache,Memcached ${{ matrix.coverage && '--coverage-clover ./clover.xml' || '' }}
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.xml
flags: phpunit-memcached
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-memcached]
if: always()
name: phpunit-memcached-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-memcached.result != 'success' }}; then exit 1; fi

@ -0,0 +1,144 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit mysql
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-mysql-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-mysql:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0']
mysql-versions: ['8.0', '8.3']
include:
- mysql-versions: '8.0'
php-versions: '8.3'
coverage: ${{ github.event_name != 'pull_request' }}
name: MySQL ${{ matrix.mysql-versions }} (PHP ${{ matrix.php-versions }}) - database tests
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
mysql:
image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest
ports:
- 4444:3306/tcp
env:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_USER: oc_autotest
MYSQL_PASSWORD: nextcloud
MYSQL_DATABASE: oc_autotest
options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 5
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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, mysql, pdo_mysql
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Enable ONLY_FULL_GROUP_BY MySQL option
run: |
echo "SET GLOBAL sql_mode=(SELECT CONCAT(@@sql_mode,',ONLY_FULL_GROUP_BY'));" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
echo "SELECT @@sql_mode;" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
- name: Set up Nextcloud
env:
DB_PORT: 4444
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=mysql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit
run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.db.xml
flags: phpunit-mysql
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-mysql]
if: always()
name: phpunit-mysql-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-mysql.result != 'success' }}; then exit 1; fi

@ -0,0 +1,127 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
# This is the testsuite running all non-database agnostic unit tests
name: PHPUnit nodb
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-nodb-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-nodb:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
name: No DB unit tests (PHP ${{ matrix.php-versions }})
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2
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, imagick, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
# Required for tests that use pcntl
ini-values: disable_functions=""
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit nodb testsuite
run: composer run test -- --exclude-group DB,SLOWDB ${{ matrix.coverage && ' --coverage-clover ./clover.nodb.xml' || '' }}
- name: Upload nodb code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.nodb.xml
flags: phpunit-nodb
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-nodb]
if: always()
name: phpunit-nodb-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-nodb.result != 'success' }}; then exit 1; fi

@ -2,6 +2,8 @@ name: PHPUnit oci
on: on:
pull_request: pull_request:
schedule:
- cron: "5 2 * * *"
permissions: permissions:
contents: read contents: read
@ -12,13 +14,13 @@ concurrency:
jobs: jobs:
changes: changes:
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
outputs: outputs:
src: ${{ steps.changes.outputs.src}} src: ${{ steps.changes.outputs.src }}
steps: steps:
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 - uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes id: changes
continue-on-error: true continue-on-error: true
with: with:
@ -26,36 +28,52 @@ jobs:
src: src:
- '.github/workflows/**' - '.github/workflows/**'
- '3rdparty/**' - '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**' - '**/lib/**'
- '**/templates/**'
- '**/tests/**' - '**/tests/**'
- '**/vendor-bin/**' - 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php' - '.php-cs-fixer.dist.php'
- 'composer.json' - 'composer.json'
- 'composer.lock' - 'composer.lock'
- '**.php' - '**.php'
phpunit-oci: phpunit-oci:
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }} needs: changes
if: needs.changes.outputs.src != 'false' && ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy: strategy:
matrix: matrix:
php-versions: ['8.0', '8.1', '8.2'] oracle-versions: ['11']
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.3'
coverage: ${{ github.event_name != 'pull_request' }}
name: Oracle ${{ matrix.oracle-versions }} (PHP ${{ matrix.php-versions }}) - database tests
services: services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
oracle: oracle:
image: ghcr.io/gvenzl/oracle-xe:11 image: ghcr.io/gvenzl/oracle-xe:${{ matrix.oracle-versions }}
# Provide passwords and other environment variables to container # Provide passwords and other environment variables to container
env: env:
ORACLE_RANDOM_PASSWORD: true ORACLE_RANDOM_PASSWORD: true
APP_USER: autotest APP_USER: oc_autotest
APP_USER_PASSWORD: owncloud APP_USER_PASSWORD: nextcloud
# Forward Oracle port # Forward Oracle port
ports: ports:
- 1521:1521/tcp - 4444:1521/tcp
# Provide healthcheck script options for startup # Provide healthcheck script options for startup
options: >- options: >-
@ -71,24 +89,38 @@ jobs:
submodules: true submodules: true
- name: Set up php ${{ matrix.php-versions }} - name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2 uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
with: with:
php-version: ${{ matrix.php-versions }} php-version: ${{ matrix.php-versions }}
extensions: ctype, curl, dom, fileinfo, gd, imagick, intl, json, mbstring, oci8, openssl, pcntl, pdo_sqlite, posix, sqlite, xml, zip # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
coverage: none extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, oci8
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development ini-file: development
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud - name: Set up Nextcloud
env:
DB_PORT: 4444
run: | run: |
composer install
mkdir data mkdir data
./occ maintenance:install --verbose --database=oci --database-name=XE --database-host=127.0.0.1 --database-port=1521 --database-user=autotest --database-pass=owncloud --admin-user admin --admin-pass admin cp tests/redis.config.php config/
php -f index.php cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=oci --database-name=XE --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=oc_autotest --database-pass=nextcloud --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit - name: PHPUnit
run: composer run test:db run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.db.xml
flags: phpunit-oci
- name: Run repair steps - name: Run repair steps
run: | run: |
@ -97,7 +129,7 @@ jobs:
summary: summary:
permissions: permissions:
contents: none contents: none
runs-on: ubuntu-latest runs-on: ubuntu-latest-low
needs: [changes, phpunit-oci] needs: [changes, phpunit-oci]
if: always() if: always()

@ -0,0 +1,143 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit pgsql
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-pgsql-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-pgsql:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0']
# To keep the matrix smaller we ignore PostgreSQL '11', '13', '14' as we already test 10 and 15 as lower and upper bound
postgres-versions: ['10', '15', '16']
include:
- php-versions: '8.3'
postgres-versions: '15'
coverage: ${{ github.event_name != 'pull_request' }}
name: PostgreSQL ${{ matrix.postgres-versions }} (PHP ${{ matrix.php-versions }}) - database tests
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
postgres:
image: ghcr.io/nextcloud/continuous-integration-postgres-${{ matrix.postgres-versions }}:latest
ports:
- 4444:5432/tcp
env:
POSTGRES_USER: root
POSTGRES_PASSWORD: rootpassword
POSTGRES_DB: nextcloud
options: --mount type=tmpfs,destination=/var/lib/postgresql/data --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2
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, pgsql, pdo_pgsql
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud
env:
DB_PORT: 4444
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=pgsql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: PHPUnit database tests
run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.db.xml
flags: phpunit-postgres
- name: Run repair steps
run: |
./occ maintenance:repair --include-expensive
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-pgsql]
if: always()
name: phpunit-pgsql-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-pgsql.result != 'success' }}; then exit 1; fi

@ -0,0 +1,127 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
name: PHPUnit sqlite
on:
pull_request:
schedule:
- cron: "5 2 * * *"
permissions:
contents: read
concurrency:
group: phpunit-sqlite-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- '**/tests/**'
- 'vendor/**'
- 'vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
phpunit-sqlite:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.0', '8.1', '8.2', '8.3']
include:
- php-versions: '8.1'
coverage: ${{ github.event_name != 'pull_request' }}
name: SQLite (PHP ${{ matrix.php-versions }})
services:
cache:
image: ghcr.io/nextcloud/continuous-integration-redis:latest
ports:
- 6379:6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2
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: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up dependencies
run: composer i
- name: Set up Nextcloud
run: |
mkdir data
cp tests/redis.config.php config/
cp tests/preseed-config.php config/config.php
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f tests/enable_all.php | grep -i -C9999 error && echo "Error during app setup" && exit 1 || exit 0
- name: Nextcloud debug information
run: ./occ app:list && echo "======= System config =======" && ./occ config:list system
- name: PHPUnit database tests
run: composer run test:db ${{ matrix.coverage && ' -- --coverage-clover ./clover.db.xml' || '' }}
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@v4
with:
files: ./clover.db.xml
flags: phpunit-sqlite
- name: Print logs
if: always()
run: |
cat data/nextcloud.log
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, phpunit-sqlite]
if: always()
name: phpunit-sqlite-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-sqlite.result != 'success' }}; then exit 1; fi

@ -1,130 +0,0 @@
name: S3 External storage
on:
pull_request:
paths:
- 'apps/files_external/**'
concurrency:
group: s3-external-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
APP_NAME: files_external
jobs:
s3-external-tests-minio:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0', '8.1']
name: php${{ matrix.php-versions }}-minio
services:
minio:
env:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
image: bitnami/minio:2021.10.6
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
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 password
./occ app:enable --force ${{ env.APP_NAME }}
php -S localhost:8080 &
- name: PHPUnit
run: |
echo "<?php return ['run' => true, 'secret' => 'actually-not-secret', 'passwordsalt' => 'actually-not-secret', 'hostname' => 'localhost','key' => 'minio','secret' => 'minio123', 'bucket' => 'bucket', 'port' => 9000, 'use_ssl' => false, 'autocreate' => true, 'use_path_style' => true];" > apps/${{ env.APP_NAME }}/tests/config.amazons3.php
composer run test:files_external apps/files_external/tests/Storage/Amazons3Test.php
composer run test:files_external apps/files_external/tests/Storage/VersionedAmazonS3Test.php
- name: S3 logs
if: always()
run: |
docker ps -a
docker logs $(docker ps -aq)
s3-external-tests-localstack:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0', '8.1']
name: php${{ matrix.php-versions }}-localstack
services:
minio:
env:
SERVICES: s3
DEBUG: 1
image: localstack/localstack:0.12.7
ports:
- "4566:4566"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
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 password
./occ app:enable --force ${{ env.APP_NAME }}
php -S localhost:8080 &
- name: PHPUnit
run: |
echo "<?php return ['run' => true,'hostname' => 'localhost','key' => 'ignored','secret' => 'ignored', 'bucket' => 'bucket', 'port' => 4566, 'use_ssl' => false, 'autocreate' => true, 'use_path_style' => true];" > apps/${{ env.APP_NAME }}/tests/config.amazons3.php
composer run test:files_external apps/files_external/tests/Storage/Amazons3Test.php
composer run test:files_external apps/files_external/tests/Storage/VersionedAmazonS3Test.php
- name: S3 logs
if: always()
run: |
docker ps -a
docker logs $(docker ps -aq)
s3-external-summary:
runs-on: ubuntu-latest
needs: [s3-external-tests-minio, s3-external-tests-localstack]
if: always()
steps:
- name: Summary status
run: if ${{ needs.s3-external-tests-minio.result != 'success' }} || ${{ needs.s3-external-tests-localstack.result != 'success' }}; then exit 1; fi

@ -1,95 +0,0 @@
name: S3 primary storage integration tests
on:
pull_request:
paths:
- '.github/workflows/**'
- '3rdparty/**'
- '**/*.php'
- '**/lib/**'
- '**/tests/**'
- '**/vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
concurrency:
group: s3-external-integration-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
s3-primary-integration-tests-minio:
runs-on: ubuntu-20.04
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
key: ['objectstore', 'objectstore_multibucket']
name: php${{ matrix.php-versions }}-${{ matrix.key }}-minio
services:
redis:
image: redis
ports:
- "6379:6379"
minio:
env:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
image: bitnami/minio:2021.12.29
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd, redis
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- 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
run: |
mkdir data
echo '<?php $CONFIG=["${{ matrix.key }}" => ["class" => "OC\Files\ObjectStore\S3", "arguments" => ["bucket" => "nextcloud", "autocreate" => true, "key" => "minio", "secret" => "minio123", "hostname" => "localhost", "port" => 9000, "use_ssl" => false, "use_path_style" => true, "uploadPartSize" => 52428800]]];' > config/config.php
echo '<?php $CONFIG=["redis" => ["host" => "localhost", "port" => 6379], "memcache.local" => "\OC\Memcache\Redis", "memcache.distributed" => "\OC\Memcache\Redis"];' > config/redis.config.php
./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
php -f index.php
- name: Integration
run: |
cd build/integration
bash run.sh --tags "~@failure-s3" features/webdav-related.feature
- name: S3 logs
if: always()
run: |
cat data/nextcloud.log
docker ps -a
docker ps -aq | while read container ; do IMAGE=$(docker inspect --format='{{.Config.Image}}' $container); echo $IMAGE; docker logs $container; echo "\n\n" ; done
s3-primary-integration-summary:
runs-on: ubuntu-latest
needs: [s3-primary-integration-tests-minio]
if: always()
steps:
- name: Summary status
run: if ${{ needs.s3-primary-integration-tests-minio.result != 'success' }}; then exit 1; fi

@ -1,87 +0,0 @@
name: S3 primary storage
on:
pull_request:
paths:
- '.github/workflows/**'
- '3rdparty/**'
- '**/*.php'
- '**/lib/**'
- '**/tests/**'
- '**/vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
concurrency:
group: s3-primary-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
s3-primary-tests-minio:
runs-on: ubuntu-20.04
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
key: ['objectstore', 'objectstore_multibucket']
name: php${{ matrix.php-versions }}-${{ matrix.key }}-minio
services:
minio:
env:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
image: bitnami/minio:2021.12.29
ports:
- "9000:9000"
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
mkdir data
echo '<?php $CONFIG=["${{ matrix.key }}" => ["class" => "OC\Files\ObjectStore\S3", "arguments" => ["bucket" => "nextcloud", "autocreate" => true, "key" => "minio", "secret" => "minio123", "hostname" => "localhost", "port" => 9000, "use_ssl" => false, "use_path_style" => true, "uploadPartSize" => 52428800]]];' > config/config.php
./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 password
php -f index.php
- 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
run: composer run test:db
- name: S3 logs
if: always()
run: |
docker ps -a
docker logs $(docker ps -aq)
s3-primary-summary:
runs-on: ubuntu-latest
needs: [s3-primary-tests-minio]
if: always()
steps:
- name: Summary status
run: if ${{ needs.s3-primary-tests-minio.result != 'success' }}; then exit 1; fi

@ -1,73 +0,0 @@
name: SFTP unit tests
on:
pull_request:
paths:
- 'apps/files_external/**'
env:
APP_NAME: files_external
concurrency:
group: sftp-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
sftp-tests:
runs-on: ubuntu-latest
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
strategy:
# do not stop on another job's failure
fail-fast: false
matrix:
php-versions: ['8.0']
sftpd: ['openssh']
name: php${{ matrix.php-versions }}-${{ matrix.sftpd }}
steps:
- name: Checkout server
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
submodules: true
- name: Set up sftpd
run: |
sudo mkdir /tmp/sftp
sudo chown -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 }}
uses: shivammathur/setup-php@c5fc0d8281aba02c7fda07d3a70cc5371548067d #v2.25.2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, fileinfo, intl, sqlite, pdo_sqlite, zip, gd
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
run: |
composer install
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 password
./occ app:enable --force ${{ env.APP_NAME }}
php -S localhost:8080 &
- name: PHPUnit
run: |
echo "<?php return ['run' => true, 'host' => 'localhost:2222','user' => 'test','password' => 'test', 'root' => 'data'];" > apps/${{ env.APP_NAME }}/tests/config.sftp.php
composer run test:files_external apps/files_external/tests/Storage/SftpTest.php
- name: sftpd logs
if: always()
run: |
ls -l /tmp/sftp
docker logs sftp
sftp-summary:
runs-on: ubuntu-latest
needs: sftp-tests
if: always()
steps:
- name: Summary status
run: if ${{ needs.sftp-tests.result != 'success' }}; then exit 1; fi

@ -15,7 +15,7 @@ jobs:
issues: write issues: write
steps: steps:
- uses: actions/stale@v8 - uses: actions/stale@v9
with: with:
repo-token: ${{ secrets.COMMAND_BOT_PAT }} repo-token: ${{ secrets.COMMAND_BOT_PAT }}
stale-issue-message: > stale-issue-message: >

@ -40,7 +40,7 @@ jobs:
- name: Upload Analysis results to GitHub - name: Upload Analysis results to GitHub
if: always() if: always()
uses: github/codeql-action/upload-sarif@v2 uses: github/codeql-action/upload-sarif@v3
with: with:
sarif_file: results.sarif sarif_file: results.sarif
@ -68,7 +68,7 @@ jobs:
- name: Upload Security Analysis results to GitHub - name: Upload Security Analysis results to GitHub
if: always() if: always()
uses: github/codeql-action/upload-sarif@v2 uses: github/codeql-action/upload-sarif@v3
with: with:
sarif_file: results.sarif sarif_file: results.sarif

@ -12,7 +12,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
branches: ["master", "stable27", "stable26", "stable25", "stable24", "stable23", "stable22"] branches: ["master", "stable28", "stable27", "stable26", "stable25", "stable24", "stable23", "stable22"]
name: update-ca-certificate-bundle-${{ matrix.branches }} name: update-ca-certificate-bundle-${{ matrix.branches }}
@ -26,7 +26,7 @@ jobs:
run: curl --etag-compare build/ca-bundle-etag.txt --etag-save build/ca-bundle-etag.txt --output resources/config/ca-bundle.crt https://curl.se/ca/cacert.pem run: curl --etag-compare build/ca-bundle-etag.txt --etag-save build/ca-bundle-etag.txt --output resources/config/ca-bundle.crt https://curl.se/ca/cacert.pem
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 uses: peter-evans/create-pull-request@a4f52f8033a6168103c2538976c07b467e8163bc
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}
commit-message: "fix(security): Update CA certificate bundle" commit-message: "fix(security): Update CA certificate bundle"
@ -40,3 +40,4 @@ jobs:
labels: | labels: |
dependencies dependencies
3. to review 3. to review
reviewers: ChristophWurst, miaulalala, nickvergessen

@ -0,0 +1,46 @@
name: Update code signing revocation list
on:
workflow_dispatch:
schedule:
- cron: "5 2 * * *"
jobs:
update-code-signing-crl:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
branches: ["master", "stable28", "stable27", "stable26", "stable25", "stable24", "stable23", "stable22"]
name: update-code-signing-crl-${{ matrix.branches }}
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
ref: ${{ matrix.branches }}
submodules: true
- name: Download CRL file from Appstore repository
run: curl --output resources/codesigning/root.crl https://raw.githubusercontent.com/nextcloud/appstore/master/nextcloudappstore/certificate/nextcloud.crl
- name: Verify CRL is from CRT
run: openssl crl -verify -in resources/codesigning/root.crl -CAfile resources/codesigning/root.crt -noout
- name: Create Pull Request
uses: peter-evans/create-pull-request@a4f52f8033a6168103c2538976c07b467e8163bc
with:
token: ${{ secrets.COMMAND_BOT_PAT }}
commit-message: "fix(security): Update code signing revocation list"
committer: GitHub <noreply@github.com>
author: nextcloud-command <nextcloud-command@users.noreply.github.com>
signoff: true
branch: automated/noid/${{ matrix.branches }}-update-code-signing-crl
title: "[${{ matrix.branches }}] fix(security): Update code signing revocation list"
body: |
Auto-generated update of code signing revocation list from [Appstore](https://github.com/nextcloud/appstore/commits/master/nextcloudappstore/certificate/nextcloud.crl)
labels: |
dependencies
3. to review
reviewers: mgallien, miaulalala, nickvergessen

@ -14,7 +14,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
branches: ["master", "stable27", "stable26", "stable25"] branches: ["master", "stable28", "stable27", "stable26"]
name: update-psalm-baseline-${{ matrix.branches }} name: update-psalm-baseline-${{ matrix.branches }}
@ -28,7 +28,7 @@ jobs:
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
with: with:
php-version: '8.0' php-version: '8.0'
extensions: ctype,curl,dom,fileinfo,gd,intl,json,mbstring,openssl,pdo_sqlite,posix,sqlite,xml,zip extensions: apcu,ctype,curl,dom,fileinfo,ftp,gd,intl,json,ldap,mbstring,openssl,pdo_sqlite,posix,sqlite,xml,zip
coverage: none coverage: none
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -37,11 +37,11 @@ jobs:
run: composer install run: composer install
- name: Psalm - name: Psalm
run: composer run psalm -- --monochrome --no-progress --output-format=text --update-baseline run: composer run psalm:ci -- --monochrome --no-progress --output-format=text --update-baseline
continue-on-error: true continue-on-error: true
- name: Psalm OCP - name: Psalm OCP
run: composer run psalm -- -c psalm-ocp.xml --monochrome --no-progress --output-format=github --update-baseline run: composer run psalm:ci -- -c psalm-ocp.xml --monochrome --no-progress --output-format=github --update-baseline
continue-on-error: true continue-on-error: true
- name: Reset composer - name: Reset composer
@ -50,7 +50,7 @@ jobs:
git checkout composer.json composer.lock lib/composer git checkout composer.json composer.lock lib/composer
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 uses: peter-evans/create-pull-request@a4f52f8033a6168103c2538976c07b467e8163bc
with: with:
token: ${{ secrets.COMMAND_BOT_PAT }} token: ${{ secrets.COMMAND_BOT_PAT }}
commit-message: Update psalm baseline commit-message: Update psalm baseline

4
.gitignore vendored

@ -129,6 +129,8 @@ nbproject
/build/bin /build/bin
/build/lib/ /build/lib/
/build/jsdocs/ /build/jsdocs/
/build/integration/output/
/build/integration/phpserver.log
/npm-debug.log /npm-debug.log
/PhantomJS_* /PhantomJS_*
@ -162,6 +164,7 @@ tests/acceptance/vendor/
composer.phar composer.phar
/lib/composer/bin /lib/composer/bin
/lib/composer/bamarni
/vendor-bin/**/vendor /vendor-bin/**/vendor
./.htaccess ./.htaccess
@ -170,3 +173,4 @@ core/js/mimetypelist.js
# Tests - cypress # Tests - cypress
cypress/snapshots cypress/snapshots
cypress/videos cypress/videos
cypress/downloads

@ -94,5 +94,19 @@
RewriteRule ^(?:\.(?!well-known)|autotest|occ|issue|indie|db_|console).* - [R=404,L] RewriteRule ^(?:\.(?!well-known)|autotest|occ|issue|indie|db_|console).* - [R=404,L]
</IfModule> </IfModule>
# Clients like xDavv5 on Android, or Cyberduck, use chunked requests.
# When FastCGI or FPM is used with apache, requests arrive to Nextcloud without any content.
# This leads to the creation of empty files.
# The following directive will force the problematic requests to be buffered before being forwarded to Nextcloud.
# This way, the "Transfer-Encoding" header is removed, the "Content-Length" header is set, and the request content is proxied to Nextcloud.
# Here are more information about the issue:
# - https://docs.cyberduck.io/mountainduck/issues/fastcgi/
# - https://docs.nextcloud.com/server/latest/admin_manual/issues/general_troubleshooting.html#troubleshooting-webdav
<IfModule setenvif.c>
<Location "/remote.php">
SetEnvIf Transfer-Encoding "chunked" proxy-sendcl=1
</Location>
</IfModule>
AddDefaultCharset utf-8 AddDefaultCharset utf-8
Options -Indexes Options -Indexes

@ -20,6 +20,7 @@ $config
->notPath('composer') ->notPath('composer')
->notPath('node_modules') ->notPath('node_modules')
->notPath('vendor') ->notPath('vendor')
->in('apps')
->in(__DIR__); ->in(__DIR__);
// Ignore additional app directories // Ignore additional app directories

@ -1 +1 @@
Subproject commit e6c45c6c0d4f92ffec621446fcc3b34584772b13 Subproject commit e8a165a3811f1b454694337aaff47c30888ca9fc

@ -1,14 +1,14 @@
# Security Policy # Security Policy
[Security](https://nextcloud.com/security/) is very important to us. [Security](https://nextcloud.com/security/) is very important to us.
If you believe you have found a security vulnerability that meets our definition of a security If you believe you have found a security vulnerability that meets our definition of a security
vulnerability, please report is as described below. vulnerability, please report is as described below.
## Context ## Context
Please review our [threat model and accepted risks](https://nextcloud.com/security/threat-model) to learn what Please review our [threat model and accepted risks](https://nextcloud.com/security/threat-model) to learn what
is currently considered a security vulnerability versus expected behavior. And review what is considered is currently considered a security vulnerability versus expected behavior. And review what is considered
[in scope or bounty eligible](https://hackerone.com/nextcloud/policy_scopes). [in scope or bounty eligible](https://hackerone.com/nextcloud/policy_scopes).
@ -31,13 +31,17 @@ Your report should include:
You should receive an initial acknowledgement within 24 hours in most cases. You should receive an initial acknowledgement within 24 hours in most cases.
A member of the security team will confirm the vulnerability, determine its impact, follow-up with any questions, A member of the security team will confirm the vulnerability, determine its impact, follow-up with any questions,
and coordinate the fix and publication. and coordinate the fix and publication.
The fix will be applied to all applicable and still supported stable branches, tested, and packaged in the next security release. The fix will be applied to all applicable and still supported stable branches, tested, and packaged in the next security release.
The vulnerability will be publicly announced after the release. Finally, your name will be added The vulnerability will be publicly announced after the release. Finally, your name will be added
to the [hall of fame](https://hackerone.com/nextcloud/thanks) as a thank you from the entire Nextcloud to the [hall of fame](https://hackerone.com/nextcloud/thanks) as a thank you from the entire Nextcloud
community. community.
If the vulnerability involves an app that is not maintained by Nextcloud (i.e. hosted by the
Nextcloud project but community maintained, or hosted elsewhere), the security team will try to coordinate with the
current maintainer and help to get the issue fixed in similar fashion.
### Bug Bounties ### Bug Bounties
@ -47,8 +51,7 @@ on past bounty ranges can be found at [hackerone.com/nextcloud](https://hackeron
## Existing Security Advisories ## Existing Security Advisories
Published security advisories for the Nextcloud Server, Clients and Apps can be viewed at Published security advisories for the Nextcloud Server, Clients and Apps can be viewed at
[https://github.com/nextcloud/security-advisories/security/advisories](https://github.com/nextcloud/security-advisories/security/advisories [https://github.com/nextcloud/security-advisories/security/advisories](https://github.com/nextcloud/security-advisories/security/advisories).
).
## Supported Versions ## Supported Versions

@ -5,7 +5,7 @@
<name>Auditing / Logging</name> <name>Auditing / Logging</name>
<summary>Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions.</summary> <summary>Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions.</summary>
<description>Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions.</description> <description>Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions.</description>
<version>1.18.0</version> <version>1.19.0</version>
<licence>agpl</licence> <licence>agpl</licence>
<author>Nextcloud</author> <author>Nextcloud</author>
<namespace>AdminAudit</namespace> <namespace>AdminAudit</namespace>
@ -15,7 +15,7 @@
<category>monitoring</category> <category>monitoring</category>
<bugs>https://github.com/nextcloud/server/issues</bugs> <bugs>https://github.com/nextcloud/server/issues</bugs>
<dependencies> <dependencies>
<nextcloud min-version="28" max-version="28"/> <nextcloud min-version="29" max-version="29"/>
</dependencies> </dependencies>
<background-jobs> <background-jobs>
<job>OCA\AdminAudit\BackgroundJobs\Rotate</job> <job>OCA\AdminAudit\BackgroundJobs\Rotate</job>

@ -1,7 +1,7 @@
OC.L10N.register( OC.L10N.register(
"admin_audit", "admin_audit",
{ {
"Auditing / Logging" : "التدقيق / السجلات", "Auditing / Logging" : "المراجعة / السجلات",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "خاصية سجلات المراقبة لـ نكست كلاود مثل الوصول إلى سجلات الملفات أو المعلومات الحساسة الاخرى." "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "تُوفِّر إمكانيات تسجيل و مراجعة سجل الحركات على نكست كلاود."
}, },
"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"); "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");

@ -1,5 +1,5 @@
{ "translations": { { "translations": {
"Auditing / Logging" : "التدقيق / السجلات", "Auditing / Logging" : "المراجعة / السجلات",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "خاصية سجلات المراقبة لـ نكست كلاود مثل الوصول إلى سجلات الملفات أو المعلومات الحساسة الاخرى." "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "تُوفِّر إمكانيات تسجيل و مراجعة سجل الحركات على نكست كلاود."
},"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;" },"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"
} }

@ -0,0 +1,7 @@
OC.L10N.register(
"admin_audit",
{
"Auditing / Logging" : "Audit / Giriş",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Nextcloud üçün fayl girişləri və ya başqa həssas hərəkətlər kimi giriş imkanlarını təmin edir."
},
"nplurals=2; plural=(n != 1);");

@ -0,0 +1,5 @@
{ "translations": {
"Auditing / Logging" : "Audit / Giriş",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Nextcloud üçün fayl girişləri və ya başqa həssas hərəkətlər kimi giriş imkanlarını təmin edir."
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

@ -1,7 +1,7 @@
OC.L10N.register( OC.L10N.register(
"admin_audit", "admin_audit",
{ {
"Auditing / Logging" : "Auditieren / Protokollieren", "Auditing / Logging" : "Auditieren/Protokollieren",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Stellt Protokollierungsfunktionen für Nextcloud zur Verfügung wie Dateizugriffe oder andere vertrauliche Aktionen." "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Stellt Protokollierungsfunktionen für Nextcloud zur Verfügung wie Dateizugriffe oder andere vertrauliche Aktionen."
}, },
"nplurals=2; plural=(n != 1);"); "nplurals=2; plural=(n != 1);");

@ -1,5 +1,5 @@
{ "translations": { { "translations": {
"Auditing / Logging" : "Auditieren / Protokollieren", "Auditing / Logging" : "Auditieren/Protokollieren",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Stellt Protokollierungsfunktionen für Nextcloud zur Verfügung wie Dateizugriffe oder andere vertrauliche Aktionen." "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Stellt Protokollierungsfunktionen für Nextcloud zur Verfügung wie Dateizugriffe oder andere vertrauliche Aktionen."
},"pluralForm" :"nplurals=2; plural=(n != 1);" },"pluralForm" :"nplurals=2; plural=(n != 1);"
} }

@ -4,4 +4,4 @@ OC.L10N.register(
"Auditing / Logging" : "פיקוח / תיעוד", "Auditing / Logging" : "פיקוח / תיעוד",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "מספק יכולות תיעוד ל־Nextcloud כגון תיעוד גישה ליומן התיעוד או פעולות רגישות אחרות." "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "מספק יכולות תיעוד ל־Nextcloud כגון תיעוד גישה ליומן התיעוד או פעולות רגישות אחרות."
}, },
"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;"); "nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;");

@ -1,5 +1,5 @@
{ "translations": { { "translations": {
"Auditing / Logging" : "פיקוח / תיעוד", "Auditing / Logging" : "פיקוח / תיעוד",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "מספק יכולות תיעוד ל־Nextcloud כגון תיעוד גישה ליומן התיעוד או פעולות רגישות אחרות." "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "מספק יכולות תיעוד ל־Nextcloud כגון תיעוד גישה ליומן התיעוד או פעולות רגישות אחרות."
},"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;" },"pluralForm" :"nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;"
} }

@ -0,0 +1,7 @@
OC.L10N.register(
"admin_audit",
{
"Auditing / Logging" : "Eftirlit / Atvikaskráning",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Býður upp á atvikaskráningu fyrir Nextcloud, eins og að skrá aðgang að skrám og fleiri viðkvæmar aðgerðir."
},
"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);");

@ -0,0 +1,5 @@
{ "translations": {
"Auditing / Logging" : "Eftirlit / Atvikaskráning",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Býður upp á atvikaskráningu fyrir Nextcloud, eins og að skrá aðgang að skrám og fleiri viðkvæmar aðgerðir."
},"pluralForm" :"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);"
}

@ -2,6 +2,6 @@ OC.L10N.register(
"admin_audit", "admin_audit",
{ {
"Auditing / Logging" : "Auditoria / Registro", "Auditing / Logging" : "Auditoria / Registro",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Fornece recursos de registro para Nextcloud, como registros de acesso a arquivos ou outras ações sensíveis." "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Fornece habilidades de registro para o NextCloud, como acessos de arquivo de log ou ações sensíveis."
}, },
"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); "nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");

@ -1,5 +1,5 @@
{ "translations": { { "translations": {
"Auditing / Logging" : "Auditoria / Registro", "Auditing / Logging" : "Auditoria / Registro",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Fornece recursos de registro para Nextcloud, como registros de acesso a arquivos ou outras ações sensíveis." "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Fornece habilidades de registro para o NextCloud, como acessos de arquivo de log ou ações sensíveis."
},"pluralForm" :"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" },"pluralForm" :"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
} }

@ -34,7 +34,8 @@ class Action {
public function __construct( public function __construct(
private IAuditLogger $logger, private IAuditLogger $logger,
) {} ) {
}
/** /**
* Log a single action with a log level of info * Log a single action with a log level of info
@ -45,9 +46,9 @@ class Action {
* @param bool $obfuscateParameters * @param bool $obfuscateParameters
*/ */
public function log(string $text, public function log(string $text,
array $params, array $params,
array $elements, array $elements,
bool $obfuscateParameters = false): void { bool $obfuscateParameters = false): void {
foreach ($elements as $element) { foreach ($elements as $element) {
if (!isset($params[$element])) { if (!isset($params[$element])) {
if ($obfuscateParameters) { if ($obfuscateParameters) {

@ -29,7 +29,7 @@ namespace OCA\AdminAudit\Actions;
class Console extends Action { class Console extends Action {
/** /**
* @param $arguments * @param array $arguments
*/ */
public function runCommand(array $arguments): void { public function runCommand(array $arguments): void {
if (!isset($arguments[1]) || $arguments[1] === '_completion') { if (!isset($arguments[1]) || $arguments[1] === '_completion') {

@ -61,7 +61,7 @@ class UserManagement extends Action {
*/ */
public function assign(string $uid): void { public function assign(string $uid): void {
$this->log( $this->log(
'UserID assigned: "%s"', 'UserID assigned: "%s"',
[ 'uid' => $uid ], [ 'uid' => $uid ],
[ 'uid' ] [ 'uid' ]
); );

@ -70,7 +70,6 @@ use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class Application extends App implements IBootstrap { class Application extends App implements IBootstrap {
/** @var LoggerInterface */ /** @var LoggerInterface */
protected $logger; protected $logger;
@ -101,7 +100,7 @@ class Application extends App implements IBootstrap {
* Register hooks in order to log them * Register hooks in order to log them
*/ */
private function registerHooks(IAuditLogger $logger, private function registerHooks(IAuditLogger $logger,
ContainerInterface $serverContainer): void { ContainerInterface $serverContainer): void {
$this->userManagementHooks($logger, $serverContainer->get(IUserSession::class)); $this->userManagementHooks($logger, $serverContainer->get(IUserSession::class));
$this->groupHooks($logger, $serverContainer->get(IGroupManager::class)); $this->groupHooks($logger, $serverContainer->get(IGroupManager::class));
$this->authHooks($logger); $this->authHooks($logger);
@ -122,7 +121,7 @@ class Application extends App implements IBootstrap {
} }
private function userManagementHooks(IAuditLogger $logger, private function userManagementHooks(IAuditLogger $logger,
IUserSession $userSession): void { IUserSession $userSession): void {
$userActions = new UserManagement($logger); $userActions = new UserManagement($logger);
Util::connectHook('OC_User', 'post_createUser', $userActions, 'create'); Util::connectHook('OC_User', 'post_createUser', $userActions, 'create');
@ -136,7 +135,7 @@ class Application extends App implements IBootstrap {
} }
private function groupHooks(IAuditLogger $logger, private function groupHooks(IAuditLogger $logger,
IGroupManager $groupManager): void { IGroupManager $groupManager): void {
$groupActions = new GroupManagement($logger); $groupActions = new GroupManagement($logger);
assert($groupManager instanceof GroupManager); assert($groupManager instanceof GroupManager);
@ -167,7 +166,7 @@ class Application extends App implements IBootstrap {
} }
private function appHooks(IAuditLogger $logger, private function appHooks(IAuditLogger $logger,
IEventDispatcher $eventDispatcher): void { IEventDispatcher $eventDispatcher): void {
$eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function (ManagerEvent $event) use ($logger) { $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function (ManagerEvent $event) use ($logger) {
$appActions = new AppManagement($logger); $appActions = new AppManagement($logger);
$appActions->enableApp($event->getAppID()); $appActions->enableApp($event->getAppID());
@ -183,7 +182,7 @@ class Application extends App implements IBootstrap {
} }
private function consoleHooks(IAuditLogger $logger, private function consoleHooks(IAuditLogger $logger,
IEventDispatcher $eventDispatcher): void { IEventDispatcher $eventDispatcher): void {
$eventDispatcher->addListener(ConsoleEvent::class, function (ConsoleEvent $event) use ($logger) { $eventDispatcher->addListener(ConsoleEvent::class, function (ConsoleEvent $event) use ($logger) {
$appActions = new Console($logger); $appActions = new Console($logger);
$appActions->runCommand($event->getArguments()); $appActions->runCommand($event->getArguments());
@ -191,7 +190,7 @@ class Application extends App implements IBootstrap {
} }
private function fileHooks(IAuditLogger $logger, private function fileHooks(IAuditLogger $logger,
IEventDispatcher $eventDispatcher): void { IEventDispatcher $eventDispatcher): void {
$fileActions = new Files($logger); $fileActions = new Files($logger);
$eventDispatcher->addListener( $eventDispatcher->addListener(
BeforePreviewFetchedEvent::class, BeforePreviewFetchedEvent::class,
@ -264,7 +263,7 @@ class Application extends App implements IBootstrap {
} }
private function securityHooks(IAuditLogger $logger, private function securityHooks(IAuditLogger $logger,
IEventDispatcher $eventDispatcher): void { IEventDispatcher $eventDispatcher): void {
$eventDispatcher->addListener(TwoFactorProviderChallengePassed::class, function (TwoFactorProviderChallengePassed $event) use ($logger) { $eventDispatcher->addListener(TwoFactorProviderChallengePassed::class, function (TwoFactorProviderChallengePassed $event) use ($logger) {
$security = new Security($logger); $security = new Security($logger);
$security->twofactorSuccess($event->getUser(), $event->getProvider()); $security->twofactorSuccess($event->getUser(), $event->getProvider());

@ -32,8 +32,7 @@ use Psr\Log\LoggerInterface;
*/ */
class AuditLogger implements IAuditLogger { class AuditLogger implements IAuditLogger {
/** @var LoggerInterface */ private LoggerInterface $parentLogger;
private $parentLogger;
public function __construct(ILogFactory $logFactory, IConfig $config) { public function __construct(ILogFactory $logFactory, IConfig $config) {
$auditType = $config->getSystemValueString('log_type_audit', 'file'); $auditType = $config->getSystemValueString('log_type_audit', 'file');
@ -50,39 +49,39 @@ class AuditLogger implements IAuditLogger {
$this->parentLogger = $logFactory->getCustomPsrLogger($logFile, $auditType, $auditTag); $this->parentLogger = $logFactory->getCustomPsrLogger($logFile, $auditType, $auditTag);
} }
public function emergency($message, array $context = array()) { public function emergency($message, array $context = array()): void {
$this->parentLogger->emergency($message, $context); $this->parentLogger->emergency($message, $context);
} }
public function alert($message, array $context = array()) { public function alert($message, array $context = array()): void {
$this->parentLogger->alert($message, $context); $this->parentLogger->alert($message, $context);
} }
public function critical($message, array $context = array()) { public function critical($message, array $context = array()): void {
$this->parentLogger->critical($message, $context); $this->parentLogger->critical($message, $context);
} }
public function error($message, array $context = array()) { public function error($message, array $context = array()): void {
$this->parentLogger->error($message, $context); $this->parentLogger->error($message, $context);
} }
public function warning($message, array $context = array()) { public function warning($message, array $context = array()): void {
$this->parentLogger->warning($message, $context); $this->parentLogger->warning($message, $context);
} }
public function notice($message, array $context = array()) { public function notice($message, array $context = array()): void {
$this->parentLogger->notice($message, $context); $this->parentLogger->notice($message, $context);
} }
public function info($message, array $context = array()) { public function info($message, array $context = array()): void {
$this->parentLogger->info($message, $context); $this->parentLogger->info($message, $context);
} }
public function debug($message, array $context = array()) { public function debug($message, array $context = array()): void {
$this->parentLogger->debug($message, $context); $this->parentLogger->debug($message, $context);
} }
public function log($level, $message, array $context = array()) { public function log($level, $message, array $context = array()): void {
$this->parentLogger->log($level, $message, $context); $this->parentLogger->log($level, $message, $context);
} }
} }

@ -27,8 +27,8 @@ declare(strict_types=1);
*/ */
namespace OCA\AdminAudit\BackgroundJobs; namespace OCA\AdminAudit\BackgroundJobs;
use OCP\BackgroundJob\TimedJob;
use OCP\AppFramework\Utility\ITimeFactory; use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
use OCP\IConfig; use OCP\IConfig;
use OCP\Log\RotationTrait; use OCP\Log\RotationTrait;

@ -30,6 +30,7 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener; use OCP\EventDispatcher\IEventListener;
use OCP\Log\Audit\CriticalActionPerformedEvent; use OCP\Log\Audit\CriticalActionPerformedEvent;
/** @template-implements IEventListener<CriticalActionPerformedEvent> */
class CriticalActionPerformedEventListener extends Action implements IEventListener { class CriticalActionPerformedEventListener extends Action implements IEventListener {
public function handle(Event $event): void { public function handle(Event $event): void {
if (!($event instanceof CriticalActionPerformedEvent)) { if (!($event instanceof CriticalActionPerformedEvent)) {

@ -30,17 +30,15 @@ use OCA\AdminAudit\Actions\Security;
use OCA\AdminAudit\AuditLogger; use OCA\AdminAudit\AuditLogger;
use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\IUser; use OCP\IUser;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase; use Test\TestCase;
class SecurityTest extends TestCase { class SecurityTest extends TestCase {
/** @var AuditLogger|\PHPUnit\Framework\MockObject\MockObject */ private AuditLogger|MockObject $logger;
private $logger;
/** @var Security */ private Security $security;
private $security;
/** @var IUser|\PHPUnit\Framework\MockObject\MockObject */ private MockObject|IUser $user;
private $user;
protected function setUp(): void { protected function setUp(): void {
parent::setUp(); parent::setUp();

@ -5,7 +5,7 @@
<name>Cloud Federation API</name> <name>Cloud Federation API</name>
<summary>Enable clouds to communicate with each other and exchange data</summary> <summary>Enable clouds to communicate with each other and exchange data</summary>
<description>The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data.</description> <description>The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data.</description>
<version>1.11.0</version> <version>1.12.0</version>
<licence>agpl</licence> <licence>agpl</licence>
<author>Bjoern Schiessle</author> <author>Bjoern Schiessle</author>
<namespace>CloudFederationAPI</namespace> <namespace>CloudFederationAPI</namespace>
@ -15,6 +15,6 @@
<category>integration</category> <category>integration</category>
<bugs>https://github.com/nextcloud/server/issues</bugs> <bugs>https://github.com/nextcloud/server/issues</bugs>
<dependencies> <dependencies>
<nextcloud min-version="28" max-version="28"/> <nextcloud min-version="29" max-version="29"/>
</dependencies> </dependencies>
</info> </info>

@ -38,11 +38,11 @@ return [
'verb' => 'POST', 'verb' => 'POST',
'root' => '/ocm', 'root' => '/ocm',
], ],
// [ // [
// 'name' => 'RequestHandler#inviteAccepted', // 'name' => 'RequestHandler#inviteAccepted',
// 'url' => '/invite-accepted', // 'url' => '/invite-accepted',
// 'verb' => 'POST', // 'verb' => 'POST',
// 'root' => '/ocm', // 'root' => '/ocm',
// ] // ]
], ],
]; ];

@ -0,0 +1,8 @@
OC.L10N.register(
"cloud_federation_api",
{
"Cloud Federation API" : "API de Federación en la Nube",
"Enable clouds to communicate with each other and exchange data" : "Permitir que las nubes se comuniquen entre sí e intercambien datos",
"The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "La API de Federación de Nubes permite que varias instancias de Nextcloud se comuniquen entre sí y intercambien datos."
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");

@ -0,0 +1,6 @@
{ "translations": {
"Cloud Federation API" : "API de Federación en la Nube",
"Enable clouds to communicate with each other and exchange data" : "Permitir que las nubes se comuniquen entre sí e intercambien datos",
"The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "La API de Federación de Nubes permite que varias instancias de Nextcloud se comuniquen entre sí y intercambien datos."
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}

@ -0,0 +1,8 @@
OC.L10N.register(
"cloud_federation_api",
{
"Cloud Federation API" : "API de la federación en la nube",
"Enable clouds to communicate with each other and exchange data" : "Permitir que las nubes se comuniquen entre sí e intercambien datos",
"The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "La API de la federación en la nube permite que varias instancias de Nextcloud se comuniquen entre sí e intercambien datos."
},
"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");

@ -0,0 +1,6 @@
{ "translations": {
"Cloud Federation API" : "API de la federación en la nube",
"Enable clouds to communicate with each other and exchange data" : "Permitir que las nubes se comuniquen entre sí e intercambien datos",
"The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "La API de la federación en la nube permite que varias instancias de Nextcloud se comuniquen entre sí e intercambien datos."
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
}

@ -30,6 +30,7 @@ use OCA\CloudFederationAPI\Config;
use OCA\CloudFederationAPI\ResponseDefinitions; use OCA\CloudFederationAPI\ResponseDefinitions;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\JSONResponse;
use OCP\Federation\Exceptions\ActionNotSupportedException; use OCP\Federation\Exceptions\ActionNotSupportedException;
use OCP\Federation\Exceptions\AuthenticationFailedException; use OCP\Federation\Exceptions\AuthenticationFailedException;
@ -55,6 +56,7 @@ use Psr\Log\LoggerInterface;
* @psalm-import-type CloudFederationAPIValidationError from ResponseDefinitions * @psalm-import-type CloudFederationAPIValidationError from ResponseDefinitions
* @psalm-import-type CloudFederationAPIError from ResponseDefinitions * @psalm-import-type CloudFederationAPIError from ResponseDefinitions
*/ */
#[OpenAPI(scope: OpenAPI::SCOPE_FEDERATION)]
class RequestHandlerController extends Controller { class RequestHandlerController extends Controller {
public function __construct( public function __construct(
string $appName, string $appName,

@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
/** /**

@ -1,3 +0,0 @@
{
"directory": "js/vendor"
}

@ -1,3 +0,0 @@
# compiled vue templates
src/templates.js
js/

@ -5,7 +5,7 @@
<name>Comments</name> <name>Comments</name>
<summary>Files app plugin to add comments to files</summary> <summary>Files app plugin to add comments to files</summary>
<description>Files app plugin to add comments to files</description> <description>Files app plugin to add comments to files</description>
<version>1.18.0</version> <version>1.19.0</version>
<licence>agpl</licence> <licence>agpl</licence>
<author>Arthur Schiwon</author> <author>Arthur Schiwon</author>
<author>Vincent Petry</author> <author>Vincent Petry</author>
@ -16,7 +16,7 @@
<category>social</category> <category>social</category>
<bugs>https://github.com/nextcloud/server/issues</bugs> <bugs>https://github.com/nextcloud/server/issues</bugs>
<dependencies> <dependencies>
<nextcloud min-version="28" max-version="28"/> <nextcloud min-version="29" max-version="29"/>
</dependencies> </dependencies>
<activity> <activity>

@ -15,7 +15,6 @@ OC.L10N.register(
"No comments yet, start the conversation!" : "Nog geen kommentaar, begin die gesprek!", "No comments yet, start the conversation!" : "Nog geen kommentaar, begin die gesprek!",
"Retry" : "Herprobeer", "Retry" : "Herprobeer",
"Comment" : "Kommentaar", "Comment" : "Kommentaar",
"%1$s commented" : "%1$s het kommentaar gelewer",
"_%n unread comment_::_%n unread comments_" : ["%n ongelese kommentaar","%n ongelese kommentare"] "_%n unread comment_::_%n unread comments_" : ["%n ongelese kommentaar","%n ongelese kommentare"]
}, },
"nplurals=2; plural=(n != 1);"); "nplurals=2; plural=(n != 1);");

@ -13,7 +13,6 @@
"No comments yet, start the conversation!" : "Nog geen kommentaar, begin die gesprek!", "No comments yet, start the conversation!" : "Nog geen kommentaar, begin die gesprek!",
"Retry" : "Herprobeer", "Retry" : "Herprobeer",
"Comment" : "Kommentaar", "Comment" : "Kommentaar",
"%1$s commented" : "%1$s het kommentaar gelewer",
"_%n unread comment_::_%n unread comments_" : ["%n ongelese kommentaar","%n ongelese kommentare"] "_%n unread comment_::_%n unread comments_" : ["%n ongelese kommentaar","%n ongelese kommentare"]
},"pluralForm" :"nplurals=2; plural=(n != 1);" },"pluralForm" :"nplurals=2; plural=(n != 1);"
} }

@ -9,14 +9,17 @@ OC.L10N.register(
"%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s", "%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s",
"{author} commented on {file}" : "{author} علّق على {file}", "{author} commented on {file}" : "{author} علّق على {file}",
"<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات", "<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "تمت الإشارة إليك في \"{file}\" في تعليق لمستخدم. لكن هذا المستخدم تم حذف حسابه بعدها", "You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "تمت الإشارة إليك في \"{file}\"، في تعليقٍ من قِبَل حسابٍ تمّ حذفه سلفاً",
"{user} mentioned you in a comment on \"{file}\"" : "أشار إليك {user} في تعليق على {file}", "{user} mentioned you in a comment on \"{file}\"" : "أشار إليك {user} في تعليق على {file}",
"Files app plugin to add comments to files" : "المكوِّن الإضافي لتطبيق الملفات لإضافة تعليقات إلى الملفات", "Files app plugin to add comments to files" : "المكوِّن الإضافي لتطبيق الملفات لإضافة تعليقات إلى الملفات",
"Edit comment" : "تعديل التعليق", "Edit comment" : "تعديل التعليق",
"Delete comment" : "حذف التعليق", "Delete comment" : "حذف التعليق",
"Cancel edit" : "إلغاء التعديل", "Cancel edit" : "إلغاء التعديل",
"New comment" : "ملاحظة جديدة",
"Write a comment …" : "أكتُب ملاحظةً ...",
"Post comment" : "أضف تعليق", "Post comment" : "أضف تعليق",
"\"@\" for mentions, \":\" for emoji, \"/\" for smart picker" : "\"@\" للإشارات, \":\" للإيموجي, \"/\" للاقط الذكي", "@ for mentions, : for emoji, / for smart picker" : "@ للإشارات، : للإيموجي، / للاقط الذكي",
"Could not reload comments" : "تعذّرت إعادة تحميل الملاحظات",
"No comments yet, start the conversation!" : "لا يوجد تعليقات, ابدأ النقاش الآن!", "No comments yet, start the conversation!" : "لا يوجد تعليقات, ابدأ النقاش الآن!",
"No more messages" : "لامزيد من الرسائل", "No more messages" : "لامزيد من الرسائل",
"Retry" : "أعد المحاولة", "Retry" : "أعد المحاولة",
@ -28,7 +31,7 @@ OC.L10N.register(
"Comment deleted" : "التعليق حُذف", "Comment deleted" : "التعليق حُذف",
"An error occurred while trying to delete the comment" : "حدث خطأ أثناء محاولة حذف التعليق", "An error occurred while trying to delete the comment" : "حدث خطأ أثناء محاولة حذف التعليق",
"An error occurred while trying to create the comment" : "حدث خطأ أثناء محاولة إنشاء التعليق", "An error occurred while trying to create the comment" : "حدث خطأ أثناء محاولة إنشاء التعليق",
"%1$s commented" : "%1$s كتب تعليق", "You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "تمت الإشارة إليك في \"{file}\" في تعليق لمستخدم. لكن هذا المستخدم تم حذف حسابه بعدها",
"_%n unread comment_::_%n unread comments_" : ["%n تعليق غير مقروء","%n تعليق غير مقروء","تعليقان غير مقروءة","%n تعليقات غير مقروء","%n تعليق غير مقروء","%n تعليق غير مقروء"] "_%n unread comment_::_%n unread comments_" : ["%n تعليق غير مقروء","%n تعليق غير مقروء","تعليقان غير مقروءة","%n تعليقات غير مقروء","%n تعليق غير مقروء","%n تعليق غير مقروء"]
}, },
"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"); "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");

@ -7,14 +7,17 @@
"%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s", "%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s",
"{author} commented on {file}" : "{author} علّق على {file}", "{author} commented on {file}" : "{author} علّق على {file}",
"<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات", "<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "تمت الإشارة إليك في \"{file}\" في تعليق لمستخدم. لكن هذا المستخدم تم حذف حسابه بعدها", "You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "تمت الإشارة إليك في \"{file}\"، في تعليقٍ من قِبَل حسابٍ تمّ حذفه سلفاً",
"{user} mentioned you in a comment on \"{file}\"" : "أشار إليك {user} في تعليق على {file}", "{user} mentioned you in a comment on \"{file}\"" : "أشار إليك {user} في تعليق على {file}",
"Files app plugin to add comments to files" : "المكوِّن الإضافي لتطبيق الملفات لإضافة تعليقات إلى الملفات", "Files app plugin to add comments to files" : "المكوِّن الإضافي لتطبيق الملفات لإضافة تعليقات إلى الملفات",
"Edit comment" : "تعديل التعليق", "Edit comment" : "تعديل التعليق",
"Delete comment" : "حذف التعليق", "Delete comment" : "حذف التعليق",
"Cancel edit" : "إلغاء التعديل", "Cancel edit" : "إلغاء التعديل",
"New comment" : "ملاحظة جديدة",
"Write a comment …" : "أكتُب ملاحظةً ...",
"Post comment" : "أضف تعليق", "Post comment" : "أضف تعليق",
"\"@\" for mentions, \":\" for emoji, \"/\" for smart picker" : "\"@\" للإشارات, \":\" للإيموجي, \"/\" للاقط الذكي", "@ for mentions, : for emoji, / for smart picker" : "@ للإشارات، : للإيموجي، / للاقط الذكي",
"Could not reload comments" : "تعذّرت إعادة تحميل الملاحظات",
"No comments yet, start the conversation!" : "لا يوجد تعليقات, ابدأ النقاش الآن!", "No comments yet, start the conversation!" : "لا يوجد تعليقات, ابدأ النقاش الآن!",
"No more messages" : "لامزيد من الرسائل", "No more messages" : "لامزيد من الرسائل",
"Retry" : "أعد المحاولة", "Retry" : "أعد المحاولة",
@ -26,7 +29,7 @@
"Comment deleted" : "التعليق حُذف", "Comment deleted" : "التعليق حُذف",
"An error occurred while trying to delete the comment" : "حدث خطأ أثناء محاولة حذف التعليق", "An error occurred while trying to delete the comment" : "حدث خطأ أثناء محاولة حذف التعليق",
"An error occurred while trying to create the comment" : "حدث خطأ أثناء محاولة إنشاء التعليق", "An error occurred while trying to create the comment" : "حدث خطأ أثناء محاولة إنشاء التعليق",
"%1$s commented" : "%1$s كتب تعليق", "You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "تمت الإشارة إليك في \"{file}\" في تعليق لمستخدم. لكن هذا المستخدم تم حذف حسابه بعدها",
"_%n unread comment_::_%n unread comments_" : ["%n تعليق غير مقروء","%n تعليق غير مقروء","تعليقان غير مقروءة","%n تعليقات غير مقروء","%n تعليق غير مقروء","%n تعليق غير مقروء"] "_%n unread comment_::_%n unread comments_" : ["%n تعليق غير مقروء","%n تعليق غير مقروء","تعليقان غير مقروءة","%n تعليقات غير مقروء","%n تعليق غير مقروء","%n تعليق غير مقروء"]
},"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;" },"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"
} }

@ -4,17 +4,33 @@ OC.L10N.register(
"Comments" : "Comentarios", "Comments" : "Comentarios",
"You commented" : "Comentesti", "You commented" : "Comentesti",
"{author} commented" : "{author} comentó", "{author} commented" : "{author} comentó",
"You commented on %1$s" : "Comentesti en %1$s", "You commented on %1$s" : "Comentesti en: %1$s",
"You commented on {file}" : "Comentesti en {file}", "You commented on {file}" : "Comentesti en: {file}",
"%1$s commented on %2$s" : "%1$s comentó en %2$s", "%1$s commented on %2$s" : "%1$s comentó en: %2$s",
"{author} commented on {file}" : "{autor} comentó en {ficheru}", "{author} commented on {file}" : "{author} comentó en: {file}",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros", "<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros",
"Edit comment" : "Editar comentariu", "{user} mentioned you in a comment on \"{file}\"" : "{user} mentóte nun comentariu de: «{file}»",
"Delete comment" : "Desaniciar comentariu", "Files app plugin to add comments to files" : "Plugin de l'aplicación Ficheros p'amestar comentarios a los ficheros",
"No comments yet, start the conversation!" : "Entá nun hai comentarios. ¡Entama una conversación!", "Edit comment" : "Editar el comentariu",
"Delete comment" : "Desaniciar el comentariu",
"Cancel edit" : "Anular la edición",
"New comment" : "Comentariu nuevu",
"Write a comment …" : "Escribi un comentariu…",
"Post comment" : "Espublizar el comentariu",
"@ for mentions, : for emoji, / for smart picker" : "@ pa les menciones, : pa los fustaxes, / pal selector intelixente",
"Could not reload comments" : "Nun se pudieron recargar los comentarios",
"No comments yet, start the conversation!" : "Nun hai comentarios, ¡anicia una conversación!",
"No more messages" : "Nun hai más mensaxes",
"Retry" : "Retentar", "Retry" : "Retentar",
"_%n unread comment_::_%n unread comments_" : ["%n comentariu ensin lleer","%n comentarios ensin lleer"], "Failed to mark comments as read" : "Nun se pudieron marcar los comentarios como lleíos",
"Unable to load the comments list" : "Nun ye posible cargar la llista de comentarios",
"_1 new comment_::_{unread} new comments_" : ["1 comentariu nuevu","{unread} comentarios nuevos"],
"Comment" : "Comentariu", "Comment" : "Comentariu",
"%1$s commented" : "%1$s comentó" "An error occurred while trying to edit the comment" : "Prodúxose un error mentanto se tentaba d'editar el comentariu",
"Comment deleted" : "Desanicióse'l comentariu",
"An error occurred while trying to delete the comment" : "Prodúxose un error mentanto se tentaba de desaniciar el comentariu",
"An error occurred while trying to create the comment" : "Prodúxose un error mentanto se tentaba de crear el comentariu",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Un usuariu que ta desaniciáu mentóte nun comentariu de: {file}",
"_%n unread comment_::_%n unread comments_" : ["%n comentariu ensin lleer","%n comentarios ensin lleer"]
}, },
"nplurals=2; plural=(n != 1);"); "nplurals=2; plural=(n != 1);");

@ -2,17 +2,33 @@
"Comments" : "Comentarios", "Comments" : "Comentarios",
"You commented" : "Comentesti", "You commented" : "Comentesti",
"{author} commented" : "{author} comentó", "{author} commented" : "{author} comentó",
"You commented on %1$s" : "Comentesti en %1$s", "You commented on %1$s" : "Comentesti en: %1$s",
"You commented on {file}" : "Comentesti en {file}", "You commented on {file}" : "Comentesti en: {file}",
"%1$s commented on %2$s" : "%1$s comentó en %2$s", "%1$s commented on %2$s" : "%1$s comentó en: %2$s",
"{author} commented on {file}" : "{autor} comentó en {ficheru}", "{author} commented on {file}" : "{author} comentó en: {file}",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros", "<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros",
"Edit comment" : "Editar comentariu", "{user} mentioned you in a comment on \"{file}\"" : "{user} mentóte nun comentariu de: «{file}»",
"Delete comment" : "Desaniciar comentariu", "Files app plugin to add comments to files" : "Plugin de l'aplicación Ficheros p'amestar comentarios a los ficheros",
"No comments yet, start the conversation!" : "Entá nun hai comentarios. ¡Entama una conversación!", "Edit comment" : "Editar el comentariu",
"Delete comment" : "Desaniciar el comentariu",
"Cancel edit" : "Anular la edición",
"New comment" : "Comentariu nuevu",
"Write a comment …" : "Escribi un comentariu…",
"Post comment" : "Espublizar el comentariu",
"@ for mentions, : for emoji, / for smart picker" : "@ pa les menciones, : pa los fustaxes, / pal selector intelixente",
"Could not reload comments" : "Nun se pudieron recargar los comentarios",
"No comments yet, start the conversation!" : "Nun hai comentarios, ¡anicia una conversación!",
"No more messages" : "Nun hai más mensaxes",
"Retry" : "Retentar", "Retry" : "Retentar",
"_%n unread comment_::_%n unread comments_" : ["%n comentariu ensin lleer","%n comentarios ensin lleer"], "Failed to mark comments as read" : "Nun se pudieron marcar los comentarios como lleíos",
"Unable to load the comments list" : "Nun ye posible cargar la llista de comentarios",
"_1 new comment_::_{unread} new comments_" : ["1 comentariu nuevu","{unread} comentarios nuevos"],
"Comment" : "Comentariu", "Comment" : "Comentariu",
"%1$s commented" : "%1$s comentó" "An error occurred while trying to edit the comment" : "Prodúxose un error mentanto se tentaba d'editar el comentariu",
"Comment deleted" : "Desanicióse'l comentariu",
"An error occurred while trying to delete the comment" : "Prodúxose un error mentanto se tentaba de desaniciar el comentariu",
"An error occurred while trying to create the comment" : "Prodúxose un error mentanto se tentaba de crear el comentariu",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Un usuariu que ta desaniciáu mentóte nun comentariu de: {file}",
"_%n unread comment_::_%n unread comments_" : ["%n comentariu ensin lleer","%n comentarios ensin lleer"]
},"pluralForm" :"nplurals=2; plural=(n != 1);" },"pluralForm" :"nplurals=2; plural=(n != 1);"
} }

@ -9,7 +9,6 @@ OC.L10N.register(
"%1$s commented on %2$s" : "%1$s коментиран за %2$s", "%1$s commented on %2$s" : "%1$s коментиран за %2$s",
"{author} commented on {file}" : "{author} коментира за {file}", "{author} commented on {file}" : "{author} коментира за {file}",
"<strong>Comments</strong> for files" : "<strong>Коментари</strong> за файлове", "<strong>Comments</strong> for files" : "<strong>Коментари</strong> за файлове",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Бяхте споменат/а към “{file}”, в коментар от потребител, който вече е изтрит",
"{user} mentioned you in a comment on \"{file}\"" : "{user} ви спомена в коментар за “{file}”", "{user} mentioned you in a comment on \"{file}\"" : "{user} ви спомена в коментар за “{file}”",
"Files app plugin to add comments to files" : "Добавка на приложението Файлове за добавяне на коментари към файловете", "Files app plugin to add comments to files" : "Добавка на приложението Файлове за добавяне на коментари към файловете",
"Edit comment" : "Редактирай коментра", "Edit comment" : "Редактирай коментра",
@ -26,7 +25,7 @@ OC.L10N.register(
"Comment deleted" : " Изтрит е коментар", "Comment deleted" : " Изтрит е коментар",
"An error occurred while trying to delete the comment" : "Възникна грешка при опит за изтриване на коментара", "An error occurred while trying to delete the comment" : "Възникна грешка при опит за изтриване на коментара",
"An error occurred while trying to create the comment" : "Възникна грешка при опит за създаване на коментар", "An error occurred while trying to create the comment" : "Възникна грешка при опит за създаване на коментар",
"%1$s commented" : "%1$s коментира", "You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Бяхте споменат/а към “{file}”, в коментар от потребител, който вече е изтрит",
"_%n unread comment_::_%n unread comments_" : ["%n непрочетен коментар","%n непрочетени коментари"] "_%n unread comment_::_%n unread comments_" : ["%n непрочетен коментар","%n непрочетени коментари"]
}, },
"nplurals=2; plural=(n != 1);"); "nplurals=2; plural=(n != 1);");

@ -7,7 +7,6 @@
"%1$s commented on %2$s" : "%1$s коментиран за %2$s", "%1$s commented on %2$s" : "%1$s коментиран за %2$s",
"{author} commented on {file}" : "{author} коментира за {file}", "{author} commented on {file}" : "{author} коментира за {file}",
"<strong>Comments</strong> for files" : "<strong>Коментари</strong> за файлове", "<strong>Comments</strong> for files" : "<strong>Коментари</strong> за файлове",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Бяхте споменат/а към “{file}”, в коментар от потребител, който вече е изтрит",
"{user} mentioned you in a comment on \"{file}\"" : "{user} ви спомена в коментар за “{file}”", "{user} mentioned you in a comment on \"{file}\"" : "{user} ви спомена в коментар за “{file}”",
"Files app plugin to add comments to files" : "Добавка на приложението Файлове за добавяне на коментари към файловете", "Files app plugin to add comments to files" : "Добавка на приложението Файлове за добавяне на коментари към файловете",
"Edit comment" : "Редактирай коментра", "Edit comment" : "Редактирай коментра",
@ -24,7 +23,7 @@
"Comment deleted" : " Изтрит е коментар", "Comment deleted" : " Изтрит е коментар",
"An error occurred while trying to delete the comment" : "Възникна грешка при опит за изтриване на коментара", "An error occurred while trying to delete the comment" : "Възникна грешка при опит за изтриване на коментара",
"An error occurred while trying to create the comment" : "Възникна грешка при опит за създаване на коментар", "An error occurred while trying to create the comment" : "Възникна грешка при опит за създаване на коментар",
"%1$s commented" : "%1$s коментира", "You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Бяхте споменат/а към “{file}”, в коментар от потребител, който вече е изтрит",
"_%n unread comment_::_%n unread comments_" : ["%n непрочетен коментар","%n непрочетени коментари"] "_%n unread comment_::_%n unread comments_" : ["%n непрочетен коментар","%n непрочетени коментари"]
},"pluralForm" :"nplurals=2; plural=(n != 1);" },"pluralForm" :"nplurals=2; plural=(n != 1);"
} }

@ -9,13 +9,14 @@ OC.L10N.register(
"%1$s commented on %2$s" : "%1$s ha escrit un comentari a %2$s", "%1$s commented on %2$s" : "%1$s ha escrit un comentari a %2$s",
"{author} commented on {file}" : "{author} ha escrit un comentari a {file}", "{author} commented on {file}" : "{author} ha escrit un comentari a {file}",
"<strong>Comments</strong> for files" : "<strong>Comentaris</strong> per a fitxers", "<strong>Comments</strong> for files" : "<strong>Comentaris</strong> per a fitxers",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Se us ha esmentat a «{file}» en un comentari d'un usuari que s'ha suprimit",
"{user} mentioned you in a comment on \"{file}\"" : "{user} us ha esmentat en un comentari a «{file}»", "{user} mentioned you in a comment on \"{file}\"" : "{user} us ha esmentat en un comentari a «{file}»",
"Files app plugin to add comments to files" : "Connector de l'aplicació Fitxers per a afegir comentaris als fitxers", "Files app plugin to add comments to files" : "Connector de l'aplicació Fitxers per a afegir comentaris als fitxers",
"Edit comment" : "Edita el comentari", "Edit comment" : "Edita el comentari",
"Delete comment" : "Suprimeix el comentari", "Delete comment" : "Suprimeix el comentari",
"Cancel edit" : "Cancel·la l'edició", "Cancel edit" : "Cancel·la l'edició",
"Post comment" : "Publica el comentari", "Post comment" : "Publica el comentari",
"@ for mentions, : for emoji, / for smart picker" : "@ per a mencions, : per a emojis, / per al selector intel·ligent",
"Could not reload comments" : "No s'han pogut tornar a carregar els comentaris",
"No comments yet, start the conversation!" : "Encara no hi ha cap comentari. Enceteu la conversa!", "No comments yet, start the conversation!" : "Encara no hi ha cap comentari. Enceteu la conversa!",
"No more messages" : "No hi ha més missatges", "No more messages" : "No hi ha més missatges",
"Retry" : "Torna-ho a provar", "Retry" : "Torna-ho a provar",
@ -27,7 +28,7 @@ OC.L10N.register(
"Comment deleted" : "S'ha suprimit el comentari", "Comment deleted" : "S'ha suprimit el comentari",
"An error occurred while trying to delete the comment" : "S'ha produït un error en intentar suprimir el comentari", "An error occurred while trying to delete the comment" : "S'ha produït un error en intentar suprimir el comentari",
"An error occurred while trying to create the comment" : "S'ha produït un error en intentar crear el comentari", "An error occurred while trying to create the comment" : "S'ha produït un error en intentar crear el comentari",
"%1$s commented" : "%1$s ha escrit un comentari", "You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Se us ha esmentat a «{file}» en un comentari d'un usuari que s'ha suprimit",
"_%n unread comment_::_%n unread comments_" : ["%n comentari sense llegir","%n comentaris sense llegir"] "_%n unread comment_::_%n unread comments_" : ["%n comentari sense llegir","%n comentaris sense llegir"]
}, },
"nplurals=2; plural=(n != 1);"); "nplurals=2; plural=(n != 1);");

@ -7,13 +7,14 @@
"%1$s commented on %2$s" : "%1$s ha escrit un comentari a %2$s", "%1$s commented on %2$s" : "%1$s ha escrit un comentari a %2$s",
"{author} commented on {file}" : "{author} ha escrit un comentari a {file}", "{author} commented on {file}" : "{author} ha escrit un comentari a {file}",
"<strong>Comments</strong> for files" : "<strong>Comentaris</strong> per a fitxers", "<strong>Comments</strong> for files" : "<strong>Comentaris</strong> per a fitxers",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Se us ha esmentat a «{file}» en un comentari d'un usuari que s'ha suprimit",
"{user} mentioned you in a comment on \"{file}\"" : "{user} us ha esmentat en un comentari a «{file}»", "{user} mentioned you in a comment on \"{file}\"" : "{user} us ha esmentat en un comentari a «{file}»",
"Files app plugin to add comments to files" : "Connector de l'aplicació Fitxers per a afegir comentaris als fitxers", "Files app plugin to add comments to files" : "Connector de l'aplicació Fitxers per a afegir comentaris als fitxers",
"Edit comment" : "Edita el comentari", "Edit comment" : "Edita el comentari",
"Delete comment" : "Suprimeix el comentari", "Delete comment" : "Suprimeix el comentari",
"Cancel edit" : "Cancel·la l'edició", "Cancel edit" : "Cancel·la l'edició",
"Post comment" : "Publica el comentari", "Post comment" : "Publica el comentari",
"@ for mentions, : for emoji, / for smart picker" : "@ per a mencions, : per a emojis, / per al selector intel·ligent",
"Could not reload comments" : "No s'han pogut tornar a carregar els comentaris",
"No comments yet, start the conversation!" : "Encara no hi ha cap comentari. Enceteu la conversa!", "No comments yet, start the conversation!" : "Encara no hi ha cap comentari. Enceteu la conversa!",
"No more messages" : "No hi ha més missatges", "No more messages" : "No hi ha més missatges",
"Retry" : "Torna-ho a provar", "Retry" : "Torna-ho a provar",
@ -25,7 +26,7 @@
"Comment deleted" : "S'ha suprimit el comentari", "Comment deleted" : "S'ha suprimit el comentari",
"An error occurred while trying to delete the comment" : "S'ha produït un error en intentar suprimir el comentari", "An error occurred while trying to delete the comment" : "S'ha produït un error en intentar suprimir el comentari",
"An error occurred while trying to create the comment" : "S'ha produït un error en intentar crear el comentari", "An error occurred while trying to create the comment" : "S'ha produït un error en intentar crear el comentari",
"%1$s commented" : "%1$s ha escrit un comentari", "You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Se us ha esmentat a «{file}» en un comentari d'un usuari que s'ha suprimit",
"_%n unread comment_::_%n unread comments_" : ["%n comentari sense llegir","%n comentaris sense llegir"] "_%n unread comment_::_%n unread comments_" : ["%n comentari sense llegir","%n comentaris sense llegir"]
},"pluralForm" :"nplurals=2; plural=(n != 1);" },"pluralForm" :"nplurals=2; plural=(n != 1);"
} }

@ -9,14 +9,16 @@ OC.L10N.register(
"%1$s commented on %2$s" : "%1$s okomentoval(a) %2$s", "%1$s commented on %2$s" : "%1$s okomentoval(a) %2$s",
"{author} commented on {file}" : "{author} okomentoval(a) {file}", "{author} commented on {file}" : "{author} okomentoval(a) {file}",
"<strong>Comments</strong> for files" : "<strong>Komentáře</strong> k souborům", "<strong>Comments</strong> for files" : "<strong>Komentáře</strong> k souborům",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Byli jste zmíněni u souboru „{file}“, v komentáři od uživatele, který byl později smazán",
"{user} mentioned you in a comment on \"{file}\"" : "{user} vás zmínil(a) v komentáři u „{file}“", "{user} mentioned you in a comment on \"{file}\"" : "{user} vás zmínil(a) v komentáři u „{file}“",
"Files app plugin to add comments to files" : "Zásuvný modul do aplikace Soubory pro přidávání komentářů k souborům", "Files app plugin to add comments to files" : "Zásuvný modul do aplikace Soubory pro přidávání komentářů k souborům",
"Edit comment" : "Upravit komentář", "Edit comment" : "Upravit komentář",
"Delete comment" : "Smazat komentář", "Delete comment" : "Smazat komentář",
"Cancel edit" : "Zrušit úpravu", "Cancel edit" : "Zrušit úpravu",
"New comment" : "Nový komentář",
"Write a comment …" : "Napsat komentář…",
"Post comment" : "Odeslat komentář", "Post comment" : "Odeslat komentář",
"\"@\" for mentions, \":\" for emoji, \"/\" for smart picker" : "„@“ pro zmínění, „:“ pro emotikony, „/“ pro inteligentní výběr", "@ for mentions, : for emoji, / for smart picker" : "@ pro zmínění, : pro emotikony, / pro inteligentní výběr",
"Could not reload comments" : "Znovunačtení komentářů se nezdařilo",
"No comments yet, start the conversation!" : "Zatím bez komentářů, začněte konverzaci!", "No comments yet, start the conversation!" : "Zatím bez komentářů, začněte konverzaci!",
"No more messages" : "Žádné další zprávy", "No more messages" : "Žádné další zprávy",
"Retry" : "Zkusit znovu", "Retry" : "Zkusit znovu",
@ -28,7 +30,7 @@ OC.L10N.register(
"Comment deleted" : "Komentář smazán", "Comment deleted" : "Komentář smazán",
"An error occurred while trying to delete the comment" : "Došlo k chybě při pokusu o smazání komentáře", "An error occurred while trying to delete the comment" : "Došlo k chybě při pokusu o smazání komentáře",
"An error occurred while trying to create the comment" : "Došlo k chybě při pokusu o vytvoření komentáře", "An error occurred while trying to create the comment" : "Došlo k chybě při pokusu o vytvoření komentáře",
"%1$s commented" : "%1$s okomentováno", "You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Byli jste zmíněni u souboru „{file}“, v komentáři od uživatele, který byl později smazán",
"_%n unread comment_::_%n unread comments_" : ["%n nepřečtený komentář","%n nepřečtené komentáře","%n nepřečtených komentářů","%n nepřečtené komentáře"] "_%n unread comment_::_%n unread comments_" : ["%n nepřečtený komentář","%n nepřečtené komentáře","%n nepřečtených komentářů","%n nepřečtené komentáře"]
}, },
"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;"); "nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;");

@ -7,14 +7,16 @@
"%1$s commented on %2$s" : "%1$s okomentoval(a) %2$s", "%1$s commented on %2$s" : "%1$s okomentoval(a) %2$s",
"{author} commented on {file}" : "{author} okomentoval(a) {file}", "{author} commented on {file}" : "{author} okomentoval(a) {file}",
"<strong>Comments</strong> for files" : "<strong>Komentáře</strong> k souborům", "<strong>Comments</strong> for files" : "<strong>Komentáře</strong> k souborům",
"You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Byli jste zmíněni u souboru „{file}“, v komentáři od uživatele, který byl později smazán",
"{user} mentioned you in a comment on \"{file}\"" : "{user} vás zmínil(a) v komentáři u „{file}“", "{user} mentioned you in a comment on \"{file}\"" : "{user} vás zmínil(a) v komentáři u „{file}“",
"Files app plugin to add comments to files" : "Zásuvný modul do aplikace Soubory pro přidávání komentářů k souborům", "Files app plugin to add comments to files" : "Zásuvný modul do aplikace Soubory pro přidávání komentářů k souborům",
"Edit comment" : "Upravit komentář", "Edit comment" : "Upravit komentář",
"Delete comment" : "Smazat komentář", "Delete comment" : "Smazat komentář",
"Cancel edit" : "Zrušit úpravu", "Cancel edit" : "Zrušit úpravu",
"New comment" : "Nový komentář",
"Write a comment …" : "Napsat komentář…",
"Post comment" : "Odeslat komentář", "Post comment" : "Odeslat komentář",
"\"@\" for mentions, \":\" for emoji, \"/\" for smart picker" : "„@“ pro zmínění, „:“ pro emotikony, „/“ pro inteligentní výběr", "@ for mentions, : for emoji, / for smart picker" : "@ pro zmínění, : pro emotikony, / pro inteligentní výběr",
"Could not reload comments" : "Znovunačtení komentářů se nezdařilo",
"No comments yet, start the conversation!" : "Zatím bez komentářů, začněte konverzaci!", "No comments yet, start the conversation!" : "Zatím bez komentářů, začněte konverzaci!",
"No more messages" : "Žádné další zprávy", "No more messages" : "Žádné další zprávy",
"Retry" : "Zkusit znovu", "Retry" : "Zkusit znovu",
@ -26,7 +28,7 @@
"Comment deleted" : "Komentář smazán", "Comment deleted" : "Komentář smazán",
"An error occurred while trying to delete the comment" : "Došlo k chybě při pokusu o smazání komentáře", "An error occurred while trying to delete the comment" : "Došlo k chybě při pokusu o smazání komentáře",
"An error occurred while trying to create the comment" : "Došlo k chybě při pokusu o vytvoření komentáře", "An error occurred while trying to create the comment" : "Došlo k chybě při pokusu o vytvoření komentáře",
"%1$s commented" : "%1$s okomentováno", "You were mentioned on \"{file}\", in a comment by a user that has since been deleted" : "Byli jste zmíněni u souboru „{file}“, v komentáři od uživatele, který byl později smazán",
"_%n unread comment_::_%n unread comments_" : ["%n nepřečtený komentář","%n nepřečtené komentáře","%n nepřečtených komentářů","%n nepřečtené komentáře"] "_%n unread comment_::_%n unread comments_" : ["%n nepřečtený komentář","%n nepřečtené komentáře","%n nepřečtených komentářů","%n nepřečtené komentáře"]
},"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;" },"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;"
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save