From 2b216d3d752951988ce05b02bde74c35d1d043c1 Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Mon, 7 Sep 2026 05:06:25 -0700 Subject: [PATCH] ci: add tag-triggered release packaging workflow Adds .gitea/workflows/release.yml, triggered only on a pushed v* tag, which builds all three platforms (reusing the exact same configure/build/test commands as build.yml, now factored out into .gitea/scripts/ so the two workflows can't drift), zips each platform's build/package/ output, and creates a draft Gitea Release with the archives attached. This is packaging automation only -- it does not resolve or bypass the C1 WebRTC/OpenH264 release gate documented in README.md's Status section. Nothing publishes until a human deliberately pushes a version tag (which should not happen before owner sign-off) and then explicitly publishes the resulting draft. The generated release notes lead with a restatement of the open C1 question specifically so that second step can't be taken by accident. build.yml is refactored (not rewritten) to call the same shared scripts; its job/step behavior is otherwise unchanged. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE --- .gitea/scripts/linux-build.sh | 17 +++ .gitea/scripts/linux-deps.sh | 7 ++ .gitea/scripts/macos-build.sh | 40 ++++++ .gitea/scripts/macos-deps.sh | 5 + .gitea/scripts/publish-release.sh | 155 +++++++++++++++++++++++ .gitea/scripts/windows-build.ps1 | 38 ++++++ .gitea/workflows/build.yml | 126 +++---------------- .gitea/workflows/release.yml | 196 ++++++++++++++++++++++++++++++ README.md | 22 +++- 9 files changed, 493 insertions(+), 113 deletions(-) create mode 100755 .gitea/scripts/linux-build.sh create mode 100755 .gitea/scripts/linux-deps.sh create mode 100755 .gitea/scripts/macos-build.sh create mode 100755 .gitea/scripts/macos-deps.sh create mode 100755 .gitea/scripts/publish-release.sh create mode 100644 .gitea/scripts/windows-build.ps1 create mode 100644 .gitea/workflows/release.yml diff --git a/.gitea/scripts/linux-build.sh b/.gitea/scripts/linux-build.sh new file mode 100755 index 0000000..116145d --- /dev/null +++ b/.gitea/scripts/linux-build.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml -- +# this is the actual Linux configure/build/test/verify sequence. Edit once, +# here, so both workflows stay in sync instead of drifting copies. +# +# Linux keeps its distribution libobs; the buildspec bootstrap (macOS/Windows) +# is for the two platforms that have no such package. +set -euo pipefail + +cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSTPLUGIN_BOOTSTRAP_OBS=OFF +cmake --build build +ctest --test-dir build --output-on-failure + +# Show what was built +ls -la build/package/bin/64bit build/package/data/locale build/package/licenses +ldd build/package/bin/64bit/streamer-tools-camera.so | grep -E 'obs|livekit' +nm -D build/package/bin/64bit/streamer-tools-camera.so | grep -E ' T obs_module_(load|unload)' diff --git a/.gitea/scripts/linux-deps.sh b/.gitea/scripts/linux-deps.sh new file mode 100755 index 0000000..26da8ae --- /dev/null +++ b/.gitea/scripts/linux-deps.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml -- +# both need the exact same Linux build dependencies. Edit once, here. +set -euo pipefail + +sudo apt-get update -qq +sudo apt-get install -y -qq cmake ninja-build libobs-dev libcurl4-openssl-dev diff --git a/.gitea/scripts/macos-build.sh b/.gitea/scripts/macos-build.sh new file mode 100755 index 0000000..0b30c19 --- /dev/null +++ b/.gitea/scripts/macos-build.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml -- +# this is the actual macOS configure/build/test/verify sequence. Edit once, +# here, so both workflows stay in sync instead of drifting copies. +# +# The buildspec bootstrap runs here: it fetches obs-deps + the pinned +# obs-studio source and builds libobs before this project configures. +# +# If that fails, fall back to a core-library-only build rather than going +# red: the core library and its tests are what this job mainly guards, and +# the fallback is loud (a workflow warning, plus the check below reporting no +# module) rather than silent. Do not remove the warning -- a green job that +# quietly stopped building the plugin is worse than a red one. +set -euo pipefail + +if ! cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release; then + echo "::warning::OBS SDK bootstrap failed on macOS; building the core library only. The plugin module was NOT built." + rm -rf build + cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSTPLUGIN_BOOTSTRAP_OBS=OFF +fi + +cmake --build build +ctest --test-dir build --output-on-failure + +# Show what was built. +# +# This is not purely informational: the macOS bootstrap has been reliably +# building the real module in CI (6/6 tests, artifact uploaded -- see +# README), so a missing module here is a regression to fail loudly on, not +# the old silent fallback. (This is separate from the macOS packaging gap in +# README -- that the module doesn't yet load as an OBS.app bundle -- which +# this check does not and cannot test.) +ls -la .deps/Frameworks/libobs.framework/Resources/cmake || true +if [ ! -f build/package/bin/streamer-tools-camera.so ]; then + echo "::error::no plugin module was built -- build/package/bin/streamer-tools-camera.so is missing. The macOS from-source libobs bootstrap is expected to succeed; treat this as a build failure, not a core-library-only fallback." + exit 1 +fi +ls -la build/package/bin +otool -L build/package/bin/streamer-tools-camera.so +otool -L build/package/bin/streamer-tools-camera.so | grep -E 'obs|livekit' diff --git a/.gitea/scripts/macos-deps.sh b/.gitea/scripts/macos-deps.sh new file mode 100755 index 0000000..ba19c44 --- /dev/null +++ b/.gitea/scripts/macos-deps.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml. +set -euo pipefail + +brew install cmake ninja diff --git a/.gitea/scripts/publish-release.sh b/.gitea/scripts/publish-release.sh new file mode 100755 index 0000000..2fa1bd4 --- /dev/null +++ b/.gitea/scripts/publish-release.sh @@ -0,0 +1,155 @@ +#!/usr/bin/env bash +# Creates a (draft) Gitea Release for the tag that triggered +# .gitea/workflows/release.yml, and uploads every archive in $DIST_DIR as a +# release asset. +# +# RELEASE GATE: see the README's `## Status` section and +# third_party/livekit/README.md. The WebRTC/OpenH264 attribution question +# ("C1") is unresolved -- this script does not decide that question, it just +# makes sure the generated release notes put the reminder where whoever +# publishes the draft will actually read it. Pushing a version tag is the +# human decision this whole workflow hangs off of; this script does not add +# or remove any judgment about whether that decision was the right one. +# +# Required env: GITEA_TOKEN, SERVER, OWNER, REPO, TAG, SHA, DIST_DIR +# Optional env: MACOS_BUNDLE_FOUND ("true"/"false", default "false") +set -euo pipefail + +: "${GITEA_TOKEN:?}" +: "${SERVER:?}" +: "${OWNER:?}" +: "${REPO:?}" +: "${TAG:?}" +: "${SHA:?}" +: "${DIST_DIR:?}" +MACOS_BUNDLE_FOUND="${MACOS_BUNDLE_FOUND:-false}" + +if [ "${MACOS_BUNDLE_FOUND}" = "true" ]; then + MACOS_NOTE="This archive contains a \`.plugin\` bundle." +else + MACOS_NOTE="This archive is packaged as a bare \`streamer-tools-camera.so\` (the layout \`build/package/\` currently produces on macOS), **not** an OBS.app-loadable \`.plugin\` bundle. It will not load in the OBS GUI as-is." +fi + +NOTES_FILE="$(mktemp)" +cat > "${NOTES_FILE}" < **This build has not been cleared for redistribution.** The plugin +> statically/dynamically pulls in Google WebRTC and OpenH264 code through the +> LiveKit SDK, and whether that can be redistributed as a public download -- +> the "C1" attribution/patent question -- has not been resolved. See the +> \`## Status\` section of \`README.md\` and \`third_party/livekit/README.md\` +> for the specifics. By publishing this release, you are personally taking on +> that open question -- if C1 hasn't been signed off on, don't publish it. +> +> (The separate GPLv2/Apache-2.0 license-compatibility question, "C2", is +> resolved: this project's own first-party code is Apache-2.0, matching the +> vendored LiveKit binaries.) +> +> This release was created as a **draft**. It stays invisible to anyone +> without write access to this repo until someone with write access opens it +> here and clicks Publish -- a second, deliberate step past pushing the tag. + +# streamer-tools Camera Plugin -- ${TAG} + +Built from commit \`${SHA}\`. + +**Nobody has yet run this plugin in the OBS GUI, on any platform.** See "What +is verified, and how" in \`README.md\` for exactly what has and has not been +checked, including which claims are backed by automated tests versus a human +watching OBS. + +| Platform | Archive | Notes | +|---|---|---| +| Linux (x64) | \`streamer-tools-camera-${TAG}-linux-x64.zip\` | Functionally complete and verified end to end against a real LiveKit server and a real libobs (see README); OBS GUI itself still unverified | +| Windows (x64) | \`streamer-tools-camera-${TAG}-windows-x64.zip\` | Built and tested by this workflow's Windows job; the WinHTTP backend has never been exercised against a real streamer-tools server, only a loopback test server -- see README's Windows CI section | +| macOS | \`streamer-tools-camera-${TAG}-macos.zip\` | Built and tested by this workflow's macOS job. ${MACOS_NOTE} See the "macOS packaging gap" in README | + +## Installing + +### Linux + +\`\`\` +mkdir -p ~/.config/obs-studio/plugins/streamer-tools-camera +unzip streamer-tools-camera-${TAG}-linux-x64.zip -d /tmp/stplugin-camera +cp -r /tmp/stplugin-camera/bin /tmp/stplugin-camera/data \\ + ~/.config/obs-studio/plugins/streamer-tools-camera/ +\`\`\` + +Start OBS, then Sources -> \`+\` -> "streamer-tools Camera" -> fill in the +server URL, room slug and read key from the room's settings page -> +"Refresh camera list" -> pick a camera. This is the same drop-in layout +README's "Testing this by hand" documents for a source build, adapted for a +downloaded zip -- known-good on Linux. + +### Windows (installation path not yet verified in real OBS) + +Per \`AddExtraModulePaths()\` in obs-studio's \`UI/window-basic-main.cpp\`, OBS +on Windows searches a plugins directory for \`bin\\64bit\\.dll\` plus a +sibling \`data\\\`. Unzip the archive and copy its \`bin\\\` and \`data\\\` into +your OBS plugins directory (typically +\`%APPDATA%\\obs-studio\\plugins\\streamer-tools-camera\\\`), matching the +Linux layout above. This has not been confirmed against a real OBS install on +Windows -- report back if you try it. + +### macOS (installation path not yet verified in real OBS; packaging gap) + +OBS on macOS loads plugins as \`.plugin\` bundles under +\`~/Library/Application Support/obs-studio/plugins/\`. As of this release, +this project's \`build/package/\` output on macOS is **not yet that bundle +shape** -- see the "macOS packaging gap" section of \`README.md\`. Treat the +macOS archive here as a build-verification artifact, not a working +drop-in, until that gap is closed. + +## What this is + +Native OBS Studio source plugin that pulls streamer-tools camera feeds +directly from LiveKit over WebRTC. See \`README.md\` in the repository for +the full design, what is and is not verified, and current CI status. +EOF + +echo "----- release notes -----" +cat "${NOTES_FILE}" +echo "--------------------------" + +BODY_JSON="$(python3 - "$TAG" "$NOTES_FILE" <<'PYEOF' +import json, sys +tag, notes_file = sys.argv[1], sys.argv[2] +with open(notes_file) as f: + notes = f.read() +print(json.dumps({ + "tag_name": tag, + "name": tag, + "body": notes, + "draft": True, + "prerelease": False, +})) +PYEOF +)" + +echo "Creating release for tag ${TAG} ..." +RESP="$(curl -sS -f -X POST \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "${BODY_JSON}" \ + "${SERVER}/api/v1/repos/${OWNER}/${REPO}/releases")" + +RELEASE_ID="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' <<<"${RESP}")" +echo "Created release id ${RELEASE_ID} (draft)." + +shopt -s nullglob +ASSETS=("${DIST_DIR}"/*) +if [ "${#ASSETS[@]}" -eq 0 ]; then + echo "::error::no archives found in ${DIST_DIR} -- nothing to upload." + exit 1 +fi + +for f in "${ASSETS[@]}"; do + name="$(basename "${f}")" + echo "Uploading ${name} ..." + curl -sS -f -X POST \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -F "attachment=@${f}" \ + "${SERVER}/api/v1/repos/${OWNER}/${REPO}/releases/${RELEASE_ID}/assets?name=${name}" \ + > /dev/null +done + +echo "Done. Draft release: ${SERVER}/${OWNER}/${REPO}/releases/${RELEASE_ID}" diff --git a/.gitea/scripts/windows-build.ps1 b/.gitea/scripts/windows-build.ps1 new file mode 100644 index 0000000..b746695 --- /dev/null +++ b/.gitea/scripts/windows-build.ps1 @@ -0,0 +1,38 @@ +# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml -- +# this is the actual Windows configure/build/test/verify sequence. Edit once, +# here, so both workflows stay in sync instead of drifting copies. +# +# The default Visual Studio generator is required, not Ninja: +# cmake/windows/buildspec.cmake keys the dependency slice off +# CMAKE_VS_PLATFORM_NAME, which only a VS generator sets. +# +# Same fallback as macOS, and the same warning: a green job that quietly +# stopped building the plugin is worse than a red one. PowerShell, not bash: +# self-hosted Windows runners here cannot be assumed to have a working bash +# (WSL as local system is refused). + +cmake -S . -B build -A x64 +if ($LASTEXITCODE -ne 0) { + Write-Host "::warning::OBS SDK bootstrap failed on Windows; building the core library only. The plugin module was NOT built." + Remove-Item -Recurse -Force build -ErrorAction SilentlyContinue + cmake -S . -B build -A x64 -DSTPLUGIN_BOOTSTRAP_OBS=OFF + if ($LASTEXITCODE -ne 0) { exit 1 } +} + +cmake --build build --config Release + +ctest --test-dir build -C Release --output-on-failure + +# Show what was built. +# +# This is not purely informational: the from-source libobs bootstrap is +# expected to work reliably on this runner (that is the whole point of the +# buildspec bootstrap + find_package fix), so a missing module here is a +# regression to fail loudly on, not the old silent fallback. +$module = "build\package\bin\64bit\streamer-tools-camera.dll" +if (Test-Path $module) { + Get-ChildItem build\package\bin\64bit +} else { + Write-Host "::error::no plugin module was built -- $module is missing. The Windows from-source libobs bootstrap is expected to succeed; treat this as a build failure, not a core-library-only fallback." + exit 1 +} diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index d07c346..6794994 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -10,6 +10,11 @@ name: Build # downloads the pinned obs-deps bundle and obs-studio source and builds just # `libobs`. That step is the slow one: several minutes on a cold runner. # +# The actual per-platform dependency-install and configure/build/test/verify +# commands live in .gitea/scripts/ and are shared with +# .gitea/workflows/release.yml, so the two workflows can't drift apart -- +# edit the scripts, not either workflow, to change how a platform builds. +# # RELEASE GATE: this workflow only builds, tests, and uploads CI-internal # workflow artifacts (actions/upload-artifact, below) -- it does not create a # Gitea Release, push a tag-triggered publish, or otherwise distribute @@ -19,6 +24,10 @@ name: Build # (The separate GPLv2/Apache-2.0 license-compatibility question is resolved: # this project's own code is Apache-2.0.) If a real release/publish step is # ever added here, it must carry that same gate. +# +# (.gitea/workflows/release.yml is that publish step, gated on a pushed +# version tag rather than on every push -- see the gate reminder baked into +# its generated release notes.) on: push: @@ -38,26 +47,10 @@ jobs: uses: actions/checkout@v4 - name: Install build dependencies - run: | - sudo apt-get update -qq - sudo apt-get install -y -qq cmake ninja-build libobs-dev libcurl4-openssl-dev + run: .gitea/scripts/linux-deps.sh - - name: Configure - # Linux keeps its distribution libobs; the buildspec bootstrap is for - # the two platforms that have no such package. - run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSTPLUGIN_BOOTSTRAP_OBS=OFF - - - name: Build - run: cmake --build build - - - name: Test (core library) - run: ctest --test-dir build --output-on-failure - - - name: Show what was built - run: | - ls -la build/package/bin/64bit build/package/data/locale build/package/licenses - ldd build/package/bin/64bit/streamer-tools-camera.so | grep -E 'obs|livekit' - nm -D build/package/bin/64bit/streamer-tools-camera.so | grep -E ' T obs_module_(load|unload)' + - name: Configure, build, test, verify + run: .gitea/scripts/linux-build.sh - name: Upload plugin continue-on-error: true @@ -74,51 +67,10 @@ jobs: uses: actions/checkout@v4 - name: Install build dependencies - run: brew install cmake ninja + run: .gitea/scripts/macos-deps.sh - - name: Configure - # The buildspec bootstrap runs here: it fetches obs-deps + the pinned - # obs-studio source and builds libobs before this project configures. - # - # If that fails, fall back to a core-library-only build rather than - # going red: the core library and its tests are what this job mainly - # guards, and the fallback is loud (a workflow warning, plus the - # "Show what was built" step below reporting no module) rather than - # silent. Do not remove the warning -- a green job that quietly stopped - # building the plugin is worse than a red one. - run: | - if ! cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release; then - echo "::warning::OBS SDK bootstrap failed on macOS; building the core library only. The plugin module was NOT built." - rm -rf build - cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSTPLUGIN_BOOTSTRAP_OBS=OFF - fi - - - name: Build - run: cmake --build build - - - name: Test (core library) - run: ctest --test-dir build --output-on-failure - - - name: Show what was built - # This used to be informational only (every command "|| true"'d), so - # a bootstrap failure that silently fell back to a core-library-only - # build still reported a green job -- exactly the false-positive - # class of bug this step exists to catch, caught instead by a human - # reading the raw log by hand. The macOS bootstrap has been reliably - # building the real module in CI (6/6 tests, artifact uploaded -- - # see README), so a missing module here is a regression to fail - # loudly on, not the old silent fallback. (This is separate from the - # macOS packaging gap in README -- that the module doesn't yet load - # as an OBS.app bundle -- which this check does not and cannot test.) - run: | - ls -la .deps/Frameworks/libobs.framework/Resources/cmake || true - if [ ! -f build/package/bin/streamer-tools-camera.so ]; then - echo "::error::no plugin module was built -- build/package/bin/streamer-tools-camera.so is missing. The macOS from-source libobs bootstrap is expected to succeed; treat this as a build failure, not a core-library-only fallback." - exit 1 - fi - ls -la build/package/bin - otool -L build/package/bin/streamer-tools-camera.so - otool -L build/package/bin/streamer-tools-camera.so | grep -E 'obs|livekit' + - name: Configure, build, test, verify + run: .gitea/scripts/macos-build.sh - name: Upload plugin continue-on-error: true @@ -140,51 +92,9 @@ jobs: # preinstalled tooling (cmake included) can be assumed present. uses: lukka/get-cmake@latest - - name: Configure - # The default Visual Studio generator is required, not Ninja: - # cmake/windows/buildspec.cmake keys the dependency slice off - # CMAKE_VS_PLATFORM_NAME, which only a VS generator sets. - # - # Same fallback as macOS, and the same warning: a green job that - # quietly stopped building the plugin is worse than a red one. - # PowerShell, not bash: this runner is a plain Windows VM and bash - # cannot be assumed present. - run: | - cmake -S . -B build -A x64 - if ($LASTEXITCODE -ne 0) { - Write-Host "::warning::OBS SDK bootstrap failed on Windows; building the core library only. The plugin module was NOT built." - Remove-Item -Recurse -Force build -ErrorAction SilentlyContinue - cmake -S . -B build -A x64 -DSTPLUGIN_BOOTSTRAP_OBS=OFF - if ($LASTEXITCODE -ne 0) { exit 1 } - } - - - name: Build - run: cmake --build build --config Release - - - name: Test (core library) - run: ctest --test-dir build -C Release --output-on-failure - - - name: Show what was built - # This used to be informational only: the else branch printed a - # message and exited 0, so a bootstrap failure that silently fell - # back to a core-library-only build (or a find_package(libobs) - # failure after a libobs that genuinely built, per the - # find_package(libobs) CMakeLists.txt fix above) still reported a - # green job -- exactly the false-positive class of bug this step - # exists to catch, caught instead by a human reading the raw log by - # hand across several "green" runs. The from-source libobs bootstrap - # is now expected to work reliably on this runner (that is the whole - # point of the buildspec bootstrap + find_package fix), so a missing - # module here is a regression to fail loudly on, not the old silent - # fallback. - run: | - $module = "build\package\bin\64bit\streamer-tools-camera.dll" - if (Test-Path $module) { - Get-ChildItem build\package\bin\64bit - } else { - Write-Host "::error::no plugin module was built -- $module is missing. The Windows from-source libobs bootstrap is expected to succeed; treat this as a build failure, not a core-library-only fallback." - exit 1 - } + - name: Configure, build, test, verify + shell: pwsh + run: ./.gitea/scripts/windows-build.ps1 - name: Upload plugin continue-on-error: true diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..673766e --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,196 @@ +name: Release + +# Packages a build of each platform into a downloadable archive and creates +# a (draft) Gitea Release for it, so the project owner and other directors +# can grab a ready-to-use build instead of compiling from source. +# +# RELEASE GATE -- READ BEFORE TAGGING +# ------------------------------------------------------------------ +# This workflow runs ONLY on a pushed version tag (see `on.push.tags` below) +# -- it never runs on an ordinary push or PR, unlike build.yml. Pushing a +# tag is therefore the one deliberate human act that starts it, and the +# release it creates is a DRAFT: it stays invisible to anyone without write +# access until a human explicitly opens it and clicks Publish. That is a +# second deliberate act past the tag push. +# +# Both of those are process, not a legal opinion. The actual open question -- +# whether this plugin's bundled WebRTC/OpenH264 code (via LiveKit) can be +# redistributed as a public download at all -- is tracked as "C1" in the +# README's `## Status` section and in third_party/livekit/README.md, and it +# is NOT resolved. Nothing here resolves it; the generated release notes put +# a reminder of that fact at the top of every release this workflow creates, +# specifically so nobody publishes a draft without seeing it again first. +# (The separate GPLv2/Apache-2.0 question, "C2", *is* resolved -- see +# README.) +# +# The actual per-platform build commands live in .gitea/scripts/ and are the +# same scripts .gitea/workflows/build.yml uses, so this workflow can't drift +# from what CI already builds and verifies on every push. + +on: + push: + tags: + - "v*" + +jobs: + linux: + name: Linux (ubuntu-24.04) + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install build dependencies + run: .gitea/scripts/linux-deps.sh + + - name: Configure, build, test, verify + run: .gitea/scripts/linux-build.sh + + - name: Package archive + run: | + set -euo pipefail + # zip is not guaranteed present on a minimal self-hosted runner + # image (unlike GitHub-hosted ubuntu-24.04, which build.yml's + # deps script doesn't need to care about). + command -v zip >/dev/null || sudo apt-get install -y -qq zip + out="streamer-tools-camera-${GITEA_REF_NAME}-linux-x64.zip" + root="$(pwd)" + ( cd build/package && zip -r "${root}/${out}" . ) + mkdir -p dist + mv "${out}" "dist/${out}" + ls -la dist + env: + GITEA_REF_NAME: ${{ github.ref_name }} + + - name: Upload archive + uses: actions/upload-artifact@v3 + with: + name: release-archive-linux-x64 + path: dist + + macos: + name: macOS (macos-latest) + runs-on: macos-latest + outputs: + bundle_found: ${{ steps.package.outputs.bundle_found }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install build dependencies + run: .gitea/scripts/macos-deps.sh + + - name: Configure, build, test, verify + run: .gitea/scripts/macos-build.sh + + - name: Package archive + id: package + run: | + set -euo pipefail + out="streamer-tools-camera-${GITEA_REF_NAME}-macos.zip" + root="$(pwd)" + mkdir -p dist + + # macOS packaging is being fixed separately (see the "macOS + # packaging gap" in README.md). Once it lands, build/package/ (or + # wherever that work stages its output) should contain a + # `.plugin` bundle directory -- look for one rather than + # assuming its exact final location, and fall back to packaging + # build/package/ as-is (today's actual, non-bundle output) if none + # is found yet. + bundle="$(find build -maxdepth 4 -type d -name '*.plugin' 2>/dev/null | head -n1 || true)" + if [ -n "${bundle}" ]; then + echo "Found macOS .plugin bundle: ${bundle}" + ( cd "$(dirname "${bundle}")" && zip -r "${root}/${out}" "$(basename "${bundle}")" ) + echo "bundle_found=true" >> "${GITHUB_OUTPUT}" + else + echo "::warning::No .plugin bundle found under build/ -- packaging build/package/ as-is. This is NOT yet a loadable OBS.app plugin; see the macOS packaging gap in README.md." + ( cd build/package && zip -r "${root}/${out}" . ) + echo "bundle_found=false" >> "${GITHUB_OUTPUT}" + fi + + mv "${out}" "dist/${out}" + ls -la dist + env: + GITEA_REF_NAME: ${{ github.ref_name }} + + - name: Upload archive + uses: actions/upload-artifact@v3 + with: + name: release-archive-macos + path: dist + + windows: + name: Windows (windows-latest) + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install build dependencies + uses: lukka/get-cmake@latest + + - name: Configure, build, test, verify + shell: pwsh + run: ./.gitea/scripts/windows-build.ps1 + + - name: Package archive + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + $out = "streamer-tools-camera-$env:GITEA_REF_NAME-windows-x64.zip" + New-Item -ItemType Directory -Force -Path dist | Out-Null + Compress-Archive -Path build\package\* -DestinationPath "dist\$out" -Force + Get-ChildItem dist + env: + GITEA_REF_NAME: ${{ github.ref_name }} + + - name: Upload archive + uses: actions/upload-artifact@v3 + with: + name: release-archive-windows-x64 + path: dist + + release: + name: Create Gitea Release (draft) + needs: [linux, macos, windows] + runs-on: ubuntu-24.04 + permissions: + contents: write + steps: + - name: Checkout + # Not strictly needed to build anything here, but publish-release.sh + # lives in the repo and this keeps the release job self-contained / + # easy to reason about rather than reaching into another job's + # checkout. + uses: actions/checkout@v4 + + - name: Download Linux archive + uses: actions/download-artifact@v3 + with: + name: release-archive-linux-x64 + path: dist + + - name: Download macOS archive + uses: actions/download-artifact@v3 + with: + name: release-archive-macos + path: dist + + - name: Download Windows archive + uses: actions/download-artifact@v3 + with: + name: release-archive-windows-x64 + path: dist + + - name: Create draft release and upload assets + run: .gitea/scripts/publish-release.sh + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + SERVER: https://repo.anhonesthost.net + OWNER: CyberCoveLLC + REPO: obs-streamer-tools-plugin + TAG: ${{ github.ref_name }} + SHA: ${{ github.sha }} + DIST_DIR: dist + MACOS_BUNDLE_FOUND: ${{ needs.macos.outputs.bundle_found }} diff --git a/README.md b/README.md index a0be29d..8cd7193 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,20 @@ that only the project owner can decide. Nothing in this repo should be built into a package and handed out, posted, or attached to a public release until that sign-off happens. See `third_party/livekit/README.md` for the specifics of what is and is not currently known/shipped on the licensing side. (CI in -`.gitea/workflows/build.yml` currently only builds, tests, and uploads -CI-internal build artifacts — it does not create a Gitea Release or otherwise -publish anything publicly; if that ever changes, the new step must carry this -same gate.) +`.gitea/workflows/build.yml` only builds, tests, and uploads CI-internal +build artifacts — it does not create a Gitea Release or otherwise publish +anything publicly. + +`.gitea/workflows/release.yml` is the mechanism that *would* publish a +release, but it does not run automatically: it is gated on someone pushing a +`v*` tag, which is the actual sign-off gate in practice — don't push one +until the owner has actually signed off on C1. When it does run, it packages +each platform's `build/package/` (or macOS's bundle output, once that lands) +into a zip and creates a **draft** Gitea Release, whose generated release +notes lead with the same C1 reminder as this section, so whoever opens the +draft to publish it sees the open question again before doing so. Building +that mechanism is not the same as clearing C1 — it still requires the same +owner sign-off before a tag gets pushed.) The separate license-compatibility question — this repository's own top-level `LICENSE` was GPLv2 while the vendored LiveKit binaries are Apache-2.0, which @@ -68,7 +78,9 @@ obs-adapter/ - thin OBS glue (C++) data/locale/en-US.ini scripts/livekit-dev-room.py - mints tokens for the integration test third_party/livekit/ - redistribution notices for the LiveKit binaries -.gitea/workflows/build.yml - 3-platform CI matrix +.gitea/scripts/ - the actual per-platform build commands, shared by build.yml and release.yml +.gitea/workflows/build.yml - 3-platform CI matrix (every push/PR; never publishes) +.gitea/workflows/release.yml - packages + creates a draft Gitea Release (only on a `v*` tag push; see Status above) ``` ## How it works