Skip to content

Commit c1b14a5

Browse files
dkulpclaude
andcommitted
Add rolling 'latest' SPM channel + share publish logic
Extract the xLights-spm publish into submodules/spm/publish.sh with two channels: 'release' (per-tag assets -> main + semver tag, called from Release.yml) and 'latest' (rolling 'latest' prerelease with SHA-stamped assets -> force-pushed 'latest' branch, called from CI.yml on every push to main). SHA-stamped asset filenames give each build a fresh URL so GitHub's CDN can't serve stale bytes under a reused URL. Consumers track bleeding edge via branch: "latest". Package.swift.in gains a __SUFFIX__ placeholder. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7b47dc1 commit c1b14a5

4 files changed

Lines changed: 132 additions & 57 deletions

File tree

.github/workflows/CI.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ jobs:
1010
build:
1111

1212
runs-on: macOS-26
13+
permissions:
14+
contents: write # GITHUB_TOKEN needs this to manage the `latest` release
1315

1416
steps:
1517
- uses: actions/checkout@v2
@@ -24,4 +26,14 @@ jobs:
2426
brew install automake libtool cmake nasm
2527
- name: Build
2628
run: ./build.sh
27-
29+
# Publish the rolling "latest" ANGLE Swift package on every push to main:
30+
# (re)build the `latest` prerelease with SHA-stamped assets and force-push
31+
# the xLights-spm `latest` branch. Consumers track it via branch: "latest".
32+
# Skipped on PRs / when SPM_REPO_TOKEN is absent.
33+
- name: Publish Swift package (latest)
34+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
35+
env:
36+
SPM_REPO_TOKEN: ${{ secrets.SPM_REPO_TOKEN }}
37+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38+
run: ./submodules/spm/publish.sh latest
39+

.github/workflows/Release.yml

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -28,59 +28,13 @@ jobs:
2828
allowUpdates: true
2929
artifacts: "output/*"
3030
token: ${{ secrets.GITHUB_TOKEN }}
31-
# Publish the ANGLE Swift package to xLightsSequencer/xLights-spm.
32-
# The xcframework zips were just attached to this release; we regenerate
33-
# Package.swift (from submodules/spm/Package.swift.in) with their URLs +
34-
# checksums, refresh the vendored headers, and tag the package repo with a
31+
# Publish the stable ANGLE Swift package to xLightsSequencer/xLights-spm:
32+
# regenerate Package.swift from the just-attached release assets and tag a
3533
# semver derived from this build's tag (xlights_2026.10 -> 2026.10.0).
36-
#
37-
# Requires repo secret SPM_REPO_TOKEN: a token with Contents:read/write on
38-
# xLightsSequencer/xLights-spm (GITHUB_TOKEN is scoped to this repo only).
39-
# Skipped (with a notice) when the secret is absent or there is no tag.
40-
- name: Publish Swift package
34+
# Requires repo/org secret SPM_REPO_TOKEN (Contents:write on xLights-spm);
35+
# the script no-ops with a notice when it is absent.
36+
- name: Publish Swift package (release)
4137
if: startsWith(github.ref, 'refs/tags/')
4238
env:
4339
SPM_REPO_TOKEN: ${{ secrets.SPM_REPO_TOKEN }}
44-
run: |
45-
set -e
46-
if [ -z "${SPM_REPO_TOKEN}" ]; then
47-
echo "::notice::SPM_REPO_TOKEN not set — skipping xLights-spm publish."
48-
exit 0
49-
fi
50-
51-
VER="${GITHUB_REF_NAME#xlights_}.0" # xlights_2026.10 -> 2026.10.0
52-
ASSET_BASE="https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}"
53-
echo "Publishing xLights-spm ${VER} (assets from ${GITHUB_REF_NAME})"
54-
55-
EGL_MAC_SHA=$(swift package compute-checksum output/libEGL-macos.xcframework.zip)
56-
EGL_IOS_SHA=$(swift package compute-checksum output/libEGL-ios.xcframework.zip)
57-
GLES_MAC_SHA=$(swift package compute-checksum output/libGLESv2-macos.xcframework.zip)
58-
GLES_IOS_SHA=$(swift package compute-checksum output/libGLESv2-ios.xcframework.zip)
59-
60-
git clone --depth 1 "https://x-access-token:${SPM_REPO_TOKEN}@github.com/xLightsSequencer/xLights-spm.git" spm-repo
61-
cd spm-repo
62-
63-
mkdir -p Sources/ANGLE/include
64-
# Refresh vendored headers from this build.
65-
rm -rf Sources/ANGLE/include/EGL Sources/ANGLE/include/GLES2 \
66-
Sources/ANGLE/include/GLES3 Sources/ANGLE/include/KHR
67-
cp -R ../include/EGL ../include/GLES2 ../include/GLES3 ../include/KHR Sources/ANGLE/include/
68-
# SPM C target needs at least one source file.
69-
[ -f Sources/ANGLE/shim.c ] || printf '// header-only umbrella target for ANGLE\n' > Sources/ANGLE/shim.c
70-
[ -f .gitignore ] || printf '.build/\n*.xcframework/\n' > .gitignore
71-
72-
sed -e "s|__ASSET_BASE__|${ASSET_BASE}|g" \
73-
-e "s|__LIBEGL_MACOS_SHA__|${EGL_MAC_SHA}|g" \
74-
-e "s|__LIBEGL_IOS_SHA__|${EGL_IOS_SHA}|g" \
75-
-e "s|__LIBGLESV2_MACOS_SHA__|${GLES_MAC_SHA}|g" \
76-
-e "s|__LIBGLESV2_IOS_SHA__|${GLES_IOS_SHA}|g" \
77-
../submodules/spm/Package.swift.in > Package.swift
78-
79-
git config user.name "github-actions[bot]"
80-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
81-
git add -A
82-
git commit -m "ANGLE ${VER} (from ${GITHUB_REF_NAME})" || echo "No changes to commit"
83-
git push origin HEAD:main
84-
git tag -f "${VER}"
85-
git push -f origin "${VER}"
86-
echo "::notice::Published xLights-spm ${VER}"
40+
run: ./submodules/spm/publish.sh release

submodules/spm/Package.swift.in

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ let package = Package(
2929

3030
// macOS: library (dylib) slices — the prebuilt dylib keeps its
3131
// @rpath/<name>.dylib id, which matches dylib-style embedding.
32-
.binaryTarget(name: "libEGL_macos", url: "__ASSET_BASE__/libEGL-macos.xcframework.zip", checksum: "__LIBEGL_MACOS_SHA__"),
33-
.binaryTarget(name: "libGLESv2_macos", url: "__ASSET_BASE__/libGLESv2-macos.xcframework.zip", checksum: "__LIBGLESV2_MACOS_SHA__"),
32+
.binaryTarget(name: "libEGL_macos", url: "__ASSET_BASE__/libEGL-macos__SUFFIX__.xcframework.zip", checksum: "__LIBEGL_MACOS_SHA__"),
33+
.binaryTarget(name: "libGLESv2_macos", url: "__ASSET_BASE__/libGLESv2-macos__SUFFIX__.xcframework.zip", checksum: "__LIBGLESV2_MACOS_SHA__"),
3434

3535
// iOS: framework slices (device + simulator).
36-
.binaryTarget(name: "libEGL_ios", url: "__ASSET_BASE__/libEGL-ios.xcframework.zip", checksum: "__LIBEGL_IOS_SHA__"),
37-
.binaryTarget(name: "libGLESv2_ios", url: "__ASSET_BASE__/libGLESv2-ios.xcframework.zip", checksum: "__LIBGLESV2_IOS_SHA__"),
36+
.binaryTarget(name: "libEGL_ios", url: "__ASSET_BASE__/libEGL-ios__SUFFIX__.xcframework.zip", checksum: "__LIBEGL_IOS_SHA__"),
37+
.binaryTarget(name: "libGLESv2_ios", url: "__ASSET_BASE__/libGLESv2-ios__SUFFIX__.xcframework.zip", checksum: "__LIBGLESV2_IOS_SHA__"),
3838
]
3939
)

submodules/spm/publish.sh

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/bin/bash
2+
#
3+
# Publish the ANGLE Swift package to xLightsSequencer/xLights-spm.
4+
#
5+
# Usage: submodules/spm/publish.sh <release|latest>
6+
#
7+
# release Stable channel (run from the tag-triggered release workflow).
8+
# Uses the per-tag release assets already attached by the release
9+
# step, generates Package.swift pointing at them, pushes to the
10+
# xLights-spm `main` branch and tags a semver derived from the deps
11+
# tag: xlights_2026.10 -> 2026.10.0. Consumers: from: "2026.10.0".
12+
#
13+
# latest Rolling channel (run from CI on every push to main). (Re)builds a
14+
# `latest` prerelease on this repo with SHA-stamped assets (a fresh
15+
# URL each commit, so GitHub's CDN can never serve stale bytes under
16+
# a reused URL), generates Package.swift pointing at them, and
17+
# force-pushes the xLights-spm `latest` branch. Consumers:
18+
# branch: "latest".
19+
#
20+
# Required env:
21+
# SPM_REPO_TOKEN token with Contents:read/write on xLights-spm
22+
# GH_TOKEN token for `gh` against THIS repo (latest channel only)
23+
# plus the standard GitHub Actions GITHUB_* variables.
24+
#
25+
# If SPM_REPO_TOKEN is absent the script no-ops with a notice (so forks / PRs
26+
# and unconfigured repos don't fail the build).
27+
set -e
28+
29+
CHANNEL="${1:?usage: publish.sh <release|latest>}"
30+
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
31+
BASE_DEPS_DIR=$( cd -- "${SCRIPT_DIR}/../.." &> /dev/null && pwd )
32+
cd "${BASE_DEPS_DIR}"
33+
34+
if [ -z "${SPM_REPO_TOKEN}" ]; then
35+
echo "::notice::SPM_REPO_TOKEN not set — skipping xLights-spm publish."
36+
exit 0
37+
fi
38+
39+
REPO_URL="https://github.com/${GITHUB_REPOSITORY}"
40+
41+
case "${CHANNEL}" in
42+
release)
43+
SUFFIX=""
44+
ASSET_BASE="${REPO_URL}/releases/download/${GITHUB_REF_NAME}"
45+
SPM_VER="${GITHUB_REF_NAME#xlights_}.0" # xlights_2026.10 -> 2026.10.0
46+
;;
47+
latest)
48+
SHA="$(git rev-parse --short HEAD)"
49+
SUFFIX="-${SHA}"
50+
ASSET_BASE="${REPO_URL}/releases/download/latest"
51+
# Ensure the rolling prerelease exists, then clear its old assets.
52+
gh release create latest --prerelease --title "latest" \
53+
--notes "Rolling latest build of the ANGLE Swift package." 2>/dev/null || true
54+
for a in $(gh release view latest --json assets -q '.assets[].name' 2>/dev/null); do
55+
gh release delete-asset latest "$a" -y 2>/dev/null || true
56+
done
57+
# SHA-stamped copies of the freshly built zips, then upload them.
58+
for FW in libEGL libGLESv2; do
59+
for v in macos ios; do
60+
cp "output/${FW}-${v}.xcframework.zip" "output/${FW}-${v}${SUFFIX}.xcframework.zip"
61+
done
62+
done
63+
gh release upload latest output/*"${SUFFIX}".xcframework.zip --clobber
64+
;;
65+
*) echo "unknown channel: ${CHANNEL}" >&2; exit 1 ;;
66+
esac
67+
68+
# Checksums of the (suffixed) zips consumers will actually download.
69+
sha() { swift package compute-checksum "output/$1${SUFFIX}.xcframework.zip"; }
70+
EGL_MAC_SHA=$(sha libEGL-macos)
71+
EGL_IOS_SHA=$(sha libEGL-ios)
72+
GLES_MAC_SHA=$(sha libGLESv2-macos)
73+
GLES_IOS_SHA=$(sha libGLESv2-ios)
74+
75+
rm -rf spm-repo
76+
git clone --depth 1 "https://x-access-token:${SPM_REPO_TOKEN}@github.com/xLightsSequencer/xLights-spm.git" spm-repo
77+
cd spm-repo
78+
79+
mkdir -p Sources/ANGLE/include
80+
rm -rf Sources/ANGLE/include/EGL Sources/ANGLE/include/GLES2 \
81+
Sources/ANGLE/include/GLES3 Sources/ANGLE/include/KHR
82+
cp -R ../include/EGL ../include/GLES2 ../include/GLES3 ../include/KHR Sources/ANGLE/include/
83+
[ -f Sources/ANGLE/shim.c ] || printf '// header-only umbrella target for ANGLE\n' > Sources/ANGLE/shim.c
84+
[ -f .gitignore ] || printf '.build/\n' > .gitignore
85+
86+
sed -e "s|__ASSET_BASE__|${ASSET_BASE}|g" \
87+
-e "s|__SUFFIX__|${SUFFIX}|g" \
88+
-e "s|__LIBEGL_MACOS_SHA__|${EGL_MAC_SHA}|g" \
89+
-e "s|__LIBEGL_IOS_SHA__|${EGL_IOS_SHA}|g" \
90+
-e "s|__LIBGLESV2_MACOS_SHA__|${GLES_MAC_SHA}|g" \
91+
-e "s|__LIBGLESV2_IOS_SHA__|${GLES_IOS_SHA}|g" \
92+
../submodules/spm/Package.swift.in > Package.swift
93+
94+
git config user.name "github-actions[bot]"
95+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
96+
git add -A
97+
98+
if [ "${CHANNEL}" = "release" ]; then
99+
git commit -m "ANGLE ${SPM_VER} (from ${GITHUB_REF_NAME})" || echo "No changes to commit"
100+
git push origin HEAD:main
101+
git tag -f "${SPM_VER}"
102+
git push -f origin "${SPM_VER}"
103+
echo "::notice::Published xLights-spm ${SPM_VER}"
104+
else
105+
git checkout -B latest
106+
git commit -m "ANGLE latest (${GITHUB_SHA})" || echo "No changes to commit"
107+
git push -f origin latest
108+
echo "::notice::Published xLights-spm latest branch (${SHA})"
109+
fi

0 commit comments

Comments
 (0)