diff --git a/.editorconfig b/.editorconfig old mode 100755 new mode 100644 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md old mode 100755 new mode 100644 index f7efbf14..879ae0dd --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -6,7 +6,7 @@ * Read, and fill the Pull Request template * If this is a fix for a typo (in code, documentation, or the README) please file an issue and let us sort it out. We do not need a PR * If the PR is addressing an existing issue include, closes #\, in the body of the PR commit message -* If you want to discuss changes, you can also bring it up in [#dev-talk](https://discordapp.com/channels/354974912613449730/757585807061155840) in our [Discord server](https://discord.gg/YWrKVTn) +* If you want to discuss changes, you can also bring it up in [#dev-talk](https://discordapp.com/channels/354974912613449730/757585807061155840) in our [Discord server](https://linuxserver.io/discord) ## Common files @@ -105,10 +105,10 @@ docker build \ -t linuxserver/nextcloud:latest . ``` -The ARM variants can be built on x86_64 hardware using `multiarch/qemu-user-static` +The ARM variants can be built on x86_64 hardware and vice versa using `lscr.io/linuxserver/qemu-static` ```bash -docker run --rm --privileged multiarch/qemu-user-static:register --reset +docker run --rm --privileged lscr.io/linuxserver/qemu-static --reset ``` Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64`. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml old mode 100755 new mode 100644 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml old mode 100755 new mode 100644 index dcb34e3f..f9bb59cc --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,11 +1,11 @@ blank_issues_enabled: false contact_links: - name: Discord chat support - url: https://discord.gg/YWrKVTn + url: https://linuxserver.io/discord about: Realtime support / chat with the community and the team. - - name: Discourse discussion forum - url: https://discourse.linuxserver.io + - name: Github Discussions + url: https://github.com/orgs/linuxserver/discussions about: Post on our community forum. - name: Documentation diff --git a/.github/ISSUE_TEMPLATE/issue.bug.yml b/.github/ISSUE_TEMPLATE/issue.bug.yml old mode 100755 new mode 100644 diff --git a/.github/ISSUE_TEMPLATE/issue.feature.yml b/.github/ISSUE_TEMPLATE/issue.feature.yml old mode 100755 new mode 100644 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index aeab469a..d251efd6 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,7 +3,6 @@ [linuxserverurl]: https://linuxserver.io [![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)][linuxserverurl] - @@ -12,7 +11,6 @@ - @@ -21,11 +19,16 @@ ------------------------------ - - [ ] I have read the [contributing](https://github.com/linuxserver/docker-nextcloud/blob/master/.github/CONTRIBUTING.md) guideline and understand that I have made the correct modifications +- [ ] I have read the [contributing](https://github.com/linuxserver/docker-nextcloud/blob/master/.github/CONTRIBUTING.md) guideline and understand that I have made the correct modifications + + + +- [ ] An LLM assisted me in writing the code or text for this PR +- [ ] An LLM agent wrote the code or text for this PR ------------------------------ - + ## Description: @@ -38,6 +41,5 @@ - ## Source / References: diff --git a/.github/workflows/call_issue_pr_tracker.yml b/.github/workflows/call_issue_pr_tracker.yml old mode 100755 new mode 100644 index 2c307843..d07cf121 --- a/.github/workflows/call_issue_pr_tracker.yml +++ b/.github/workflows/call_issue_pr_tracker.yml @@ -8,6 +8,9 @@ on: pull_request_review: types: [submitted,edited,dismissed] +permissions: + contents: read + jobs: manage-project: permissions: diff --git a/.github/workflows/call_issues_cron.yml b/.github/workflows/call_issues_cron.yml old mode 100755 new mode 100644 index 3cade4bc..716c188d --- a/.github/workflows/call_issues_cron.yml +++ b/.github/workflows/call_issues_cron.yml @@ -4,6 +4,9 @@ on: - cron: '35 2 * * *' workflow_dispatch: +permissions: + contents: read + jobs: stale: permissions: diff --git a/.github/workflows/external_trigger.yml b/.github/workflows/external_trigger.yml old mode 100755 new mode 100644 index 87a03f96..29e9bfa9 --- a/.github/workflows/external_trigger.yml +++ b/.github/workflows/external_trigger.yml @@ -3,26 +3,39 @@ name: External Trigger Main on: workflow_dispatch: +permissions: + contents: read + jobs: external-trigger-master: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.1 + - uses: linuxserver/github-workflows/.github/actions/checkout@v1 - name: External Trigger if: github.ref == 'refs/heads/master' + env: + SKIP_EXTERNAL_TRIGGER: ${{ vars.SKIP_EXTERNAL_TRIGGER }} run: | printf "# External trigger for docker-nextcloud\n\n" >> $GITHUB_STEP_SUMMARY - if [ -n "${{ secrets.PAUSE_EXTERNAL_TRIGGER_NEXTCLOUD_MASTER }}" ]; then + if grep -q "^nextcloud_master_" <<< "${SKIP_EXTERNAL_TRIGGER}"; then + echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` contains \`nextcloud_master_\`; will skip trigger if version matches." >> $GITHUB_STEP_SUMMARY + elif grep -q "^nextcloud_master" <<< "${SKIP_EXTERNAL_TRIGGER}"; then echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY - echo "> Github secret \`PAUSE_EXTERNAL_TRIGGER_NEXTCLOUD_MASTER\` is set; skipping trigger." >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` contains \`nextcloud_master\`; skipping trigger." >> $GITHUB_STEP_SUMMARY exit 0 fi echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY - echo "> External trigger running off of master branch. To disable this trigger, set a Github secret named \`PAUSE_EXTERNAL_TRIGGER_NEXTCLOUD_MASTER\`" >> $GITHUB_STEP_SUMMARY + echo "> External trigger running off of master branch. To disable this trigger, add \`nextcloud_master\` into the Github organizational variable \`SKIP_EXTERNAL_TRIGGER\`." >> $GITHUB_STEP_SUMMARY printf "\n## Retrieving external version\n\n" >> $GITHUB_STEP_SUMMARY EXT_RELEASE=$(curl -u ${{ secrets.CR_USER }}:${{ secrets.CR_PAT }} -sX GET https://api.github.com/repos/nextcloud/server/releases | jq -r '.[] | select(.prerelease != true) | .tag_name' | sed 's|^v||g' | sort -rV | head -1) echo "Type is \`custom_version_command\`" >> $GITHUB_STEP_SUMMARY + if grep -q "^nextcloud_master_${EXT_RELEASE}" <<< "${SKIP_EXTERNAL_TRIGGER}"; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_EXTERNAL_TRIGGER\` matches current external release; skipping trigger." >> $GITHUB_STEP_SUMMARY + exit 0 + fi if [ -z "${EXT_RELEASE}" ] || [ "${EXT_RELEASE}" == "null" ]; then echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY echo "> Can't retrieve external version, exiting" >> $GITHUB_STEP_SUMMARY @@ -33,24 +46,43 @@ jobs: "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} exit 1 fi - EXT_RELEASE=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g') - echo "External version: \`${EXT_RELEASE}\`" >> $GITHUB_STEP_SUMMARY + EXT_RELEASE_SANITIZED=$(echo ${EXT_RELEASE} | sed 's/[~,%@+;:/]//g') + echo "Sanitized external version: \`${EXT_RELEASE_SANITIZED}\`" >> $GITHUB_STEP_SUMMARY echo "Retrieving last pushed version" >> $GITHUB_STEP_SUMMARY image="linuxserver/nextcloud" tag="latest" token=$(curl -sX GET \ "https://ghcr.io/token?scope=repository%3Alinuxserver%2Fnextcloud%3Apull" \ | jq -r '.token') - multidigest=$(curl -s \ - --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ - --header "Authorization: Bearer ${token}" \ - "https://ghcr.io/v2/${image}/manifests/${tag}" \ - | jq -r 'first(.manifests[].digest)') - digest=$(curl -s \ + multidigest=$(curl -s \ + --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Accept: application/vnd.oci.image.index.v1+json" \ + --header "Authorization: Bearer ${token}" \ + "https://ghcr.io/v2/${image}/manifests/${tag}") + if jq -e '.layers // empty' <<< "${multidigest}" >/dev/null 2>&1; then + # If there's a layer element it's a single-arch manifest so just get that digest + digest=$(jq -r '.config.digest' <<< "${multidigest}") + else + # Otherwise it's multi-arch or has manifest annotations + if jq -e '.manifests[]?.annotations // empty' <<< "${multidigest}" >/dev/null 2>&1; then + # Check for manifest annotations and delete if found + multidigest=$(jq 'del(.manifests[] | select(.annotations))' <<< "${multidigest}") + fi + if [[ $(jq '.manifests | length' <<< "${multidigest}") -gt 1 ]]; then + # If there's still more than one digest, it's multi-arch + multidigest=$(jq -r ".manifests[] | select(.platform.architecture == \"amd64\").digest?" <<< "${multidigest}") + else + # Otherwise it's single arch + multidigest=$(jq -r ".manifests[].digest?" <<< "${multidigest}") + fi + if digest=$(curl -s \ --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ + --header "Accept: application/vnd.oci.image.manifest.v1+json" \ --header "Authorization: Bearer ${token}" \ - "https://ghcr.io/v2/${image}/manifests/${multidigest}" \ - | jq -r '.config.digest') + "https://ghcr.io/v2/${image}/manifests/${multidigest}"); then + digest=$(jq -r '.config.digest' <<< "${digest}"); + fi + fi image_info=$(curl -sL \ --header "Authorization: Bearer ${token}" \ "https://ghcr.io/v2/${image}/blobs/${digest}") @@ -71,33 +103,45 @@ jobs: exit 1 fi echo "Last pushed version: \`${IMAGE_VERSION}\`" >> $GITHUB_STEP_SUMMARY - if [ "${EXT_RELEASE}" == "${IMAGE_VERSION}" ]; then - echo "Version \`${EXT_RELEASE}\` already pushed, exiting" >> $GITHUB_STEP_SUMMARY + if [ "${EXT_RELEASE_SANITIZED}" == "${IMAGE_VERSION}" ]; then + echo "Sanitized version \`${EXT_RELEASE_SANITIZED}\` already pushed, exiting" >> $GITHUB_STEP_SUMMARY exit 0 elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-nextcloud/job/master/lastBuild/api/json | jq -r '.building') == "true" ]; then echo "New version \`${EXT_RELEASE}\` found; but there already seems to be an active build on Jenkins; exiting" >> $GITHUB_STEP_SUMMARY exit 0 else - printf "\n## Trigger new build\n\n" >> $GITHUB_STEP_SUMMARY - echo "New version \`${EXT_RELEASE}\` found; old version was \`${IMAGE_VERSION}\`. Triggering new build" >> $GITHUB_STEP_SUMMARY - response=$(curl -iX POST \ - https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-nextcloud/job/master/buildWithParameters?PACKAGE_CHECK=false \ - --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") - echo "Jenkins [job queue url](${response%$'\r'})" >> $GITHUB_STEP_SUMMARY - echo "Sleeping 10 seconds until job starts" >> $GITHUB_STEP_SUMMARY - sleep 10 - buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url') - buildurl="${buildurl%$'\r'}" - echo "Jenkins job [build url](${buildurl})" >> $GITHUB_STEP_SUMMARY - echo "Attempting to change the Jenkins job description" >> $GITHUB_STEP_SUMMARY - curl -iX POST \ - "${buildurl}submitDescription" \ - --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \ - --data-urlencode "description=GHA external trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ - --data-urlencode "Submit=Submit" - echo "**** Notifying Discord ****" - TRIGGER_REASON="A version change was detected for nextcloud tag latest. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE}" - curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, - "description": "**Build Triggered** \n**Reason:** '"${TRIGGER_REASON}"' \n**Build URL:** '"${buildurl}display/redirect"' \n"}], - "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + if [[ "${artifacts_found}" == "false" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> New version detected, but not all artifacts are published yet; skipping trigger" >> $GITHUB_STEP_SUMMARY + FAILURE_REASON="New version ${EXT_RELEASE} for nextcloud tag latest is detected, however not all artifacts are uploaded to upstream release yet. Will try again later." + curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, + "description": "**Trigger Failed** \n**Reason:** '"${FAILURE_REASON}"' \n"}], + "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + else + printf "\n## Trigger new build\n\n" >> $GITHUB_STEP_SUMMARY + echo "New sanitized version \`${EXT_RELEASE_SANITIZED}\` found; old version was \`${IMAGE_VERSION}\`. Triggering new build" >> $GITHUB_STEP_SUMMARY + if [[ "${artifacts_found}" == "true" ]]; then + echo "All artifacts seem to be uploaded." >> $GITHUB_STEP_SUMMARY + fi + response=$(curl -iX POST \ + https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-nextcloud/job/master/buildWithParameters?PACKAGE_CHECK=false \ + --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") + echo "Jenkins [job queue url](${response%$'\r'})" >> $GITHUB_STEP_SUMMARY + echo "Sleeping 10 seconds until job starts" >> $GITHUB_STEP_SUMMARY + sleep 10 + buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url') + buildurl="${buildurl%$'\r'}" + echo "Jenkins job [build url](${buildurl})" >> $GITHUB_STEP_SUMMARY + echo "Attempting to change the Jenkins job description" >> $GITHUB_STEP_SUMMARY + curl -iX POST \ + "${buildurl}submitDescription" \ + --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \ + --data-urlencode "description=GHA external trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ + --data-urlencode "Submit=Submit" + echo "**** Notifying Discord ****" + TRIGGER_REASON="A version change was detected for nextcloud tag latest. Old version:${IMAGE_VERSION} New version:${EXT_RELEASE_SANITIZED}" + curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, + "description": "**Build Triggered** \n**Reason:** '"${TRIGGER_REASON}"' \n**Build URL:** '"${buildurl}display/redirect"' \n"}], + "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + fi fi diff --git a/.github/workflows/external_trigger_scheduler.yml b/.github/workflows/external_trigger_scheduler.yml old mode 100755 new mode 100644 index 100fd673..9b2655cc --- a/.github/workflows/external_trigger_scheduler.yml +++ b/.github/workflows/external_trigger_scheduler.yml @@ -5,11 +5,14 @@ on: - cron: '27 * * * *' workflow_dispatch: +permissions: + contents: read + jobs: external-trigger-scheduler: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.1 + - uses: linuxserver/github-workflows/.github/actions/checkout@v1 with: fetch-depth: '0' diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml old mode 100755 new mode 100644 index aebf625f..ab80c94e --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -2,12 +2,18 @@ name: Greetings on: [pull_request_target, issues] +permissions: + contents: read + jobs: greeting: + permissions: + issues: write + pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/first-interaction@v1 + - uses: linuxserver/github-workflows/.github/actions/first-interaction@v1 with: - issue-message: 'Thanks for opening your first issue here! Be sure to follow the relevant issue templates, or risk having this issue marked as invalid.' - pr-message: 'Thanks for opening this pull request! Be sure to follow the [pull request template](https://github.com/linuxserver/docker-nextcloud/blob/master/.github/PULL_REQUEST_TEMPLATE.md)!' - repo-token: ${{ secrets.GITHUB_TOKEN }} + issue_message: 'Thanks for opening your first issue here! Be sure to follow the relevant issue templates, or risk having this issue marked as invalid.' + pr_message: 'Thanks for opening this pull request! Be sure to follow the [pull request template](https://github.com/linuxserver/docker-nextcloud/blob/master/.github/PULL_REQUEST_TEMPLATE.md)!' + repo_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/package_trigger.yml b/.github/workflows/package_trigger.yml deleted file mode 100755 index d1cec1f3..00000000 --- a/.github/workflows/package_trigger.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Package Trigger Main - -on: - workflow_dispatch: - -jobs: - package-trigger-master: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4.1.1 - - - name: Package Trigger - if: github.ref == 'refs/heads/master' - run: | - printf "# Package trigger for docker-nextcloud\n\n" >> $GITHUB_STEP_SUMMARY - if [ -n "${{ secrets.PAUSE_PACKAGE_TRIGGER_NEXTCLOUD_MASTER }}" ]; then - echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY - echo "> Github secret \`PAUSE_PACKAGE_TRIGGER_NEXTCLOUD_MASTER\` is set; skipping trigger." >> $GITHUB_STEP_SUMMARY - exit 0 - fi - if [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-nextcloud/job/master/lastBuild/api/json | jq -r '.building') == "true" ]; then - echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY - echo "> There already seems to be an active build on Jenkins; skipping package trigger" >> $GITHUB_STEP_SUMMARY - exit 0 - fi - echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY - echo "> Package trigger running off of master branch. To disable, set a Github secret named \`PAUSE_PACKAGE_TRIGGER_NEXTCLOUD_MASTER\`" >> $GITHUB_STEP_SUMMARY - response=$(curl -iX POST \ - https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-nextcloud/job/master/buildWithParameters?PACKAGE_CHECK=true \ - --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") - echo "Jenkins [job queue url](${response%$'\r'})" >> $GITHUB_STEP_SUMMARY - echo "Sleeping 10 seconds until job starts" >> $GITHUB_STEP_SUMMARY - sleep 10 - buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url') - buildurl="${buildurl%$'\r'}" - echo "Jenkins job [build url](${buildurl})" >> $GITHUB_STEP_SUMMARY - echo "Attempting to change the Jenkins job description" >> $GITHUB_STEP_SUMMARY - curl -iX POST \ - "${buildurl}submitDescription" \ - --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \ - --data-urlencode "description=GHA package trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ - --data-urlencode "Submit=Submit" diff --git a/.github/workflows/package_trigger_scheduler.yml b/.github/workflows/package_trigger_scheduler.yml old mode 100755 new mode 100644 index 3fcd26ed..32e4680d --- a/.github/workflows/package_trigger_scheduler.yml +++ b/.github/workflows/package_trigger_scheduler.yml @@ -5,15 +5,20 @@ on: - cron: '42 11 * * 2' workflow_dispatch: +permissions: + contents: read + jobs: package-trigger-scheduler: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.1 + - uses: linuxserver/github-workflows/.github/actions/checkout@v1 with: fetch-depth: '0' - name: Package Trigger Scheduler + env: + SKIP_PACKAGE_TRIGGER: ${{ vars.SKIP_PACKAGE_TRIGGER }} run: | printf "# Package trigger scheduler for docker-nextcloud\n\n" >> $GITHUB_STEP_SUMMARY printf "Found the branches:\n\n%s\n" "$(git for-each-ref --format='- %(refname:lstrip=3)' refs/remotes)" >> $GITHUB_STEP_SUMMARY @@ -24,27 +29,75 @@ jobs: continue fi printf "\n## Evaluating \`%s\`\n\n" ${br} >> $GITHUB_STEP_SUMMARY - ls_branch=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-nextcloud/${br}/jenkins-vars.yml | yq -r '.ls_branch') - if [ "${br}" == "${ls_branch}" ]; then + JENKINS_VARS=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-nextcloud/${br}/jenkins-vars.yml) + if ! curl -sfX GET https://raw.githubusercontent.com/linuxserver/docker-nextcloud/${br}/Jenkinsfile >/dev/null 2>&1; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> No Jenkinsfile found. Branch is either deprecated or is an early dev branch." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif [[ "${br}" == $(yq -r '.ls_branch' <<< "${JENKINS_VARS}") ]]; then echo "Branch appears to be live; checking workflow." >> $GITHUB_STEP_SUMMARY - if curl -sfX GET https://raw.githubusercontent.com/linuxserver/docker-nextcloud/${br}/.github/workflows/package_trigger.yml > /dev/null 2>&1; then - echo "Triggering package trigger workflow for branch ${br}" >> $GITHUB_STEP_SUMMARY - triggered_branches="${triggered_branches}${br} " - curl -iX POST \ - -H "Authorization: token ${{ secrets.CR_PAT }}" \ - -H "Accept: application/vnd.github.v3+json" \ - -d "{\"ref\":\"refs/heads/${br}\"}" \ - https://api.github.com/repos/linuxserver/docker-nextcloud/actions/workflows/package_trigger.yml/dispatches - sleep 30 + README_VARS=$(curl -sX GET https://raw.githubusercontent.com/linuxserver/docker-nextcloud/${br}/readme-vars.yml) + if [[ $(yq -r '.project_deprecation_status' <<< "${README_VARS}") == "true" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Branch appears to be deprecated; skipping trigger." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif [[ $(yq -r '.skip_package_check' <<< "${JENKINS_VARS}") == "true" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Skipping branch ${br} due to \`skip_package_check\` being set in \`jenkins-vars.yml\`." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif grep -q "^nextcloud_${br}" <<< "${SKIP_PACKAGE_TRIGGER}"; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Github organizational variable \`SKIP_PACKAGE_TRIGGER\` contains \`nextcloud_${br}\`; skipping trigger." >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " + elif [ $(curl -s https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-nextcloud/job/${br}/lastBuild/api/json | jq -r '.building' 2>/dev/null) == "true" ]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> There already seems to be an active build on Jenkins; skipping package trigger for ${br}" >> $GITHUB_STEP_SUMMARY + skipped_branches="${skipped_branches}${br} " else - echo "Skipping branch ${br} due to no package trigger workflow present." >> $GITHUB_STEP_SUMMARY + echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY + echo "> Triggering package trigger for branch ${br}" >> $GITHUB_STEP_SUMMARY + printf "> To disable, add \`nextcloud_%s\` into the Github organizational variable \`SKIP_PACKAGE_TRIGGER\`.\n\n" "${br}" >> $GITHUB_STEP_SUMMARY + triggered_branches="${triggered_branches}${br} " + response=$(curl -iX POST \ + https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-nextcloud/job/${br}/buildWithParameters?PACKAGE_CHECK=true \ + --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} | grep -i location | sed "s|^[L|l]ocation: \(.*\)|\1|") + if [[ -z "${response}" ]]; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Jenkins build could not be triggered. Skipping branch." + continue + fi + echo "Jenkins [job queue url](${response%$'\r'})" >> $GITHUB_STEP_SUMMARY + echo "Sleeping 10 seconds until job starts" >> $GITHUB_STEP_SUMMARY + sleep 10 + buildurl=$(curl -s "${response%$'\r'}api/json" | jq -r '.executable.url') + buildurl="${buildurl%$'\r'}" + echo "Jenkins job [build url](${buildurl})" >> $GITHUB_STEP_SUMMARY + echo "Attempting to change the Jenkins job description" >> $GITHUB_STEP_SUMMARY + if ! curl -ifX POST \ + "${buildurl}submitDescription" \ + --user ${{ secrets.JENKINS_USER }}:${{ secrets.JENKINS_TOKEN }} \ + --data-urlencode "description=GHA package trigger https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ + --data-urlencode "Submit=Submit"; then + echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY + echo "> Unable to change the Jenkins job description." + fi + sleep 20 fi else echo "Skipping branch ${br} due to being detected as dev branch." >> $GITHUB_STEP_SUMMARY fi done - echo "**** Package check build(s) triggered for branch(es): ${triggered_branches} ****" - echo "**** Notifying Discord ****" - curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, - "description": "**Package Check Build(s) Triggered for nextcloud** \n**Branch(es):** '"${triggered_branches}"' \n**Build URL:** '"https://ci.linuxserver.io/blue/organizations/jenkins/Docker-Pipeline-Builders%2Fdocker-nextcloud/activity/"' \n"}], - "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + if [[ -n "${triggered_branches}" ]] || [[ -n "${skipped_branches}" ]]; then + if [[ -n "${triggered_branches}" ]]; then + NOTIFY_BRANCHES="**Triggered:** ${triggered_branches} \n" + NOTIFY_BUILD_URL="**Build URL:** https://ci.linuxserver.io/blue/organizations/jenkins/Docker-Pipeline-Builders%2Fdocker-nextcloud/activity/ \n" + echo "**** Package check build(s) triggered for branch(es): ${triggered_branches} ****" + fi + if [[ -n "${skipped_branches}" ]]; then + NOTIFY_BRANCHES="${NOTIFY_BRANCHES}**Skipped:** ${skipped_branches} \n" + fi + echo "**** Notifying Discord ****" + curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://cdn.discordapp.com/avatars/354986384542662657/df91181b3f1cf0ef1592fbe18e0962d7.png","embeds": [{"color": 9802903, + "description": "**Package Check Build(s) for nextcloud** \n'"${NOTIFY_BRANCHES}"''"${NOTIFY_BUILD_URL}"'"}], + "username": "Github Actions"}' ${{ secrets.DISCORD_WEBHOOK }} + fi diff --git a/.github/workflows/permissions.yml b/.github/workflows/permissions.yml old mode 100755 new mode 100644 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..e9e5feae --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,127 @@ + + +# AGENTS.md - LinuxServer.io container image repository + +This file is for AI coding agents (and the humans driving them) working in a LinuxServer.io `docker-*` image repository. Read it fully before proposing or making any change. + +We welcome contributions, including AI-assisted ones, but this is a volunteer-run project that ships 150+ images to millions of users from one shared template. A change that looks like an improvement in isolation is often wrong for us. When this file and your instincts disagree, this file wins. When this file is silent, copy what the surrounding code already does. + +## 1. Decide where the change belongs before writing any code + +Our images are built for **broad consumption**. Every package, env var and init step we add is something we have to maintain, rebuild weekly and support forever, for every user, whether they use it or not. We do not ship Swiss Army Knife images. Work down this list and stop at the first match: + +1. **It is a bug or feature in the application itself** (not in our packaging): it belongs upstream with the app's developers. Do not patch, fork or work around upstream application behaviour in the image. +2. **It is an unsupported or reasonable-endeavours environment** (Podman, k8s, Portainer, Watchtower, NFS/SMB `/config`, LXC, custom entrypoints, etc. See the [Support Policy](https://docs.linuxserver.io/misc/support-policy/)): we will not add logic to the image to accommodate it. +3. **It only matters to one user or one setup**: use a private [custom script](https://docs.linuxserver.io/general/container-customization/#custom-scripts) in `/custom-cont-init.d` or [custom service](https://docs.linuxserver.io/general/container-customization/#custom-services) in `/custom-services.d`. No PR needed. +4. **It is useful to a subset of users** (an extra package, plugin dependency, alternative UI, hardware driver, third party integration, extra daemon, niche toggle): it is a **[Docker Mod](https://github.com/linuxserver/docker-mods)**, not a change to this repo. Check whether one already exists first (`universal-*` mods work on every image; `-*` mods are image specific). If not, create one from the template in the docker-mods repo; each mod lives on its own branch there. +5. **The large majority of this image's users benefit, or the image is actually broken**: a PR to this repo is appropriate. Examples: the app fails to start, a new upstream release needs a new runtime dependency, a base image rebase, a permissions bug, a wrong default, incorrect docs in `readme-vars.yml`. + +If you are an agent and the requested change lands on 1-4, **stop and tell your operator** where it belongs instead of writing the PR. "It is only a few lines" is not a reason to put it in the image. If in doubt, a human should open an issue or ask in `#contibutor-discussion` on [Discord](https://linuxserver.io/discord) before doing the work. + +### If it is a mod + +Mods are the pressure valve that keeps the images small. Roughly what lives there today, and therefore does **not** belong in an image: extra OS/pip packages and language toolchains, GPU/hardware driver stacks, alternative web UIs and themes, third party plugins and scanners, integrations with external services (Cloudflare, CrowdSec, Apprise, GeoIP, VPN providers), Docker socket automation, sidecar daemons (redis, tunnels), post-processing scripts, and env-var-to-config-file shims. + +- Follow the README and `template` branch in [docker-mods](https://github.com/linuxserver/docker-mods). A mod is a `FROM scratch` single layer of files extracted over `/` at container start, wired into s6 as `init-mod---*` / `svc-mod--` units. +- Mods never call `apk`/`apt`/`pip` directly; they append to `/mod-repo-packages-to-install.list` or `/mod-pip-packages-to-install.list` and let the base image do one batched install. Handle Alpine and Ubuntu package names where the mod is universal. +- Most good mods are a 10-40 line script. If yours is not, reconsider the approach. +- A mod is also the proving ground. If a mod becomes something nearly everyone uses, the team may absorb it into the image later and turn the mod into a no-op with a deprecation notice. That is the team's call, not a reason to skip the mod step. + +## 2. Repository layout and what you must not edit + +| Path | Notes | +| --- | --- | +| `Dockerfile`, `Dockerfile.aarch64` (sometimes `Dockerfile.riscv64`) | One per architecture. **Any change must be replicated to all of them.** They normally differ only in base image tag and arch strings. | +| `root/` | Copied to `/` in the image. s6-overlay v3 services live in `root/etc/s6-overlay/s6-rc.d/`, defaults in `root/defaults/`, one-time upgrade steps in `root/migrations/`. | +| `readme-vars.yml` | **Source of truth for the README, docs site, Unraid template and changelog.** Edit this. | +| `jenkins-vars.yml` | Build pipeline variables (version detection, CI test settings). Rarely needs touching. | +| `README.md` | **Generated. Never edit.** | +| `Jenkinsfile` | **Generated. Never edit.** | +| `package_versions.txt` | **Generated by CI. Never edit.** | +| `.github/**`, `.editorconfig`, `LICENSE`, `AGENTS.md` | **Generated / globally distributed. Never edit here.** Changes go to [docker-jenkins-builder](https://github.com/linuxserver/docker-jenkins-builder). | + +Do not add new top level files or tooling: no `docker-compose.yml`, `Makefile`, test suites, linter configs, pre-commit hooks, extra workflows, `CHANGELOG.md`, `SECURITY.md`, devcontainers, or helper scripts. The repo is intentionally small. + +Some repos have multiple live branches that publish different tags (`nightly`, `develop`, `libtorrentv1`, etc.). Each is maintained independently. Target the branch the change applies to, never merge one into another, and do not assume `master` or `main` is the only one that matters. + +## 3. Code style: keep it simple, match what is there + +The goal of every image is the thinnest possible layer between our base image and the upstream app: install it, drop a sane default config into `/config` on first run, fix permissions, start it. Prefer deleting logic to adding it. The base image already handles PUID/PGID, `UMASK`, `TZ`, `FILE__` secrets, mods, custom scripts, cron and device permissions; never reimplement those. + +### Dockerfiles + +- Base is always `ghcr.io/linuxserver/baseimage-*`. Do not change distro, switch to upstream/distroless images, or add multi-stage complexity unless a maintainer asked for it. Base image rebases are done by the team. +- Follow the existing shape exactly: a single `RUN` chain joined with `&& \`, each step announced with `echo "**** doing thing ****"`, two space indentation, a `**** cleanup ****` step at the end removing `/tmp/*` and package caches. +- Packages are listed **one per line in alphabetical order**. Build-only dependencies go in a `build-dependencies` virtual package (Alpine) or are purged (Ubuntu) in the same layer. +- Do not hardcode or pin the application version. Keep the `if [ -z ${APP_VERSION+x} ]; then ...` pattern; CI supplies the version as a build arg and `jenkins-vars.yml` defines how it is detected. +- Do not add `HEALTHCHECK`, `USER`, `ENTRYPOINT` or `CMD`. The base image owns init (`/init`), and the container must start as root unless the image already documents non-root support. +- Do not touch the `LABEL maintainer` or `build_version` lines. + +### Init scripts and services (`root/etc/s6-overlay/s6-rc.d/`) + +- Naming: `init--config` (oneshot) and `svc-` (longrun). Wire them in using empty files in `dependencies.d/` and `user/contents.d/`, exactly as the existing ones do. Oneshots have `type`, `up` (the path to `run`) and `run`. No legacy `cont-init.d` / `services.d`. +- Every script starts with: + + ```bash + #!/usr/bin/with-contenv bash + # shellcheck shell=bash + ``` + +- Bash, four space indentation, `[[ ]]` tests, `"${VAR}"` quoting, short lowercase `#` comments. Scripts must be shellcheck clean. +- Use `lsiown` instead of `chown`, run the app as `abc` via `s6-setuidgid abc`, and `exec` the final process so s6 supervises it. Keep `s6-notifyoncheck` readiness checks where they exist. +- If `readme-vars.yml` has `nonroot_supported: true` or `readonly_supported: true`, every new privileged operation (chown, writing outside `/config` and `/run`, `s6-setuidgid`) must be guarded the same way the existing code does it (`if [[ -z ${LSIO_NON_ROOT_USER} ]]; then` etc.). Do not break those modes. +- User data and config live in `/config`. Copy defaults only if the file does not already exist; never overwrite user config on startup. If an existing user's config must change, add a numbered script in `root/migrations/`. +- Avoid recursive `lsiown` on large data paths (media, downloads); it makes startup take minutes for real users. +- New environment variables are a last resort. If the app can be configured through its own config file or UI, that is the answer. We do not wrap app settings in env vars. + +## 4. Documentation and changelog + +- All user-facing docs changes go in `readme-vars.yml` (`app_setup_block`, `param_env_vars`, `opt_param_*`, etc.). Reference: [`_container-vars-blank`](https://github.com/linuxserver/docker-jenkins-builder/blob/master/ansible/vars/_container-vars-blank). +- Any change to a Dockerfile or to anything under `root/` needs a new entry at the **top** of `changelogs:` in `readme-vars.yml`, one short factual line: + + ```yaml + - {date: "DD.MM.YY:", desc: "Add libfoo to fix thumbnail generation."} + ``` + +- Optionally regenerate the templated files to check your vars render (see the [jenkins-builder README](https://github.com/linuxserver/docker-jenkins-builder#running-against-local-project)), but do not hand edit the output. + +## 5. Test it for real + +A change that has not been built and run is not ready. At minimum: + +```bash +docker build --no-cache --pull -t lscr.io/linuxserver/:test . +docker run --rm -e PUID=1000 -e PGID=1000 -e TZ=Etc/UTC -v "$(pwd)/testconfig:/config" -p : lscr.io/linuxserver/:test +``` + +Confirm the init completes (`[ls.io-init] done.`), the app comes up, and it survives a restart against an **existing** `/config`, not just a fresh one. If you touched the aarch64 Dockerfile with anything arch specific, build that too (`lscr.io/linuxserver/qemu-static`). If you, the agent, cannot run Docker, say so plainly in your output; do not claim testing that did not happen. + +## 6. Pull requests + +- **Disclose AI use.** If any part of the PR (code, description, or the investigation behind it) was produced with an AI tool, say so in the PR description: which tool, and what it was used for. Agents: add this line yourself, do not leave it to the operator. Undisclosed AI-generated PRs will be closed. Disclosure does not count against a PR; a human who cannot explain their own PR does. +- **A human is accountable.** The person opening the PR must have read and understood every line, built and run the image, and be able to answer review questions in their own words. Do not paste maintainer questions into a chatbot and paste the answers back. Fully autonomous agents must not open PRs or issues on our repos. +- **One focused change per PR.** The smallest diff that fixes the problem. No drive-by refactors, reformatting, comment rewording, "modernisation", dependency shuffling, or fixes for things nobody reported. +- **No typo / wording-only PRs.** Open an issue instead and we will sort it out. +- **Finish before you open.** Do not open drafts and iterate in public with a stream of fixup commits. +- **Fill in the PR template honestly**, keep its structure, and tick the contributing checkbox only if it is true. Description, benefit to the wider userbase, how it was tested (real commands, real output), and links. Write it short and plain: no generated summaries, emoji headers, or bullet lists restating the diff. +- Reference the issue with `closes #` when there is one. For anything non trivial, there should be an human-submitted issue or Discord discussion first. +- Commit messages are short, plain, imperative sentences (`Add libfoo for thumbnail support`). No conventional-commit prefixes, no emoji. +- A PR is a proposal; it may be declined even if it works. The most common reason is section 1 of this file. + +## 7. Issues + +- GitHub issues are for reproducible bugs in **our image** and for feature requests. +- Agents must not file issues on a user's behalf from a guess. An issue needs a real reproduction on the latest image, with mods and custom scripts disabled, the compose/run command and full container logs from startup, using the issue template. +- Do not submit AI-generated root cause analyses or "security audits" of the image as issues. Scanner output about CVEs in upstream or distro packages is not actionable; images are rebuilt regularly to pull in distro fixes. +- Support questions must always be submitted by a human and go to [Discord](https://linuxserver.io/discord) or the [forum](https://github.com/orgs/linuxserver/discussions); see [how to get support](https://docs.linuxserver.io/general/how-to-get-support/). + +## 8. Quick self check before you finish + +- [ ] This change benefits most users of this image, and is not a mod, custom script, or upstream issue. +- [ ] Only hand-maintained files were edited (`Dockerfile*`, `root/**`, `readme-vars.yml`, rarely `jenkins-vars.yml`). +- [ ] Every Dockerfile variant got the same change; packages are alphabetical. +- [ ] Style matches the neighbouring code; shebang and shellcheck directive present; non-root / read-only guards preserved. +- [ ] Changelog entry added at the top of `changelogs:` with today's date as `DD.MM.YY:`. +- [ ] Image was built and run, including against an existing `/config`. +- [ ] The diff contains nothing the task did not require. +- [ ] PR description discloses AI use and a human has reviewed everything. diff --git a/Dockerfile b/Dockerfile index 2058ad3b..cb672249 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -FROM ghcr.io/linuxserver/baseimage-alpine-nginx:3.20 +FROM ghcr.io/linuxserver/baseimage-alpine-nginx:3.24 # set version label ARG BUILD_DATE @@ -22,45 +22,43 @@ RUN \ imagemagick-pdf \ imagemagick-svg \ libxml2 \ - php83-apcu \ - php83-bcmath \ - php83-bz2 \ - php83-dom \ - php83-exif \ - php83-ftp \ - php83-gd \ - php83-gmp \ - php83-imap \ - php83-intl \ - php83-ldap \ - php83-opcache \ - php83-pcntl \ - php83-pdo_mysql \ - php83-pdo_pgsql \ - php83-pdo_sqlite \ - php83-pecl-imagick \ - php83-pecl-mcrypt \ - php83-pecl-memcached \ - php83-pecl-smbclient \ - php83-pgsql \ - php83-posix \ - php83-redis \ - php83-sodium \ - php83-sqlite3 \ - php83-sysvsem \ - php83-xmlreader \ + php85-apcu \ + php85-bcmath \ + php85-bz2 \ + php85-dom \ + php85-exif \ + php85-ftp \ + php85-gd \ + php85-gmp \ + php85-imap \ + php85-intl \ + php85-ldap \ + php85-pcntl \ + php85-pdo_mysql \ + php85-pdo_pgsql \ + php85-pdo_sqlite \ + php85-pecl-imagick \ + php85-pecl-memcached \ + php85-pecl-smbclient \ + php85-pgsql \ + php85-posix \ + php85-redis \ + php85-sodium \ + php85-sqlite3 \ + php85-sysvsem \ + php85-xmlreader \ rsync \ samba-client \ util-linux \ sudo && \ echo "**** configure php-fpm to pass env vars ****" && \ - sed -E -i 's/^;?clear_env ?=.*$/clear_env = no/g' /etc/php83/php-fpm.d/www.conf && \ - grep -qxF 'clear_env = no' /etc/php83/php-fpm.d/www.conf || echo 'clear_env = no' >> /etc/php83/php-fpm.d/www.conf && \ - echo "env[PATH] = /usr/local/bin:/usr/bin:/bin" >> /etc/php83/php-fpm.conf && \ + sed -E -i 's/^;?clear_env ?=.*$/clear_env = no/g' /etc/php85/php-fpm.d/www.conf && \ + if ! grep -qxF 'clear_env = no' /etc/php85/php-fpm.d/www.conf; then echo 'clear_env = no' >> /etc/php85/php-fpm.d/www.conf; fi && \ + echo "env[PATH] = /usr/local/bin:/usr/bin:/bin" >> /etc/php85/php-fpm.conf && \ echo "**** configure php for nextcloud ****" && \ { \ echo 'apc.enable_cli=1'; \ - } >> /etc/php83/conf.d/apcu.ini && \ + } >> /etc/php85/conf.d/apcu.ini && \ { \ echo 'opcache.enable=1'; \ echo 'opcache.interned_strings_buffer=32'; \ @@ -69,17 +67,17 @@ RUN \ echo 'opcache.save_comments=1'; \ echo 'opcache.revalidate_freq=60'; \ echo 'opcache.jit=1255'; \ - echo 'opcache.jit_buffer_size=128M'; \ - } >> "/etc/php83/conf.d/00_opcache.ini" && \ + echo 'opcache.jit_buffer_size=8M'; \ + } >> "/etc/php85/conf.d/00_opcache.ini" && \ { \ - echo 'memory_limit=512M'; \ - echo 'upload_max_filesize=512M'; \ - echo 'post_max_size=512M'; \ - echo 'max_input_time=300'; \ - echo 'max_execution_time=300'; \ + echo 'memory_limit=-1'; \ + echo 'upload_max_filesize=100G'; \ + echo 'post_max_size=100G'; \ + echo 'max_input_time=3600'; \ + echo 'max_execution_time=3600'; \ echo 'output_buffering=0'; \ echo 'always_populate_raw_post_data=-1'; \ - } >> "/etc/php83/conf.d/nextcloud.ini" && \ + } >> "/etc/php85/conf.d/nextcloud.ini" && \ echo "**** install nextcloud ****" && \ mkdir -p \ /app/www/src/ && \ diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index 1277906e..6ee4978d 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -FROM ghcr.io/linuxserver/baseimage-alpine-nginx:arm64v8-3.20 +FROM ghcr.io/linuxserver/baseimage-alpine-nginx:arm64v8-3.24 # set version label ARG BUILD_DATE @@ -22,45 +22,43 @@ RUN \ imagemagick-pdf \ imagemagick-svg \ libxml2 \ - php83-apcu \ - php83-bcmath \ - php83-bz2 \ - php83-dom \ - php83-exif \ - php83-ftp \ - php83-gd \ - php83-gmp \ - php83-imap \ - php83-intl \ - php83-ldap \ - php83-opcache \ - php83-pcntl \ - php83-pdo_mysql \ - php83-pdo_pgsql \ - php83-pdo_sqlite \ - php83-pecl-imagick \ - php83-pecl-mcrypt \ - php83-pecl-memcached \ - php83-pecl-smbclient \ - php83-pgsql \ - php83-posix \ - php83-redis \ - php83-sodium \ - php83-sqlite3 \ - php83-sysvsem \ - php83-xmlreader \ + php85-apcu \ + php85-bcmath \ + php85-bz2 \ + php85-dom \ + php85-exif \ + php85-ftp \ + php85-gd \ + php85-gmp \ + php85-imap \ + php85-intl \ + php85-ldap \ + php85-pcntl \ + php85-pdo_mysql \ + php85-pdo_pgsql \ + php85-pdo_sqlite \ + php85-pecl-imagick \ + php85-pecl-memcached \ + php85-pecl-smbclient \ + php85-pgsql \ + php85-posix \ + php85-redis \ + php85-sodium \ + php85-sqlite3 \ + php85-sysvsem \ + php85-xmlreader \ rsync \ samba-client \ util-linux \ sudo && \ echo "**** configure php-fpm to pass env vars ****" && \ - sed -E -i 's/^;?clear_env ?=.*$/clear_env = no/g' /etc/php83/php-fpm.d/www.conf && \ - grep -qxF 'clear_env = no' /etc/php83/php-fpm.d/www.conf || echo 'clear_env = no' >> /etc/php83/php-fpm.d/www.conf && \ - echo "env[PATH] = /usr/local/bin:/usr/bin:/bin" >> /etc/php83/php-fpm.conf && \ + sed -E -i 's/^;?clear_env ?=.*$/clear_env = no/g' /etc/php85/php-fpm.d/www.conf && \ + if ! grep -qxF 'clear_env = no' /etc/php85/php-fpm.d/www.conf; then echo 'clear_env = no' >> /etc/php85/php-fpm.d/www.conf; fi && \ + echo "env[PATH] = /usr/local/bin:/usr/bin:/bin" >> /etc/php85/php-fpm.conf && \ echo "**** configure php for nextcloud ****" && \ { \ echo 'apc.enable_cli=1'; \ - } >> /etc/php83/conf.d/apcu.ini && \ + } >> /etc/php85/conf.d/apcu.ini && \ { \ echo 'opcache.enable=1'; \ echo 'opcache.interned_strings_buffer=32'; \ @@ -69,17 +67,17 @@ RUN \ echo 'opcache.save_comments=1'; \ echo 'opcache.revalidate_freq=60'; \ echo 'opcache.jit=1255'; \ - echo 'opcache.jit_buffer_size=128M'; \ - } >> "/etc/php83/conf.d/00_opcache.ini" && \ + echo 'opcache.jit_buffer_size=8M'; \ + } >> "/etc/php85/conf.d/00_opcache.ini" && \ { \ - echo 'memory_limit=512M'; \ - echo 'upload_max_filesize=512M'; \ - echo 'post_max_size=512M'; \ - echo 'max_input_time=300'; \ - echo 'max_execution_time=300'; \ + echo 'memory_limit=-1'; \ + echo 'upload_max_filesize=100G'; \ + echo 'post_max_size=100G'; \ + echo 'max_input_time=3600'; \ + echo 'max_execution_time=3600'; \ echo 'output_buffering=0'; \ echo 'always_populate_raw_post_data=-1'; \ - } >> "/etc/php83/conf.d/nextcloud.ini" && \ + } >> "/etc/php85/conf.d/nextcloud.ini" && \ echo "**** install nextcloud ****" && \ mkdir -p \ /app/www/src/ && \ diff --git a/Jenkinsfile b/Jenkinsfile index 22dae0df..5c834111 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,7 +8,7 @@ pipeline { } // Input to determine if this is a package check parameters { - string(defaultValue: 'false', description: 'package check run', name: 'PACKAGE_CHECK') + string(defaultValue: 'false', description: 'package check run', name: 'PACKAGE_CHECK') } // Configuration for the variables used for this specific repo environment { @@ -51,20 +51,87 @@ pipeline { ''' } } + /* ############################ + Bash Function For GHCR Retry + ############################ */ + // Create a reusable script for a ghcr retry bash function + stage("Create Bash Function"){ + steps{ + sh '''#! /bin/bash + # create our retry function + retry_ghcr() { + local max_attempts=7 + local base_delay=10 + local max_delay=90 + local attempt=1 + local errfile exit_code delay pause + errfile=$(mktemp) + while true; do + # run inside an if so a caller's set -e cannot abort before we get to retry + if "$@" 2> >(tee "${errfile}" >&2); then + exit_code=0 + else + exit_code=$? + fi + # make sure tee has finished writing before we read the file + wait $! 2>/dev/null || true + if [[ "${exit_code}" == "0" ]]; then + rm -f "${errfile}" + return 0 + elif ! grep -q -i -E "retry-after:|toomanyrequests|too many requests" "${errfile}"; then + rm -f "${errfile}" + return "${exit_code}" + elif (( attempt >= max_attempts )); then + rm -f "${errfile}" + echo "retry: $* failed after ${attempt} attempts (exit ${exit_code})" >&2 + return "${exit_code}" + else + # exponential delay: base * 2^(attempt-1), capped at max_delay + delay=$(( base_delay * 2 ** (attempt - 1) )) + (( delay > max_delay )) && delay="${max_delay}" + # jitter between half and full delay so parallel builds spread out + pause=$(( delay / 2 + RANDOM % (delay / 2 + 1) )) + echo "retry: attempt ${attempt}/${max_attempts} failed (exit ${exit_code}); waiting ${pause}s..." >&2 + sleep "${pause}" + ((attempt++)) + fi + done + } + + declare -f retry_ghcr > ${WORKSPACE}/retry_ghcr.sh + ''' + } + } // Setup all the basic environment variables needed for the build stage("Set ENV Variables base"){ steps{ echo "Running on node: ${NODE_NAME}" sh '''#! /bin/bash - containers=$(docker ps -aq) + echo "Pruning builder" + docker builder prune -f --builder container || : + containers=$(docker ps -q) if [[ -n "${containers}" ]]; then - docker stop ${containers} + BUILDX_CONTAINER_ID=$(docker ps -qf 'name=buildx_buildkit') + for container in ${containers}; do + if [[ "${container}" == "${BUILDX_CONTAINER_ID}" ]]; then + echo "skipping buildx container in docker stop" + else + echo "Stopping container ${container}" + docker stop ${container} + fi + done fi - docker system prune -af --volumes || : ''' + docker system prune -f --volumes || : + docker image prune -af || : + ''' script{ env.EXIT_STATUS = '' + env.CI_TEST_ATTEMPTED = '' + env.PUSH_ATTEMPTED = '' env.LS_RELEASE = sh( - script: '''docker run --rm quay.io/skopeo/stable:v1 inspect docker://ghcr.io/${LS_USER}/${CONTAINER_NAME}:latest 2>/dev/null | jq -r '.Labels.build_version' | awk '{print $3}' | grep '\\-ls' || : ''', + script: '''#! /bin/bash + source ${WORKSPACE}/retry_ghcr.sh + retry_ghcr docker run --rm quay.io/skopeo/stable:v1 inspect docker://ghcr.io/${LS_USER}/${CONTAINER_NAME}:latest | jq -r '.Labels.build_version' | awk '{print $3}' | grep '\\-ls' || : ''', returnStdout: true).trim() env.LS_RELEASE_NOTES = sh( script: '''cat readme-vars.yml | awk -F \\" '/date: "[0-9][0-9].[0-9][0-9].[0-9][0-9]:/ {print $4;exit;}' | sed -E ':a;N;$!ba;s/\\r{0,1}\\n/\\\\n/g' ''', @@ -81,8 +148,16 @@ pipeline { env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/commit/' + env.GIT_COMMIT env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DOCKERHUB_IMAGE + '/tags/' env.PULL_REQUEST = env.CHANGE_ID - env.TEMPLATED_FILES = 'Jenkinsfile README.md LICENSE .editorconfig ./.github/CONTRIBUTING.md ./.github/FUNDING.yml ./.github/ISSUE_TEMPLATE/config.yml ./.github/ISSUE_TEMPLATE/issue.bug.yml ./.github/ISSUE_TEMPLATE/issue.feature.yml ./.github/PULL_REQUEST_TEMPLATE.md ./.github/workflows/external_trigger_scheduler.yml ./.github/workflows/greetings.yml ./.github/workflows/package_trigger_scheduler.yml ./.github/workflows/call_issue_pr_tracker.yml ./.github/workflows/call_issues_cron.yml ./.github/workflows/permissions.yml ./.github/workflows/external_trigger.yml ./.github/workflows/package_trigger.yml' + env.TEMPLATED_FILES = 'Jenkinsfile README.md LICENSE .editorconfig AGENTS.md ./.github/CONTRIBUTING.md ./.github/FUNDING.yml ./.github/ISSUE_TEMPLATE/config.yml ./.github/ISSUE_TEMPLATE/issue.bug.yml ./.github/ISSUE_TEMPLATE/issue.feature.yml ./.github/PULL_REQUEST_TEMPLATE.md ./.github/workflows/external_trigger_scheduler.yml ./.github/workflows/greetings.yml ./.github/workflows/package_trigger_scheduler.yml ./.github/workflows/call_issue_pr_tracker.yml ./.github/workflows/call_issues_cron.yml ./.github/workflows/permissions.yml ./.github/workflows/external_trigger.yml' + if ( env.SYFT_IMAGE_TAG == null ) { + env.SYFT_IMAGE_TAG = 'latest' + } + if ( env.GITLAB_TIMEOUT == null ) { + env.GITLAB_TIMEOUT = '600' + } } + echo "Using syft image tag ${SYFT_IMAGE_TAG}" + echo "Using gitlab registry timeout ${GITLAB_TIMEOUT}" sh '''#! /bin/bash echo "The default github branch detected as ${GH_DEFAULT_BRANCH}" ''' script{ @@ -191,6 +266,8 @@ pipeline { env.VERSION_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER env.META_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN + env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'latest' } } } @@ -215,6 +292,8 @@ pipeline { env.META_TAG = env.EXT_RELEASE_CLEAN + '-pkg-' + env.PACKAGE_TAG + '-dev-' + env.COMMIT_SHA env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DEV_DOCKERHUB_IMAGE + '/tags/' + env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'develop' } } } @@ -239,6 +318,8 @@ pipeline { env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/pull/' + env.PULL_REQUEST env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.PR_DOCKERHUB_IMAGE + '/tags/' + env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'develop' } } } @@ -257,11 +338,13 @@ pipeline { } sh '''curl -sL https://raw.githubusercontent.com/linuxserver/docker-jenkins-builder/master/checkrun.sh | /bin/bash''' sh '''#! /bin/bash + source ${WORKSPACE}/retry_ghcr.sh + retry_ghcr docker pull ghcr.io/linuxserver/baseimage-alpine:3.23 docker run --rm \ -v ${WORKSPACE}:/mnt \ -e AWS_ACCESS_KEY_ID=\"${S3_KEY}\" \ -e AWS_SECRET_ACCESS_KEY=\"${S3_SECRET}\" \ - ghcr.io/linuxserver/baseimage-alpine:3.20 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ + ghcr.io/linuxserver/baseimage-alpine:3.23 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ apk add --no-cache python3 && \ python3 -m venv /lsiopy && \ pip install --no-cache-dir -U pip && \ @@ -283,7 +366,8 @@ pipeline { sh '''#! /bin/bash set -e TEMPDIR=$(mktemp -d) - docker pull ghcr.io/linuxserver/jenkins-builder:latest + source ${WORKSPACE}/retry_ghcr.sh + retry_ghcr docker pull ghcr.io/linuxserver/jenkins-builder:latest # Cloned repo paths for templating: # ${TEMPDIR}/docker-${CONTAINER_NAME}: Cloned branch master of ${LS_USER}/${LS_REPO} for running the jenkins builder on # ${TEMPDIR}/repo/${LS_REPO}: Cloned branch master of ${LS_USER}/${LS_REPO} for commiting various templated file changes and pushing back to Github @@ -311,7 +395,7 @@ pipeline { echo "Jenkinsfile is up to date." fi echo "Starting Stage 2 - Delete old templates" - OLD_TEMPLATES=".github/ISSUE_TEMPLATE.md .github/ISSUE_TEMPLATE/issue.bug.md .github/ISSUE_TEMPLATE/issue.feature.md .github/workflows/call_invalid_helper.yml .github/workflows/stale.yml" + OLD_TEMPLATES=".github/ISSUE_TEMPLATE.md .github/ISSUE_TEMPLATE/issue.bug.md .github/ISSUE_TEMPLATE/issue.feature.md .github/workflows/call_invalid_helper.yml .github/workflows/stale.yml .github/workflows/package_trigger.yml" for i in ${OLD_TEMPLATES}; do if [[ -f "${i}" ]]; then TEMPLATES_TO_DELETE="${i} ${TEMPLATES_TO_DELETE}" @@ -335,6 +419,36 @@ pipeline { else echo "No templates to delete" fi + echo "Starting Stage 2.5 - Update init diagram" + if ! grep -q 'init_diagram:' readme-vars.yml; then + echo "Adding the key 'init_diagram' to readme-vars.yml" + sed -i '\\|^#.*changelog.*$|d' readme-vars.yml + sed -i 's|^changelogs:|# init diagram\\ninit_diagram:\\n\\n# changelog\\nchangelogs:|' readme-vars.yml + fi + mkdir -p ${TEMPDIR}/d2 + retry_ghcr docker pull ghcr.io/linuxserver/d2-builder:latest + docker run --rm -v ${TEMPDIR}/d2:/output -e PUID=$(id -u) -e PGID=$(id -g) -e RAW="true" ghcr.io/linuxserver/d2-builder:latest ${CONTAINER_NAME}:latest + ls -al ${TEMPDIR}/d2 + yq -ei ".init_diagram |= load_str(\\"${TEMPDIR}/d2/${CONTAINER_NAME}-latest.d2\\")" readme-vars.yml + if [[ $(md5sum readme-vars.yml | cut -c1-8) != $(md5sum ${TEMPDIR}/docker-${CONTAINER_NAME}/readme-vars.yml | cut -c1-8) ]]; then + echo "'init_diagram' has been updated. Updating repo and exiting build, new one will trigger based on commit." + mkdir -p ${TEMPDIR}/repo + git clone https://github.com/${LS_USER}/${LS_REPO}.git ${TEMPDIR}/repo/${LS_REPO} + cd ${TEMPDIR}/repo/${LS_REPO} + git checkout -f master + cp ${WORKSPACE}/readme-vars.yml ${TEMPDIR}/repo/${LS_REPO}/readme-vars.yml + git add readme-vars.yml + git commit -m 'Bot Updating Templated Files' + git pull https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master + git push https://LinuxServer-CI:${GITHUB_TOKEN}@github.com/${LS_USER}/${LS_REPO}.git master + echo "true" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + echo "Updating templates and exiting build, new one will trigger based on commit" + rm -Rf ${TEMPDIR} + exit 0 + else + echo "false" > /tmp/${COMMIT_SHA}-${BUILD_NUMBER} + echo "Init diagram is unchanged" + fi echo "Starting Stage 3 - Update templates" CURRENTHASH=$(grep -hs ^ ${TEMPLATED_FILES} | md5sum | cut -c1-8) cd ${TEMPDIR}/docker-${CONTAINER_NAME} @@ -529,22 +643,78 @@ pipeline { steps { echo "Running on node: ${NODE_NAME}" sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile" - sh "docker buildx build \ - --label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ - --label \"org.opencontainers.image.authors=linuxserver.io\" \ - --label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-nextcloud/packages\" \ - --label \"org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-nextcloud\" \ - --label \"org.opencontainers.image.source=https://github.com/linuxserver/docker-nextcloud\" \ - --label \"org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}\" \ - --label \"org.opencontainers.image.revision=${COMMIT_SHA}\" \ - --label \"org.opencontainers.image.vendor=linuxserver.io\" \ - --label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ - --label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ - --label \"org.opencontainers.image.title=Nextcloud\" \ - --label \"org.opencontainers.image.description=[Nextcloud](https://nextcloud.com/) gives you access to all your files wherever you are. Where are your photos and documents? With Nextcloud you pick a server of your choice, at home, in a data center or at a provider. And that is where your files will be. Nextcloud runs on that server, protecting your data and giving you access from your desktop or mobile devices. Through Nextcloud you also access, sync and share your existing data on that FTP drive at the office, a Dropbox or a NAS you have at home. \" \ - --no-cache --pull -t ${IMAGE}:${META_TAG} --platform=linux/amd64 \ - --provenance=false --sbom=false \ - --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." + sh '''#! /bin/bash + source ${WORKSPACE}/retry_ghcr.sh + retry_ghcr docker buildx build \ + --label "org.opencontainers.image.created=${GITHUB_DATE}" \ + --label "org.opencontainers.image.authors=linuxserver.io" \ + --label "org.opencontainers.image.url=https://github.com/linuxserver/docker-nextcloud/packages" \ + --label "org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-nextcloud" \ + --label "org.opencontainers.image.source=https://github.com/linuxserver/docker-nextcloud" \ + --label "org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}" \ + --label "org.opencontainers.image.revision=${COMMIT_SHA}" \ + --label "org.opencontainers.image.vendor=linuxserver.io" \ + --label "org.opencontainers.image.licenses=GPL-3.0-only" \ + --label "org.opencontainers.image.ref.name=${COMMIT_SHA}" \ + --label "org.opencontainers.image.title=Nextcloud" \ + --label "org.opencontainers.image.description=[Nextcloud](https://nextcloud.com/) gives you access to all your files wherever you are. Where are your photos and documents? With Nextcloud you pick a server of your choice, at home, in a data center or at a provider. And that is where your files will be. Nextcloud runs on that server, protecting your data and giving you access from your desktop or mobile devices. Through Nextcloud you also access, sync and share your existing data on that FTP drive at the office, a Dropbox or a NAS you have at home. " \ + --no-cache --pull -t ${IMAGE}:${META_TAG} --platform=linux/amd64 \ + --provenance=true --sbom=true --builder=container --load \ + --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION="${VERSION_TAG}" --build-arg BUILD_DATE=${GITHUB_DATE} . + ''' + sh '''#! /bin/bash + set -e + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker tag ${IMAGE}:${META_TAG} ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} + done + ''' + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: 'Quay.io-Robot', + usernameVariable: 'QUAYUSER', + passwordVariable: 'QUAYPASS' + ] + ]) { + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + # run a registry.gitlab.com command under what is left of the gitlab time budget + gitlab_timeout() { + local remaining=$(( GITLAB_DEADLINE - SECONDS )) + if (( remaining <= 0 )); then + echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2 + return 124 + fi + timeout "${remaining}" "$@" + } + GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT )) + + echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin + echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin + echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + if [[ "${i}" == *"registry.gitlab.com"* ]]; then + TIMEOUT_CMD="gitlab_timeout" + else + TIMEOUT_CMD="" + fi + ${TIMEOUT_CMD} docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" + done + for p in "${!pids[@]}"; do + wait "$p" || { if [[ "${pids[$p]}" != *"quay.io"* && "${pids[$p]}" != *"registry.gitlab.com"* ]]; then exit 1; fi; } + done + fi + ''' + } + } } } // Build MultiArch Docker containers for push to LS Repo @@ -561,22 +731,78 @@ pipeline { steps { echo "Running on node: ${NODE_NAME}" sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile" - sh "docker buildx build \ - --label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ - --label \"org.opencontainers.image.authors=linuxserver.io\" \ - --label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-nextcloud/packages\" \ - --label \"org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-nextcloud\" \ - --label \"org.opencontainers.image.source=https://github.com/linuxserver/docker-nextcloud\" \ - --label \"org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}\" \ - --label \"org.opencontainers.image.revision=${COMMIT_SHA}\" \ - --label \"org.opencontainers.image.vendor=linuxserver.io\" \ - --label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ - --label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ - --label \"org.opencontainers.image.title=Nextcloud\" \ - --label \"org.opencontainers.image.description=[Nextcloud](https://nextcloud.com/) gives you access to all your files wherever you are. Where are your photos and documents? With Nextcloud you pick a server of your choice, at home, in a data center or at a provider. And that is where your files will be. Nextcloud runs on that server, protecting your data and giving you access from your desktop or mobile devices. Through Nextcloud you also access, sync and share your existing data on that FTP drive at the office, a Dropbox or a NAS you have at home. \" \ - --no-cache --pull -t ${IMAGE}:amd64-${META_TAG} --platform=linux/amd64 \ - --provenance=false --sbom=false \ - --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." + sh '''#! /bin/bash + source ${WORKSPACE}/retry_ghcr.sh + retry_ghcr docker buildx build \ + --label "org.opencontainers.image.created=${GITHUB_DATE}" \ + --label "org.opencontainers.image.authors=linuxserver.io" \ + --label "org.opencontainers.image.url=https://github.com/linuxserver/docker-nextcloud/packages" \ + --label "org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-nextcloud" \ + --label "org.opencontainers.image.source=https://github.com/linuxserver/docker-nextcloud" \ + --label "org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}" \ + --label "org.opencontainers.image.revision=${COMMIT_SHA}" \ + --label "org.opencontainers.image.vendor=linuxserver.io" \ + --label "org.opencontainers.image.licenses=GPL-3.0-only" \ + --label "org.opencontainers.image.ref.name=${COMMIT_SHA}" \ + --label "org.opencontainers.image.title=Nextcloud" \ + --label "org.opencontainers.image.description=[Nextcloud](https://nextcloud.com/) gives you access to all your files wherever you are. Where are your photos and documents? With Nextcloud you pick a server of your choice, at home, in a data center or at a provider. And that is where your files will be. Nextcloud runs on that server, protecting your data and giving you access from your desktop or mobile devices. Through Nextcloud you also access, sync and share your existing data on that FTP drive at the office, a Dropbox or a NAS you have at home. " \ + --no-cache --pull -t ${IMAGE}:amd64-${META_TAG} --platform=linux/amd64 \ + --provenance=true --sbom=true --builder=container --load \ + --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION="${VERSION_TAG}" --build-arg BUILD_DATE=${GITHUB_DATE} . + ''' + sh '''#! /bin/bash + set -e + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker tag ${IMAGE}:amd64-${META_TAG} ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} + done + ''' + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: 'Quay.io-Robot', + usernameVariable: 'QUAYUSER', + passwordVariable: 'QUAYPASS' + ] + ]) { + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + # run a registry.gitlab.com command under what is left of the gitlab time budget + gitlab_timeout() { + local remaining=$(( GITLAB_DEADLINE - SECONDS )) + if (( remaining <= 0 )); then + echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2 + return 124 + fi + timeout "${remaining}" "$@" + } + GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT )) + + echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin + echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin + echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + if [[ "${i}" == *"registry.gitlab.com"* ]]; then + TIMEOUT_CMD="gitlab_timeout" + else + TIMEOUT_CMD="" + fi + ${TIMEOUT_CMD} docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" + done + for p in "${!pids[@]}"; do + wait "$p" || { if [[ "${pids[$p]}" != *"quay.io"* && "${pids[$p]}" != *"registry.gitlab.com"* ]]; then exit 1; fi; } + done + fi + ''' + } + } } } stage('Build ARM64') { @@ -585,37 +811,125 @@ pipeline { } steps { echo "Running on node: ${NODE_NAME}" - echo 'Logging into Github' + sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile.aarch64" sh '''#! /bin/bash - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + # create our retry function + retry_ghcr() { + local max_attempts=7 + local base_delay=10 + local max_delay=90 + local attempt=1 + local errfile exit_code delay pause + errfile=$(mktemp) + while true; do + # run inside an if so a caller's set -e cannot abort before we get to retry + if "$@" 2> >(tee "${errfile}" >&2); then + exit_code=0 + else + exit_code=$? + fi + # make sure tee has finished writing before we read the file + wait $! 2>/dev/null || true + if [[ "${exit_code}" == "0" ]]; then + rm -f "${errfile}" + return 0 + elif ! grep -q -i -E "retry-after:|toomanyrequests|too many requests" "${errfile}"; then + rm -f "${errfile}" + return "${exit_code}" + elif (( attempt >= max_attempts )); then + rm -f "${errfile}" + echo "retry: $* failed after ${attempt} attempts (exit ${exit_code})" >&2 + return "${exit_code}" + else + # exponential delay: base * 2^(attempt-1), capped at max_delay + delay=$(( base_delay * 2 ** (attempt - 1) )) + (( delay > max_delay )) && delay="${max_delay}" + # jitter between half and full delay so parallel builds spread out + pause=$(( delay / 2 + RANDOM % (delay / 2 + 1) )) + echo "retry: attempt ${attempt}/${max_attempts} failed (exit ${exit_code}); waiting ${pause}s..." >&2 + sleep "${pause}" + ((attempt++)) + fi + done + } + + retry_ghcr docker buildx build \ + --label "org.opencontainers.image.created=${GITHUB_DATE}" \ + --label "org.opencontainers.image.authors=linuxserver.io" \ + --label "org.opencontainers.image.url=https://github.com/linuxserver/docker-nextcloud/packages" \ + --label "org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-nextcloud" \ + --label "org.opencontainers.image.source=https://github.com/linuxserver/docker-nextcloud" \ + --label "org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}" \ + --label "org.opencontainers.image.revision=${COMMIT_SHA}" \ + --label "org.opencontainers.image.vendor=linuxserver.io" \ + --label "org.opencontainers.image.licenses=GPL-3.0-only" \ + --label "org.opencontainers.image.ref.name=${COMMIT_SHA}" \ + --label "org.opencontainers.image.title=Nextcloud" \ + --label "org.opencontainers.image.description=[Nextcloud](https://nextcloud.com/) gives you access to all your files wherever you are. Where are your photos and documents? With Nextcloud you pick a server of your choice, at home, in a data center or at a provider. And that is where your files will be. Nextcloud runs on that server, protecting your data and giving you access from your desktop or mobile devices. Through Nextcloud you also access, sync and share your existing data on that FTP drive at the office, a Dropbox or a NAS you have at home. " \ + --no-cache --pull -f Dockerfile.aarch64 -t ${IMAGE}:arm64v8-${META_TAG} --platform=linux/arm64 \ + --provenance=true --sbom=true --builder=container --load \ + --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION="${VERSION_TAG}" --build-arg BUILD_DATE=${GITHUB_DATE} . ''' - sh "sed -r -i 's|(^FROM .*)|\\1\\n\\nENV LSIO_FIRST_PARTY=true|g' Dockerfile.aarch64" - sh "docker buildx build \ - --label \"org.opencontainers.image.created=${GITHUB_DATE}\" \ - --label \"org.opencontainers.image.authors=linuxserver.io\" \ - --label \"org.opencontainers.image.url=https://github.com/linuxserver/docker-nextcloud/packages\" \ - --label \"org.opencontainers.image.documentation=https://docs.linuxserver.io/images/docker-nextcloud\" \ - --label \"org.opencontainers.image.source=https://github.com/linuxserver/docker-nextcloud\" \ - --label \"org.opencontainers.image.version=${EXT_RELEASE_CLEAN}-ls${LS_TAG_NUMBER}\" \ - --label \"org.opencontainers.image.revision=${COMMIT_SHA}\" \ - --label \"org.opencontainers.image.vendor=linuxserver.io\" \ - --label \"org.opencontainers.image.licenses=GPL-3.0-only\" \ - --label \"org.opencontainers.image.ref.name=${COMMIT_SHA}\" \ - --label \"org.opencontainers.image.title=Nextcloud\" \ - --label \"org.opencontainers.image.description=[Nextcloud](https://nextcloud.com/) gives you access to all your files wherever you are. Where are your photos and documents? With Nextcloud you pick a server of your choice, at home, in a data center or at a provider. And that is where your files will be. Nextcloud runs on that server, protecting your data and giving you access from your desktop or mobile devices. Through Nextcloud you also access, sync and share your existing data on that FTP drive at the office, a Dropbox or a NAS you have at home. \" \ - --no-cache --pull -f Dockerfile.aarch64 -t ${IMAGE}:arm64v8-${META_TAG} --platform=linux/arm64 \ - --provenance=false --sbom=false \ - --build-arg ${BUILD_VERSION_ARG}=${EXT_RELEASE} --build-arg VERSION=\"${VERSION_TAG}\" --build-arg BUILD_DATE=${GITHUB_DATE} ." - sh "docker tag ${IMAGE}:arm64v8-${META_TAG} ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}" - retry_backoff(5,5) { - sh "docker push ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER}" + sh '''#! /bin/bash + set -e + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + docker tag ${IMAGE}:arm64v8-${META_TAG} ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} + done + ''' + withCredentials([ + [ + $class: 'UsernamePasswordMultiBinding', + credentialsId: 'Quay.io-Robot', + usernameVariable: 'QUAYUSER', + passwordVariable: 'QUAYPASS' + ] + ]) { + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + # run a registry.gitlab.com command under what is left of the gitlab time budget + gitlab_timeout() { + local remaining=$(( GITLAB_DEADLINE - SECONDS )) + if (( remaining <= 0 )); then + echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2 + return 124 + fi + timeout "${remaining}" "$@" + } + GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT )) + + echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin + echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin + echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin + echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + if [[ "${i}" == *"registry.gitlab.com"* ]]; then + TIMEOUT_CMD="gitlab_timeout" + else + TIMEOUT_CMD="" + fi + ${TIMEOUT_CMD} docker push ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" + done + for p in "${!pids[@]}"; do + wait "$p" || { if [[ "${pids[$p]}" != *"quay.io"* && "${pids[$p]}" != *"registry.gitlab.com"* ]]; then exit 1; fi; } + done + fi + ''' + } } sh '''#! /bin/bash containers=$(docker ps -aq) if [[ -n "${containers}" ]]; then docker stop ${containers} fi - docker system prune -af --volumes || : ''' + docker system prune -f --volumes || : + docker image prune -af || : + ''' } } } @@ -637,10 +951,12 @@ pipeline { LOCAL_CONTAINER=${IMAGE}:${META_TAG} fi touch ${TEMPDIR}/package_versions.txt + source ${WORKSPACE}/retry_ghcr.sh + retry_ghcr docker pull ghcr.io/anchore/syft:${SYFT_IMAGE_TAG} docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ -v ${TEMPDIR}:/tmp \ - ghcr.io/anchore/syft:latest \ + ghcr.io/anchore/syft:${SYFT_IMAGE_TAG} \ ${LOCAL_CONTAINER} -o table=/tmp/package_versions.txt NEW_PACKAGE_TAG=$(md5sum ${TEMPDIR}/package_versions.txt | cut -c1-8 ) echo "Package tag sha from current packages in buit container is ${NEW_PACKAGE_TAG} comparing to old ${PACKAGE_TAG} from github" @@ -716,12 +1032,22 @@ pipeline { script{ env.CI_URL = 'https://ci-tests.linuxserver.io/' + env.IMAGE + '/' + env.META_TAG + '/index.html' env.CI_JSON_URL = 'https://ci-tests.linuxserver.io/' + env.IMAGE + '/' + env.META_TAG + '/report.json' + env.CI_TEST_ATTEMPTED = 'true' } sh '''#! /bin/bash set -e - docker pull ghcr.io/linuxserver/ci:latest + if grep -q 'docker-baseimage' <<< "${LS_REPO}"; then + echo "Detected baseimage, setting LSIO_FIRST_PARTY=true" + if [ -n "${CI_DOCKERENV}" ]; then + CI_DOCKERENV="LSIO_FIRST_PARTY=true|${CI_DOCKERENV}" + else + CI_DOCKERENV="LSIO_FIRST_PARTY=true" + fi + fi + source ${WORKSPACE}/retry_ghcr.sh + retry_ghcr docker pull ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} if [ "${MULTIARCH}" == "true" ]; then - docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} --platform=arm64 + retry_ghcr docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} --platform=arm64 docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} fi docker run --rm \ @@ -731,6 +1057,7 @@ pipeline { -e DOCKER_LOGS_TIMEOUT=\"${CI_DELAY}\" \ -e TAGS=\"${CI_TAGS}\" \ -e META_TAG=\"${META_TAG}\" \ + -e RELEASE_TAG=\"latest\" \ -e PORT=\"${CI_PORT}\" \ -e SSL=\"${CI_SSL}\" \ -e BASE=\"${DIST_IMAGE}\" \ @@ -740,7 +1067,11 @@ pipeline { -e WEB_SCREENSHOT=\"${CI_WEB}\" \ -e WEB_AUTH=\"${CI_AUTH}\" \ -e WEB_PATH=\"${CI_WEBPATH}\" \ - -t ghcr.io/linuxserver/ci:latest \ + -e NODE_NAME=\"${NODE_NAME}\" \ + -e SYFT_IMAGE_TAG=\"${CI_SYFT_IMAGE_TAG:-${SYFT_IMAGE_TAG}}\" \ + -e COMMIT_SHA=\"${COMMIT_SHA}\" \ + -e BUILD_NUMBER=\"${BUILD_NUMBER}\" \ + -t ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} \ python3 test_build.py''' } } @@ -755,37 +1086,44 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - withCredentials([ - [ - $class: 'UsernamePasswordMultiBinding', - credentialsId: 'Quay.io-Robot', - usernameVariable: 'QUAYUSER', - passwordVariable: 'QUAYPASS' - ] - ]) { - retry_backoff(5,5) { - sh '''#! /bin/bash - set -e - echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin - echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin - echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin - for PUSHIMAGE in "${GITHUBIMAGE}" "${GITLABIMAGE}" "${QUAYIMAGE}" "${IMAGE}"; do - docker tag ${IMAGE}:${META_TAG} ${PUSHIMAGE}:${META_TAG} - docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:latest - docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker tag ${PUSHIMAGE}:${META_TAG} ${PUSHIMAGE}:${SEMVER} - fi - docker push ${PUSHIMAGE}:latest - docker push ${PUSHIMAGE}:${META_TAG} - docker push ${PUSHIMAGE}:${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker push ${PUSHIMAGE}:${SEMVER} - fi + script{ + env.PUSH_ATTEMPTED = 'true' + } + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + # run a registry.gitlab.com command under what is left of the gitlab time budget + gitlab_timeout() { + local remaining=$(( GITLAB_DEADLINE - SECONDS )) + if (( remaining <= 0 )); then + echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2 + return 124 + fi + timeout "${remaining}" "$@" + } + GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT )) + + for PUSHIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do + if [[ "${PUSHIMAGE}" == "${GITLABIMAGE}" ]]; then + TIMEOUT_CMD="gitlab_timeout" + else + TIMEOUT_CMD="" + fi + [[ ${PUSHIMAGE%%/*} =~ \\. ]] && PUSHIMAGEPLUS="${PUSHIMAGE}" || PUSHIMAGEPLUS="docker.io/${PUSHIMAGE}" + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + if [[ "${PUSHIMAGEPLUS}" == "$(cut -d "/" -f1 <<< ${i})"* ]]; then + CACHEIMAGE=${i} + fi done - ''' - } + ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${META_TAG} -t ${PUSHIMAGE}:latest -t ${PUSHIMAGE}:${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" && "${PUSHIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + if [ -n "${SEMVER}" ]; then + ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" && "${PUSHIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + fi + done + ''' } } } @@ -796,57 +1134,69 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - withCredentials([ - [ - $class: 'UsernamePasswordMultiBinding', - credentialsId: 'Quay.io-Robot', - usernameVariable: 'QUAYUSER', - passwordVariable: 'QUAYPASS' - ] - ]) { - retry_backoff(5,5) { - sh '''#! /bin/bash - set -e - echo $DOCKERHUB_TOKEN | docker login -u linuxserverci --password-stdin - echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin - echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin - echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin - if [ "${CI}" == "false" ]; then - docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} --platform=arm64 - docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} + script{ + env.PUSH_ATTEMPTED = 'true' + } + retry_backoff(5,5) { + sh '''#! /bin/bash + set -e + # run a registry.gitlab.com command under what is left of the gitlab time budget + gitlab_timeout() { + local remaining=$(( GITLAB_DEADLINE - SECONDS )) + if (( remaining <= 0 )); then + echo "gitlab timeout budget of ${GITLAB_TIMEOUT}s used up, skipping: $*" >&2 + return 124 fi - for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do - docker tag ${IMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} - docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-latest - docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} - docker tag ${IMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} - docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-latest - docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker tag ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:amd64-${SEMVER} - docker tag ${MANIFESTIMAGE}:arm64v8-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${SEMVER} - fi - docker push ${MANIFESTIMAGE}:amd64-${META_TAG} - docker push ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} - docker push ${MANIFESTIMAGE}:amd64-latest - docker push ${MANIFESTIMAGE}:arm64v8-${META_TAG} - docker push ${MANIFESTIMAGE}:arm64v8-latest - docker push ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker push ${MANIFESTIMAGE}:amd64-${SEMVER} - docker push ${MANIFESTIMAGE}:arm64v8-${SEMVER} - fi - done - for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do - docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest - docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} - docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} - if [ -n "${SEMVER}" ]; then - docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} - fi + timeout "${remaining}" "$@" + } + GITLAB_DEADLINE=$(( SECONDS + GITLAB_TIMEOUT )) + + for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do + if [[ "${MANIFESTIMAGE}" == "${GITLABIMAGE}" ]]; then + TIMEOUT_CMD="gitlab_timeout" + else + TIMEOUT_CMD="" + fi + if [[ "${MANIFESTIMAGE%%/*}" =~ \\. ]]; then + MANIFESTIMAGEPLUS="${MANIFESTIMAGE}" + else + MANIFESTIMAGEPLUS="docker.io/${MANIFESTIMAGE}" + fi + IFS=',' read -ra CACHE <<< "$BUILDCACHE" + for i in "${CACHE[@]}"; do + if [[ "${MANIFESTIMAGEPLUS}" == "$(cut -d "/" -f1 <<< ${i})"* ]]; then + CACHEIMAGE=${i} + fi done - ''' - } + ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${META_TAG} -t ${MANIFESTIMAGE}:amd64-latest -t ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${META_TAG} -t ${MANIFESTIMAGE}:arm64v8-latest -t ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + if [ -n "${SEMVER}" ]; then + ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + ${TIMEOUT_CMD} docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${SEMVER} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + fi + done + for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do + if [[ "${MANIFESTIMAGE}" == "${GITLABIMAGE}" ]]; then + TIMEOUT_CMD="gitlab_timeout" + else + TIMEOUT_CMD="" + fi + ${TIMEOUT_CMD} docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + ${TIMEOUT_CMD} docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + ${TIMEOUT_CMD} docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + if [ -n "${SEMVER}" ]; then + ${TIMEOUT_CMD} docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" && "${MANIFESTIMAGE}" != "${GITLABIMAGE}" ]]; then exit 1; fi; } + fi + done + ''' } } } @@ -861,23 +1211,41 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { - echo "Pushing New tag for current commit ${META_TAG}" - sh '''curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \ - -d '{"tag":"'${META_TAG}'",\ - "object": "'${COMMIT_SHA}'",\ - "message": "Tagging Release '${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}' to master",\ - "type": "commit",\ - "tagger": {"name": "LinuxServer-CI","email": "ci@linuxserver.io","date": "'${GITHUB_DATE}'"}}' ''' - echo "Pushing New release for Tag" sh '''#! /bin/bash - echo "Updating to ${EXT_RELEASE_CLEAN}" > releasebody.json - echo '{"tag_name":"'${META_TAG}'",\ - "target_commitish": "master",\ - "name": "'${META_TAG}'",\ - "body": "**LinuxServer Changes:**\\n\\n'${LS_RELEASE_NOTES}'\\n\\n**Remote Changes:**\\n\\n' > start - printf '","draft": false,"prerelease": false}' >> releasebody.json - paste -d'\\0' start releasebody.json > releasebody.json.done - curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done''' + echo "Auto-generating release notes" + if [ "$(git tag --points-at HEAD)" != "" ]; then + echo "Existing tag points to current commit, suggesting no new LS changes" + AUTO_RELEASE_NOTES="No changes" + else + AUTO_RELEASE_NOTES=$(curl -fsL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github+json" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases/generate-notes \ + -d '{"tag_name":"'${META_TAG}'",\ + "target_commitish": "master"}' \ + | jq -r '.body' | sed 's|## What.s Changed||') + fi + echo "Pushing New tag for current commit ${META_TAG}" + curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \ + -d '{"tag":"'${META_TAG}'",\ + "object": "'${COMMIT_SHA}'",\ + "message": "Tagging Release '${EXT_RELEASE_CLEAN}'-ls'${LS_TAG_NUMBER}' to master",\ + "type": "commit",\ + "tagger": {"name": "LinuxServer-CI","email": "ci@linuxserver.io","date": "'${GITHUB_DATE}'"}}' + echo "Pushing New release for Tag" + curl -H "Authorization: token ${GITHUB_TOKEN}" -s https://api.github.com/repos/nextcloud-releases/server/releases/tags/v${EXT_RELEASE} | jq -r '. |.body' > releasebody.json + jq -n \ + --arg tag_name "$META_TAG" \ + --arg target_commitish "master" \ + --arg ci_url "${CI_URL:-N/A}" \ + --arg ls_notes "$AUTO_RELEASE_NOTES" \ + --arg remote_notes "$(cat releasebody.json)" \ + '{ + "tag_name": $tag_name, + "target_commitish": $target_commitish, + "name": $tag_name, + "body": ("**CI Report:**\\n\\n" + $ci_url + "\\n\\n**LinuxServer Changes:**\\n\\n" + $ls_notes + "\\n\\n**Remote Changes:**\\n\\n" + $remote_notes), + "draft": false, + "prerelease": false }' > releasebody.json.done + curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done + ''' } } // Add protection to the release branch @@ -915,90 +1283,136 @@ EOF ) ''' } } - // If this is a Pull request send the CI link as a comment on it - stage('Pull Request Comment') { - when { - not {environment name: 'CHANGE_ID', value: ''} - environment name: 'EXIT_STATUS', value: '' - } - steps { - sh '''#! /bin/bash - # Function to retrieve JSON data from URL - get_json() { - local url="$1" - local response=$(curl -s "$url") - if [ $? -ne 0 ]; then - echo "Failed to retrieve JSON data from $url" - return 1 - fi - local json=$(echo "$response" | jq .) - if [ $? -ne 0 ]; then - echo "Failed to parse JSON data from $url" - return 1 - fi - echo "$json" + } + /* ###################### + Comment on PR and Send status to Discord + ###################### */ + post { + always { + script { + env.JOB_DATE = sh( + script: '''date '+%Y-%m-%dT%H:%M:%S%:z' ''', + returnStdout: true).trim() + if (env.EXIT_STATUS == "ABORTED"){ + sh 'echo "build aborted"' + }else{ + if (currentBuild.currentResult == "SUCCESS"){ + if (env.GITHUBIMAGE =~ /lspipepr/){ + env.JOB_WEBHOOK_STATUS='Success' + env.JOB_WEBHOOK_COLOUR=3957028 + env.JOB_WEBHOOK_FOOTER='PR Build' + }else if (env.GITHUBIMAGE =~ /lsiodev/){ + env.JOB_WEBHOOK_STATUS='Success' + env.JOB_WEBHOOK_COLOUR=3957028 + env.JOB_WEBHOOK_FOOTER='Dev Build' + }else{ + env.JOB_WEBHOOK_STATUS='Success' + env.JOB_WEBHOOK_COLOUR=1681177 + env.JOB_WEBHOOK_FOOTER='Live Build' } + }else{ + if (env.GITHUBIMAGE =~ /lspipepr/){ + env.JOB_WEBHOOK_STATUS='Failure' + env.JOB_WEBHOOK_COLOUR=12669523 + env.JOB_WEBHOOK_FOOTER='PR Build' + }else if (env.GITHUBIMAGE =~ /lsiodev/){ + env.JOB_WEBHOOK_STATUS='Failure' + env.JOB_WEBHOOK_COLOUR=12669523 + env.JOB_WEBHOOK_FOOTER='Dev Build' + }else{ + env.JOB_WEBHOOK_STATUS='Failure' + env.JOB_WEBHOOK_COLOUR=16711680 + env.JOB_WEBHOOK_FOOTER='Live Build' + } + } + sh ''' curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/jenkins-avatar.png","embeds": [{"'color'": '${JOB_WEBHOOK_COLOUR}',\ + "footer": {"text" : "'"${JOB_WEBHOOK_FOOTER}"'"},\ + "timestamp": "'${JOB_DATE}'",\ + "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** '${JOB_WEBHOOK_STATUS}'\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\ + "username": "Jenkins"}' ${BUILDS_DISCORD} ''' + } + } + script { + if (env.GITHUBIMAGE =~ /lspipepr/){ + if (env.CI_TEST_ATTEMPTED == "true" || env.PUSH_ATTEMPTED == "true"){ + sh '''#! /bin/bash + # Function to retrieve JSON data from URL + get_json() { + local url="$1" + local response=$(curl -s "$url") + if [ $? -ne 0 ]; then + echo "Failed to retrieve JSON data from $url" + return 1 + fi + local json=$(echo "$response" | jq .) + if [ $? -ne 0 ]; then + echo "Failed to parse JSON data from $url" + return 1 + fi + echo "$json" + } - build_table() { - local data="$1" + build_table() { + local data="$1" - # Get the keys in the JSON data - local keys=$(echo "$data" | jq -r 'to_entries | map(.key) | .[]') + # Get the keys in the JSON data + local keys=$(echo "$data" | jq -r 'to_entries | map(.key) | .[]') - # Check if keys are empty - if [ -z "$keys" ]; then - echo "JSON report data does not contain any keys or the report does not exist." - return 1 - fi + # Check if keys are empty + if [ -z "$keys" ]; then + echo "JSON report data does not contain any keys or the report does not exist." + return 1 + fi - # Build table header - local header="| Tag | Passed |\\n| --- | --- |\\n" + # Build table header + local header="| Tag | Passed |\\n| --- | --- |\\n" - # Loop through the JSON data to build the table rows - local rows="" - for build in $keys; do - local status=$(echo "$data" | jq -r ".[\\"$build\\"].test_success") - if [ "$status" = "true" ]; then - status="✅" - else - status="❌" - fi - local row="| "$build" | "$status" |\\n" - rows="${rows}${row}" - done + # Loop through the JSON data to build the table rows + local rows="" + for build in $keys; do + local status=$(echo "$data" | jq -r ".[\\"$build\\"].test_success") + if [ "$status" = "true" ]; then + status="✅" + else + status="❌" + fi + local row="| "$build" | "$status" |\\n" + rows="${rows}${row}" + done - local table="${header}${rows}" - local escaped_table=$(echo "$table" | sed 's/\"/\\\\"/g') - echo "$escaped_table" - } + local table="${header}${rows}" + local escaped_table=$(echo "$table" | sed 's/\"/\\\\"/g') + echo "$escaped_table" + } - if [[ "${CI}" = "true" ]]; then - # Retrieve JSON data from URL - data=$(get_json "$CI_JSON_URL") - # Create table from JSON data - table=$(build_table "$data") - echo -e "$table" + if [[ "${CI}" = "true" ]]; then + # Retrieve JSON data from URL + data=$(get_json "$CI_JSON_URL") + # Create table from JSON data + table=$(build_table "$data") + echo -e "$table" - curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ - -d "{\\"body\\": \\"I am a bot, here are the test results for this PR: \\n${CI_URL}\\n${SHELLCHECK_URL}\\n${table}\\"}" - else - curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ - -d "{\\"body\\": \\"I am a bot, here is the pushed image/manifest for this PR: \\n\\n\\`${GITHUBIMAGE}:${META_TAG}\\`\\"}" - fi + curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ + -d "{\\"body\\": \\"I am a bot, here are the test results for this PR for commit ${COMMIT_SHA:0:7} : \\n${CI_URL}\\n${SHELLCHECK_URL}\\n${table}\\"}" + else + curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ + -d "{\\"body\\": \\"I am a bot, here is the pushed image/manifest for this PR for commit ${COMMIT_SHA:0:7} : \\n\\n\\`${GITHUBIMAGE}:${META_TAG}\\`\\"}" + fi + ''' + } else { + sh '''#! /bin/bash + curl -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/$LS_USER/$LS_REPO/issues/$PULL_REQUEST/comments" \ + -d "{\\"body\\": \\"I am a bot, the build for PR commit ${COMMIT_SHA:0:7} failed and as a result no CI test was attempted and no images were pushed.\\"}" ''' - + } + } } - } - } - /* ###################### - Send status to Discord - ###################### */ - post { - always { sh '''#!/bin/bash rm -rf /config/.ssh/id_sign rm -rf /config/.ssh/id_sign.pub @@ -1006,30 +1420,25 @@ EOF git config --global --unset user.signingkey git config --global --unset commit.gpgsign ''' - script{ - if (env.EXIT_STATUS == "ABORTED"){ - sh 'echo "build aborted"' - } - else if (currentBuild.currentResult == "SUCCESS"){ - sh ''' curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/jenkins-avatar.png","embeds": [{"color": 1681177,\ - "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** Success\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\ - "username": "Jenkins"}' ${BUILDS_DISCORD} ''' - } - else { - sh ''' curl -X POST -H "Content-Type: application/json" --data '{"avatar_url": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/jenkins-avatar.png","embeds": [{"color": 16711680,\ - "description": "**Build:** '${BUILD_NUMBER}'\\n**CI Results:** '${CI_URL}'\\n**ShellCheck Results:** '${SHELLCHECK_URL}'\\n**Status:** failure\\n**Job:** '${RUN_DISPLAY_URL}'\\n**Change:** '${CODE_URL}'\\n**External Release:**: '${RELEASE_LINK}'\\n**DockerHub:** '${DOCKERHUB_LINK}'\\n"}],\ - "username": "Jenkins"}' ${BUILDS_DISCORD} ''' - } - } } cleanup { sh '''#! /bin/bash - echo "Performing docker system prune!!" - containers=$(docker ps -aq) + echo "Pruning builder!!" + docker builder prune -f --builder container || : + containers=$(docker ps -q) if [[ -n "${containers}" ]]; then - docker stop ${containers} + BUILDX_CONTAINER_ID=$(docker ps -qf 'name=buildx_buildkit') + for container in ${containers}; do + if [[ "${container}" == "${BUILDX_CONTAINER_ID}" ]]; then + echo "skipping buildx container in docker stop" + else + echo "Stopping container ${container}" + docker stop ${container} + fi + done fi - docker system prune -af --volumes || : + docker system prune -f --volumes || : + docker image prune -af || : ''' cleanWs() } diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/README.md b/README.md index ad979007..9bdb8b33 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,8 @@ [![linuxserver.io](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/linuxserver_medium.png)](https://linuxserver.io) [![Blog](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=Blog)](https://blog.linuxserver.io "all the things you can do with our containers including How-To guides, opinions and much more!") -[![Discord](https://img.shields.io/discord/354974912613449730.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Discord&logo=discord)](https://discord.gg/YWrKVTn "realtime support / chat with the community and the team.") -[![Discourse](https://img.shields.io/discourse/https/discourse.linuxserver.io/topics.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&logo=discourse)](https://discourse.linuxserver.io "post on our community forum.") -[![Fleet](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=Fleet)](https://fleet.linuxserver.io "an online web interface which displays all of our maintained images.") +[![Discord](https://img.shields.io/discord/354974912613449730.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Discord&logo=discord)](https://linuxserver.io/discord "realtime support / chat with the community and the team.") +[![Discussions](https://img.shields.io/badge/Github-Discussions-94398d?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&logo=github)](https://github.com/orgs/linuxserver/discussions "post on our community forum.") [![GitHub](https://img.shields.io/static/v1.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=linuxserver.io&message=GitHub&logo=github)](https://github.com/linuxserver "view the source for all of our repositories.") [![Open Collective](https://img.shields.io/opencollective/all/linuxserver.svg?color=94398d&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=Supporters&logo=open%20collective)](https://opencollective.com/linuxserver "please consider helping us by either donating or contributing to our budget") @@ -20,9 +19,8 @@ The [LinuxServer.io](https://linuxserver.io) team brings you another container r Find us at: * [Blog](https://blog.linuxserver.io) - all the things you can do with our containers including How-To guides, opinions and much more! -* [Discord](https://discord.gg/YWrKVTn) - realtime support / chat with the community and the team. -* [Discourse](https://discourse.linuxserver.io) - post on our community forum. -* [Fleet](https://fleet.linuxserver.io) - an online web interface which displays all of our maintained images. +* [Discord](https://linuxserver.io/discord) - realtime support / chat with the community and the team. +* [Discussions](https://github.com/orgs/linuxserver/discussions) - post on our community forum. * [GitHub](https://github.com/linuxserver) - view the source for all of our repositories. * [Open Collective](https://opencollective.com/linuxserver) - please consider helping us by either donating or contributing to our budget @@ -57,7 +55,6 @@ The architectures supported by this image are: | :----: | :----: | ---- | | x86-64 | ✅ | amd64-\ | | arm64 | ✅ | arm64v8-\ | -| armhf | ❌ | | ## Version Tags @@ -137,6 +134,9 @@ If you are using a reverse proxy which validates certificates, you need to [disa To help you get started creating a container from this image you can either use docker-compose or the docker cli. +>[!NOTE] +>Unless a parameter is flagged as 'optional', it is *mandatory* and a value must be provided. + ### docker-compose (recommended, [click here for more info](https://docs.linuxserver.io/general/docker-compose)) ```yaml @@ -178,7 +178,7 @@ Containers are configured using parameters passed at runtime (such as those abov | Parameter | Function | | :----: | --- | -| `-p 443` | WebUI | +| `-p 443:443` | WebUI | | `-e PUID=1000` | for UserID - see below for explanation | | `-e PGID=1000` | for GroupID - see below for explanation | | `-e TZ=Etc/UTC` | specify a timezone to use, see this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List). | @@ -321,7 +321,8 @@ Below are the instructions for updating containers: ### Image Update Notifications - Diun (Docker Image Update Notifier) -**tip**: We recommend [Diun](https://crazymax.dev/diun/) for update notifications. Other tools that automatically update containers unattended are not recommended or supported. +>[!TIP] +>We recommend [Diun](https://crazymax.dev/diun/) for update notifications. Other tools that automatically update containers unattended are not recommended or supported. ## Building locally @@ -336,16 +337,20 @@ docker build \ -t lscr.io/linuxserver/nextcloud:latest . ``` -The ARM variants can be built on x86_64 hardware using `multiarch/qemu-user-static` +The ARM variants can be built on x86_64 hardware and vice versa using `lscr.io/linuxserver/qemu-static` ```bash -docker run --rm --privileged multiarch/qemu-user-static:register --reset +docker run --rm --privileged lscr.io/linuxserver/qemu-static --reset ``` Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64`. ## Versions +* **14.10.26:** - Rebase to Alpine 3.24 with php 8.5. Tweak opcache settings according to upstream docs. Import upstream release notes in Github releases. +* **10.07.25:** - Rebase to Alpine 3.22. +* **12.02.25:** - Rebase to Alpine 3.21. +* **09.01.25:** - Fix uploading large files. Existing users should update their nginx confs. * **09.07.24:** - Add `previous` tag for n-1 releases. * **24.06.24:** - Rebase to Alpine 3.20. Existing users should update their nginx confs to avoid http2 deprecation warnings. * **19.05.24:** - Added util-linux package required for taskset. diff --git a/jenkins-vars.yml b/jenkins-vars.yml index a6ad6182..121b9829 100644 --- a/jenkins-vars.yml +++ b/jenkins-vars.yml @@ -4,6 +4,8 @@ project_name: docker-nextcloud external_type: na custom_version_command: "curl -sX GET https://api.github.com/repos/nextcloud/server/releases | jq -r '.[] | select(.prerelease != true) | .tag_name' | sed 's|^v||g' | sort -rV | head -1" +custom_release_notes_command: |- + curl -H "Authorization: token ${GITHUB_TOKEN}" -s https://api.github.com/repos/nextcloud-releases/server/releases/tags/v${EXT_RELEASE} | jq -r '. |.body' > releasebody.json release_type: stable release_tag: latest ls_branch: master diff --git a/package_versions.txt b/package_versions.txt index 9b3c65aa..735dc9da 100755 --- a/package_versions.txt +++ b/package_versions.txt @@ -1,452 +1,570 @@ -NAME VERSION TYPE -@nextcloud/text 3.10.0 npm -Process Wrapper 1.0.0.0 dotnet (+1 duplicate) -activity 2.21.0 npm -agetty 2.40.1-r1 apk -alpine-baselayout 3.6.5-r0 apk -alpine-baselayout-data 3.6.5-r0 apk -alpine-keys 2.4-r1 apk -alpine-release 3.20.3-r0 apk -alsa-lib 1.2.11-r0 apk -amphp/amp v2.6.2 php-composer -amphp/byte-stream v1.8.1 php-composer -amphp/parallel v1.4.3 php-composer -amphp/parser v1.1.0 php-composer -amphp/process v1.1.4 php-composer -amphp/serialization v1.0.0 php-composer -amphp/sync v1.4.2 php-composer -aom-libs 3.9.1-r0 apk -apache2-utils 2.4.62-r0 apk -apk-tools 2.14.4-r0 apk -apr 1.7.5-r0 apk -apr-util 1.6.3-r1 apk -argon2-libs 20190702-r5 apk -avahi-libs 0.8-r17 apk -aws/aws-crt-php v1.0.2 php-composer -aws/aws-sdk-php 3.240.8 php-composer -bamarni/composer-bin-plugin 1.8.2 php-composer -bantu/ini-get-wrapper v1.0.1 php-composer -bash 5.2.26-r0 apk -beberlei/assert v3.3.1 php-composer -blkid 2.40.1-r1 apk -brick/math 0.9.2 php-composer -brotli-libs 1.1.0-r2 apk -bruteforcesettings 2.9.0 npm -busybox 1.36.1-r29 apk -busybox-binsh 1.36.1-r29 apk -c-ares 1.28.1-r0 apk -c-client 2007f-r15 apk -ca-certificates 20240705-r0 apk -ca-certificates-bundle 20240705-r0 apk -cairo 1.18.0-r0 apk -cairo-gobject 1.18.0-r0 apk -catatonit 0.2.0-r0 apk -cfdisk 2.40.1-r1 apk -christian-riesen/base32 1.6.0 php-composer -cjson 1.7.18-r0 apk -composer 2.7.9 binary -coreutils 9.5-r1 apk -coreutils-env 9.5-r1 apk -coreutils-fmt 9.5-r1 apk -coreutils-sha512sum 9.5-r1 apk -cups-libs 2.4.9-r0 apk -curl 8.9.1-r1 apk -cweagans/composer-patches 1.7.3 php-composer -dbus-libs 1.14.10-r1 apk -deepdiver/zipstreamer v2.0.3 php-composer -deepdiver1975/tarstreamer v2.1.0 php-composer -dmesg 2.40.1-r1 apk -doctrine/cache 2.2.0 php-composer -doctrine/dbal 3.8.3 php-composer -doctrine/deprecations 1.1.2 php-composer -doctrine/event-manager 1.2.0 php-composer -doctrine/lexer 2.1.0 php-composer -egulias/email-validator 3.2.6 php-composer -ffmpeg 6.1.1-r8 apk -ffmpeg-libavcodec 6.1.1-r8 apk -ffmpeg-libavdevice 6.1.1-r8 apk -ffmpeg-libavfilter 6.1.1-r8 apk -ffmpeg-libavformat 6.1.1-r8 apk -ffmpeg-libavutil 6.1.1-r8 apk -ffmpeg-libpostproc 6.1.1-r8 apk -ffmpeg-libswresample 6.1.1-r8 apk -ffmpeg-libswscale 6.1.1-r8 apk -fftw-double-libs 3.3.10-r5 apk -fgrosse/phpasn1 v2.3.0 php-composer -files_downloadlimit 1.1.0 npm -files_pdfviewer 2.10.0 npm -findmnt 2.40.1-r1 apk -findutils 4.9.0-r5 apk -firstrunwizard 2.18.0 npm -flock 2.40.1-r1 apk -fontconfig 2.15.0-r1 apk -freetype 2.13.2-r0 apk -fribidi 1.0.15-r0 apk -fstrim 2.40.1-r1 apk -fusonic/linq v1.1.0 php-composer -fusonic/opengraph v2.2.0 php-composer -gdbm 1.23-r1 apk -gdk-pixbuf 2.42.12-r0 apk -ghostscript 10.03.1-r0 apk -giflib 5.2.2-r0 apk -giggsey/libphonenumber-for-php-lite 8.13.27 php-composer -git 2.45.2-r0 apk -git-init-template 2.45.2-r0 apk -glib 2.80.4-r0 apk -glslang-libs 1.3.261.1-r0 apk -gmp 6.3.0-r1 apk -gnu-libiconv 1.17-r2 apk -gnu-libiconv-libs 1.17-r2 apk -gnutls 3.8.5-r0 apk -graphite2 1.3.14-r6 apk -guzzlehttp/guzzle 7.8.1 php-composer -guzzlehttp/promises 1.5.3 php-composer -guzzlehttp/psr7 2.6.2 php-composer -guzzlehttp/uri-template v0.2.0 php-composer -harfbuzz 8.5.0-r0 apk -hexdump 2.40.1-r1 apk -hexogen/kdtree v0.2.5 php-composer -hwdata-pci 0.382-r0 apk -icewind/searchdav v3.1.0 php-composer -icewind/smb v3.5.4 php-composer -icewind/streams v0.7.7 php-composer (+1 duplicate) -icu-data-en 74.2-r0 apk -icu-libs 74.2-r0 apk -imagemagick 7.1.1.32-r2 apk -imagemagick-heic 7.1.1.32-r2 apk -imagemagick-jpeg 7.1.1.32-r2 apk -imagemagick-jxl 7.1.1.32-r2 apk -imagemagick-libs 7.1.1.32-r2 apk -imagemagick-pango 7.1.1.32-r2 apk -imagemagick-pdf 7.1.1.32-r2 apk -imagemagick-svg 7.1.1.32-r2 apk -imagemagick-tiff 7.1.1.32-r2 apk -imagemagick-webp 7.1.1.32-r2 apk -imath 3.1.12-r0 apk -jansson 2.14-r4 apk -jbig2dec 0.20-r0 apk -jq 1.7.1-r0 apk -justinrainbow/json-schema v5.2.13 php-composer -kornrunner/blurhash v1.2.2 php-composer -lame-libs 3.100-r5 apk -laravel/serializable-closure v1.3.3 php-composer -lcms2 2.16-r0 apk -ldb 2.8.0-r1 apk -league/flysystem 2.5.0 php-composer -league/mime-type-detection 1.11.0 php-composer -league/uri 6.4.0 php-composer -league/uri-interfaces 2.2.0 php-composer -libSvtAv1Enc 2.0.0-r1 apk -libacl 2.3.2-r0 apk -libarchive 3.7.4-r0 apk -libass 0.17.2-r0 apk -libasyncns 0.8-r3 apk -libattr 2.5.2-r0 apk -libauth-samba 4.19.6-r0 apk -libavif 1.0.4-r0 apk -libblkid 2.40.1-r1 apk -libbluray 1.3.4-r1 apk -libbsd 0.12.2-r0 apk -libbz2 1.0.8-r6 apk -libcap-ng 0.8.5-r0 apk -libcap2 2.70-r0 apk -libcrypto3 3.3.2-r0 apk -libcurl 8.9.1-r1 apk -libdav1d 1.4.2-r0 apk -libde265 1.0.15-r0 apk -libdovi 3.3.0-r0 apk -libdrm 2.4.120-r0 apk -libeconf 0.6.3-r0 apk -libedit 20240517.3.1-r0 apk -libevent 2.1.12-r7 apk -libexpat 2.6.3-r0 apk -libfdisk 2.40.1-r1 apk -libffi 3.4.6-r0 apk -libflac 1.4.3-r1 apk -libformw 6.4_p20240420-r1 apk -libgcc 13.2.1_git20240309-r0 apk -libgomp 13.2.1_git20240309-r0 apk -libheif 1.17.6-r1 apk -libhwy 1.0.7-r0 apk -libice 1.1.1-r6 apk -libidn2 2.3.7-r0 apk -libintl 0.22.5-r0 apk -libjpeg-turbo 3.0.3-r0 apk -libjxl 0.10.2-r0 apk -libldap 2.6.7-r0 apk -libltdl 2.4.7-r3 apk -libmcrypt 2.5.8-r10 apk -libmd 1.1.0-r0 apk -libmemcached-libs 1.1.4-r1 apk -libmount 2.40.1-r1 apk -libncursesw 6.4_p20240420-r1 apk -libogg 1.3.5-r5 apk -libopenmpt 0.7.7-r0 apk -libpanelw 6.4_p20240420-r1 apk -libpciaccess 0.18.1-r0 apk -libplacebo 6.338.2-r1 apk -libpng 1.6.43-r0 apk -libpq 16.3-r0 apk -libproc2 4.0.4-r0 apk -libpsl 0.21.5-r1 apk -libpulse 17.0-r0 apk -librist 0.2.10-r1 apk -librsvg 2.58.0-r0 apk -libsasl 2.1.28-r6 apk -libsharpyuv 1.3.2-r0 apk -libsm 1.2.4-r4 apk -libsmartcols 2.40.1-r1 apk -libsmbclient 4.19.6-r0 apk -libsndfile 1.2.2-r0 apk -libsodium 1.0.19-r0 apk -libsrt 1.5.3-r0 apk -libssh 0.10.6-r0 apk -libssl3 3.3.2-r0 apk -libstdc++ 13.2.1_git20240309-r0 apk -libtasn1 4.19.0-r2 apk -libtheora 1.1.1-r18 apk -libunibreak 6.1-r0 apk -libunistring 1.2-r0 apk -libuuid 2.40.1-r1 apk -libva 2.21.0-r0 apk -libvdpau 1.5-r3 apk -libvorbis 1.3.7-r2 apk -libvpx 1.14.1-r0 apk -libwbclient 4.19.6-r0 apk -libwebp 1.3.2-r0 apk -libwebpdemux 1.3.2-r0 apk -libwebpmux 1.3.2-r0 apk -libx11 1.8.9-r1 apk -libxau 1.0.11-r4 apk -libxcb 1.16.1-r0 apk -libxdmcp 1.1.5-r1 apk -libxext 1.3.6-r2 apk -libxfixes 6.0.1-r4 apk -libxft 2.3.8-r3 apk -libxml2 2.12.7-r0 apk -libxpm 3.5.17-r0 apk -libxrender 0.9.11-r5 apk -libxt 1.3.0-r5 apk -libxxhash 0.8.2-r2 apk -libzip 1.10.1-r0 apk -libzmq 4.3.5-r2 apk -lilv-libs 0.24.24-r1 apk -linux-pam 1.6.0-r0 apk -lmdb 0.9.32-r0 apk -logger 2.40.1-r1 apk -logreader 2.14.0 npm -logrotate 3.21.0-r1 apk -losetup 2.40.1-r1 apk -lsblk 2.40.1-r1 apk -lz4-libs 1.9.4-r5 apk -mbedtls 3.6.1-r0 apk -mcookie 2.40.1-r1 apk -mexitek/phpcolors v1.0.4 php-composer -microsoft/azure-storage-blob 1.5.4 php-composer -microsoft/azure-storage-common 1.5.2 php-composer -mlocati/ip-lib 1.18.0 php-composer -mount 2.40.1-r1 apk -mpg123-libs 1.32.6-r0 apk -mtdowling/jmespath.php 2.6.1 php-composer -musl 1.2.5-r0 apk -musl-utils 1.2.5-r0 apk -nano 8.0-r0 apk -ncurses-terminfo-base 6.4_p20240420-r1 apk -netcat-openbsd 1.226-r0 apk -nettle 3.9.1-r0 apk -nextcloud 1.0.0 npm -nextcloud/lognormalizer v1.0.0 php-composer -nghttp2-libs 1.62.1-r0 apk -nginx 1.26.2-r0 apk -notifications 2.17.0 npm -numactl 2.0.18-r0 apk -onevpl-libs 2023.3.1-r2 apk -oniguruma 6.9.9-r0 apk -openexr-libiex 3.1.13-r1 apk -openexr-libilmthread 3.1.13-r1 apk -openexr-libopenexr 3.1.13-r1 apk -openjpeg 2.5.2-r0 apk -openssl 3.3.2-r0 apk -opus 1.5.2-r0 apk -orc 0.4.39-r0 apk -p11-kit 0.25.3-r0 apk -pango 1.52.2-r0 apk -partx 2.40.1-r1 apk -password_policy 1.19.0 npm -pcre 8.45-r3 apk -pcre2 10.43-r0 apk -pear/archive_tar 1.4.14 php-composer -pear/console_getopt v1.4.3 php-composer -pear/pear-core-minimal v1.10.14 php-composer -pear/pear_exception v1.0.2 php-composer -photos 2.5.0 npm -php-http/guzzle7-adapter 1.0.0 php-composer -php-http/httplug 2.2.0 php-composer -php-http/promise 1.1.0 php-composer -php-opencloud/openstack v3.2.1 php-composer -php83 8.3.10-r0 apk -php83-bcmath 8.3.10-r0 apk -php83-bz2 8.3.10-r0 apk -php83-common 8.3.10-r0 apk -php83-ctype 8.3.10-r0 apk -php83-curl 8.3.10-r0 apk -php83-dom 8.3.10-r0 apk -php83-exif 8.3.10-r0 apk -php83-fileinfo 8.3.10-r0 apk -php83-fpm 8.3.10-r0 apk -php83-ftp 8.3.10-r0 apk -php83-gd 8.3.10-r0 apk -php83-gmp 8.3.10-r0 apk -php83-iconv 8.3.10-r0 apk -php83-imap 8.3.10-r0 apk -php83-intl 8.3.10-r0 apk -php83-ldap 8.3.10-r0 apk -php83-mbstring 8.3.10-r0 apk -php83-mysqlnd 8.3.10-r0 apk -php83-opcache 8.3.10-r0 apk -php83-openssl 8.3.10-r0 apk -php83-pcntl 8.3.10-r0 apk -php83-pdo 8.3.10-r0 apk -php83-pdo_mysql 8.3.10-r0 apk -php83-pdo_pgsql 8.3.10-r0 apk -php83-pdo_sqlite 8.3.10-r0 apk -php83-pecl-apcu 5.1.23-r0 apk -php83-pecl-igbinary 3.2.15-r0 apk -php83-pecl-imagick 3.7.0-r0 apk -php83-pecl-mcrypt 1.0.7-r0 apk -php83-pecl-memcached 3.2.0-r0 apk -php83-pecl-msgpack 2.2.0-r2 apk -php83-pecl-redis 6.0.2-r0 apk -php83-pecl-smbclient 1.1.1-r0 apk -php83-pgsql 8.3.10-r0 apk -php83-phar 8.3.10-r0 apk -php83-posix 8.3.10-r0 apk -php83-session 8.3.10-r0 apk -php83-simplexml 8.3.10-r0 apk -php83-sockets 8.3.10-r0 apk -php83-sodium 8.3.10-r0 apk -php83-sqlite3 8.3.10-r0 apk -php83-sysvsem 8.3.10-r0 apk -php83-xml 8.3.10-r0 apk -php83-xmlreader 8.3.10-r0 apk -php83-xmlwriter 8.3.10-r0 apk -php83-zip 8.3.10-r0 apk -phpseclib/phpseclib 2.0.47 php-composer -pimple/pimple v3.5.0 php-composer -pixman 0.43.2-r0 apk -pkgconf 2.2.0-r0 apk -popt 1.19-r3 apk -privacy 1.13.0 npm -procps-ng 4.0.4-r0 apk -psr/cache 3.0.0 php-composer -psr/clock 1.0.0 php-composer -psr/container 2.0.2 php-composer -psr/event-dispatcher 1.0.0 php-composer -psr/http-client 1.0.3 php-composer -psr/http-factory 1.0.2 php-composer -psr/http-message 1.1 php-composer -psr/log 1.1.4 php-composer (+1 duplicate) -punic/punic 3.8.1 php-composer -ralouphie/getallheaders 3.0.3 php-composer -ramsey/collection 1.1.3 php-composer -ramsey/uuid 4.1.1 php-composer -rav1e-libs 0.7.1-r0 apk -readline 8.2.10-r0 apk -recommendations 2.1.0 npm -related_resources 1.4.0 npm -rsync 3.3.0-r0 apk -rubix/ml dev-chore/bump-flysystem-v2.1.1 php-composer -rubix/tensor 2.2.3 php-composer -rullzer/easytotp v0.1.4 php-composer -runuser 2.40.1-r1 apk -sabre/dav 4.5.0 php-composer -sabre/event 5.1.4 php-composer -sabre/http 5.1.10 php-composer -sabre/uri 2.3.3 php-composer -sabre/vobject 4.5.4 php-composer -sabre/xml 2.2.6 php-composer -samba-client 4.19.6-r0 apk -samba-client-libs 4.19.6-r0 apk -samba-common 4.19.6-r0 apk -samba-libs 4.19.6-r0 apk -samba-util-libs 4.19.6-r0 apk -scanelf 1.3.7-r2 apk -scssphp/scssphp v1.12.1 php-composer -sdl2 2.28.5-r1 apk -serd-libs 0.32.2-r0 apk -setarch 2.40.1-r1 apk -setpriv 2.40.1-r1 apk -sfdisk 2.40.1-r1 apk -shaderc 2024.0-r0 apk -shadow 4.15.1-r0 apk -shared-mime-info 2.4-r0 apk -skalibs 2.14.1.1-r0 apk -sord-libs 0.16.16-r0 apk -soxr 0.1.3-r7 apk -speexdsp 1.2.1-r2 apk -spirv-tools 1.3.261.1-r0 apk -spomky-labs/base64url v2.0.4 php-composer -spomky-labs/cbor-php v2.0.1 php-composer -sqlite-libs 3.45.3-r1 apk -sratom 0.6.16-r0 apk -ssl_client 1.36.1-r29 apk -stecman/symfony-console-completion 0.11.0 php-composer -sudo 1.9.15_p5-r0 apk -support 1.12.0 npm -suspicious_login 7.0.0 npm -symfony/console v5.4.35 php-composer -symfony/css-selector v5.4.11 php-composer -symfony/deprecation-contracts v3.0.2 php-composer -symfony/dom-crawler v5.4.11 php-composer -symfony/event-dispatcher v5.4.26 php-composer -symfony/event-dispatcher-contracts v3.0.2 php-composer -symfony/http-foundation v5.4.25 php-composer -symfony/mailer v5.4.22 php-composer -symfony/mime v5.4.19 php-composer -symfony/polyfill-ctype v1.28.0 php-composer -symfony/polyfill-intl-grapheme v1.28.0 php-composer -symfony/polyfill-intl-idn v1.28.0 php-composer -symfony/polyfill-intl-normalizer v1.28.0 php-composer -symfony/polyfill-mbstring v1.27.0 php-composer -symfony/polyfill-mbstring v1.28.0 php-composer -symfony/polyfill-php72 v1.28.0 php-composer -symfony/polyfill-php73 v1.26.0 php-composer -symfony/polyfill-php73 v1.28.0 php-composer -symfony/polyfill-php80 v1.27.0 php-composer -symfony/polyfill-php80 v1.28.0 php-composer -symfony/process v5.4.34 php-composer -symfony/routing v5.4.25 php-composer -symfony/service-contracts v3.0.2 php-composer -symfony/string v6.0.19 php-composer -symfony/translation v5.4.24 php-composer -symfony/translation-contracts v2.4.0 php-composer -talloc 2.4.2-r1 apk -tdb-libs 1.4.9-r1 apk -tevent 0.16.1-r0 apk -thecodingmachine/safe v1.3.3 php-composer -tiff 4.6.0t-r0 apk -twofactor_totp 11.0.0-dev npm -tzdata 2024b-r0 apk -umount 2.40.1-r1 apk -util-linux 2.40.1-r1 apk -util-linux-misc 2.40.1-r1 apk -utmps-libs 0.1.2.2-r1 apk -uuidgen 2.40.1-r1 apk -v4l-utils-libs 1.24.1-r1 apk -vidstab 1.1.1-r0 apk -viewer 2.3.0 npm -vulkan-loader 1.3.261.1-r0 apk -wapmorgan/mp3info 0.1.0 php-composer -wayland-libs-client 1.22.0-r4 apk -web-auth/cose-lib v3.3.9 php-composer -web-auth/metadata-service v3.3.9 php-composer -web-auth/webauthn-lib v3.3.9 php-composer -wipefs 2.40.1-r1 apk -x264-libs 0.164_git20231001-r0 apk -x265-libs 3.6-r0 apk -xvidcore 1.3.7-r2 apk -xz-libs 5.6.2-r0 apk -zimg 3.0.5-r2 apk -zix-libs 0.4.2-r0 apk -zlib 1.3.1-r1 apk -zstd-libs 1.5.6-r0 apk +NAME VERSION TYPE +Process Wrapper 0.0.0.0 binary (+1 duplicate) +acl-libs 2.3.2-r1 apk +activity 8.0.0-dev.0 npm +agetty 2.42.3-r1 apk +aligned 0.4.2 rust-crate +aligned-vec 0.6.4 rust-crate +alpine-baselayout 3.7.2-r1 apk +alpine-baselayout-data 3.7.2-r1 apk +alpine-keys 2.6-r0 apk +alpine-release 3.24.3-r0 apk +alsa-lib 1.2.15.3-r0 apk +amphp/amp v2.6.5 php-composer +amphp/byte-stream v1.8.2 php-composer +amphp/parallel v1.4.4 php-composer +amphp/parser v1.1.1 php-composer +amphp/process v1.1.9 php-composer +amphp/serialization v1.0.0 php-composer +amphp/sync v1.4.2 php-composer +andrewdalpino/okbloomer 1.0.0 php-composer +anstream 0.6.19 rust-crate +anstyle 1.0.11 rust-crate +anstyle-parse 0.2.7 rust-crate +anstyle-query 1.1.3 rust-crate +anyhow 1.0.98 rust-crate (+1 duplicate) +aom-libs 3.14.1-r0 apk +apache2-utils 2.4.69-r0 apk +apk-tools 3.0.8-r0 apk +apr 1.7.6-r0 apk +apr-util 1.6.4-r0 apk +arg_enum_proc_macro 0.3.4 rust-crate +argon2-libs 20190702-r5 apk +arrayvec 0.7.6 rust-crate +as-slice 0.2.1 rust-crate +av-metrics 0.9.1 rust-crate +av-scenechange 0.14.1 rust-crate +av1-grain 0.2.4 rust-crate +avahi-libs 0.9_rc4-r0 apk +aws/aws-crt-php v1.2.7 php-composer +aws/aws-sdk-php 3.398.3 php-composer +bamarni/composer-bin-plugin 1.9.1 php-composer (+1 duplicate) +bantu/ini-get-wrapper v1.0.1 php-composer +bash 5.3.9-r1 apk +bitflags 2.9.1 rust-crate +bitstream-io 2.6.0 rust-crate +bitstream-io 4.2.0 rust-crate +bitvec 1.0.1 rust-crate +bitvec_helpers 3.1.6 rust-crate +blkid 2.42.3-r1 apk +brick/math 0.12.1 php-composer +brick/math 0.17.2 php-composer +brotli-libs 1.2.1-r0 apk +bubblewrap 0.12.0-r0 apk +busybox 1.37.0-r31 apk +busybox-binsh 1.37.0-r31 apk +c-ares 1.34.9-r0 apk +c-client 2007f-r16 apk +ca-certificates 20261020-r0 apk +ca-certificates-bundle 20261020-r0 apk +cairo 1.18.4-r1 apk +catatonit 0.2.1-r0 apk +cfdisk 2.42.3-r1 apk +cfg-if 1.0.1 rust-crate +christian-riesen/base32 1.6.0 php-composer +cjson 1.7.19-r1 apk +clap 4.5.40 rust-crate +clap_builder 4.5.40 rust-crate +clap_complete 4.5.54 rust-crate +clap_lex 0.7.5 rust-crate +colorchoice 1.0.4 rust-crate +composer 2.10.3 binary +console 0.15.11 rust-crate +core2 0.4.0 rust-crate +coreutils 9.11-r0 apk +coreutils-env 9.11-r0 apk +coreutils-fmt 9.11-r0 apk +coreutils-sha512sum 9.11-r0 apk +crc 3.3.0 rust-crate +crc-catalog 2.4.0 rust-crate +crossbeam 0.8.4 rust-crate +crossbeam-channel 0.5.15 rust-crate +crossbeam-deque 0.8.6 rust-crate +crossbeam-epoch 0.9.18 rust-crate +crossbeam-queue 0.3.12 rust-crate +crossbeam-utils 0.8.21 rust-crate +cups-libs 2.4.19-r1 apk +curl 8.22.0-r0 apk +cweagans/composer-configurable-plugin 2.0.0 php-composer +cweagans/composer-patches 2.0.0 php-composer +dbus-libs 1.16.2-r2 apk +deepdiver/zipstreamer v3.0.1 php-composer +deepdiver1975/tarstreamer v2.1.0 php-composer +dmesg 2.42.3-r1 apk +doctrine/dbal 3.10.4 php-composer +doctrine/deprecations 1.1.6 php-composer +doctrine/event-manager 2.0.1 php-composer +doctrine/lexer 3.0.1 php-composer +dolby_vision 3.3.2 rust-crate +egulias/email-validator 4.0.4 php-composer +either 1.15.0 rust-crate +equator 0.4.2 rust-crate +errno 0.3.12 rust-crate +fern 0.7.1 rust-crate +ffmpeg 8.1.3-r0 apk +ffmpeg-libavcodec 8.1.3-r0 apk +ffmpeg-libavdevice 8.1.3-r0 apk +ffmpeg-libavfilter 8.1.3-r0 apk +ffmpeg-libavformat 8.1.3-r0 apk +ffmpeg-libavutil 8.1.3-r0 apk +ffmpeg-libswresample 8.1.3-r0 apk +ffmpeg-libswscale 8.1.3-r0 apk +fftw-double-libs 3.3.11-r0 apk +files_downloadlimit 5.3.0-dev.0 npm +files_pdfviewer 8.0.0-dev.0 npm +findmnt 2.42.3-r1 apk +findutils 4.10.0-r1 apk +firebase/php-jwt v7.0.5 php-composer +firstrunwizard 8.0.0-dev.0 npm +flock 2.42.3-r1 apk +fontconfig 2.17.1-r1 apk +freetype 2.14.3-r0 apk +fribidi 1.0.16-r3 apk +fstrim 2.42.3-r1 apk +funty 2.0.0 rust-crate +fusonic/opengraph v3.1.0 php-composer +gapple/structured-fields v2.3.3 php-composer +gdbm 1.26-r0 apk +gdk-pixbuf 2.44.7-r1 apk +getrandom 0.3.3 rust-crate +ghostscript 10.08.0-r0 apk +giggsey/libphonenumber-for-php-lite 9.0.36 php-composer +git 2.54.0-r0 apk +git-init-template 2.54.0-r0 apk +glib 2.88.1-r1 apk +glslang-libs 1.4.341.0-r0 apk +glycin-image-rs 2.1.5-r0 apk +glycin-svg 2.1.5-r0 apk +gmp 6.3.0-r4 apk +gnu-libiconv 1.18-r0 apk +gnu-libiconv-libs 1.18-r0 apk +gnutls 3.8.13-r0 apk +graphite2 1.3.14-r6 apk +guzzlehttp/guzzle 7.15.2 php-composer +guzzlehttp/promises 2.5.1 php-composer +guzzlehttp/psr7 2.13.0 php-composer +guzzlehttp/psr7 2.13.1 php-composer +guzzlehttp/uri-template v1.0.4 php-composer +harfbuzz 13.2.1-r0 apk +hexdump 2.42.3-r1 apk +hexogen/kdtree v0.2.6 php-composer +hwdata-pci 0.408-r0 apk +icewind/searchdav v3.2.0 php-composer +icewind/smb 3.8.1 php-composer +icewind/streams v0.7.8 php-composer +icu-data-en 78.1-r0 apk +icu-libs 78.1-r0 apk +imagemagick 7.1.2.34-r0 apk +imagemagick-heic 7.1.2.34-r0 apk +imagemagick-jp2 7.1.2.34-r0 apk +imagemagick-jpeg 7.1.2.34-r0 apk +imagemagick-jxl 7.1.2.34-r0 apk +imagemagick-libs 7.1.2.34-r0 apk +imagemagick-pango 7.1.2.34-r0 apk +imagemagick-pdf 7.1.2.34-r0 apk +imagemagick-svg 7.1.2.34-r0 apk +imagemagick-tiff 7.1.2.34-r0 apk +imagemagick-webp 7.1.2.34-r0 apk +interpolate_name 0.2.4 rust-crate +is_terminal_polyfill 1.70.1 rust-crate +itertools 0.10.5 rust-crate +itertools 0.14.0 rust-crate +ivf 0.1.4 rust-crate +jansson 2.15.0-r0 apk +jbig2dec 0.20-r0 apk +joomla/string 3.0.4 php-composer +jq 1.8.2-r0 apk +json-c 0.18-r1 apk +justinrainbow/json-schema 6.10.0 php-composer +kornrunner/blurhash v1.2.2 php-composer +lab 0.11.0 rust-crate +lame-libs 3.100-r5 apk +laravel/serializable-closure v2.0.15 php-composer +lcms2 2.19-r0 apk +lcobucci/clock 3.5.0 php-composer +ldb 4.23.8-r0 apk +libSvtAv1Enc 4.1.0-r0 apk +libapk 3.0.8-r0 apk +libarchive 3.8.10-r0 apk +libass 0.17.4-r1 apk +libasyncns 0.8-r5 apk +libattr 2.5.2-r2 apk +libauth-samba 4.23.8-r0 apk +libavif 1.4.1-r0 apk +libblkid 2.42.3-r1 apk +libbluray 1.4.0-r0 apk +libbsd 0.12.2-r0 apk +libbz2 1.0.8-r6 apk +libc 0.2.172 rust-crate (+1 duplicate) +libcap-ng 0.8.5-r2 apk +libcap2 2.78-r0 apk +libcrypto3 3.5.9-r0 apk +libcurl 8.22.0-r0 apk +libdav1d 1.5.3-r0 apk +libde265 1.1.3-r0 apk +libdovi 3.3.2-r0 apk +libdrm 2.4.134-r0 apk +libdvdcss 1.4.3-r0 apk +libdvdnav 6.1.1-r1 apk +libdvdread 6.1.3-r2 apk +libeconf 0.8.3-r0 apk +libedit 20260508.3.1-r1 apk +libevent 2.1.13-r0 apk +libexpat 2.9.0-r0 apk +libfdisk 2.42.3-r1 apk +libffi 3.5.2-r1 apk +libflac 1.4.3-r2 apk +libformw 6.6_p20260516-r0 apk +libgcc 15.2.0-r5 apk +libglycin 2.1.5-r0 apk +libgomp 15.2.0-r5 apk +libheif 1.23.4-r0 apk +libheif-aom 1.23.4-r0 apk +libheif-dav1d 1.23.4-r0 apk +libheif-ffmpeg 1.23.4-r0 apk +libheif-jpeg 1.23.4-r0 apk +libheif-libde265 1.23.4-r0 apk +libheif-openjpeg 1.23.4-r0 apk +libheif-rav1e 1.23.4-r0 apk +libheif-svtenc 1.23.4-r0 apk +libheif-x264 1.23.4-r0 apk +libheif-x265 1.23.4-r0 apk +libhwy 1.3.0-r0 apk +libice 1.1.2-r0 apk +libidn2 2.3.8-r0 apk +libintl 1.0-r0 apk +libjpeg-turbo 3.1.3-r0 apk +libjxl 0.11.2-r1 apk +libldap 2.6.15-r0 apk +libltdl 2.6.0-r1 apk +libmd 1.2.0-r0 apk +libmemcached-libs 1.1.4-r1 apk +libmount 2.42.3-r1 apk +libncursesw 6.6_p20260516-r0 apk +libogg 1.3.6-r0 apk +libopenmpt 0.8.9-r0 apk +libpanelw 6.6_p20260516-r0 apk +libpciaccess 0.19-r0 apk +libplacebo 7.360.1-r0 apk +libpng 1.6.59-r0 apk +libpq 18.6-r0 apk +libproc2 4.0.6-r0 apk +libpsl 0.21.5-r3 apk +libpulse 17.0-r7 apk +libraqm 0.10.2-r0 apk +librist 0.2.15-r0 apk +librsvg 2.62.3-r0 apk +libsasl 2.1.28-r9 apk +libseccomp 2.6.1-r0 apk +libsharpyuv 1.6.0-r0 apk +libsm 1.2.6-r0 apk +libsmartcols 2.42.3-r1 apk +libsmbclient 4.23.8-r0 apk +libsndfile 1.2.2-r2 apk +libsodium 1.0.22-r0 apk +libsrt 1.5.3-r1 apk +libssh 0.12.2-r0 apk +libssl3 3.5.9-r0 apk +libstdc++ 15.2.0-r5 apk +libtasn1 4.21.0-r0 apk +libtheora 1.2.0-r1 apk +libudfread 1.2.0-r1 apk +libunibreak 6.1-r0 apk +libunistring 1.4.2-r0 apk +libuuid 2.42.3-r1 apk +libva 2.23.0-r0 apk +libvdpau 1.5-r4 apk +libvorbis 1.3.7-r2 apk +libvpl 2.15.0-r1 apk +libvpx 1.15.2-r1 apk +libwbclient 4.23.8-r0 apk +libwebp 1.6.0-r0 apk +libwebpdemux 1.6.0-r0 apk +libwebpmux 1.6.0-r0 apk +libx11 1.8.14-r0 apk +libxau 1.0.12-r0 apk +libxcb 1.17.0-r2 apk +libxdmcp 1.1.5-r1 apk +libxext 1.3.7-r0 apk +libxfixes 6.0.2-r0 apk +libxft 2.3.9-r0 apk +libxml2 2.13.9-r2 apk +libxpm 3.5.20-r0 apk +libxrender 0.9.13-r0 apk +libxt 1.3.1-r0 apk +libxxhash 0.8.3-r1 apk +libyuv 0.0.1928-r0 apk +libzip 1.11.4-r2 apk +libzmq 4.3.5-r2 apk +lilv-libs 0.24.26-r1 apk +linux-pam 1.7.1-r2 apk +linux-raw-sys 0.9.4 rust-crate +lmdb 0.9.35-r0 apk +log 0.4.27 rust-crate +logger 2.42.3-r1 apk +logreader 8.0.0-dev.0 npm +logrotate 3.22.0-r0 apk +losetup 2.42.3-r1 apk +lsblk 2.42.3-r1 apk +lscpu 2.42.3-r1 apk +lz4-libs 1.10.0-r1 apk +marc-mabe/php-enum v4.7.1 php-composer +masterminds/html5 2.10.0 php-composer +maybe-rayon 0.1.1 rust-crate +mbedtls3 3.6.7-r0 apk +mcookie 2.42.3-r1 apk +memchr 2.7.5 rust-crate +mexitek/phpcolors v1.0.4 php-composer +microsoft/azure-storage-blob 1.5.4 php-composer +microsoft/azure-storage-common 1.5.2 php-composer +minimal-lexical 0.2.1 rust-crate +minishlink/web-push v11.0.0 php-composer +mlocati/ip-lib 1.22.0 php-composer +mount 2.42.3-r1 apk +mpg123-libs 1.33.5-r0 apk +mtdowling/jmespath.php 2.9.1 php-composer +musl 1.2.6-r3 apk +musl-utils 1.2.6-r3 apk +nano 9.3-r0 apk +ncurses-terminfo-base 6.6_p20260516-r0 apk +nelexa/buffer 1.3.0 php-composer +netcat-openbsd 1.234.1-r0 apk +nettle 3.10.2-r0 apk +new_debug_unreachable 1.0.6 rust-crate +nextcloud 1.0.0 npm +nextcloud/lognormalizer v3.0.1 php-composer +nghttp2-libs 1.70.0-r0 apk +nginx 1.30.6-r0 apk +nom 7.1.3 rust-crate +nom 8.0.0 rust-crate +noop_proc_macro 0.3.0 rust-crate +notifications 8.0.0-dev.0 npm +num-bigint 0.4.6 rust-crate +num-derive 0.4.2 rust-crate +num-integer 0.1.46 rust-crate +num-rational 0.4.2 rust-crate +num-traits 0.2.19 rust-crate +numactl 2.0.19-r0 apk +office 1.1.0-dev.0 npm +once_cell 1.21.3 rust-crate +oniguruma 6.9.10-r0 apk +openjpeg 2.5.4-r2 apk +openssl 3.5.9-r0 apk +opus 1.6.1-r0 apk +orc 0.4.41-r0 apk +p11-kit 0.26.2-r0 apk +pango 1.57.1-r0 apk +paragonie/constant_time_encoding v3.1.3 php-composer +partx 2.42.3-r1 apk +password_policy 7.0.0-dev.0 npm +paste 1.0.15 rust-crate +pastey 0.1.0 rust-crate +pcre2 10.49-r0 apk +pear/archive_tar 1.6.0 php-composer +pear/console_getopt v1.4.3 php-composer +pear/pear-core-minimal v1.10.18 php-composer +pear/pear_exception v1.0.2 php-composer +photos 8.0.0-dev.0 npm +php-http/discovery 1.20.0 php-composer +php-http/guzzle7-adapter 1.1.0 php-composer +php-http/httplug 2.4.1 php-composer (+1 duplicate) +php-http/promise 1.3.1 php-composer (+1 duplicate) +php-opencloud/openstack v3.17.0 php-composer +php85 8.5.12-r0 apk +php85-bcmath 8.5.12-r0 apk +php85-bz2 8.5.12-r0 apk +php85-common 8.5.12-r0 apk +php85-ctype 8.5.12-r0 apk +php85-curl 8.5.12-r0 apk +php85-dom 8.5.12-r0 apk +php85-exif 8.5.12-r0 apk +php85-fileinfo 8.5.12-r0 apk +php85-fpm 8.5.12-r0 apk +php85-ftp 8.5.12-r0 apk +php85-gd 8.5.12-r0 apk +php85-gmp 8.5.12-r0 apk +php85-iconv 8.5.12-r0 apk +php85-intl 8.5.12-r0 apk +php85-ldap 8.5.12-r0 apk +php85-mbstring 8.5.12-r0 apk +php85-mysqlnd 8.5.12-r0 apk +php85-openssl 8.5.12-r0 apk +php85-pcntl 8.5.12-r0 apk +php85-pdo 8.5.12-r0 apk +php85-pdo_mysql 8.5.12-r0 apk +php85-pdo_pgsql 8.5.12-r0 apk +php85-pdo_sqlite 8.5.12-r0 apk +php85-pecl-apcu 5.1.28-r0 apk +php85-pecl-igbinary 3.2.17_rc1-r0 apk +php85-pecl-imagick 3.8.1-r0 apk +php85-pecl-imap 1.0.3-r0 apk +php85-pecl-memcached 3.4.0-r0 apk +php85-pecl-msgpack 3.0.1-r0 apk +php85-pecl-redis 6.3.0-r0 apk +php85-pecl-smbclient 1.2.0_pre-r0 apk +php85-pgsql 8.5.12-r0 apk +php85-phar 8.5.12-r0 apk +php85-posix 8.5.12-r0 apk +php85-session 8.5.12-r0 apk +php85-simplexml 8.5.12-r0 apk +php85-sockets 8.5.12-r0 apk +php85-sodium 8.5.12-r0 apk +php85-sqlite3 8.5.12-r0 apk +php85-sysvsem 8.5.12-r0 apk +php85-xml 8.5.12-r0 apk +php85-xmlreader 8.5.12-r0 apk +php85-xmlwriter 8.5.12-r0 apk +php85-zip 8.5.12-r0 apk +phpseclib/phpseclib 3.0.57 php-composer +pimple/pimple v3.6.2 php-composer +pixman 0.46.4-r0 apk +pkgconf 2.5.1-r0 apk +popt 1.19-r4 apk +ppv-lite86 0.2.21 rust-crate +predis/predis v3.5.1 php-composer +privacy 7.0.0-dev.0 npm +proc-macro2 1.0.95 rust-crate +procps-ng 4.0.6-r0 apk +profiling 1.0.16 rust-crate +psr/cache 3.0.0 php-composer +psr/clock 1.0.0 php-composer (+1 duplicate) +psr/container 2.0.2 php-composer +psr/event-dispatcher 1.0.0 php-composer +psr/http-client 1.0.3 php-composer (+1 duplicate) +psr/http-factory 1.1.0 php-composer (+1 duplicate) +psr/http-message 2.0 php-composer (+1 duplicate) +psr/log 3.0.2 php-composer (+2 duplicates) +punic/punic 3.8.1 php-composer +quote 1.0.40 rust-crate +radium 0.7.0 rust-crate +ralouphie/getallheaders 3.0.3 php-composer (+1 duplicate) +rand 0.9.1 rust-crate +rand_chacha 0.9.0 rust-crate +rand_core 0.9.3 rust-crate +rav1e 0.8.1 rust-crate +rav1e-libs 0.8.1-r0 apk +rayon 1.10.0 rust-crate +rayon-core 1.12.1 rust-crate +readline 8.3.3-r1 apk +recommendations 8.0.0-dev.0 npm +rsync 3.5.0-r0 apk +rubix/ml 2.5.3 php-composer +rubix/tensor 3.0.5 php-composer +rullzer/easytotp v0.1.4 php-composer +runuser 2.42.3-r1 apk +rustix 1.0.7 rust-crate +sabre/dav 4.7.0 php-composer +sabre/event 5.1.7 php-composer +sabre/http 5.1.12 php-composer +sabre/uri 2.3.4 php-composer +sabre/vobject 4.5.6 php-composer +sabre/xml 2.2.11 php-composer +samba-client 4.23.8-r0 apk +samba-client-libs 4.23.8-r0 apk +samba-common 4.23.8-r0 apk +samba-libs 4.23.8-r0 apk +samba-util-libs 4.23.8-r0 apk +scan_fmt 0.2.6 rust-crate +scanelf 1.3.9-r1 apk +serd-libs 0.32.8-r0 apk +serverinfo 6.0.0 npm +setarch 2.42.3-r1 apk +setpriv 2.42.3-r1 apk +sfdisk 2.42.3-r1 apk +shaderc 2026.1-r0 apk +shadow 4.18.0-r1 apk +shared-mime-info 2.4-r7 apk +signal-hook 0.3.18 rust-crate +signal-hook-registry 1.4.5 rust-crate +simd_helpers 0.1.0 rust-crate +skalibs-libs 2.15.0.0-r0 apk +sord-libs 0.16.22-r0 apk +soxr 0.1.3-r7 apk +speexdsp 1.2.1-r2 apk +spirv-tools 1.4.341.0-r0 apk +spomky-labs/base64url v2.0.4 php-composer +spomky-labs/cbor-php 3.0.4 php-composer +spomky-labs/pki-framework 1.2.1 php-composer +spomky-labs/pki-framework 1.6.0 php-composer +sqlite-libs 3.53.4-r0 apk +sratom 0.6.20-r0 apk +ssl_client 1.37.0-r31 apk +stable_deref_trait 1.2.0 rust-crate +stecman/symfony-console-completion v0.15.0 php-composer +sudo 1.9.17_p2-r2 apk +support 7.0.0-dev.0 npm +symfony/console v7.4.15 php-composer +symfony/css-selector v6.4.24 php-composer +symfony/deprecation-contracts v3.6.0 php-composer +symfony/deprecation-contracts v3.7.1 php-composer (+1 duplicate) +symfony/dom-crawler v7.4.12 php-composer +symfony/event-dispatcher v7.4.15 php-composer +symfony/event-dispatcher-contracts v3.7.0 php-composer +symfony/filesystem v7.4.8 php-composer +symfony/http-foundation v7.4.15 php-composer +symfony/mailer v7.4.15 php-composer +symfony/mime v7.4.13 php-composer +symfony/polyfill-intl-grapheme v1.41.0 php-composer +symfony/polyfill-intl-idn v1.38.1 php-composer +symfony/polyfill-intl-normalizer v1.38.0 php-composer +symfony/polyfill-mbstring v1.33.0 php-composer +symfony/polyfill-php80 v1.33.0 php-composer +symfony/polyfill-php80 v1.37.0 php-composer +symfony/polyfill-php82 v1.33.0 php-composer +symfony/polyfill-php83 v1.33.0 php-composer +symfony/polyfill-php83 v1.41.0 php-composer +symfony/polyfill-php84 v1.38.1 php-composer (+1 duplicate) +symfony/polyfill-php85 v1.41.0 php-composer +symfony/polyfill-php86 v1.41.0 php-composer +symfony/polyfill-uuid v1.29.0 php-composer +symfony/process v6.4.33 php-composer +symfony/routing v6.4.41 php-composer +symfony/service-contracts v3.7.0 php-composer +symfony/string v7.4.15 php-composer +symfony/translation v6.4.32 php-composer +symfony/translation-contracts v3.4.3 php-composer +symfony/uid v6.4.32 php-composer +syn 2.0.102 rust-crate +talloc 2.4.4-r1 apk +tap 1.0.1 rust-crate +tdb-libs 1.4.15-r1 apk +terminal_size 0.4.2 rust-crate +tevent 0.17.1-r1 apk +text 9.0.0-dev.0 npm +thiserror 1.0.69 rust-crate +thiserror 2.0.12 rust-crate +tiff 4.7.2-r0 apk +tinyvec 1.9.0 rust-crate +tzdata 2026e-r0 apk +umount 2.42.3-r1 apk +unicode-ident 1.0.18 rust-crate +unicode-width 0.2.1 rust-crate +utf8parse 0.2.2 rust-crate +util-linux 2.42.3-r1 apk +util-linux-misc 2.42.3-r1 apk +utmps-libs 0.1.3.3-r0 apk +uuidgen 2.42.3-r1 apk +v4l-utils-libs 1.32.0-r1 apk +v_frame 0.3.9 rust-crate +vidstab 1.1.1-r0 apk +viewer 8.0.0-dev.0 npm +vulkan-loader 1.4.347-r0 apk +wamania/php-stemmer v4.0.0 php-composer +wapmorgan/mp3info 0.1.1 php-composer +wayland-libs-client 1.25.0-r0 apk +web-auth/cose-lib 4.3.0 php-composer +web-auth/webauthn-lib 4.9.3 php-composer +web-token/jwt-library 4.1.7 php-composer +wipefs 2.42.3-r1 apk +woltlab/webp-exif v0.1.5 php-composer +wyz 0.5.1 rust-crate +x264-libs 0.164.3108-r1 apk +x265-libs 4.1-r0 apk +xvidcore 1.3.7-r2 apk +xz-libs 5.8.4-r0 apk +y4m 0.8.0 rust-crate +zerocopy 0.8.25 rust-crate +zimg 3.0.6-r0 apk +zix-libs 0.8.0-r0 apk +zlib 1.3.2-r1 apk +zstd-libs 1.5.7-r2 apk diff --git a/readme-vars.yml b/readme-vars.yml index fcbf8a47..635848bd 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -9,30 +9,29 @@ project_blurb: | Where are your photos and documents? With Nextcloud you pick a server of your choice, at home, in a data center or at a provider. And that is where your files will be. Nextcloud runs on that server, protecting your data and giving you access from your desktop or mobile devices. Through Nextcloud you also access, sync and share your existing data on that FTP drive at the office, a Dropbox or a NAS you have at home. project_lsio_github_repo_url: "https://github.com/linuxserver/docker-{{ project_name }}" - +project_categories: "Cloud,Documents" # supported architectures available_architectures: - - { arch: "{{ arch_x86_64 }}", tag: "amd64-latest"} - - { arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"} - + - {arch: "{{ arch_x86_64 }}", tag: "amd64-latest"} + - {arch: "{{ arch_arm64 }}", tag: "arm64v8-latest"} # development version development_versions: true development_versions_items: - - { tag: "latest", desc: "Stable Nextcloud releases" } - - { tag: "develop", desc: "Beta Nextcloud pre-releases *only*" } - - { tag: "previous", desc: "Nextcloud releases from the previous major version" } - + - {tag: "latest", desc: "Stable Nextcloud releases"} + - {tag: "develop", desc: "Beta Nextcloud pre-releases *only*"} + - {tag: "previous", desc: "Nextcloud releases from the previous major version"} # container parameters common_param_env_vars_enabled: true param_container_name: "{{ project_name }}" param_usage_include_vols: true param_volumes: - - { vol_path: "/config", vol_host_path: "/path/to/{{ project_name }}/config", desc: "Persistent config files" } - - { vol_path: "/data", vol_host_path: "/path/to/data", desc: "Your personal data." } + - {vol_path: "/config", vol_host_path: "/path/to/{{ project_name }}/config", desc: "Persistent config files"} + - {vol_path: "/data", vol_host_path: "/path/to/data", desc: "Your personal data."} param_usage_include_ports: true param_ports: - - { external_port: "443", internal_port: "443", port_desc: "WebUI" } - + - {external_port: "443", internal_port: "443", port_desc: "WebUI"} +readonly_supported: false +nonroot_supported: false # application setup block app_setup_block_enabled: true app_setup_block: | @@ -92,67 +91,122 @@ app_setup_block: | ``` Afterwards, you can set `"path" => OC::$SERVERROOT . "/your_custom_apps_folder",` in your `config.php` file, per the [official documentation](https://docs.nextcloud.com/server/latest/admin_manual/apps_management.html#using-custom-app-directories). - +# init diagram +init_diagram: | + "nextcloud:latest": { + docker-mods + base { + fix-attr +\nlegacy cont-init + } + docker-mods -> base + legacy-services + custom services + init-services -> legacy-services + init-services -> custom services + custom services -> legacy-services + legacy-services -> ci-service-check + init-migrations -> init-adduser + init-nginx-end -> init-config + init-os-end -> init-config + init-config -> init-config-end + init-crontab-config -> init-config-end + init-nextcloud-config -> init-config-end + init-config -> init-crontab-config + init-mods-end -> init-custom-files + init-adduser -> init-device-perms + base -> init-envfile + init-os-end -> init-folders + init-php -> init-keygen + base -> init-migrations + init-config-end -> init-mods + init-mods-package-install -> init-mods-end + init-mods -> init-mods-package-install + init-nginx-end -> init-nextcloud-config + init-samples -> init-nginx + init-version-checks -> init-nginx-end + init-adduser -> init-os-end + init-device-perms -> init-os-end + init-envfile -> init-os-end + init-keygen -> init-permissions + init-nginx -> init-php + init-folders -> init-samples + init-custom-files -> init-services + init-permissions -> init-version-checks + init-services -> svc-cron + svc-cron -> legacy-services + init-services -> svc-nginx + svc-nginx -> legacy-services + init-services -> svc-php-fpm + svc-php-fpm -> legacy-services + } + Base Images: { + "baseimage-alpine-nginx:3.24" <- "baseimage-alpine:3.24" + } + "nextcloud:latest" <- Base Images # changelog changelogs: - - { date: "09.07.24:", desc: "Add `previous` tag for n-1 releases."} - - { date: "24.06.24:", desc: "Rebase to Alpine 3.20. Existing users should update their nginx confs to avoid http2 deprecation warnings."} - - { date: "19.05.24:", desc: "Added util-linux package required for taskset."} - - { date: "10.04.24:", desc: "Added imagemagick-pdf."} - - { date: "05.04.24:", desc: "Added imagemagick-heic. Manual update to `config.php` required - see above."} - - { date: "02.04.24:", desc: "Existing users should update: site-confs/default.conf - Add support for the Client Push (notify_push) plugin and the [new mod](https://github.com/linuxserver/docker-mods/tree/nextcloud-notify-push)."} - - { date: "22.03.24:", desc: "Add imagemagick-svg module."} - - { date: "06.03.24:", desc: "Rebase to Alpine 3.19 with php 8.3."} - - { date: "02.01.24:", desc: "Existing users should update: site-confs/default.conf - Cleanup default site conf." } - - { date: "22.12.23:", desc: "Site default conf updating to include mime.types for js and mjs and update location to include more file types." } - - { date: "28.10.23:", desc: "Disable web upgrades using occ during init." } - - { date: "31.08.23:", desc: "Re-add updatenotification app. This allows users to be notified for app updates, but also notifies for NextCloud updates. Updating NextCloud via the web UI is not supported when using this image." } - - { date: "14.08.23:", desc: "Add develop branch." } - - { date: "25.06.23:", desc: "Move Nextcloud installation inside container. Remove CLI updater. [See changes announcement](https://info.linuxserver.io/issues/2023-06-25-nextcloud/)." } - - { date: "21.06.23:", desc: "Existing users should update `/config/nginx/site-confs/default.conf` - Security fix for real ip settings." } - - { date: "25.05.23:", desc: "Rebase to Alpine 3.18, deprecate armhf." } - - { date: "13.04.23:", desc: "Move ssl.conf include to default.conf." } - - { date: "21.03.23:", desc: "Add php81-sysvsem as new dep for v26. Update default X-Robots-Tag to `noindex, nofollow``." } - - { date: "02.03.23:", desc: "Set permissions on crontabs during init." } - - { date: "20.01.23:", desc: "Rebase to alpine 3.17 with php8.1." } - - { date: "10.10.22:", desc: "Rebasing to alpine 3.15 with php8. Restructure nginx configs ([see changes announcement](https://info.linuxserver.io/issues/2022-08-20-nginx-base))." } - - { date: "30.09.22:", desc: "Disabled `output_buffering` as per [nextcloud docs](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/big_file_upload_configuration.html" } - - { date: "21.05.22:", desc: "Update version check endpoint." } - - { date: "28.04.22:", desc: "Increase OPCache interned strings buffered setting to 16." } - - { date: "14.04.22:", desc: "Nginx default site config updated for v23 (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container). Fix LDAP connection." } - - { date: "11.09.21:", desc: "Rebasing to alpine 3.14" } - - { date: "21.03.21:", desc: "Publish `php8` tag for testing." } - - { date: "25.02.21:", desc: "Nginx default site config updated for v21 (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)." } - - { date: "21.01.21:", desc: "Fix php iconv (was breaking the mail addon). If installed, attempt to remove broken CODE Server app during startup." } - - { date: "20.01.21:", desc: "Increase php fcgi timeout to prevent 504 Gateway timeout errors (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)." } - - { date: "16.01.21:", desc: "Rebasing to alpine 3.13. Users with issues on 32-bit arm, [see this article](https://docs.linuxserver.io/faq#my-host-is-incompatible-with-images-based-on-ubuntu-focal-and-alpine-3-13)." } - - { date: "12.08.20:", desc: "Various updates to default site config, including added support for webfinger (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)." } - - { date: "03.06.20:", desc: "Rebasing to alpine 3.12" } - - { date: "03.06.20:", desc: "Add php7-bcmath and php7-fileinfo" } - - { date: "31.05.20:", desc: "Add aliases for occ and updater.phar" } - - { date: "31.03.20:", desc: "Allow crontab to be user customized, fix logrotate." } - - { date: "17.01.20:", desc: "Updated php.ini defaults and site config, including an optional HSTS directive (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)." } - - { date: "19.12.19:", desc: "Rebasing to alpine 3.11." } - - { date: "18.11.19:", desc: "Nginx default site config updated for v17 (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)." } - - { date: "28.10.19:", desc: "Change cronjob to run every 5 minutes." } - - { date: "24.10.19:", desc: "Nginx default site config updated due to CVE-2019-11043 (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)." } - - { date: "14.07.19:", desc: "Download nextcloud during build time." } - - { date: "28.06.19:", desc: "Rebasing to alpine 3.10." } - - { date: "23.03.19:", desc: "Switching to new Base images, shift to arm32v7 tag." } - - { date: "27.02.19:", desc: "Updating base nginx config to sync up with v15 requirements." } - - { date: "22.02.19:", desc: "Rebasing to alpine 3.9." } - - { date: "28.01.19:", desc: "Add pipeline logic and multi arch." } - - { date: "25.01.19:", desc: "Add php7-phar for occ upgrades." } - - { date: "05.09.18:", desc: "Rebase to alpine 3.8." } - - { date: "11.06.18:", desc: "Use latest rather than specific version for initial install." } - - { date: "26.04.18:", desc: "Bump default install to 13.0.1." } - - { date: "06.02.18:", desc: "Bump default install to 13.0.0." } - - { date: "26.01.18:", desc: "Rebase to alpine 3.7, bump default install to 12.0.5." } - - { date: "12.12.17:", desc: "Bump default install to 12.0.4, fix continuation lines." } - - { date: "15.10.17:", desc: "Sed php.ini for opcache requirements in newer nextcloud versions." } - - { date: "20.09.17:", desc: "Bump default install to 12.0.3." } - - { date: "19.08.17:", desc: "Bump default install to 12.0.2." } - - { date: "25.05.17:", desc: "Rebase to alpine 3.6." } - - { date: "22.05.17:", desc: "Update to nextcloud 12.0, adding required dependecies and note about commenting out SAMEORIGIN; line." } - - { date: "03.05.17:", desc: "Use community repo of memcache." } - - { date: "07.03.17:", desc: "Release into main repository and upgrade to php7 and Alpine 3.5." } + - {date: "14.10.26:", desc: "Rebase to Alpine 3.24 with php 8.5. Tweak opcache settings according to upstream docs. Import upstream release notes in Github releases."} + - {date: "10.07.25:", desc: "Rebase to Alpine 3.22."} + - {date: "12.02.25:", desc: "Rebase to Alpine 3.21."} + - {date: "09.01.25:", desc: "Fix uploading large files. Existing users should update their nginx confs."} + - {date: "09.07.24:", desc: "Add `previous` tag for n-1 releases."} + - {date: "24.06.24:", desc: "Rebase to Alpine 3.20. Existing users should update their nginx confs to avoid http2 deprecation warnings."} + - {date: "19.05.24:", desc: "Added util-linux package required for taskset."} + - {date: "10.04.24:", desc: "Added imagemagick-pdf."} + - {date: "05.04.24:", desc: "Added imagemagick-heic. Manual update to `config.php` required - see above."} + - {date: "02.04.24:", desc: "Existing users should update: site-confs/default.conf - Add support for the Client Push (notify_push) plugin and the [new mod](https://github.com/linuxserver/docker-mods/tree/nextcloud-notify-push)."} + - {date: "22.03.24:", desc: "Add imagemagick-svg module."} + - {date: "06.03.24:", desc: "Rebase to Alpine 3.19 with php 8.3."} + - {date: "02.01.24:", desc: "Existing users should update: site-confs/default.conf - Cleanup default site conf."} + - {date: "22.12.23:", desc: "Site default conf updating to include mime.types for js and mjs and update location to include more file types."} + - {date: "28.10.23:", desc: "Disable web upgrades using occ during init."} + - {date: "31.08.23:", desc: "Re-add updatenotification app. This allows users to be notified for app updates, but also notifies for NextCloud updates. Updating NextCloud via the web UI is not supported when using this image."} + - {date: "14.08.23:", desc: "Add develop branch."} + - {date: "25.06.23:", desc: "Move Nextcloud installation inside container. Remove CLI updater. [See changes announcement](https://info.linuxserver.io/issues/2023-06-25-nextcloud/)."} + - {date: "21.06.23:", desc: "Existing users should update `/config/nginx/site-confs/default.conf` - Security fix for real ip settings."} + - {date: "25.05.23:", desc: "Rebase to Alpine 3.18, deprecate armhf."} + - {date: "13.04.23:", desc: "Move ssl.conf include to default.conf."} + - {date: "21.03.23:", desc: "Add php81-sysvsem as new dep for v26. Update default X-Robots-Tag to `noindex, nofollow``."} + - {date: "02.03.23:", desc: "Set permissions on crontabs during init."} + - {date: "20.01.23:", desc: "Rebase to alpine 3.17 with php8.1."} + - {date: "10.10.22:", desc: "Rebasing to alpine 3.15 with php8. Restructure nginx configs ([see changes announcement](https://info.linuxserver.io/issues/2022-08-20-nginx-base))."} + - {date: "30.09.22:", desc: "Disabled `output_buffering` as per [nextcloud docs](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/big_file_upload_configuration.html"} + - {date: "21.05.22:", desc: "Update version check endpoint."} + - {date: "28.04.22:", desc: "Increase OPCache interned strings buffered setting to 16."} + - {date: "14.04.22:", desc: "Nginx default site config updated for v23 (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container). Fix LDAP connection."} + - {date: "11.09.21:", desc: "Rebasing to alpine 3.14"} + - {date: "21.03.21:", desc: "Publish `php8` tag for testing."} + - {date: "25.02.21:", desc: "Nginx default site config updated for v21 (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)."} + - {date: "21.01.21:", desc: "Fix php iconv (was breaking the mail addon). If installed, attempt to remove broken CODE Server app during startup."} + - {date: "20.01.21:", desc: "Increase php fcgi timeout to prevent 504 Gateway timeout errors (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)."} + - {date: "16.01.21:", desc: "Rebasing to alpine 3.13. Users with issues on 32-bit arm, [see this article](https://docs.linuxserver.io/faq#my-host-is-incompatible-with-images-based-on-ubuntu-focal-and-alpine-3-13)."} + - {date: "12.08.20:", desc: "Various updates to default site config, including added support for webfinger (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)."} + - {date: "03.06.20:", desc: "Rebasing to alpine 3.12"} + - {date: "03.06.20:", desc: "Add php7-bcmath and php7-fileinfo"} + - {date: "31.05.20:", desc: "Add aliases for occ and updater.phar"} + - {date: "31.03.20:", desc: "Allow crontab to be user customized, fix logrotate."} + - {date: "17.01.20:", desc: "Updated php.ini defaults and site config, including an optional HSTS directive (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)."} + - {date: "19.12.19:", desc: "Rebasing to alpine 3.11."} + - {date: "18.11.19:", desc: "Nginx default site config updated for v17 (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)."} + - {date: "28.10.19:", desc: "Change cronjob to run every 5 minutes."} + - {date: "24.10.19:", desc: "Nginx default site config updated due to CVE-2019-11043 (existing users should delete `/config/nginx/site-confs/default.conf` and restart the container)."} + - {date: "14.07.19:", desc: "Download nextcloud during build time."} + - {date: "28.06.19:", desc: "Rebasing to alpine 3.10."} + - {date: "23.03.19:", desc: "Switching to new Base images, shift to arm32v7 tag."} + - {date: "27.02.19:", desc: "Updating base nginx config to sync up with v15 requirements."} + - {date: "22.02.19:", desc: "Rebasing to alpine 3.9."} + - {date: "28.01.19:", desc: "Add pipeline logic and multi arch."} + - {date: "25.01.19:", desc: "Add php7-phar for occ upgrades."} + - {date: "05.09.18:", desc: "Rebase to alpine 3.8."} + - {date: "11.06.18:", desc: "Use latest rather than specific version for initial install."} + - {date: "26.04.18:", desc: "Bump default install to 13.0.1."} + - {date: "06.02.18:", desc: "Bump default install to 13.0.0."} + - {date: "26.01.18:", desc: "Rebase to alpine 3.7, bump default install to 12.0.5."} + - {date: "12.12.17:", desc: "Bump default install to 12.0.4, fix continuation lines."} + - {date: "15.10.17:", desc: "Sed php.ini for opcache requirements in newer nextcloud versions."} + - {date: "20.09.17:", desc: "Bump default install to 12.0.3."} + - {date: "19.08.17:", desc: "Bump default install to 12.0.2."} + - {date: "25.05.17:", desc: "Rebase to alpine 3.6."} + - {date: "22.05.17:", desc: "Update to nextcloud 12.0, adding required dependecies and note about commenting out SAMEORIGIN; line."} + - {date: "03.05.17:", desc: "Use community repo of memcache."} + - {date: "07.03.17:", desc: "Release into main repository and upgrade to php7 and Alpine 3.5."} diff --git a/root/defaults/nginx/site-confs/default.conf.sample b/root/defaults/nginx/site-confs/default.conf.sample index d11eff13..c78c67bc 100644 --- a/root/defaults/nginx/site-confs/default.conf.sample +++ b/root/defaults/nginx/site-confs/default.conf.sample @@ -1,4 +1,4 @@ -## Version 2024/07/16 - Changelog: https://github.com/linuxserver/docker-nextcloud/commits/master/root/defaults/nginx/site-confs/default.conf.sample +## Version 2025/07/10 - Changelog: https://github.com/linuxserver/docker-nextcloud/commits/master/root/defaults/nginx/site-confs/default.conf.sample # Set the `immutable` cache control options only for assets with a cache busting `v` argument map $arg_v $asset_immutable { @@ -11,6 +11,8 @@ server { listen [::]:80 default_server; listen 443 ssl default_server; listen [::]:443 ssl default_server; + listen 443 quic reuseport default_server; + listen [::]:443 quic reuseport default_server; server_name _; @@ -25,7 +27,7 @@ server { # https://docs.nextcloud.com/server/latest/admin_manual/installation/nginx.html#nextcloud-in-the-webroot-of-nginx # set max upload size and increase upload timeout: - client_max_body_size 512M; + client_max_body_size 0; client_body_timeout 300s; fastcgi_buffers 64 4K; diff --git a/root/etc/s6-overlay/s6-rc.d/init-nextcloud-config/run b/root/etc/s6-overlay/s6-rc.d/init-nextcloud-config/run index ffe42494..bba0b8d1 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-nextcloud-config/run +++ b/root/etc/s6-overlay/s6-rc.d/init-nextcloud-config/run @@ -10,7 +10,7 @@ mkdir -p \ /data # migrate legacy install (copy inside container) -if [ -f /config/www/nextcloud/version.php ]; then +if [[ -f /config/www/nextcloud/version.php ]]; then echo "Migrating legacy install (this can take a while) ...)" rsync -rlD --remove-source-files --exclude-from=/app/upgrade.exclude /config/www/nextcloud/ /app/www/public/ rm -rf /config/www/nextcloud/updater/ @@ -26,7 +26,7 @@ fi # symlink config folders for dir in apps config themes; do - if [ "$(readlink /app/www/public/${dir})" != "/config/www/nextcloud/${dir}" ]; then + if [[ "$(readlink /app/www/public/${dir})" != "/config/www/nextcloud/${dir}" ]]; then rm -rf "/app/www/public/${dir}" ln -s "/config/www/nextcloud/${dir}" "/app/www/public/${dir}" lsiown abc:abc "/config/www/nextcloud/${dir}" "/app/www/public/${dir}" @@ -34,9 +34,9 @@ for dir in apps config themes; do done # get versions -image_version=$(php -r "require '/app/www/src/version.php'; echo implode('.', \$OC_Version);" 2>/dev/null) -installed_version=$(php -r "require '/config/www/nextcloud/config/config.php'; echo \$CONFIG['version'];" 2>/dev/null) -if [ "${installed_version}" = "" ]; then +image_version=$(php -r "require '/app/www/src/version.php'; echo implode('.', \$OC_Version);" 2>/dev/null | xargs) +installed_version=$(php -r "require '/config/www/nextcloud/config/config.php'; echo \$CONFIG['version'];" 2>/dev/null | xargs) +if [[ "${installed_version}" = "" ]]; then installed_version="0.0.0.0" fi image_major="${image_version%%.*}" @@ -54,23 +54,23 @@ if vergt "${installed_version}" "${image_version}"; then sleep infinity fi -if [ "${installed_version}" != "0.0.0.0" ] && vergt "${image_major}" "${max_upgrade}"; then +if [[ "${installed_version}" != "0.0.0.0" ]] && vergt "${image_major}" "${max_upgrade}"; then echo "Can't start Nextcloud because the version of the data (${installed_version}) is more than one major version behind the docker image version (${image_version}) and upgrading more than one major version is not supported. Please run an image tagged for the major version ${max_upgrade} first." sleep infinity fi -if [ "${installed_version}" = "0.0.0.0" ] || [ ! -f /app/www/public/version.php ] || [ -z "$(ls -A /config/www/nextcloud/apps 2>/dev/null)" ]; then +if [[ "${installed_version}" = "0.0.0.0" ]] || [[ ! -f /app/www/public/version.php ]] || [[ -z "$(ls -A /config/www/nextcloud/apps 2>/dev/null)" ]]; then touch /tmp/needs_install fi -if [ "${installed_version}" != "0.0.0.0" ] && vergt "${image_version}" "${installed_version}"; then +if [[ "${installed_version}" != "0.0.0.0" ]] && vergt "${image_version}" "${installed_version}"; then touch /tmp/needs_upgrade fi # initialize nextcloud -if [ -f /config/www/nextcloud/config/needs_migration ] || [ -f /tmp/needs_install ] || [ -f /tmp/needs_upgrade ]; then +if [[ -f /config/www/nextcloud/config/needs_migration ]] || [[ -f /tmp/needs_install ]] || [[ -f /tmp/needs_upgrade ]]; then echo "Initializing nextcloud ${image_version} (this can take a while) ..." - if [ -f /config/www/nextcloud/config/needs_migration ] || [ -f /tmp/needs_upgrade ]; then + if [[ -f /config/www/nextcloud/config/needs_migration ]] || [[ -f /tmp/needs_upgrade ]]; then echo "Upgrading nextcloud from ${installed_version} ..." shippedApps=$(jq -r .shippedApps[] /app/www/src/core/shipped.json) for app in ${shippedApps}; do @@ -80,11 +80,11 @@ if [ -f /config/www/nextcloud/config/needs_migration ] || [ -f /tmp/needs_instal rsync -rlD --exclude-from=/app/upgrade.exclude /app/www/src/ /app/www/public/ for dir in apps config themes; do - if [ -f /config/www/nextcloud/config/needs_migration ] || [ -f /tmp/needs_upgrade ] || [ -z "$(ls -A /app/www/public/${dir} 2>/dev/null)" ]; then + if [[ -f /config/www/nextcloud/config/needs_migration ]] || [[ -f /tmp/needs_upgrade ]] || [[ -z "$(ls -A /app/www/public/${dir} 2>/dev/null)" ]]; then rsync -rlD --include "/${dir}" --exclude '/*' /app/www/src/ /config/www/nextcloud/ fi done - if [ -z "$(ls -A /data/ 2>/dev/null)" ]; then + if [[ -z "$(ls -A /data/ 2>/dev/null)" ]]; then rsync -rlD --include "/data" --exclude '/*' /app/www/src/ / fi @@ -94,11 +94,11 @@ if [ -f /config/www/nextcloud/config/needs_migration ] || [ -f /tmp/needs_instal /app/www/public \ /config/www/nextcloud - if [ -f /config/www/nextcloud/config/needs_migration ] || [ -f /tmp/needs_upgrade ]; then + if [[ -f /config/www/nextcloud/config/needs_migration ]] || [[ -f /tmp/needs_upgrade ]]; then # Upgrade occ upgrade else - if [ "${installed_version}" = "0.0.0.0" ]; then + if [[ "${installed_version}" = "0.0.0.0" ]]; then # Install echo "New nextcloud instance" echo "Please run the web-based installer on first connect!" @@ -148,14 +148,14 @@ for APP in richdocumentscode; do echo "Removing ${APP}" fi APP_PATH=$(occ app:getpath "${APP}" 2>/dev/null) - if [ -z "${APP_PATH}" ] || [ ! -d "${APP_PATH}" ]; then + if [[ -z "${APP_PATH}" ]] || [[ ! -d "${APP_PATH}" ]]; then APP_PATH="/app/www/public/apps/${APP}" fi - if [ -d "${APP_PATH}" ]; then + if [[ -d "${APP_PATH}" ]]; then occ app:disable "${APP}" >/dev/null 2>&1 fi APP_STATUS="$(occ config:app:get "${APP}" enabled 2>/dev/null)" - if [ "${APP_STATUS}" != "no" ] && [ -n "${APP_STATUS}" ]; then + if [[ "${APP_STATUS}" != "no" ]] && [[ -n "${APP_STATUS}" ]]; then occ config:app:set "${APP}" enabled --value="no" >/dev/null 2>&1 fi occ app:remove "${APP}" >/dev/null 2>&1 @@ -163,14 +163,14 @@ for APP in richdocumentscode; do done # set data directory -if [ ! -s /config/www/nextcloud/config/config.php ]; then +if [[ ! -s /config/www/nextcloud/config/config.php ]]; then echo -e " '/data',\n);" >/config/www/nextcloud/config/config.php -elif [ -f /config/www/nextcloud/config/config.php ]; then +elif [[ -f /config/www/nextcloud/config/config.php ]]; then sed -i "s|/app/www/public/data|/data|g" /config/www/nextcloud/config/config.php fi #modify javascript mime type and add .mjs support -if [ -s /etc/nginx/mime.types ]; then +if [[ -s /etc/nginx/mime.types ]]; then sed -i 's|\bjs;|js mjs;|g' /etc/nginx/mime.types sed -i 's|\bapplication/javascript|text/javascript|g' /etc/nginx/mime.types fi