Files
jellyfin-packaging/.github/workflows/release-build.yaml
T
Joshua M. Boniface 726f9b0760 Add reprepro version obsolescence
We've moved reprepro to a version that supports keeping multiple
versions for the purpose of facilitating downgrades if people need it.
However the logic of the multiple versions functionality there does not
permit the granular rules we want. This implements them manually.

1. For Unstable builds, we only want to keep a max of 4 in the repo
(matching what we keep in the web archive). Since reprepro doesn't
support granularity of Limit at the component level, implement logic to
remove all but the most recent 4 unstables if there end up being more
than 4 after importing the new version.

2. For Stable builds, we want to keep the last point release of a given
major release (e.g. keep 10.10.13 but obsolete 10.10.12), while also
keeping older major versions (e.g. 10.9.10). Again the logic in reprepro
is too simplistic to handle this, so we implement it manually. For any
version that comes in, if the point version is above 0, we remove any
packages with a version that's one point release behind that one within
the same major version, while preserving everything else.
2025-03-30 16:47:14 -04:00

777 lines
35 KiB
YAML

name: "Release Build"
on:
schedule:
# Weekly unstable trigger on Monday at 05:00 GMT
- cron: '0 5 * * 1'
workflow_dispatch:
# Manual trigger from bot
inputs:
version:
required: true
type: string
description: 'The server and web stable release tag ("vX.Y.Z") or "master"'
permissions:
contents: read
jobs:
Docker:
runs-on: ubuntu-24.04
continue-on-error: false # true in prod, false for testing
steps:
- name: "Set dated version for unstable builds"
id: version
run: |-
if grep --silent --extended-regexp '^v[0-9]+' <<< "${{ inputs.version || 'master' }}"; then
echo "JELLYFIN_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=stable" >> $GITHUB_ENV
else
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H')" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=unstable" >> $GITHUB_ENV
fi
- name: "Install dependencies"
run: |-
sudo apt-get update
sudo apt-get install --yes python3-git python3-yaml
- name: "Checkout repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Prepare repository"
run: |-
./checkout.py ${{ inputs.version || 'master' }}
- name: "Run builder for Docker containers"
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }}
GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }}
run: |-
sudo --preserve-env ./build.py ${{ env.JELLYFIN_VERSION }} docker
Debian:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
release:
- bullseye
- bookworm
arch:
- amd64
- arm64
- armhf
continue-on-error: false # true in prod, false for testing
steps:
- name: "Set dated version for unstable builds"
id: version
run: |-
if grep --silent --extended-regexp '^v[0-9]+' <<< "${{ inputs.version || 'master' }}"; then
echo "JELLYFIN_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=stable" >> $GITHUB_ENV
else
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H')" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=unstable" >> $GITHUB_ENV
fi
- name: "Install dependencies"
run: |-
sudo apt-get update
sudo apt-get install --yes python3-git python3-yaml debsigs devscripts
- name: "Checkout repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Prepare repository"
run: |-
./checkout.py ${{ inputs.version || 'master' }}
- name: "Run builder for ${{ matrix.version }} ${{ matrix.arch }}"
run: |-
sudo --preserve-env ./build.py ${{ env.JELLYFIN_VERSION }} debian ${{ matrix.arch }} ${{ matrix.release }}
sudo chown --recursive $USER out/debian
- name: "Import repository signing GPG key"
run: |
echo -n "${{ secrets.DEBIAN_SIGNING_KEY }}" | base64 --decode | gpg --batch --yes --import
- name: "Sign Debian package and source files"
run: |
for file in out/debian/*.deb; do
debsigs --sign=origin --default-key=${{ secrets.DEBIAN_SIGNING_KEY_ID }} ${file}
done
debsign -k ${{ secrets.DEBIAN_SIGNING_KEY_ID }} out/debian/*.changes
- name: "Remove repository signing GPG key"
run: |
gpg --batch --yes --delete-secret-keys ${{ secrets.DEBIAN_SIGNING_KEY_ID }}
- name: "Upload artifacts to repository server"
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
source: "out/debian/*"
strip_components: 2
target: "/srv/incoming/server/${{ env.JELLYFIN_VERSION }}/debian/${{ matrix.release }}/${{ matrix.arch }}"
- name: "Import artifacts into reprepro"
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
debug: false
script_stop: false
script: |
set -o xtrace
if [[ ${{ env.JELLYFIN_RELEASE_TYPE }} == "stable" ]]; then
COMPONENT="main"
else
COMPONENT="unstable"
fi
# Only include the architecture-dependent deb here, as the others are done only for amd64
sudo reprepro --waitforlock 30 --basedir /srv/debian --component ${COMPONENT} includedeb ${{ matrix.release }} /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/debian/${{ matrix.release }}/${{ matrix.arch }}/*_${{ matrix.arch }}.deb || exit 1
if [[ ${{ matrix.arch }} == "amd64" ]]; then
# Only include the architecture-independent packages for amd64; the other architectures are the same and conflict
sudo reprepro --waitforlock 30 --basedir /srv/debian --component ${COMPONENT} includedeb ${{ matrix.release }} /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/debian/${{ matrix.release }}/${{ matrix.arch }}/*_all.deb || exit 1
# Only include the source DSC for amd64; the other architectures are the same and conflict
sudo reprepro --waitforlock 30 --basedir /srv/debian --component ${COMPONENT} includedsc ${{ matrix.release }} /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/debian/${{ matrix.release }}/${{ matrix.arch }}/*.dsc || exit 1
fi
# Only keep ${NKEEP} (4) unstables; we have to do this manually since reprepro doesn't have granularity for this at the component level
if [[ ${COMPONENT} == "unstable" ]]; then
NKEEP=4
# Get whatever the oldest version is; since these are dated, a simple numerical sort works
LIST="$( sudo reprepro -b /srv/debian -C unstable list ${{ matrix.release }} | awk '{ print $NF }' | sort -rn | uniq )"
COUNT=$( wc -l <<<"${LIST}" )
if [[ ${COUNT} -gt ${NKEEP} ]]; then
# Get anything that isn't in the latest ${NKEEP} entries
OBSOLETE=( sed "1,${NKEEP}d" <<<"${LIST}" )
for VERSION in ${OBSOLETE[@]}; do
for PACKAGE in jellyfin jellyfin-server jellyfin-web; do
sudo reprepro --waitforlock 30 --basedir /srv/debian --component ${COMPONENT} remove ${{ matrix.release }} ${PACKAGE}=${VERSION}
done
done
fi
fi
# Only keep the latest point release for a given stable version; i.e. 10.10.14 obsoletes 10.10.13 and removes it, while leaving 10.9.10
if [[ ${COMPONENT} == "stable" ]]; then
NEW_VERSION=${{ matrix.release }}
NEW_MAJOR_VERSION="${NEW_VERSION#v}"
NEW_MAJOR_VERSION="${NEW_MAJOR_VERSION%.*}"
NEW_POINT_VERSION="${NEW_VERSION##*.}"
if [[ ${NEW_POINT_VERSION} -gt 0 ]]; then
LAST_POINT_VERSION=$(( NEW_POINT_VERSION - 1 ))
LAST_VERSION="${NEW_MAJOR_VERSION}.${LAST_POINT_VERSION}"
for PACKAGE in jellyfin jellyfin-server jellyfin-web; do
sudo reprepro --waitforlock 30 --basedir /srv/debian --component ${COMPONENT} remove ${{ matrix.release }} ${PACKAGE}=${LAST_VERSION}
done
fi
fi
- name: "Move artifacts into repository"
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
debug: false
script_stop: false
script: |
export BASEDIR="/srv/repository/main/server/debian"
sudo mkdir -p ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }} || exit 1
sudo mv -t ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }}/ /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/debian/${{ matrix.release }}/${{ matrix.arch }}/* || exit 1
sudo rm ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || exit 1
if [[ ${{ env.JELLYFIN_RELEASE_TYPE }} == "stable" ]]; then
sudo rm ${BASEDIR}/latest || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest || exit 1
fi
Ubuntu:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
release:
- focal
- jammy
- noble
arch:
- amd64
- arm64
- armhf
continue-on-error: false # true in prod, false for testing
steps:
- name: "Set dated version for unstable builds"
id: version
run: |-
if grep --silent --extended-regexp '^v[0-9]+' <<< "${{ inputs.version || 'master' }}"; then
echo "JELLYFIN_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=stable" >> $GITHUB_ENV
else
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H')" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=unstable" >> $GITHUB_ENV
fi
- name: "Install dependencies"
run: |-
sudo apt-get update
sudo apt-get install --yes python3-git python3-yaml debsigs devscripts
- name: "Checkout repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Prepare repository"
run: |-
./checkout.py ${{ inputs.version || 'master' }}
- name: "Run builder for ${{ matrix.version }} ${{ matrix.arch }}"
run: |-
sudo --preserve-env ./build.py ${{ env.JELLYFIN_VERSION }} ubuntu ${{ matrix.arch }} ${{ matrix.release }}
sudo chown --recursive $USER out/ubuntu
- name: "Import repository signing GPG key"
run: |
echo -n "${{ secrets.DEBIAN_SIGNING_KEY }}" | base64 --decode | gpg --batch --yes --import
- name: "Sign Ubuntu package and source files"
run: |
for file in out/ubuntu/*.deb; do
debsigs --sign=origin --default-key=${{ secrets.DEBIAN_SIGNING_KEY_ID }} ${file}
done
debsign -k ${{ secrets.DEBIAN_SIGNING_KEY_ID }} out/ubuntu/*.changes
- name: "Remove repository signing GPG key"
run: |
gpg --batch --yes --delete-secret-keys ${{ secrets.DEBIAN_SIGNING_KEY_ID }}
- name: "Upload artifacts to repository server"
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
source: "out/ubuntu/*"
strip_components: 2
target: "/srv/incoming/server/${{ env.JELLYFIN_VERSION }}/ubuntu/${{ matrix.release }}/${{ matrix.arch }}"
- name: "Import artifacts into reprepro"
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
debug: false
script_stop: false
script: |
set -o xtrace
if [[ ${{ env.JELLYFIN_RELEASE_TYPE }} == "stable" ]]; then
COMPONENT="main"
else
COMPONENT="unstable"
fi
# Only include the architecture-dependent deb here, as the others are done only for amd64
sudo reprepro --waitforlock 30 --basedir /srv/ubuntu --component ${COMPONENT} includedeb ${{ matrix.release }} /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/ubuntu/${{ matrix.release }}/${{ matrix.arch }}/*_${{ matrix.arch }}.deb || exit 1
if [[ ${{ matrix.arch }} == "amd64" ]]; then
# Only include the architecture-independent packages for amd64; the other architectures are the same and conflict
sudo reprepro --waitforlock 30 --basedir /srv/ubuntu --component ${COMPONENT} includedeb ${{ matrix.release }} /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/ubuntu/${{ matrix.release }}/${{ matrix.arch }}/*_all.deb || exit 1
# Only include the source DSC for amd64; the other architectures are the same and conflict
sudo reprepro --waitforlock 30 --basedir /srv/ubuntu --component ${COMPONENT} includedsc ${{ matrix.release }} /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/ubuntu/${{ matrix.release }}/${{ matrix.arch }}/*.dsc || exit 1
fi
# Only keep ${NKEEP} (4) unstables; we have to do this manually since reprepro doesn't have granularity for this at the component level
if [[ ${COMPONENT} == "unstable" ]]; then
NKEEP=4
# Get whatever the oldest version is; since these are dated, a simple numerical sort works
LIST="$( sudo reprepro -b /srv/ubuntu -C unstable list ${{ matrix.release }} | awk '{ print $NF }' | sort -rn | uniq )"
COUNT=$( wc -l <<<"${LIST}" )
if [[ ${COUNT} -gt ${NKEEP} ]]; then
# Get anything that isn't in the latest ${NKEEP} entries
OBSOLETE=( sed "1,${NKEEP}d" <<<"${LIST}" )
for VERSION in ${OBSOLETE[@]}; do
for PACKAGE in jellyfin jellyfin-server jellyfin-web; do
sudo reprepro --waitforlock 30 --basedir /srv/ubuntu --component ${COMPONENT} remove ${{ matrix.release }} ${PACKAGE}=${VERSION}
done
done
fi
fi
# Only keep the latest point release for a given stable version; i.e. 10.10.14 obsoletes 10.10.13 and removes it, while leaving 10.9.10
if [[ ${COMPONENT} == "stable" ]]; then
NEW_VERSION=${{ matrix.release }}
NEW_MAJOR_VERSION="${NEW_VERSION#v}"
NEW_MAJOR_VERSION="${NEW_MAJOR_VERSION%.*}"
NEW_POINT_VERSION="${NEW_VERSION##*.}"
if [[ ${NEW_POINT_VERSION} -gt 0 ]]; then
LAST_POINT_VERSION=$(( NEW_POINT_VERSION - 1 ))
LAST_VERSION="${NEW_MAJOR_VERSION}.${LAST_POINT_VERSION}"
for PACKAGE in jellyfin jellyfin-server jellyfin-web; do
sudo reprepro --waitforlock 30 --basedir /srv/ubuntu --component ${COMPONENT} remove ${{ matrix.release }} ${PACKAGE}=${LAST_VERSION}
done
fi
fi
- name: "Move artifacts into repository"
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
debug: false
script_stop: false
script: |
export BASEDIR="/srv/repository/main/server/ubuntu"
sudo mkdir -p ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }} || exit 1
sudo mv -t ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }}/ /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/ubuntu/${{ matrix.release }}/${{ matrix.arch }}/* || exit 1
sudo rm ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || exit 1
if [[ ${{ env.JELLYFIN_RELEASE_TYPE }} == "stable" ]]; then
sudo rm ${BASEDIR}/latest || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest || exit 1
fi
Linux:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
arch:
- amd64
- amd64-musl
- arm64
- arm64-musl
- armhf
continue-on-error: false # true in prod, false for testing
steps:
- name: "Set dated version for unstable builds"
id: version
run: |-
if grep --silent --extended-regexp '^v[0-9]+' <<< "${{ inputs.version || 'master' }}"; then
echo "JELLYFIN_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=stable" >> $GITHUB_ENV
else
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H')" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=unstable" >> $GITHUB_ENV
fi
- name: "Install dependencies"
run: |-
sudo apt-get update
sudo apt-get install --yes python3-git python3-yaml
- name: "Checkout repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Prepare repository"
run: |-
./checkout.py ${{ inputs.version || 'master' }}
- name: "Run builder for ${{ matrix.arch }}"
run: |-
sudo --preserve-env ./build.py ${{ env.JELLYFIN_VERSION }} linux ${{ matrix.arch }}
- name: "Upload artifacts to repository server"
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
source: "out/linux/*"
strip_components: 2
target: "/srv/incoming/server/${{ env.JELLYFIN_VERSION }}/linux/${{ matrix.arch }}"
- name: "Move artifacts into repository"
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
debug: false
script_stop: true
script: |
export BASEDIR="/srv/repository/main/server/linux"
sudo mkdir -p ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }} || exit 1
sudo mv -t ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }}/ /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/linux/${{ matrix.release }}/${{ matrix.arch }}/* || exit 1
sudo rm ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || exit 1
if [[ ${{ env.JELLYFIN_RELEASE_TYPE }} == "stable" ]]; then
sudo rm ${BASEDIR}/latest || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest || exit 1
fi
Windows:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
arch:
- amd64
- arm64
outputs:
JELLYFIN_VERSION: ${{ steps.version.outputs.JELLYFIN_VERSION }}
JELLYFIN_RELEASE_TYPE: ${{ steps.version.outputs.JELLYFIN_RELEASE_TYPE }}
continue-on-error: false # true in prod, false for testing
steps:
- name: "Set dated version for unstable builds"
id: version
run: |-
if grep --silent --extended-regexp '^v[0-9]+' <<< "${{ inputs.version || 'master' }}"; then
echo "JELLYFIN_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
echo "JELLYFIN_VERSION=${{ inputs.version }}" >> $GITHUB_OUTPUT
echo "JELLYFIN_RELEASE_TYPE=stable" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=stable" >> $GITHUB_OUTPUT
else
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H')" >> $GITHUB_ENV
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H')" >> $GITHUB_OUTPUT
echo "JELLYFIN_RELEASE_TYPE=unstable" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=unstable" >> $GITHUB_OUTPUT
fi
- name: "Install dependencies"
run: |-
sudo apt-get update
sudo apt-get install --yes python3-git python3-yaml
- name: "Checkout repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Prepare repository"
run: |-
./checkout.py ${{ inputs.version || 'master' }}
- name: "Run builder for ${{ matrix.arch }}"
run: |-
sudo --preserve-env ./build.py ${{ env.JELLYFIN_VERSION }} windows ${{ matrix.arch }}
- name: "Upload artifacts to repository server"
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
source: "out/windows/*"
strip_components: 2
target: "/srv/incoming/server/${{ env.JELLYFIN_VERSION }}/windows/${{ matrix.arch }}"
- name: "Move artifacts into repository"
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
debug: false
script_stop: true
script: |
export BASEDIR="/srv/repository/main/server/windows"
sudo mkdir -p ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }} || exit 1
sudo mv -t ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }}/ /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/windows/${{ matrix.release }}/${{ matrix.arch }}/* || exit 1
sudo rm ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || exit 1
if [[ ${{ env.JELLYFIN_RELEASE_TYPE }} == "stable" ]]; then
sudo rm ${BASEDIR}/latest || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest || exit 1
fi
- name: "Store artifacts for next stage"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: windows-artifacts
retention-days: 1
if-no-files-found: ignore # Ignore for arm64 build, as no file will be found
path: out/windows/jellyfin_*-amd64.zip
WindowsInstaller:
needs:
- Windows
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
arch:
- amd64
continue-on-error: false # true in prod, false for testing
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
steps:
- name: "Set dated version for unstable builds"
id: version
shell: pwsh
run: |
$version = "${{ needs.Windows.outputs.JELLYFIN_VERSION }}"
if ($version -match "^v[0-9]+") {
$cleanVersion = $version.Substring(1)
} else {
$cleanVersion = $version
}
echo "JELLYFIN_VERSION=$cleanVersion" | Out-File -FilePath $env:GITHUB_ENV -Append
- name: "Checkout repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Install dependencies"
run: |-
python -m pip install --upgrade gitpython
- name: "Prepare repository"
run: |-
python checkout.py ${{ inputs.version || 'master' }}
- name: "Fetch artifacts from previous stage"
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
name: windows-artifacts
path: ./jellyfin-server-windows
- name: "Clone UX repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
repository: jellyfin/jellyfin-ux
path: .\jellyfin-server-windows\jellyfin-ux
- name: "Extract Jellyfin server archive"
working-directory: ./jellyfin-server-windows
run: |
New-Item -ItemType Directory -Path jellyfin
Expand-Archive -Path 'jellyfin_*-amd64.zip' -DestinationPath jellyfin -Force
Copy-Item ".\Support Files\LICENSE" -Destination $(Resolve-Path .\jellyfin\jellyfin)
- name: "Add NSSM"
working-directory: ./jellyfin-server-windows
run: |
Invoke-WebRequest 'https://repo.jellyfin.org/files/other/nssm.zip' -OutFile 'nssm.zip'
Expand-Archive 'nssm.zip'
Copy-Item ".\nssm\nssm.exe" -Destination $(Resolve-Path .\jellyfin\jellyfin)
- name: "Publish tray"
working-directory: ./jellyfin-server-windows
run: |
New-Item -Path .\jellyfin\jellyfin\jellyfin-windows-tray -ItemType Directory
dotnet publish -c Release -r win-x64 -f net472 --no-self-contained --output $(Resolve-Path .\jellyfin\jellyfin\jellyfin-windows-tray)
- name: "Build installer"
working-directory: ./jellyfin-server-windows
run: |
$env:InstallLocation = $(Resolve-Path .\jellyfin\jellyfin)
makensis /Dx64 /DUXPATH=$(Resolve-Path .\jellyfin-ux) $(Join-Path -Path $(Resolve-Path .\nsis) -ChildPath jellyfin.nsi)
- name: "Rename installer"
working-directory: ./jellyfin-server-windows/nsis
run: |
Rename-Item -Path .\jellyfin_*_windows-x64.exe -NewName ("jellyfin_${{ env.JELLYFIN_VERSION }}_windows-x64.exe")
- name: "Store artifacts for next stage"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: windows-installer-artifacts
retention-days: 1
if-no-files-found: error
path: ./jellyfin-server-windows/nsis/jellyfin_${{ env.JELLYFIN_VERSION }}_windows-x64.exe
WindowsInstallerUpload:
needs:
- Windows
- WindowsInstaller
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
arch:
- amd64
continue-on-error: false # true in prod, false for testing
steps:
- name: "Set version from previous job"
id: version
run: |-
echo "JELLYFIN_VERSION=${{ needs.Windows.outputs.JELLYFIN_VERSION }}" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=${{ needs.Windows.outputs.JELLYFIN_RELEASE_TYPE }}" >> $GITHUB_ENV
- name: "Fetch artifact from previous stage"
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
name: windows-installer-artifacts
- name: "Upload artifacts to repository server"
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
source: "jellyfin_${{ env.JELLYFIN_VERSION }}_windows-x64.exe"
target: "/srv/incoming/server/${{ env.JELLYFIN_VERSION }}/windows/${{ matrix.arch }}"
- name: "Move artifacts into repository"
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
debug: false
script_stop: true
script: |
export BASEDIR="/srv/repository/main/server/windows"
sudo mv -t ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }}/ /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/windows/${{ matrix.arch }}/jellyfin_${{ env.JELLYFIN_VERSION }}_windows-x64.exe || exit 1
MacOS:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
arch:
- amd64
- arm64
continue-on-error: false # true in prod, false for testing
steps:
- name: "Set dated version for unstable builds"
id: version
run: |-
if grep --silent --extended-regexp '^v[0-9]+' <<< "${{ inputs.version || 'master' }}"; then
echo "JELLYFIN_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=stable" >> $GITHUB_ENV
else
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H')" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=unstable" >> $GITHUB_ENV
fi
- name: "Install dependencies"
run: |-
sudo apt-get update
sudo apt-get install --yes python3-git python3-yaml
- name: "Checkout repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Prepare repository"
run: |-
./checkout.py ${{ inputs.version || 'master' }}
- name: "Run builder for ${{ matrix.version }} ${{ matrix.arch }}"
run: |-
sudo --preserve-env ./build.py ${{ env.JELLYFIN_VERSION }} macos ${{ matrix.arch }}
- name: "Upload artifacts to repository server"
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
source: "out/macos/*"
strip_components: 2
target: "/srv/incoming/server/${{ env.JELLYFIN_VERSION }}/macos/${{ matrix.arch }}"
- name: "Move artifacts into repository"
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
debug: false
script_stop: true
script: |
export BASEDIR="/srv/repository/main/server/macos"
sudo mkdir -p ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }} || exit 1
sudo mv -t ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/${{ matrix.arch }}/ /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/macos/${{ matrix.release }}/${{ matrix.arch }}/* || exit 1
sudo rm ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || exit 1
if [[ ${{ env.JELLYFIN_RELEASE_TYPE }} == "stable" ]]; then
sudo rm ${BASEDIR}/latest || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest || exit 1
fi
Portable:
runs-on: ubuntu-24.04
continue-on-error: false # true in prod, false for testing
steps:
- name: "Set dated version for unstable builds"
id: version
run: |-
if grep --silent --extended-regexp '^v[0-9]+' <<< "${{ inputs.version || 'master' }}"; then
echo "JELLYFIN_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=stable" >> $GITHUB_ENV
else
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H')" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=unstable" >> $GITHUB_ENV
fi
- name: "Install dependencies"
run: |-
sudo apt-get update
sudo apt-get install --yes python3-git python3-yaml
- name: "Checkout repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Prepare repository"
run: |-
./checkout.py ${{ inputs.version || 'master' }}
- name: "Run builder for Portable"
run: |-
sudo --preserve-env ./build.py ${{ env.JELLYFIN_VERSION }} portable
- name: "Upload artifacts to repository server"
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
source: "out/portable/*"
strip_components: 2
target: "/srv/incoming/server/${{ env.JELLYFIN_VERSION }}/portable"
- name: "Move artifacts into repository"
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
key: "${{ secrets.REPO_KEY }}"
debug: false
script_stop: true
script: |
export BASEDIR="/srv/repository/main/server/portable"
sudo mkdir -p ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/any || exit 1
sudo mv -t ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }}/any/ /srv/incoming/server/${{ env.JELLYFIN_VERSION }}/portable/${{ matrix.release }}/* || exit 1
sudo rm ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest-${{ env.JELLYFIN_RELEASE_TYPE }} || exit 1
if [[ ${{ env.JELLYFIN_RELEASE_TYPE }} == "stable" ]]; then
sudo rm ${BASEDIR}/latest || true
sudo ln -sf ${BASEDIR}/${{ env.JELLYFIN_RELEASE_TYPE }}/${{ env.JELLYFIN_VERSION }} ${BASEDIR}/latest || exit 1
fi
Nuget:
runs-on: ubuntu-24.04
steps:
- name: "Set dated version for unstable builds"
id: version
run: |-
if grep --silent --extended-regexp '^v[0-9]+' <<< "${{ inputs.version || 'master' }}"; then
echo "JELLYFIN_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=stable" >> $GITHUB_ENV
else
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H')" >> $GITHUB_ENV
echo "JELLYFIN_RELEASE_TYPE=unstable" >> $GITHUB_ENV
fi
- name: "Install dependencies"
run: |-
sudo apt-get update
sudo apt-get install --yes python3-git python3-yaml
- name: "Checkout repository"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Prepare repository"
run: |-
./checkout.py ${{ inputs.version || 'master' }}
- name: "Run builder for Nuget"
env:
NUGET_STABLE_KEY: ${{ secrets.NUGET_STABLE_KEY }}
NUGET_UNSTABLE_KEY: ${{ secrets.NUGET_UNSTABLE_KEY }}
run: |-
sudo --preserve-env ./build.py ${{ env.JELLYFIN_VERSION }} nuget