The builder image is now multi-arch (linux/amd64 + linux/arm64, pushed as srfplay-builder:latest after building all three plugin zips in each variant), so jobs no longer need an amd64 host. runs-on moves from linux/amd64 to ubuntu-latest, which draco-x86, freebox and oracle-a1 all carry, so a job no longer waits behind long jobs on draco while the ARM runners sit idle. .gitea/runner/cloud-init.yaml sets up such a runner on an Oracle Cloud Always Free Ampere VM (Ubuntu 24.04): Docker, act_runner registered instance-wide with the instance's label set, and a weekly image prune. The registration token and the optional console password hash are placeholders here and must be filled in locally before use. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
185 lines
8.0 KiB
YAML
185 lines
8.0 KiB
YAML
name: 'Nightly Build'
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- master
|
|
paths-ignore:
|
|
- '**/*.md'
|
|
- 'manifest.json'
|
|
- 'manifest-nightly.json'
|
|
|
|
jobs:
|
|
nightly-build:
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: gitea.tourolle.paris/dtourolle/srfplay-builder:latest
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
path: build-${{ github.run_id }}
|
|
|
|
- name: Compute nightly version
|
|
id: version
|
|
run: |
|
|
# Date-based nightly version: 1.0.<YYYYMMDD>.<run_number>
|
|
# The run_number suffix keeps multiple builds on the same day
|
|
# monotonically increasing so Jellyfin always offers the newest.
|
|
# Each Jellyfin generation gets its own build, so the last segment
|
|
# is <run_number><2-digit flavour code>, e.g. run 204 -> 20409/20411/20412
|
|
# (see .gitea/scripts/build-plugins.sh).
|
|
DATE=$(date -u +"%Y%m%d")
|
|
VERSION="1.0.${DATE}.${{ github.run_number }}"
|
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
|
echo "format=${VERSION}%02d" >> $GITHUB_OUTPUT
|
|
echo "Nightly version: ${VERSION}"
|
|
|
|
- name: Restore dependencies
|
|
working-directory: build-${{ github.run_id }}
|
|
run: dotnet restore Jellyfin.Plugin.SRFPlay.sln
|
|
|
|
- name: Build solution
|
|
working-directory: build-${{ github.run_id }}
|
|
run: dotnet build Jellyfin.Plugin.SRFPlay.sln --configuration Release --no-restore --no-self-contained /m:1
|
|
|
|
- name: Run tests
|
|
working-directory: build-${{ github.run_id }}
|
|
run: dotnet test Jellyfin.Plugin.SRFPlay.sln --no-build --configuration Release --verbosity normal
|
|
|
|
- name: Build Jellyfin Plugins
|
|
working-directory: build-${{ github.run_id }}
|
|
run: .gitea/scripts/build-plugins.sh "${{ steps.version.outputs.format }}"
|
|
|
|
- name: Delete existing nightly release
|
|
working-directory: build-${{ github.run_id }}
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
REPO_OWNER="${{ github.repository_owner }}"
|
|
REPO_NAME="${{ github.event.repository.name }}"
|
|
GITEA_URL="${{ github.server_url }}"
|
|
TAG="latest"
|
|
|
|
EXISTING=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/releases/tags/${TAG}")
|
|
|
|
if [ "$EXISTING" = "200" ]; then
|
|
RELEASE_ID=$(curl -s \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/releases/tags/${TAG}" | jq -r '.id')
|
|
|
|
echo "Deleting existing nightly release (ID: ${RELEASE_ID})..."
|
|
curl -s -X DELETE \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/releases/${RELEASE_ID}"
|
|
fi
|
|
|
|
curl -s -X DELETE \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/tags/${TAG}" || true
|
|
|
|
- name: Create nightly release
|
|
working-directory: build-${{ github.run_id }}
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
REPO_OWNER="${{ github.repository_owner }}"
|
|
REPO_NAME="${{ github.event.repository.name }}"
|
|
GITEA_URL="${{ github.server_url }}"
|
|
VERSION="${{ steps.version.outputs.version }}"
|
|
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
|
|
|
|
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/releases" \
|
|
-d "$(jq -n --arg tag "latest" --arg name "Nightly Build ${VERSION}" --arg body "SRFPlay Jellyfin Plugin nightly build ${VERSION} from master (${SHORT_SHA})." '{tag_name: $tag, name: $name, body: $body, target_commitish: "master", draft: false, prerelease: true}')")
|
|
|
|
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
|
BODY=$(echo "$RESPONSE" | sed '$d')
|
|
|
|
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
|
RELEASE_ID=$(echo "$BODY" | jq -r '.id')
|
|
echo "Created release with ID: ${RELEASE_ID}"
|
|
else
|
|
echo "Failed to create release. HTTP ${HTTP_CODE}"
|
|
echo "$BODY"
|
|
exit 1
|
|
fi
|
|
|
|
# Upload one plugin zip per Jellyfin generation
|
|
cut -f3 artifacts/builds.tsv | while read -r ZIP; do
|
|
echo "Uploading ${ZIP}..."
|
|
curl -f -X POST \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/zip" \
|
|
--data-binary "@${ZIP}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/releases/${RELEASE_ID}/assets?name=$(basename "${ZIP}")"
|
|
done
|
|
|
|
# Upload build.yaml
|
|
echo "Uploading build.yaml..."
|
|
curl -f -X POST \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/x-yaml" \
|
|
--data-binary "@build.yaml" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/releases/${RELEASE_ID}/assets?name=build.yaml"
|
|
|
|
echo "Nightly release updated successfully!"
|
|
|
|
- name: Update manifest-nightly.json
|
|
working-directory: build-${{ github.run_id }}
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
REPO_OWNER="${{ github.repository_owner }}"
|
|
REPO_NAME="${{ github.event.repository.name }}"
|
|
GITEA_URL="${{ github.server_url }}"
|
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
|
|
# builds.tsv is read before the checkout below replaces the tree.
|
|
BUILDS=$(cat artifacts/builds.tsv)
|
|
|
|
git config user.name "Gitea Actions"
|
|
git config user.email "actions@gitea.tourolle.paris"
|
|
git fetch origin master
|
|
# -B against origin/master, not a bare `checkout master`. The bare
|
|
# form switches to the LOCAL master that actions/checkout left at the
|
|
# run's own SHA, so if master moved while the build ran -- and this is
|
|
# a nightly, so it usually has -- the manifest is edited on a stale
|
|
# base and the push is rejected non-fast-forward. Run 1045 failed
|
|
# exactly this way, having already printed "Your branch is behind
|
|
# 'origin/master' by 1 commit" one line before committing anyway.
|
|
#
|
|
# Resetting is right rather than merely convenient: this step appends
|
|
# one entry to the manifest as it stands on master, so the base it
|
|
# edits must be master, not whatever this build started from.
|
|
git checkout -B master origin/master
|
|
|
|
# One entry per Jellyfin generation; each server installs the newest
|
|
# entry whose targetAbi it satisfies.
|
|
NEW_VERSIONS=$(echo "${BUILDS}" | jq -R -s \
|
|
--arg url "${GITEA_URL}/${REPO_OWNER}/${REPO_NAME}/releases/download/latest" \
|
|
--arg sha "${SHORT_SHA}" --arg ts "${TIMESTAMP}" \
|
|
'split("\n") | map(select(length > 0) | split("\t")
|
|
| {version: .[0], changelog: "Nightly build \(.[0]) (\($sha))", targetAbi: .[1],
|
|
sourceUrl: "\($url)/\(.[2] | split("/") | last)", checksum: .[3], timestamp: $ts})
|
|
| reverse')
|
|
|
|
# Prepend the new builds and keep only the most recent 5 nightlies
|
|
# (3 entries each, one per Jellyfin generation).
|
|
jq --argjson newvers "${NEW_VERSIONS}" \
|
|
'.[0].versions = ($newvers + .[0].versions)[0:15]' \
|
|
manifest-nightly.json > manifest.tmp && mv manifest.tmp manifest-nightly.json
|
|
|
|
git add manifest-nightly.json
|
|
git commit -m "Nightly: ${{ steps.version.outputs.version }} (${SHORT_SHA})" || echo "No changes to commit"
|
|
git push origin master
|
|
|
|
- name: Cleanup
|
|
if: always()
|
|
run: rm -rf build-${{ github.run_id }}
|