Skip to content

Commit 49eaf77

Browse files
committed
Prebuilt CI: auto-stream from mainline whisper.cpp on a schedule
Mirror the unslothai/llama.cpp nightly so new upstream whisper.cpp releases are packaged and published without a manual dispatch, tuned for whisper's slower cadence: - schedule trigger every 5 days at 22:41 UTC (~3PM San Francisco, fixed offset, not DST-adjusted). - upstream_tag now defaults to "latest"; resolve dereferences "latest" to the newest published upstream release that has been public for at least min_age_hours (default 6) as a supply-chain aging window. An explicit vMAJOR.MINOR[.PATCH] tag on manual dispatch skips the filter. - scheduled runs publish (the existing exists gate makes a run whose tag is already published a cheap no-op: resolve sets exists=true and every build and assemble job is skipped). Manual dispatch still builds or publishes any tag on demand.
1 parent 3996794 commit 49eaf77

1 file changed

Lines changed: 43 additions & 9 deletions

File tree

.github/workflows/unsloth-prebuilt.yml

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,35 @@ name: Unsloth whisper prebuilt (full release)
2424
# change what a given packaging tag shipped.
2525

2626
on:
27+
# Auto-stream from mainline whisper.cpp: every 5 days at ~3PM San Francisco
28+
# (22:41 UTC; a fixed offset, not DST-adjusted, so ~3:41PM PDT / ~2:41PM PST).
29+
# `*/5` fires on days 1,6,11,16,21,26,31, so the spacing resets at each month
30+
# boundary -- close enough given upstream tags land weeks apart. A scheduled
31+
# run resolves the newest aged upstream release and publishes it; if that
32+
# release is already published the run is a cheap no-op (resolve sets
33+
# exists=true and every build/assemble job is skipped). Manual dispatch can
34+
# still build or publish any tag on demand.
35+
schedule:
36+
- cron: '41 22 */5 * *'
2737
workflow_dispatch:
2838
inputs:
2939
upstream_tag:
30-
description: 'Upstream ggml-org/whisper.cpp tag to build (e.g. v1.9.1)'
31-
default: 'v1.9.1'
32-
required: true
40+
description: 'Upstream ggml-org/whisper.cpp tag to build, or "latest" to resolve the newest aged release'
41+
default: 'latest'
42+
required: false
3343
type: string
3444
packaging_suffix:
3545
description: 'Packaging suffix appended to the tag: <upstream_tag>-<suffix>'
3646
default: 'unsloth.1'
3747
required: true
3848
type: string
49+
min_age_hours:
50+
description: 'For "latest": only build an upstream release public for at least this many hours (blank = 6)'
51+
default: ''
52+
required: false
53+
type: string
3954
publish:
40-
description: 'Publish a GitHub Release (off = build + upload artifacts only)'
55+
description: 'Publish a GitHub Release (off = build + upload artifacts only). Scheduled runs always publish.'
4156
default: false
4257
required: false
4358
type: boolean
@@ -46,7 +61,7 @@ permissions:
4661
contents: write
4762

4863
concurrency:
49-
group: ${{ github.workflow }}-${{ github.event.inputs.upstream_tag }}-${{ github.event.inputs.packaging_suffix }}
64+
group: ${{ github.workflow }}-${{ github.event.inputs.upstream_tag || 'scheduled' }}-${{ github.event.inputs.packaging_suffix || 'auto' }}
5065
cancel-in-progress: false
5166

5267
jobs:
@@ -73,8 +88,27 @@ jobs:
7388
id: r
7489
run: |
7590
set -euo pipefail
76-
UT='${{ github.event.inputs.upstream_tag }}'
77-
SUFFIX='${{ github.event.inputs.packaging_suffix }}'
91+
UT='${{ github.event.inputs.upstream_tag || 'latest' }}'
92+
SUFFIX='${{ github.event.inputs.packaging_suffix || 'unsloth.1' }}'
93+
AGE_H='${{ github.event.inputs.min_age_hours }}'
94+
[ -n "$AGE_H" ] || AGE_H=6
95+
96+
# Resolve "latest" (the default, and what every scheduled run uses) to
97+
# the newest published upstream release that has been public for >=
98+
# AGE_H hours -- a supply-chain aging window so a yanked or malicious
99+
# upstream tag is not shipped the instant it appears. GitHub does not
100+
# guarantee list order, so pick the max by published_at explicitly. An
101+
# explicit vX.Y.Z tag (manual dispatch) skips the filter.
102+
if [ "$UT" = "latest" ]; then
103+
CUTOFF="$(date -u -d "-${AGE_H} hours" +%s)"
104+
UT="$(gh api 'repos/ggml-org/whisper.cpp/releases?per_page=100' \
105+
--jq "[.[] | select(.draft==false and .prerelease==false) | select((.published_at|fromdateiso8601) <= ${CUTOFF})] | max_by(.published_at|fromdateiso8601) | .tag_name")"
106+
if [ -z "$UT" ] || [ "$UT" = "null" ]; then
107+
echo "refusing: no ggml-org/whisper.cpp release older than ${AGE_H}h in the last 100 releases" >&2
108+
exit 1
109+
fi
110+
echo "selected upstream ${UT} (aged >= ${AGE_H}h)"
111+
fi
78112
printf '%s' "$UT" | grep -qE '^v[0-9]+\.[0-9]+(\.[0-9]+)?$' \
79113
|| { echo "refusing non-release upstream tag '$UT' (want vMAJOR.MINOR[.PATCH])" >&2; exit 1; }
80114
printf '%s' "$SUFFIX" | grep -qE '^[A-Za-z0-9._-]+$' \
@@ -320,7 +354,7 @@ jobs:
320354
echo "fingerprint verified in $checked bundles"
321355
322356
- name: Verify P0 coverage before publish
323-
if: ${{ inputs.publish && needs.resolve.outputs.exists != 'true' }}
357+
if: ${{ (inputs.publish || github.event_name == 'schedule') && needs.resolve.outputs.exists != 'true' }}
324358
run: |
325359
set -eu
326360
TAG='${{ needs.resolve.outputs.tag }}'
@@ -359,7 +393,7 @@ jobs:
359393
retention-days: 7
360394

361395
- name: Publish GitHub release (draft first, then atomic)
362-
if: ${{ inputs.publish && needs.resolve.outputs.exists != 'true' }}
396+
if: ${{ (inputs.publish || github.event_name == 'schedule') && needs.resolve.outputs.exists != 'true' }}
363397
run: |
364398
set -eux
365399
TAG='${{ needs.resolve.outputs.tag }}'

0 commit comments

Comments
 (0)