diff --git a/.github/workflows/ci-codeql-analysis.yml b/.github/workflows/ci-codeql-analysis.yml deleted file mode 100644 index 2b51105652..0000000000 --- a/.github/workflows/ci-codeql-analysis.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - schedule: - - cron: '24 2 * * 4' - -permissions: - contents: read - security-events: write - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - language: [ 'csharp' ] - - steps: - - name: Checkout repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Setup .NET - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - with: - dotnet-version: '10.0.x' - - - name: Initialize CodeQL - uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 - with: - languages: ${{ matrix.language }} - queries: +security-extended - - - name: Autobuild - uses: github/codeql-action/autobuild@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 diff --git a/.github/workflows/ci-compat.yml b/.github/workflows/ci-compat.yml deleted file mode 100644 index bf28129368..0000000000 --- a/.github/workflows/ci-compat.yml +++ /dev/null @@ -1,159 +0,0 @@ -ο»Ώname: ABI Compatibility -on: - pull_request: - -permissions: {} - -jobs: - abi-head: - name: ABI - HEAD - runs-on: ubuntu-latest - permissions: read-all - steps: - - name: Checkout repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - - - name: Setup .NET - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - with: - dotnet-version: '10.0.x' - - - name: Build - run: | - dotnet build Jellyfin.Server -o ./out - - - name: Upload Head - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: abi-head - retention-days: 14 - if-no-files-found: error - path: out/ - - abi-base: - name: ABI - BASE - if: ${{ github.base_ref != '' }} - runs-on: ubuntu-latest - permissions: read-all - steps: - - name: Checkout repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - fetch-depth: 0 - - - name: Setup .NET - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - with: - dotnet-version: '10.0.x' - - - name: Checkout common ancestor - env: - HEAD_REF: ${{ github.head_ref }} - run: | - git remote add upstream https://github.com/${{ github.event.pull_request.base.repo.full_name }} - git -c protocol.version=2 fetch --prune --progress --no-recurse-submodules upstream +refs/heads/*:refs/remotes/upstream/* +refs/tags/*:refs/tags/* - ANCESTOR_REF=$(git merge-base upstream/${{ github.base_ref }} origin/$HEAD_REF) - git checkout --progress --force $ANCESTOR_REF - - - name: Build - run: | - dotnet build Jellyfin.Server -o ./out - - - name: Upload Head - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: abi-base - retention-days: 14 - if-no-files-found: error - path: out/ - - abi-diff: - permissions: - pull-requests: write # to create or update comment (peter-evans/create-or-update-comment) - - name: ABI - Difference - if: ${{ github.event_name == 'pull_request' }} - runs-on: ubuntu-latest - needs: - - abi-head - - abi-base - - steps: - - name: Download abi-head - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: abi-head - path: abi-head - - - name: Download abi-base - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: abi-base - path: abi-base - - - name: Setup ApiCompat - run: | - dotnet tool install --global Microsoft.DotNet.ApiCompat.Tool - - - name: Run ApiCompat - id: diff - run: | - { - echo 'body<> $GITHUB_OUTPUT - - - name: Find difference comment - uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0 - id: find-comment - with: - issue-number: ${{ github.event.pull_request.number }} - direction: last - body-includes: abi-diff-workflow-comment - - - name: Reply or edit difference comment (changed) - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0 - if: ${{ steps.diff.outputs.body != '' }} - with: - issue-number: ${{ github.event.pull_request.number }} - comment-id: ${{ steps.find-comment.outputs.comment-id }} - edit-mode: replace - token: ${{ secrets.JF_BOT_TOKEN }} - body: | - -
- ABI Difference - - ``` - ${{ steps.diff.outputs.body }} - ``` - -
- - - name: Reply or edit difference comment (unchanged) - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0 - if: ${{ steps.diff.outputs.body == '' && steps.find-comment.outputs.comment-id != '' }} - with: - issue-number: ${{ github.event.pull_request.number }} - comment-id: ${{ steps.find-comment.outputs.comment-id }} - edit-mode: replace - token: ${{ secrets.JF_BOT_TOKEN }} - body: | - -
- ABI Difference - - No changes to the ABI found. See history of this comment for previous changes. - -
diff --git a/.github/workflows/ci-format.yml b/.github/workflows/ci-format.yml deleted file mode 100644 index 73c8e7e50c..0000000000 --- a/.github/workflows/ci-format.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Format -on: - push: - branches: - - master - # Run formatter against the forked branch, but - # do not allow access to secrets - # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories - pull_request: - -env: - SDK_VERSION: "10.0.x" - -jobs: - format-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - with: - dotnet-version: ${{ env.SDK_VERSION }} - - - name: Run DotNet Format - run: dotnet format --verify-no-changes --verbosity minimal diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml deleted file mode 100644 index 7fc22ed001..0000000000 --- a/.github/workflows/ci-tests.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Tests -on: - push: - branches: - - master - # Run tests against the forked branch, but - # do not allow access to secrets - # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories - pull_request: - -env: - SDK_VERSION: "10.0.x" - -jobs: - run-tests: - strategy: - matrix: - os: ["ubuntu-latest", "macos-latest", "windows-latest"] - fail-fast: false - - runs-on: "${{ matrix.os }}" - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - with: - dotnet-version: ${{ env.SDK_VERSION }} - - - name: Run DotNet CLI Tests - run: > - dotnet test Jellyfin.sln - --configuration Release - --collect:"XPlat Code Coverage" - --settings tests/coverletArgs.runsettings - --verbosity minimal - - - name: Merge code coverage results - uses: danielpalme/ReportGenerator-GitHub-Action@d3ebf1f760f7d8ab92cc44d9bcfee7ad73722a31 # v5.5.11 - with: - reports: "**/coverage.cobertura.xml" - targetdir: "merged/" - reporttypes: "Cobertura" - - # TODO - which action / tool to use to publish code coverage results? - # - name: Publish code coverage results diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml deleted file mode 100644 index d14ce6d508..0000000000 --- a/.github/workflows/commands.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Commands -on: - issue_comment: - types: - - created - - edited - pull_request: - types: - - labeled - - synchronize - -permissions: {} -jobs: - rebase: - name: Rebase - if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '@jellyfin-bot rebase') && github.event.comment.author_association == 'MEMBER' - runs-on: ubuntu-latest - steps: - - name: Notify as seen - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0 - with: - token: ${{ secrets.JF_BOT_TOKEN }} - comment-id: ${{ github.event.comment.id }} - reactions: '+1' - - - name: Checkout the latest code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - token: ${{ secrets.JF_BOT_TOKEN }} - fetch-depth: 0 - - - name: Automatic Rebase - uses: cirrus-actions/rebase@b87d48154a87a85666003575337e27b8cd65f691 # 1.8 - env: - GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }} - - rename: - name: Rename - if: contains(github.event.comment.body, '@jellyfin-bot rename') - runs-on: ubuntu-latest - steps: - - name: pull in script - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - repository: jellyfin/jellyfin-triage-script - - - name: install python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: '3.14' - cache: 'pip' - - - name: install python packages - run: pip install -r rename/requirements.txt - - - name: run rename script - run: python3 rename.py - working-directory: ./rename - env: - GH_TOKEN: ${{ secrets.JF_BOT_TOKEN }} - GH_REPO: ${{ github.repository }} - ISSUE: ${{ github.event.issue.number }} - COMMENT_ID: ${{ github.event.comment.id }} diff --git a/.github/workflows/issue-stale.yml b/.github/workflows/issue-stale.yml deleted file mode 100644 index 2ad326e894..0000000000 --- a/.github/workflows/issue-stale.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Stale Issue Labeler - -on: - schedule: - - cron: '30 1 * * *' - workflow_dispatch: - -permissions: - issues: write - pull-requests: write - actions: write - -jobs: - issues: - name: Check for stale issues - runs-on: ubuntu-latest - if: ${{ contains(github.repository, 'jellyfin/') }} - steps: - - uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0 - with: - repo-token: ${{ secrets.JF_BOT_TOKEN }} - ascending: true - days-before-stale: 120 - days-before-pr-stale: -1 - days-before-close: 21 - days-before-pr-close: -1 - operations-per-run: 500 - exempt-issue-labels: regression,security,roadmap,future,feature,enhancement,confirmed - stale-issue-label: stale - stale-issue-message: |- - This issue has gone 120 days without an update and will be closed within 21 days if there is no new activity. To prevent this issue from being closed, please confirm the issue has not already been fixed by providing updated examples or logs. - - If you have any questions you can use one of several ways to [contact us](https://jellyfin.org/contact). - close-issue-message: |- - This issue was closed due to inactivity. diff --git a/.github/workflows/issue-template-check.yml b/.github/workflows/issue-template-check.yml deleted file mode 100644 index 3220bcbeac..0000000000 --- a/.github/workflows/issue-template-check.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Check Issue Template -on: - issues: - types: - - opened -jobs: - check_issue: - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - name: pull in script - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - repository: jellyfin/jellyfin-triage-script - - - name: install python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: '3.14' - cache: 'pip' - - - name: install python packages - run: pip install -r main-repo-triage/requirements.txt - - - name: check and comment issue - working-directory: ./main-repo-triage - run: python3 single_issue_gha.py - env: - GH_TOKEN: ${{ secrets.JF_BOT_TOKEN }} - GH_REPO: ${{ github.repository }} - ISSUE: ${{ github.event.issue.number }} diff --git a/.github/workflows/openapi-generate.yml b/.github/workflows/openapi-generate.yml deleted file mode 100644 index 48bd8adb03..0000000000 --- a/.github/workflows/openapi-generate.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: OpenAPI Generate - -on: - workflow_call: - inputs: - ref: - required: true - type: string - repository: - required: true - type: string - artifact: - required: true - type: string - -permissions: - contents: read - -jobs: - main: - name: Main - runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ inputs.ref }} - repository: ${{ inputs.repository }} - - - name: Configure .NET - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - with: - dotnet-version: '10.0.x' - - - name: Create File - run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter Jellyfin.Server.Integration.Tests.OpenApiSpecTests - - - name: Upload Artifact - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: ${{ inputs.artifact }} - path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net10.0/openapi.json - retention-days: 14 - if-no-files-found: error diff --git a/.github/workflows/openapi-merge.yml b/.github/workflows/openapi-merge.yml deleted file mode 100644 index 2421c09ad7..0000000000 --- a/.github/workflows/openapi-merge.yml +++ /dev/null @@ -1,140 +0,0 @@ -name: OpenAPI Publish -on: - push: - branches: - - master - tags: - - 'v*' - -jobs: - publish-openapi: - name: OpenAPI - Publish Artifact - uses: ./.github/workflows/openapi-generate.yml - permissions: - contents: read - with: - ref: ${{ github.sha }} - repository: ${{ github.repository }} - artifact: openapi-head - - publish-unstable: - name: OpenAPI - Publish Unstable Spec - if: ${{ github.event_name != 'pull_request' && !startsWith(github.ref, 'refs/tags/v') && contains(github.repository_owner, 'jellyfin') }} - runs-on: ubuntu-latest - needs: - - publish-openapi - steps: - - name: Set unstable dated version - id: version - run: |- - echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV - - name: Download openapi-head - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: openapi-head - path: openapi-head - - name: Upload openapi.json (unstable) to repository server - uses: appleboy/scp-action@ff85246acaad7bdce478db94a363cd2bf7c90345 # v1.0.0 - with: - host: "${{ secrets.REPO_HOST }}" - username: "${{ secrets.REPO_USER }}" - key: "${{ secrets.REPO_KEY }}" - source: openapi-head/openapi.json - strip_components: 1 - target: "/srv/incoming/openapi/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}" - - name: Move openapi.json (unstable) into place - uses: appleboy/ssh-action@0ff4204d59e8e51228ff73bce53f80d53301dee2 # v1.2.5 - with: - host: "${{ secrets.REPO_HOST }}" - username: "${{ secrets.REPO_USER }}" - key: "${{ secrets.REPO_KEY }}" - debug: false - script: | - if ! test -d /run/workflows; then - sudo mkdir -p /run/workflows - sudo chown ${{ secrets.REPO_USER }} /run/workflows - fi - ( - flock -x -w 300 200 || exit 1 - TGT_DIR="/srv/repository/main/openapi" - LAST_SPEC="$( ls -lt ${TGT_DIR}/unstable/ | grep 'jellyfin-openapi' | head -1 | awk '{ print $NF }' )" - # If new and previous spec don't differ (diff retcode 0), remove incoming and finish - if diff /srv/incoming/openapi/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}/openapi.json ${TGT_DIR}/unstable/${LAST_SPEC} &>/dev/null; then - rm -r /srv/incoming/openapi/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }} - exit 0 - fi - # Move new spec into place - sudo mv /srv/incoming/openapi/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}/openapi.json ${TGT_DIR}/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}.json - # Delete previous jellyfin-openapi-unstable_previous.json - sudo rm ${TGT_DIR}/jellyfin-openapi-unstable_previous.json - # Move current jellyfin-openapi-unstable.json symlink to jellyfin-openapi-unstable_previous.json - sudo mv ${TGT_DIR}/jellyfin-openapi-unstable.json ${TGT_DIR}/jellyfin-openapi-unstable_previous.json - # Create new jellyfin-openapi-unstable.json symlink - sudo ln -s unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}.json ${TGT_DIR}/jellyfin-openapi-unstable.json - # Check that the previous openapi unstable spec link is correct - if [[ "$( readlink ${TGT_DIR}/jellyfin-openapi-unstable_previous.json )" != "unstable/${LAST_SPEC}" ]]; then - sudo rm ${TGT_DIR}/jellyfin-openapi-unstable_previous.json - sudo ln -s unstable/${LAST_SPEC} ${TGT_DIR}/jellyfin-openapi-unstable_previous.json - fi - ) 200>/run/workflows/openapi-unstable.lock - - publish-stable: - name: OpenAPI - Publish Stable Spec - if: ${{ startsWith(github.ref, 'refs/tags/v') && contains(github.repository_owner, 'jellyfin') }} - runs-on: ubuntu-latest - needs: - - publish-openapi - steps: - - name: Set version number - id: version - run: |- - echo "JELLYFIN_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV - - name: Download openapi-head - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: openapi-head - path: openapi-head - - name: Upload openapi.json (stable) to repository server - uses: appleboy/scp-action@ff85246acaad7bdce478db94a363cd2bf7c90345 # v1.0.0 - with: - host: "${{ secrets.REPO_HOST }}" - username: "${{ secrets.REPO_USER }}" - key: "${{ secrets.REPO_KEY }}" - source: openapi-head/openapi.json - strip_components: 1 - target: "/srv/incoming/openapi/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}" - - name: Move openapi.json (stable) into place - uses: appleboy/ssh-action@0ff4204d59e8e51228ff73bce53f80d53301dee2 # v1.2.5 - with: - host: "${{ secrets.REPO_HOST }}" - username: "${{ secrets.REPO_USER }}" - key: "${{ secrets.REPO_KEY }}" - debug: false - script: | - if ! test -d /run/workflows; then - sudo mkdir -p /run/workflows - sudo chown ${{ secrets.REPO_USER }} /run/workflows - fi - ( - flock -x -w 300 200 || exit 1 - TGT_DIR="/srv/repository/main/openapi" - LAST_SPEC="$( ls -lt ${TGT_DIR}/stable/ | grep 'jellyfin-openapi' | head -1 | awk '{ print $NF }' )" - # If new and previous spec don't differ (diff retcode 0), remove incoming and finish - if diff /srv/incoming/openapi/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}/openapi.json ${TGT_DIR}/stable/${LAST_SPEC} &>/dev/null; then - rm -r /srv/incoming/openapi/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }} - exit 0 - fi - # Move new spec into place - sudo mv /srv/incoming/openapi/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}/openapi.json ${TGT_DIR}/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}.json - # Delete previous jellyfin-openapi-stable_previous.json - sudo rm ${TGT_DIR}/jellyfin-openapi-stable_previous.json - # Move current jellyfin-openapi-stable.json symlink to jellyfin-openapi-stable_previous.json - sudo mv ${TGT_DIR}/jellyfin-openapi-stable.json ${TGT_DIR}/jellyfin-openapi-stable_previous.json - # Create new jellyfin-openapi-stable.json symlink - sudo ln -s stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}.json ${TGT_DIR}/jellyfin-openapi-stable.json - # Check that the previous openapi stable spec link is correct - if [[ "$( readlink ${TGT_DIR}/jellyfin-openapi-stable_previous.json )" != "stable/${LAST_SPEC}" ]]; then - sudo rm ${TGT_DIR}/jellyfin-openapi-stable_previous.json - sudo ln -s stable/${LAST_SPEC} ${TGT_DIR}/jellyfin-openapi-stable_previous.json - fi - ) 200>/run/workflows/openapi-stable.lock diff --git a/.github/workflows/openapi-pull-request.yml b/.github/workflows/openapi-pull-request.yml deleted file mode 100644 index 9ed1873942..0000000000 --- a/.github/workflows/openapi-pull-request.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: OpenAPI Check -on: - pull_request: - -jobs: - ancestor: - name: Common Ancestor - runs-on: ubuntu-latest - outputs: - base_ref: ${{ steps.ancestor.outputs.base_ref }} - steps: - - name: Checkout Repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - fetch-depth: 0 - - name: Search History - id: ancestor - run: | - git remote add upstream https://github.com/${{ github.event.pull_request.base.repo.full_name }} - git fetch --prune --progress --no-recurse-submodules upstream +refs/heads/*:refs/remotes/upstream/* +refs/tags/*:refs/tags/* - - ANCESTOR_REF=$(git merge-base upstream/${{ github.base_ref }} HEAD) - - echo "ref: ${ANCESTOR_REF}" - - echo "base_ref=${ANCESTOR_REF}" >> "$GITHUB_OUTPUT" - - head: - name: Head Artifact - uses: ./.github/workflows/openapi-generate.yml - with: - ref: ${{ github.event.pull_request.head.sha }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - artifact: openapi-head - - base: - name: Base Artifact - uses: ./.github/workflows/openapi-generate.yml - needs: - - ancestor - with: - ref: ${{ needs.ancestor.outputs.base_ref }} - repository: ${{ github.event.pull_request.base.repo.full_name }} - artifact: openapi-base - - diff: - name: Generate Report - runs-on: ubuntu-latest - needs: - - head - - base - steps: - - name: Download Head - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: openapi-head - path: openapi-head - - name: Download Base - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: openapi-base - path: openapi-base - - name: Detect Changes - id: openapi-diff - run: | - sed -i 's:allOf:oneOf:g' openapi-head/openapi.json - sed -i 's:allOf:oneOf:g' openapi-base/openapi.json - - mkdir -p /tmp/openapi-report - mv openapi-head/openapi.json /tmp/openapi-report/head.json - mv openapi-base/openapi.json /tmp/openapi-report/base.json - - docker run -v /tmp/openapi-report:/data openapitools/openapi-diff:2.1.6 /data/base.json /data/head.json --state -l ERROR --markdown /data/openapi-report.md - - name: Upload Artifact - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: openapi-report - path: /tmp/openapi-report/openapi-report.md diff --git a/.github/workflows/openapi-workflow-run.yml b/.github/workflows/openapi-workflow-run.yml deleted file mode 100644 index 0f9e84e56b..0000000000 --- a/.github/workflows/openapi-workflow-run.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: OpenAPI Report - -on: - workflow_run: - workflows: - - OpenAPI Check - types: - - completed - -jobs: - metadata: - name: Generate Metadata - runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} - outputs: - pr_number: ${{ steps.pr_number.outputs.pr_number }} - steps: - - name: Get Pull Request Number - id: pr_number - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - HEAD_SHA: ${{ github.event.workflow_run.head_sha }} - run: | - API_RESPONSE=$(gh pr list --repo "${GITHUB_REPOSITORY}" --search "${HEAD_SHA}" --state open --json number) - PR_NUMBER=$(echo "${API_RESPONSE}" | jq '.[0].number') - - echo "repository: ${GITHUB_REPOSITORY}" - echo "sha: ${HEAD_SHA}" - echo "response: ${API_RESPONSE}" - echo "pr: ${PR_NUMBER}" - - echo "pr_number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}" - - comment: - name: Pull Request Comment - runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} - needs: - - metadata - permissions: - pull-requests: write - actions: read - contents: read - steps: - - name: Download OpenAPI Report - id: download_report - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: openapi-report - path: openapi-report - run-id: ${{ github.event.workflow_run.id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - name: Push Comment - uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1 - with: - github-token: ${{ secrets.JF_BOT_TOKEN }} - file-path: ${{ steps.download_report.outputs.download-path }}/openapi-report.md - pr-number: ${{ needs.metadata.outputs.pr_number }} - comment-tag: openapi-report diff --git a/.github/workflows/project-automation.yml b/.github/workflows/project-automation.yml deleted file mode 100644 index 9a9f3214a7..0000000000 --- a/.github/workflows/project-automation.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Project Automation - -on: - push: - branches: - - master - pull_request: - issue_comment: - -permissions: {} -jobs: - project: - name: Project board - runs-on: ubuntu-latest - if: ${{ github.repository == 'jellyfin/jellyfin' }} - steps: - - name: Remove from 'Current Release' project - uses: alex-page/github-project-automation-plus@303f24a24c67ce7adf565a07e96720faf126fe36 # v0.9.0 - if: (github.event.pull_request || github.event.issue.pull_request) && !contains(github.event.*.labels.*.name, 'stable backport') - continue-on-error: true - with: - project: Current Release - action: delete - column: In progress - repo-token: ${{ secrets.JF_BOT_TOKEN }} - - - name: Add to 'Release Next' project - uses: alex-page/github-project-automation-plus@303f24a24c67ce7adf565a07e96720faf126fe36 # v0.9.0 - if: (github.event.pull_request || github.event.issue.pull_request) && github.event.action == 'opened' - continue-on-error: true - with: - project: Release Next - column: In progress - repo-token: ${{ secrets.JF_BOT_TOKEN }} - - - name: Add to 'Current Release' project - uses: alex-page/github-project-automation-plus@303f24a24c67ce7adf565a07e96720faf126fe36 # v0.9.0 - if: (github.event.pull_request || github.event.issue.pull_request) && !contains(github.event.*.labels.*.name, 'stable backport') - continue-on-error: true - with: - project: Current Release - column: In progress - repo-token: ${{ secrets.JF_BOT_TOKEN }} - - - name: Check number of comments from the team member - if: github.event.issue.pull_request == '' && github.event.comment.author_association == 'MEMBER' - id: member_comments - run: echo "::set-output name=number::$(curl -s ${{ github.event.issue.comments_url }} | jq '.[] | select(.author_association == "MEMBER") | .author_association' | wc -l)" - - - name: Move issue to needs triage - uses: alex-page/github-project-automation-plus@303f24a24c67ce7adf565a07e96720faf126fe36 # v0.9.0 - if: github.event.issue.pull_request == '' && github.event.comment.author_association == 'MEMBER' && steps.member_comments.outputs.number <= 1 - continue-on-error: true - with: - project: Issue Triage for Main Repo - column: Needs triage - repo-token: ${{ secrets.JF_BOT_TOKEN }} - - - name: Add issue to triage project - uses: alex-page/github-project-automation-plus@303f24a24c67ce7adf565a07e96720faf126fe36 # v0.9.0 - if: github.event.issue.pull_request == '' && github.event.action == 'opened' - continue-on-error: true - with: - project: Issue Triage for Main Repo - column: Pending response - repo-token: ${{ secrets.JF_BOT_TOKEN }} diff --git a/.github/workflows/pull-request-conflict.yml b/.github/workflows/pull-request-conflict.yml deleted file mode 100644 index ce671eb72e..0000000000 --- a/.github/workflows/pull-request-conflict.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Merge Conflict Labeler - -on: - push: - branches: - - master - pull_request_target: - types: [synchronize] - -permissions: {} -jobs: - main: - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - if: ${{ github.repository == 'jellyfin/jellyfin' }} - steps: - - name: Apply label - uses: eps1lon/actions-label-merge-conflict@0273be72a0bbd58fcd71d0d6c02c209b50d1e5e1 # v3.1.0 - with: - dirtyLabel: 'merge conflict' - commentOnDirty: 'This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.' - repoToken: ${{ secrets.JF_BOT_TOKEN }} diff --git a/.github/workflows/pull-request-stale.yaml b/.github/workflows/pull-request-stale.yaml deleted file mode 100644 index 2f1a8c7dce..0000000000 --- a/.github/workflows/pull-request-stale.yaml +++ /dev/null @@ -1,30 +0,0 @@ -name: Stale PR Check - -on: - schedule: - - cron: '30 */12 * * *' - workflow_dispatch: - -permissions: - pull-requests: write - actions: write - -jobs: - prs-stale-conflicts: - name: Check PRs with merge conflicts - runs-on: ubuntu-latest - if: ${{ contains(github.repository, 'jellyfin/') }} - steps: - - uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0 - with: - repo-token: ${{ secrets.JF_BOT_TOKEN }} - ascending: true - operations-per-run: 150 - # The merge conflict action will remove the label when updated - remove-stale-when-updated: false - days-before-stale: -1 - days-before-close: 90 - days-before-issue-close: -1 - stale-pr-label: merge conflict - close-pr-message: |- - This PR has been closed due to having unresolved merge conflicts. diff --git a/.github/workflows/release-bump-version.yaml b/.github/workflows/release-bump-version.yaml deleted file mode 100644 index 4d6e1ad6fa..0000000000 --- a/.github/workflows/release-bump-version.yaml +++ /dev/null @@ -1,82 +0,0 @@ -name: 'πŸ†™ Auto bump_version' - -on: - release: - types: - - published - workflow_dispatch: - inputs: - TAG_BRANCH: - required: true - description: release-x.y.z - NEXT_VERSION: - required: true - description: x.y.z - -jobs: - auto_bump_version: - runs-on: ubuntu-latest - if: ${{ github.event_name == 'release' && !contains(github.event.release.tag_name, 'rc') }} - env: - TAG_BRANCH: ${{ github.event.release.target_commitish }} - steps: - - name: Wait for deploy checks to finish - uses: jitterbit/await-check-suites@292a541bb7618078395b2ce711a0d89cfb8a568a # v1 - with: - ref: ${{ env.TAG_BRANCH }} - intervalSeconds: 60 - timeoutSeconds: 3600 - - - name: Setup YQ - uses: chrisdickinson/setup-yq@fa3192edd79d6eb0e4e12de8dde3a0c26f2b853b # latest - with: - yq-version: v4.9.8 - - - name: Checkout Repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ env.TAG_BRANCH }} - - - name: Setup EnvVars - run: |- - CURRENT_VERSION=$(yq e '.version' build.yaml) - CURRENT_MAJOR_MINOR=${CURRENT_VERSION%.*} - CURRENT_PATCH=${CURRENT_VERSION##*.} - echo "CURRENT_VERSION=${CURRENT_VERSION}" >> $GITHUB_ENV - echo "CURRENT_MAJOR_MINOR=${CURRENT_MAJOR_MINOR}" >> $GITHUB_ENV - echo "CURRENT_PATCH=${CURRENT_PATCH}" >> $GITHUB_ENV - echo "NEXT_VERSION=${CURRENT_MAJOR_MINOR}.$(($CURRENT_PATCH + 1))" >> $GITHUB_ENV - - - name: Run bump_version - run: ./bump_version ${{ env.NEXT_VERSION }} - - - name: Commit Changes - run: |- - git config user.name "jellyfin-bot" - git config user.email "team@jellyfin.org" - git checkout ${{ env.TAG_BRANCH }} - git commit -am "Bump version to ${{ env.NEXT_VERSION }}" - git push origin ${{ env.TAG_BRANCH }} - - manual_bump_version: - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' }} - env: - TAG_BRANCH: ${{ github.event.inputs.TAG_BRANCH }} - NEXT_VERSION: ${{ github.event.inputs.NEXT_VERSION }} - steps: - - name: Checkout Repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ env.TAG_BRANCH }} - - - name: Run bump_version - run: ./bump_version ${{ env.NEXT_VERSION }} - - - name: Commit Changes - run: |- - git config user.name "jellyfin-bot" - git config user.email "team@jellyfin.org" - git checkout ${{ env.TAG_BRANCH }} - git commit -am "Bump version to ${{ env.NEXT_VERSION }}" - git push origin ${{ env.TAG_BRANCH }} diff --git a/.woodpecker/ci.yaml b/.woodpecker/ci.yaml new file mode 100644 index 0000000000..2883fb1049 --- /dev/null +++ b/.woodpecker/ci.yaml @@ -0,0 +1,26 @@ +when: + - event: pull_request + - event: push + +steps: + # Restore, build and test the full solution. global.json pins the .NET 10 + # SDK (10.0.0, rollForward latestMinor), so build on the 10.0 SDK image. + - name: build-test + image: mcr.microsoft.com/dotnet/sdk:10.0 + commands: + # libSkiaSharp in the SDK image needs fontconfig to load. + - apt-get update && apt-get install -y --no-install-recommends libfontconfig1 + - dotnet --info + - dotnet restore Jellyfin.sln + - dotnet build Jellyfin.sln -c Release --no-restore + - dotnet test Jellyfin.sln -c Release --no-build --verbosity minimal --filter "Category!=RequiresDocker&FullyQualifiedName!~Integration" + backend_options: + kubernetes: + serviceAccountName: jellyfin-ha-src + resources: + requests: + memory: 2Gi + cpu: 2 + limits: + memory: 6Gi + cpu: 4 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..1e4459735f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,96 @@ +# syntax=docker/dockerfile:1 + +# ── Build stage ────────────────────────────────────────────────────────────── +FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/sdk:10.0 AS build + +WORKDIR /src + +# Restore dependencies first (layer-cache friendly) +COPY ["Jellyfin.sln", "global.json", "nuget.config", "Directory.Build.props", "Directory.Packages.props", "./"] +COPY ["SharedVersion.cs", "BannedSymbols.txt", "stylecop.json", "./"] + +# Copy all project files so dotnet restore can resolve the full dependency graph +COPY Emby.Naming/ Emby.Naming/ +COPY Emby.Photos/ Emby.Photos/ +COPY Emby.Server.Implementations/ Emby.Server.Implementations/ +COPY Jellyfin.Api/ Jellyfin.Api/ +COPY Jellyfin.Data/ Jellyfin.Data/ +COPY Jellyfin.Server/ Jellyfin.Server/ +COPY Jellyfin.Server.Implementations/ Jellyfin.Server.Implementations/ +COPY MediaBrowser.Common/ MediaBrowser.Common/ +COPY MediaBrowser.Controller/ MediaBrowser.Controller/ +COPY MediaBrowser.LocalMetadata/ MediaBrowser.LocalMetadata/ +COPY MediaBrowser.MediaEncoding/ MediaBrowser.MediaEncoding/ +COPY MediaBrowser.Model/ MediaBrowser.Model/ +COPY MediaBrowser.Providers/ MediaBrowser.Providers/ +COPY MediaBrowser.XbmcMetadata/ MediaBrowser.XbmcMetadata/ +COPY src/ src/ + +RUN dotnet restore Jellyfin.Server/Jellyfin.Server.csproj \ + --runtime linux-x64 + +# Publish the server (and all transitive dependencies, including the +# PostgreSQL provider assembly added by this fork). +# Note: TreatWarningsAsErrors is disabled for the Docker build β€” StyleCop +# analyzer violations in upstream src/ projects would otherwise block the +# image build. StyleCop is enforced in the CI pipeline, not the Dockerfile. +RUN dotnet publish Jellyfin.Server/Jellyfin.Server.csproj \ + --configuration Release \ + --runtime linux-x64 \ + --self-contained false \ + --no-restore \ + -p:TreatWarningsAsErrors=false \ + --output /app + +# ── Web client stage ────────────────────────────────────────────────────────── +# Install jellyfin-web via the official Jellyfin apt repo. +# Package suffix in the bookworm repo is +deb12 (e.g. 12.0+deb12). +# Web assets land at /usr/share/jellyfin/web/ β€” stable, prebuilt, no npm required. +# The web client version must match the server version this fork is based on. +FROM --platform=linux/amd64 debian:bookworm-slim AS webclient + +RUN apt-get update \ + && apt-get install -y --no-install-recommends curl gnupg ca-certificates \ + && curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key \ + | gpg --dearmor -o /usr/share/keyrings/jellyfin.gpg \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/jellyfin.gpg] https://repo.jellyfin.org/debian bookworm main" \ + > /etc/apt/sources.list.d/jellyfin.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends "jellyfin-web=12.0+deb12" \ + && rm -rf /var/lib/apt/lists/* \ + && echo "Web client files:" && ls /usr/share/jellyfin/web/ | head -10 + +# ── Runtime stage ───────────────────────────────────────────────────────────── +FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:10.0 + +# Install FFmpeg and native dependencies required by SkiaSharp and fontconfig. +# libicu, libssl, and liblttng-ust are already present in the dotnet/aspnet base image. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ffmpeg \ + fontconfig \ + libfontconfig1 \ + libfreetype6 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /jellyfin + +COPY --from=build /app . +COPY --from=webclient /usr/share/jellyfin/web ./jellyfin-web/ + +# Jellyfin default ports +EXPOSE 8096 +EXPOSE 8920 + +# Data / config volumes +VOLUME ["/config", "/cache", "/media"] + +ENV JELLYFIN_DATA_DIR=/config \ + JELLYFIN_CACHE_DIR=/cache \ + JELLYFIN_LOG_DIR=/config/log \ + JELLYFIN_CONFIG_DIR=/config + +ENTRYPOINT ["./jellyfin", \ + "--datadir", "/config", \ + "--cachedir", "/cache", \ + "--webdir", "/jellyfin/jellyfin-web"] diff --git a/Dockerfile.runtime b/Dockerfile.runtime new file mode 100644 index 0000000000..36f4a2b00b --- /dev/null +++ b/Dockerfile.runtime @@ -0,0 +1,55 @@ +# syntax=docker/dockerfile:1 +# Runtime-only image β€” the .NET publish step runs on the CI host (runner), +# not inside this Dockerfile. + +# ── Web client stage ────────────────────────────────────────────────────────── +# Install jellyfin-web via the official Jellyfin apt repo. +# Package suffix in the bookworm repo is +deb12 (e.g. 12.0+deb12). +# Web assets land at /usr/share/jellyfin/web/ β€” stable, prebuilt, no npm required. +# The web client version must match the server version this fork is based on. +FROM --platform=linux/amd64 debian:bookworm-slim AS webclient + +RUN apt-get update \ + && apt-get install -y --no-install-recommends curl gnupg ca-certificates \ + && curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key \ + | gpg --dearmor -o /usr/share/keyrings/jellyfin.gpg \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/jellyfin.gpg] https://repo.jellyfin.org/debian bookworm main" \ + > /etc/apt/sources.list.d/jellyfin.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends "jellyfin-web=12.0+deb12" \ + && rm -rf /var/lib/apt/lists/* + +# ── Runtime stage ───────────────────────────────────────────────────────────── +FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:10.0 + +# Install FFmpeg and native dependencies required by SkiaSharp and fontconfig. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ffmpeg \ + fontconfig \ + libfontconfig1 \ + libfreetype6 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /jellyfin + +# Copy the pre-built publish output produced by `dotnet publish` on the CI host. +COPY publish-output/ . +# Copy the jellyfin-web client assets from the webclient stage. +COPY --from=webclient /usr/share/jellyfin/web ./jellyfin-web/ + +# Jellyfin default ports +EXPOSE 8096 +EXPOSE 8920 + +# Data / config volumes +VOLUME ["/config", "/cache", "/media"] + +ENV JELLYFIN_DATA_DIR=/config \ + JELLYFIN_CACHE_DIR=/cache \ + JELLYFIN_LOG_DIR=/config/log + +ENTRYPOINT ["./jellyfin", \ + "--datadir", "/config", \ + "--cachedir", "/cache", \ + "--webdir", "/jellyfin/jellyfin-web"]