From 82e4c338ee5b6f9f151b5c3d02db009345736348 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Sat, 19 Sep 2026 23:43:50 +1000 Subject: [PATCH] publish the plugin zip to artifactapi on tag Add .woodpecker/release.yaml building the JPRM zip and uploading it to the jellyfin-plugins repo, and teach the bump targets the plugin's 4-part version. --- .woodpecker/release.yaml | 74 ++++++++++++++++++++++++++++++++++++++++ Makefile | 46 +++++++++++++++++-------- 2 files changed, 105 insertions(+), 15 deletions(-) create mode 100644 .woodpecker/release.yaml diff --git a/.woodpecker/release.yaml b/.woodpecker/release.yaml new file mode 100644 index 0000000..c0be2bd --- /dev/null +++ b/.woodpecker/release.yaml @@ -0,0 +1,74 @@ +when: + - event: tag + ref: refs/tags/v* + +steps: + # Everything runs on almalinux9-base: JPRM installs from the artifactapi pypi + # remote and the publish below PUTs to artifactapi, both over https against + # the internal CA. The Microsoft SDK image does not trust that CA (curl 60), + # so the dotnet build has to come to the image that does rather than the + # other way round. + - name: package + image: git.unkin.net/unkin/almalinux9-base:20260606 + environment: + DOTNET_CLI_TELEMETRY_OPTOUT: "1" + DOTNET_NOLOGO: "1" + commands: + - | + set -eu + VERSION=$$(sed -n 's/^version: *"\([0-9.]*\)".*/\1/p' build.yaml | head -1) + if [ "v$$VERSION" != "$$CI_COMMIT_TAG" ]; then + echo "tag $$CI_COMMIT_TAG does not match build.yaml version $$VERSION; use make patch/minor/major/hotfix" + exit 1 + fi + dnf -y -q install dotnet-sdk-10.0 python3-pip zip + pip3 install --quiet --index-url https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/pypi/simple "jprm==1.1.0" + mkdir -p dist + jprm plugin build . --output ./dist --version "$$VERSION" --dotnet-configuration Release --dotnet-framework net10.0 + ls -l dist + backend_options: + kubernetes: + serviceAccountName: jellyfin-plugin-sso + resources: + requests: + memory: 2Gi + cpu: 1 + limits: + memory: 4Gi + cpu: 2 + + # Uploads are immutable (409 on overwrite) and artifactapi has no HEAD route, + # so probe with GET and treat an existing object as a no-op re-run. + - name: publish + image: git.unkin.net/unkin/almalinux9-base:20260606 + commands: + - | + set -eu + HOST="https://artifactapi.k8s.syd1.au.unkin.net" + REPO="jellyfin-plugins" + ZIP=$$(ls dist/sso-authentication_*.zip | head -1) + VERSION=$$(echo "$$CI_COMMIT_TAG" | sed 's/^v//') + PATH_IN_REPO="unkin/jellyfin-plugin-sso/$$VERSION/$$(basename "$$ZIP")" + code=$$(curl -s -o /dev/null -w '%{http_code}' "$$HOST/api/v2/remotes/$$REPO/files/$$PATH_IN_REPO" || true) + if [ "$$code" = "200" ]; then + echo "$$PATH_IN_REPO already published (HTTP $$code); skipping upload" + exit 0 + fi + echo "Uploading $$ZIP to $$REPO/$$PATH_IN_REPO (existence probe returned $$code)" + curl -f -X PUT \ + "$$HOST/api/v2/remotes/$$REPO/files/$$PATH_IN_REPO" \ + -H "Content-Type: application/zip" \ + --data-binary @"$$ZIP" + echo + sha256sum "$$ZIP" + depends_on: [package] + backend_options: + kubernetes: + serviceAccountName: jellyfin-plugin-sso + resources: + requests: + memory: 256Mi + cpu: 250m + limits: + memory: 1Gi + cpu: 1 diff --git a/Makefile b/Makefile index 62d0bd9..e979f0f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build test lint clean patch minor major +.PHONY: build test lint clean patch minor major hotfix SLN ?= SSO-Auth.sln @@ -16,20 +16,36 @@ clean: dotnet clean $(SLN) -c Release || true rm -rf SSO-Auth/bin SSO-Auth/obj tests/SSO-Auth.Tests/bin tests/SSO-Auth.Tests/obj -_LATEST := $(shell git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$$' | head -1) -_BASE := $(if $(_LATEST),$(_LATEST),v0.0.0) -_MAJ := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f1) -_MIN := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f2) -_PAT := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f3) +# Jellyfin plugin versions are 4-part (System.Version in the plugin manifest), +# so build.yaml holds the version and the release tag must be exactly +# v; .woodpecker/release.yaml fails the build if they diverge. +_CUR := $(shell sed -n 's/^version: *"\([0-9.]*\)".*/\1/p' build.yaml | head -1) +_A := $(or $(word 1,$(subst ., ,$(_CUR))),0) +_B := $(or $(word 2,$(subst ., ,$(_CUR))),0) +_C := $(or $(word 3,$(subst ., ,$(_CUR))),0) +_D := $(or $(word 4,$(subst ., ,$(_CUR))),0) -patch: - @NEW=v$(_MAJ).$(_MIN).$(shell expr $(_PAT) + 1); \ - git tag $$NEW && echo "Tagged $$NEW" && git push origin $$NEW - -minor: - @NEW=v$(_MAJ).$(shell expr $(_MIN) + 1).0; \ - git tag $$NEW && echo "Tagged $$NEW" && git push origin $$NEW +define release + @test -n "$(_CUR)" || { echo "cannot parse version from build.yaml"; exit 1; } + @test -z "$$(git status --porcelain)" || { echo "working tree is dirty"; exit 1; } + @sed -i 's|^version: .*|version: "$(1)"|' build.yaml + @sed -i 's|[^<]*|$(1)|' SSO-Auth/SSO-Auth.csproj + @sed -i 's|[^<]*|$(1)|' SSO-Auth/SSO-Auth.csproj + @git commit -qam "release $(1)" + @git tag v$(1) + @git push origin HEAD v$(1) + @echo "Released v$(1)" +endef major: - @NEW=v$(shell expr $(_MAJ) + 1).0.0; \ - git tag $$NEW && echo "Tagged $$NEW" && git push origin $$NEW + $(call release,$(shell expr $(_A) + 1).0.0.0) + +minor: + $(call release,$(_A).$(shell expr $(_B) + 1).0.0) + +patch: + $(call release,$(_A).$(_B).$(shell expr $(_C) + 1).0) + +# Fourth component: a rebuild of an existing patch (upstream's 3.5.2.1 shape). +hotfix: + $(call release,$(_A).$(_B).$(_C).$(shell expr $(_D) + 1))