-
Notifications
You must be signed in to change notification settings - Fork 1
206 lines (192 loc) · 7.83 KB
/
Copy pathbuild-release.yml
File metadata and controls
206 lines (192 loc) · 7.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
name: Build & release moonshine-server 🛠️
# Distribution-only repo — no moonshine fork lives here.
#
# This workflow tracks upstream releases of the `moonshine-voice` PyPI package
# (UsefulSensors' streaming STT library). On a daily schedule it checks PyPI
# for the latest version; if this repo has no release for it yet, it builds
# self-contained moonshine-server bundles and publishes them.
#
# Sources at build time:
# - moonshine-voice: PyPI wheel (never forked, never vendored)
# - main.py wrapper: checked out from lemonade-sdk/lemonade
# (tools/moonshine-server/main.py)
#
# Release tag scheme: moonshine<moonshine-voice version>, e.g. moonshine0.0.62.
# lemonade pins the consumed tag in src/cpp/resources/backend_versions.json
# (moonshine.cpu) — new upstream versions are auto-built here, but lemonade
# only switches when that pin is bumped via PR.
#
# Asset names match MoonshineServer::get_install_params() in lemonade:
# moonshine-server-<tag>-linux-x64.tar.gz
# moonshine-server-<tag>-windows-x64.zip
# moonshine-server-<tag>-macos-arm64.tar.gz
# (moonshine-voice publishes wheels for win x64, linux x64/aarch64, macOS
# arm64 only — no Intel macOS, hence no macos-x64 asset.)
#
# Python is pinned to 3.12: main.py uses the `cgi` module, removed in 3.13.
on:
schedule:
- cron: '17 6 * * *' # daily upstream check
workflow_dispatch:
inputs:
moonshine_voice_version:
description: 'moonshine-voice PyPI version to build (empty = latest)'
required: false
default: ''
force:
description: 'Rebuild even if the release already exists'
type: boolean
required: false
default: false
lemonade_ref:
description: 'lemonade-sdk/lemonade ref to take main.py from'
required: false
default: 'main'
permissions:
contents: write
jobs:
check:
name: Check upstream version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.resolve.outputs.version }}
tag: ${{ steps.resolve.outputs.tag }}
need_build: ${{ steps.resolve.outputs.need_build }}
steps:
- name: Resolve latest moonshine-voice version
id: resolve
env:
GH_TOKEN: ${{ github.token }}
REQUESTED: ${{ github.event.inputs.moonshine_voice_version }}
FORCE: ${{ github.event.inputs.force }}
LEMONADE_REF: ${{ github.event.inputs.lemonade_ref || 'main' }}
run: |
set -euxo pipefail
if [ -n "${REQUESTED:-}" ]; then
VERSION="$REQUESTED"
else
VERSION=$(curl -fsSL https://pypi.org/pypi/moonshine-voice/json | jq -r '.info.version')
fi
TAG="moonshine${VERSION}"
NEED=true
if [ "${FORCE:-false}" != "true" ] && gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "Release $TAG already exists — nothing to do."
NEED=false
fi
# The main.py wrapper must exist at the lemonade ref. Until the
# moonshine backend PR merges to main, scheduled runs would fail
# here — skip gracefully instead of going red every night.
if [ "$NEED" = "true" ] && ! gh api "repos/lemonade-sdk/lemonade/contents/tools/moonshine-server/main.py?ref=${LEMONADE_REF}" --silent >/dev/null 2>&1; then
echo "::notice::tools/moonshine-server/main.py not found at lemonade ref '${LEMONADE_REF}' — skipping build."
NEED=false
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "need_build=$NEED" >> "$GITHUB_OUTPUT"
build:
name: Build (${{ matrix.platform }})
needs: check
if: needs.check.outputs.need_build == 'true'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
platform: linux-x64
archive: tar.gz
- os: ubuntu-22.04-arm
platform: linux-arm64
archive: tar.gz
- os: windows-latest
platform: windows-x64
archive: zip
- os: macos-latest
platform: macos-arm64
archive: tar.gz
env:
VERSION: ${{ needs.check.outputs.version }}
TAG: ${{ needs.check.outputs.tag }}
steps:
- name: Checkout lemonade (main.py wrapper only)
uses: actions/checkout@v4
with:
repository: lemonade-sdk/lemonade
ref: ${{ github.event.inputs.lemonade_ref || 'main' }}
sparse-checkout: tools/moonshine-server
path: lemonade
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
shell: bash
run: |
set -euxo pipefail
python -m pip install --upgrade pip
python -m pip install "moonshine-voice==${VERSION}" websockets pyinstaller
python -c "import moonshine_voice; print(moonshine_voice.__file__)"
- name: Remove foreign-platform libraries (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
set -euxo pipefail
# The macOS moonshine-voice wheel ships shared libraries for other
# platforms too (e.g. a Linux ELF libmoonshine.so). PyInstaller's
# Mach-O parser hard-fails on ELF inputs, so drop anything that is
# not Mach-O before freezing.
SITE=$(python -c "import moonshine_voice, os; print(os.path.dirname(moonshine_voice.__file__))")
find "$SITE" \( -name '*.so' -o -name '*.dylib' -o -name '*.dll' \) -print0 |
while IFS= read -r -d '' f; do
if ! file -b "$f" | grep -q 'Mach-O'; then
echo "removing foreign binary: $f"
rm -f "$f"
fi
done
- name: Build self-contained bundle (PyInstaller onedir)
shell: bash
run: |
set -euxo pipefail
# --collect-all pulls in moonshine_voice's native shared libraries and
# data files; websockets is imported lazily so declare it explicitly.
pyinstaller --noconfirm --onedir --name moonshine-server \
--collect-all moonshine_voice \
--hidden-import websockets \
lemonade/tools/moonshine-server/main.py
- name: Smoke test bundle
shell: bash
run: |
set -euxo pipefail
./dist/moonshine-server/moonshine-server --help
- name: Package asset (name must match get_install_params)
id: package
shell: bash
run: |
set -euxo pipefail
ASSET="moonshine-server-${TAG}-${{ matrix.platform }}.${{ matrix.archive }}"
cd dist
if [ "${{ matrix.archive }}" = "zip" ]; then
7z a "../$ASSET" moonshine-server
else
tar -czf "../$ASSET" moonshine-server
fi
cd ..
ls -lh "$ASSET"
echo "asset=$ASSET" >> "$GITHUB_OUTPUT"
- name: Publish release asset
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euxo pipefail
ASSET="${{ steps.package.outputs.asset }}"
# Create the release if it does not exist yet ("|| true" — another
# matrix job may create it concurrently), then upload with --clobber
# so re-runs replace the asset.
if ! gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release create "$TAG" --repo "$GITHUB_REPOSITORY" \
--title "moonshine-server $TAG" \
--notes "Self-contained moonshine-server bundles (PyInstaller, embedded Python 3.12 + moonshine-voice ${VERSION} from PyPI). Wrapper: lemonade-sdk/lemonade tools/moonshine-server/main.py." \
|| true
fi
gh release upload "$TAG" "$ASSET" --repo "$GITHUB_REPOSITORY" --clobber