@krx3d/tizentube2 1.30.710 → 1.30.730
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
name: Sync from GitHub
|
|
2
|
+
|
|
3
|
+
# Brings whatever changed on github.com/KrX3D/TizenTube into this mirror as a
|
|
4
|
+
# single pull request, and leaves that pull request to be reviewed and merged
|
|
5
|
+
# rather than writing to main itself.
|
|
6
|
+
#
|
|
7
|
+
# One pull request, not one per run: the sync branch is reused and force-moved
|
|
8
|
+
# to GitHub's current tip, and a run that finds the pull request already open
|
|
9
|
+
# updates the branch and says so instead of opening another.
|
|
10
|
+
#
|
|
11
|
+
# Lives in .gitea/workflows rather than .github/workflows deliberately. The
|
|
12
|
+
# second is synced from GitHub and holds that repository's own workflows —
|
|
13
|
+
# including the one that publishes to npm, which must never run here. See
|
|
14
|
+
# runs-on below for how that is kept from happening.
|
|
15
|
+
#
|
|
16
|
+
# It is nonetheless committed on GitHub as well, where it does nothing: GitHub
|
|
17
|
+
# Actions reads .github/workflows and only that, so this file is never parsed
|
|
18
|
+
# there and never appears in the Actions tab. It is here so that the mirror
|
|
19
|
+
# holds no commit GitHub lacks. When it lived only on the mirror, the mirror's
|
|
20
|
+
# main was permanently one commit ahead, so every sync was a real merge and
|
|
21
|
+
# left two more merge commits behind it. With the file on both sides the two
|
|
22
|
+
# branches are identical and each sync fast-forwards.
|
|
23
|
+
|
|
24
|
+
on:
|
|
25
|
+
schedule:
|
|
26
|
+
# Hourly, offset off the hour so it does not land with everything else.
|
|
27
|
+
- cron: '17 * * * *'
|
|
28
|
+
workflow_dispatch:
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
sync:
|
|
32
|
+
# Deliberately not ubuntu-latest. This repository carries the GitHub
|
|
33
|
+
# workflows too, and they all ask for ubuntu-latest — so a runner
|
|
34
|
+
# registered with this label alone can run this workflow and none of
|
|
35
|
+
# those. The Actions tab can also disable them one by one, which is worth
|
|
36
|
+
# doing as well; this is the part that holds without anyone remembering.
|
|
37
|
+
runs-on: gitea-sync
|
|
38
|
+
steps:
|
|
39
|
+
- name: Bring GitHub's changes onto the sync branch and open one pull request
|
|
40
|
+
env:
|
|
41
|
+
# A personal access token with write access to this repository.
|
|
42
|
+
# Falls back to the token Gitea Actions provides, which is enough to
|
|
43
|
+
# push but may not be allowed to open a pull request depending on the
|
|
44
|
+
# instance's settings — hence the preference.
|
|
45
|
+
SYNC_TOKEN: ${{ secrets.SYNC_TOKEN }}
|
|
46
|
+
AUTO_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
47
|
+
SERVER_URL: ${{ github.server_url }}
|
|
48
|
+
REPO: ${{ github.repository }}
|
|
49
|
+
SOURCE: https://github.com/KrX3D/TizenTube.git
|
|
50
|
+
SYNC_BRANCH: github-sync
|
|
51
|
+
BASE_BRANCH: main
|
|
52
|
+
run: |
|
|
53
|
+
set -eu
|
|
54
|
+
|
|
55
|
+
TOKEN="${SYNC_TOKEN:-${AUTO_TOKEN:-}}"
|
|
56
|
+
if [ -z "$TOKEN" ]; then
|
|
57
|
+
echo "No token available. Add a repository secret named SYNC_TOKEN"
|
|
58
|
+
echo "holding a personal access token with write access."
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# The scheme is kept rather than assumed: this instance is plain http
|
|
63
|
+
# today and may not be tomorrow.
|
|
64
|
+
case "$SERVER_URL" in
|
|
65
|
+
https://*) SCHEME=https; HOSTPART="${SERVER_URL#https://}" ;;
|
|
66
|
+
*) SCHEME=http; HOSTPART="${SERVER_URL#http://}" ;;
|
|
67
|
+
esac
|
|
68
|
+
HOSTPART="${HOSTPART%/}"
|
|
69
|
+
PUSH_URL="$SCHEME://$TOKEN@$HOSTPART/$REPO.git"
|
|
70
|
+
API="$SCHEME://$HOSTPART/api/v1/repos/$REPO"
|
|
71
|
+
|
|
72
|
+
# Only the base branch: this mirror carries 154 branches and cloning
|
|
73
|
+
# all of them to compare one would cost minutes per run.
|
|
74
|
+
git clone --quiet --single-branch --branch "$BASE_BRANCH" "$PUSH_URL" work
|
|
75
|
+
cd work
|
|
76
|
+
git config user.name "Gitea Actions"
|
|
77
|
+
git config user.email "actions@local"
|
|
78
|
+
|
|
79
|
+
git remote add github "$SOURCE"
|
|
80
|
+
git fetch --quiet --tags github "$BASE_BRANCH"
|
|
81
|
+
TIP=$(git rev-parse "github/$BASE_BRANCH")
|
|
82
|
+
echo "GitHub $BASE_BRANCH is at $TIP"
|
|
83
|
+
|
|
84
|
+
# Already contained: nothing changed since the last merge, so there is
|
|
85
|
+
# nothing to open a pull request about.
|
|
86
|
+
if git merge-base --is-ancestor "$TIP" "origin/$BASE_BRANCH"; then
|
|
87
|
+
echo "This mirror already contains it. Nothing to do."
|
|
88
|
+
exit 0
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
AHEAD=$(git rev-list --count "origin/$BASE_BRANCH..$TIP")
|
|
92
|
+
echo "$AHEAD commit(s) to bring over"
|
|
93
|
+
|
|
94
|
+
# Force, because the branch is a pointer at GitHub's tip and nothing
|
|
95
|
+
# else: anything that was on it has either been merged or superseded.
|
|
96
|
+
git push --quiet --force "$PUSH_URL" "$TIP:refs/heads/$SYNC_BRANCH"
|
|
97
|
+
# Tags come along for free and are worth having in a mirror.
|
|
98
|
+
git push --quiet --tags "$PUSH_URL" || echo "(tags unchanged or rejected, continuing)"
|
|
99
|
+
|
|
100
|
+
# One pull request: if one is already open from this branch, the push
|
|
101
|
+
# above has just updated it.
|
|
102
|
+
OPEN=$(curl -sf -H "Authorization: token $TOKEN" \
|
|
103
|
+
"$API/pulls?state=open&limit=50" \
|
|
104
|
+
| tr '}' '\n' | grep -c "\"ref\":\"$SYNC_BRANCH\"" || true)
|
|
105
|
+
if [ "${OPEN:-0}" -gt 0 ]; then
|
|
106
|
+
echo "A pull request from $SYNC_BRANCH is already open; its branch now points at $TIP."
|
|
107
|
+
exit 0
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# The commit list goes in the body, escaped for JSON and joined with
|
|
111
|
+
# literal newline escapes so no multi-line quoting is needed.
|
|
112
|
+
LIST=$(git log --oneline --no-decorate "origin/$BASE_BRANCH..$TIP" \
|
|
113
|
+
| head -40 \
|
|
114
|
+
| sed 's/\\/\\\\/g; s/"/\\"/g' \
|
|
115
|
+
| sed ':a;N;$!ba;s/\n/\\n/g')
|
|
116
|
+
TITLE="Sync $AHEAD commit(s) from GitHub"
|
|
117
|
+
BODY="Brings $AHEAD commit(s) from github.com/KrX3D/TizenTube up to \`$TIP\`.\\n\\nThis mirror is a backup; merging keeps it current without touching GitHub.\\n\\n$LIST"
|
|
118
|
+
|
|
119
|
+
printf '{"head":"%s","base":"%s","title":"%s","body":"%s"}' \
|
|
120
|
+
"$SYNC_BRANCH" "$BASE_BRANCH" "$TITLE" "$BODY" > /tmp/pr.json
|
|
121
|
+
|
|
122
|
+
HTTP=$(curl -s -o /tmp/pr-out.json -w '%{http_code}' \
|
|
123
|
+
-X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
124
|
+
"$API/pulls" --data @/tmp/pr.json)
|
|
125
|
+
echo "create pull request -> HTTP $HTTP"
|
|
126
|
+
if [ "$HTTP" = "409" ]; then
|
|
127
|
+
echo "Gitea says such a pull request already exists; the branch is updated."
|
|
128
|
+
exit 0
|
|
129
|
+
fi
|
|
130
|
+
if [ "$HTTP" != "201" ]; then
|
|
131
|
+
head -c 400 /tmp/pr-out.json
|
|
132
|
+
echo
|
|
133
|
+
echo "The branch $SYNC_BRANCH is updated regardless; the pull request can be opened by hand."
|
|
134
|
+
exit 1
|
|
135
|
+
fi
|
|
136
|
+
echo "Opened a pull request for $AHEAD commit(s)."
|
|
@@ -119,6 +119,8 @@ on:
|
|
|
119
119
|
paths-ignore:
|
|
120
120
|
- 'dist/**'
|
|
121
121
|
- 'package.json'
|
|
122
|
+
# Read by the Gitea mirror, ignored by GitHub Actions entirely.
|
|
123
|
+
- '.gitea/**'
|
|
122
124
|
push:
|
|
123
125
|
branches:
|
|
124
126
|
- main
|
|
@@ -130,6 +132,11 @@ on:
|
|
|
130
132
|
- 'LICENSE'
|
|
131
133
|
- 'AGENTS.md'
|
|
132
134
|
- 'README.md'
|
|
135
|
+
# The mirror's own workflow lives here. GitHub never runs it, and it is
|
|
136
|
+
# not in the published package, so a change to it must not publish a new
|
|
137
|
+
# version — which is exactly what it did once: #827 touched nothing but
|
|
138
|
+
# .gitea/workflows/sync-from-github.yml and bumped 1.30.710 to 1.30.720.
|
|
139
|
+
- '.gitea/**'
|
|
133
140
|
- 'package.json'
|
|
134
141
|
- 'tizen.log'
|
|
135
142
|
- 'dist/**'
|
|
@@ -222,56 +229,56 @@ jobs:
|
|
|
222
229
|
patch = 0;
|
|
223
230
|
}
|
|
224
231
|
|
|
225
|
-
// npm refuses forever to reuse a version number that was once
|
|
226
|
-
// published and later unpublished. The cleanup step in this same
|
|
227
|
-
// workflow unpublishes old releases, so 780 of the 857 numbers this
|
|
228
|
-
// package has ever used are permanently burned. Whenever
|
|
229
|
-
// package.json drops back into that range - a revert, a bad merge,
|
|
230
|
-
// an upstream sync - every run then fails with
|
|
231
|
-
// E400 Cannot publish over previously published version "x.y.z"
|
|
232
|
-
// and, because the bump is committed and pushed BEFORE publishing,
|
|
233
|
-
// main is left pinned on the burned number so every later run fails
|
|
234
|
-
// the same way. That is exactly what happened twice at 1.16.10.
|
|
235
|
-
//
|
|
236
|
-
// The registry time map lists every version ever used, live or not,
|
|
237
|
-
// so skipping past them makes the bump self-correcting.
|
|
238
|
-
//
|
|
239
|
-
// Wrapped in an async IIFE on purpose: this script is fed to `node -`
|
|
240
|
-
// on stdin, and a top-level await next to the require() above makes
|
|
241
|
-
// Node fail the whole script with ERR_AMBIGUOUS_MODULE_SYNTAX.
|
|
242
|
-
(async () => {
|
|
243
|
-
let used = null;
|
|
244
|
-
try {
|
|
245
|
-
const res = await fetch('https://registry.npmjs.org/' + pkg.name);
|
|
246
|
-
if (res.ok) {
|
|
247
|
-
const meta = await res.json();
|
|
248
|
-
const isSemver = (k) => /^[0-9]+[.][0-9]+[.][0-9]+$/.test(k);
|
|
249
|
-
used = new Set(Object.keys(meta.time || {}).filter(isSemver));
|
|
250
|
-
}
|
|
251
|
-
} catch (e) {
|
|
252
|
-
// Registry unreachable: fall through to the plain bump rather
|
|
253
|
-
// than blocking a release. A real collision still fails loudly
|
|
254
|
-
// at publish.
|
|
255
|
-
used = null;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
let newVer = `${major}.${minor}.${patch}`;
|
|
259
|
-
if (used) {
|
|
260
|
-
const firstChoice = newVer;
|
|
261
|
-
let guard = 0;
|
|
262
|
-
while (used.has(newVer) && guard++ < 500) {
|
|
263
|
-
patch += 10;
|
|
264
|
-
if (patch >= 1000) { minor += 1; patch = 0; }
|
|
265
|
-
newVer = `${major}.${minor}.${patch}`;
|
|
266
|
-
}
|
|
267
|
-
if (used.has(newVer)) throw new Error('No unused version found near ' + ver);
|
|
268
|
-
if (newVer !== firstChoice) console.log('Skipped burned version numbers: ' + firstChoice + ' -> ' + newVer);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
pkg.version = newVer;
|
|
272
|
-
fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + String.fromCharCode(10), 'utf8');
|
|
273
|
-
console.log('Bumped version: ' + ver + ' -> ' + newVer);
|
|
274
|
-
})();
|
|
232
|
+
// npm refuses forever to reuse a version number that was once
|
|
233
|
+
// published and later unpublished. The cleanup step in this same
|
|
234
|
+
// workflow unpublishes old releases, so 780 of the 857 numbers this
|
|
235
|
+
// package has ever used are permanently burned. Whenever
|
|
236
|
+
// package.json drops back into that range - a revert, a bad merge,
|
|
237
|
+
// an upstream sync - every run then fails with
|
|
238
|
+
// E400 Cannot publish over previously published version "x.y.z"
|
|
239
|
+
// and, because the bump is committed and pushed BEFORE publishing,
|
|
240
|
+
// main is left pinned on the burned number so every later run fails
|
|
241
|
+
// the same way. That is exactly what happened twice at 1.16.10.
|
|
242
|
+
//
|
|
243
|
+
// The registry time map lists every version ever used, live or not,
|
|
244
|
+
// so skipping past them makes the bump self-correcting.
|
|
245
|
+
//
|
|
246
|
+
// Wrapped in an async IIFE on purpose: this script is fed to `node -`
|
|
247
|
+
// on stdin, and a top-level await next to the require() above makes
|
|
248
|
+
// Node fail the whole script with ERR_AMBIGUOUS_MODULE_SYNTAX.
|
|
249
|
+
(async () => {
|
|
250
|
+
let used = null;
|
|
251
|
+
try {
|
|
252
|
+
const res = await fetch('https://registry.npmjs.org/' + pkg.name);
|
|
253
|
+
if (res.ok) {
|
|
254
|
+
const meta = await res.json();
|
|
255
|
+
const isSemver = (k) => /^[0-9]+[.][0-9]+[.][0-9]+$/.test(k);
|
|
256
|
+
used = new Set(Object.keys(meta.time || {}).filter(isSemver));
|
|
257
|
+
}
|
|
258
|
+
} catch (e) {
|
|
259
|
+
// Registry unreachable: fall through to the plain bump rather
|
|
260
|
+
// than blocking a release. A real collision still fails loudly
|
|
261
|
+
// at publish.
|
|
262
|
+
used = null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let newVer = `${major}.${minor}.${patch}`;
|
|
266
|
+
if (used) {
|
|
267
|
+
const firstChoice = newVer;
|
|
268
|
+
let guard = 0;
|
|
269
|
+
while (used.has(newVer) && guard++ < 500) {
|
|
270
|
+
patch += 10;
|
|
271
|
+
if (patch >= 1000) { minor += 1; patch = 0; }
|
|
272
|
+
newVer = `${major}.${minor}.${patch}`;
|
|
273
|
+
}
|
|
274
|
+
if (used.has(newVer)) throw new Error('No unused version found near ' + ver);
|
|
275
|
+
if (newVer !== firstChoice) console.log('Skipped burned version numbers: ' + firstChoice + ' -> ' + newVer);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
pkg.version = newVer;
|
|
279
|
+
fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + String.fromCharCode(10), 'utf8');
|
|
280
|
+
console.log('Bumped version: ' + ver + ' -> ' + newVer);
|
|
281
|
+
})();
|
|
275
282
|
NODE
|
|
276
283
|
|
|
277
284
|
- name: Show current version (old -> new)
|
|
@@ -413,35 +420,35 @@ jobs:
|
|
|
413
420
|
# --------------------
|
|
414
421
|
# PUBLISH
|
|
415
422
|
# --------------------
|
|
416
|
-
# --------------------
|
|
417
|
-
# Guard: never publish a tarball whose dist does not match its version
|
|
418
|
-
# --------------------
|
|
419
|
-
# Confirmed on 1.30.0: the tarball carried package.json 1.30.0 alongside a
|
|
420
|
-
# dist/userScript.js stamped 1.16.10, so every TV pulling the CDN got a
|
|
421
|
-
# build five releases old while the settings menu reported the new number.
|
|
422
|
-
#
|
|
423
|
-
# It came from re-running a failed run. A re-run replays the ORIGINAL
|
|
424
|
-
# commit, so it bumped and built at the old version, and then the
|
|
425
|
-
# `git rebase origin/main` below took main's newer package.json while
|
|
426
|
-
# keeping the dist it had already built. package.json and dist are only
|
|
427
|
-
# guaranteed to agree when a run builds them together, and nothing checked
|
|
428
|
-
# that they still did by the time publish happened.
|
|
429
|
-
- name: Verify dist matches package.json version
|
|
430
|
-
if: success()
|
|
431
|
-
run: |
|
|
432
|
-
set -euo pipefail
|
|
433
|
-
VER="$(node -p "require('./package.json').version")"
|
|
434
|
-
echo "package.json version: ${VER}"
|
|
435
|
-
for f in dist/userScript.js dist/service.js; do
|
|
436
|
-
test -f "$f" || { echo "::error::${f} is missing"; exit 1; }
|
|
437
|
-
done
|
|
438
|
-
if ! grep -qF "\"${VER}\"" dist/userScript.js; then
|
|
439
|
-
FOUND="$(grep -aoE '\"[0-9]+\.[0-9]+\.[0-9]+\"' dist/userScript.js | sort -u | head -3 | xargs echo)"
|
|
440
|
-
echo "::error::dist/userScript.js was not built from this version. package.json says ${VER}; the bundle contains ${FOUND:-no version string}. Re-run the workflow from a fresh push rather than re-running an old run, so the bump and the build happen together."
|
|
441
|
-
exit 1
|
|
442
|
-
fi
|
|
443
|
-
echo "dist/userScript.js carries ${VER}"
|
|
444
|
-
|
|
423
|
+
# --------------------
|
|
424
|
+
# Guard: never publish a tarball whose dist does not match its version
|
|
425
|
+
# --------------------
|
|
426
|
+
# Confirmed on 1.30.0: the tarball carried package.json 1.30.0 alongside a
|
|
427
|
+
# dist/userScript.js stamped 1.16.10, so every TV pulling the CDN got a
|
|
428
|
+
# build five releases old while the settings menu reported the new number.
|
|
429
|
+
#
|
|
430
|
+
# It came from re-running a failed run. A re-run replays the ORIGINAL
|
|
431
|
+
# commit, so it bumped and built at the old version, and then the
|
|
432
|
+
# `git rebase origin/main` below took main's newer package.json while
|
|
433
|
+
# keeping the dist it had already built. package.json and dist are only
|
|
434
|
+
# guaranteed to agree when a run builds them together, and nothing checked
|
|
435
|
+
# that they still did by the time publish happened.
|
|
436
|
+
- name: Verify dist matches package.json version
|
|
437
|
+
if: success()
|
|
438
|
+
run: |
|
|
439
|
+
set -euo pipefail
|
|
440
|
+
VER="$(node -p "require('./package.json').version")"
|
|
441
|
+
echo "package.json version: ${VER}"
|
|
442
|
+
for f in dist/userScript.js dist/service.js; do
|
|
443
|
+
test -f "$f" || { echo "::error::${f} is missing"; exit 1; }
|
|
444
|
+
done
|
|
445
|
+
if ! grep -qF "\"${VER}\"" dist/userScript.js; then
|
|
446
|
+
FOUND="$(grep -aoE '\"[0-9]+\.[0-9]+\.[0-9]+\"' dist/userScript.js | sort -u | head -3 | xargs echo)"
|
|
447
|
+
echo "::error::dist/userScript.js was not built from this version. package.json says ${VER}; the bundle contains ${FOUND:-no version string}. Re-run the workflow from a fresh push rather than re-running an old run, so the bump and the build happen together."
|
|
448
|
+
exit 1
|
|
449
|
+
fi
|
|
450
|
+
echo "dist/userScript.js carries ${VER}"
|
|
451
|
+
|
|
445
452
|
- name: Publish package to npm
|
|
446
453
|
if: success()
|
|
447
454
|
id: publish_npm
|
|
@@ -921,21 +928,32 @@ jobs:
|
|
|
921
928
|
|
|
922
929
|
# The purge above is fire-and-forget: jsDelivr answers "pending" and that
|
|
923
930
|
# is the end of it. Nothing checked the result, and a capture showed what
|
|
924
|
-
# that costs —
|
|
925
|
-
#
|
|
926
|
-
#
|
|
927
|
-
# TV was loading that, so a diagnostic merged that afternoon was simply
|
|
928
|
-
# not running, and its absence read as the feature being broken.
|
|
931
|
+
# that costs — a publish whose bundle did not reach the TVs for hours,
|
|
932
|
+
# which read as the new feature being broken rather than as never having
|
|
933
|
+
# arrived.
|
|
929
934
|
#
|
|
930
|
-
#
|
|
931
|
-
#
|
|
932
|
-
#
|
|
935
|
+
# What is worth checking changed when injector.js started pinning. This
|
|
936
|
+
# step used to read the unversioned path and fail the build over it,
|
|
937
|
+
# because that was the URL the TV fetched. The injector now asks the npm
|
|
938
|
+
# registry for the version and fetches an immutable @version path, and
|
|
939
|
+
# falls back to the unversioned URL only if the registry cannot be
|
|
940
|
+
# reached. So the two are no longer equally serious:
|
|
933
941
|
#
|
|
934
|
-
#
|
|
935
|
-
#
|
|
936
|
-
#
|
|
937
|
-
#
|
|
938
|
-
#
|
|
942
|
+
# @version path what every TV actually loads. Immutable, so if it
|
|
943
|
+
# does not carry this version then the publish itself
|
|
944
|
+
# is broken, not a cache. Hard failure.
|
|
945
|
+
#
|
|
946
|
+
# unversioned the fallback, and jsDelivr caches its resolution of
|
|
947
|
+
# alias "latest" for twelve hours (s-maxage=43200). It lags a
|
|
948
|
+
# publish by design, and a purge issued before npm's
|
|
949
|
+
# latest has propagated makes it worse by re-caching
|
|
950
|
+
# the old answer. A warning: failing here blocks the
|
|
951
|
+
# .wgt release over something that reaches no TV.
|
|
952
|
+
#
|
|
953
|
+
# Either way the version string has to be inside the bundle itself — a
|
|
954
|
+
# 200 proves nothing when the stale object is also a 200. jsDelivr serves
|
|
955
|
+
# from many points of presence and this reads whichever answers here, so
|
|
956
|
+
# it cannot prove every edge is current.
|
|
939
957
|
- name: Verify the CDN serves this version
|
|
940
958
|
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
941
959
|
env:
|
|
@@ -943,32 +961,72 @@ jobs:
|
|
|
943
961
|
run: |
|
|
944
962
|
set -euo pipefail
|
|
945
963
|
VER=$(cat /tmp/current_version.txt)
|
|
946
|
-
|
|
947
|
-
|
|
964
|
+
PINNED="https://cdn.jsdelivr.net/npm/${PKG}@${VER}/dist/userScript.js"
|
|
965
|
+
ALIAS="https://cdn.jsdelivr.net/npm/${PKG}/dist/userScript.js"
|
|
966
|
+
|
|
967
|
+
# Two things this got wrong before, both of which turned a correct
|
|
968
|
+
# verdict into an unreadable one.
|
|
969
|
+
#
|
|
970
|
+
# -a, because the bundle is minified and counts as binary: without it
|
|
971
|
+
# grep writes "binary file matches" to stderr and no match to stdout,
|
|
972
|
+
# which is why a run that had correctly found the alias stale could
|
|
973
|
+
# only report "an unknown version".
|
|
974
|
+
#
|
|
975
|
+
# And the major from this version rather than any three numbers. A
|
|
976
|
+
# bundle carries its dependencies' versions too, so the generic
|
|
977
|
+
# pattern plus "sort | tail -1" reported the highest-sorting of those
|
|
978
|
+
# — measured: 8.8.278 for a bundle whose own version was 1.30.710.
|
|
979
|
+
# Anchored to the major there is exactly one match, which is the
|
|
980
|
+
# package's own. All of them are printed rather than the last, so a
|
|
981
|
+
# bundle that somehow carried two cannot be described as having one.
|
|
982
|
+
MAJOR="${VER%%.*}"
|
|
983
|
+
served_version() {
|
|
984
|
+
grep -aoE "${MAJOR}\.[0-9]+\.[0-9]+" "$1" | sort -u | tr '\n' ' ' || true
|
|
985
|
+
}
|
|
948
986
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
987
|
+
echo "== the path every TV loads: ${PINNED}"
|
|
988
|
+
if ! curl -fsSL -H 'Cache-Control: no-cache' "$PINNED" -o /tmp/cdn_pinned.js; then
|
|
989
|
+
echo "::error::The CDN will not serve ${PINNED} at all, so the publish did not land."
|
|
990
|
+
exit 1
|
|
991
|
+
fi
|
|
992
|
+
if ! grep -aq "$VER" /tmp/cdn_pinned.js; then
|
|
993
|
+
echo "::error::${PINNED} exists but the bundle in it says $(served_version /tmp/cdn_pinned.js), not ${VER}. An immutable path cannot go stale, so this is a broken publish rather than a cache."
|
|
994
|
+
exit 1
|
|
995
|
+
fi
|
|
996
|
+
echo "the pinned path serves ${VER} — which is what injector.js injects."
|
|
997
|
+
|
|
998
|
+
# Then the alias, which is allowed to lag.
|
|
999
|
+
echo "== the fallback alias: ${ALIAS}"
|
|
1000
|
+
for i in $(seq 1 6); do
|
|
1001
|
+
if curl -fsSL -H 'Cache-Control: no-cache' "$ALIAS" -o /tmp/cdn_alias.js; then
|
|
1002
|
+
if grep -aq "$VER" /tmp/cdn_alias.js; then
|
|
1003
|
+
echo "attempt ${i}: the alias serves ${VER} too, so there is nothing left to wait for."
|
|
953
1004
|
exit 0
|
|
954
1005
|
fi
|
|
955
|
-
|
|
956
|
-
echo "attempt ${i}: still serving ${FOUND:-an unknown version}"
|
|
1006
|
+
echo "attempt ${i}: the alias still serves $(served_version /tmp/cdn_alias.js)"
|
|
957
1007
|
else
|
|
958
|
-
echo "attempt ${i}: the
|
|
1008
|
+
echo "attempt ${i}: the alias could not be read"
|
|
959
1009
|
fi
|
|
960
1010
|
|
|
961
|
-
# Ask again rather than only waiting
|
|
962
|
-
#
|
|
963
|
-
#
|
|
964
|
-
|
|
1011
|
+
# Ask again rather than only waiting, and this time watch the
|
|
1012
|
+
# request: the purge API is asynchronous and answers "pending", so
|
|
1013
|
+
# the previous blind sleep could not tell a finished purge from a
|
|
1014
|
+
# queued one.
|
|
1015
|
+
PURGE=$(curl -s -X POST -H 'Content-Type: application/json' \
|
|
965
1016
|
--data "{\"path\":[\"/npm/${PKG}/dist/userScript.js\",\"/npm/${PKG}/dist/service.js\",\"/npm/${PKG}@latest/dist/userScript.js\",\"/npm/${PKG}@latest/dist/service.js\"]}" \
|
|
966
|
-
https://purge.jsdelivr.net/
|
|
967
|
-
|
|
1017
|
+
https://purge.jsdelivr.net/ || true)
|
|
1018
|
+
PURGE_ID=$(printf '%s' "$PURGE" | sed -n 's/.*"id"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
|
|
1019
|
+
echo " purge requested: ${PURGE_ID:-no id returned}"
|
|
1020
|
+
for _ in $(seq 1 5); do
|
|
1021
|
+
sleep 6
|
|
1022
|
+
[ -n "$PURGE_ID" ] || break
|
|
1023
|
+
STATUS=$(curl -s "https://purge.jsdelivr.net/status/${PURGE_ID}" | sed -n 's/.*"status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
|
|
1024
|
+
echo " purge ${PURGE_ID}: ${STATUS:-unknown}"
|
|
1025
|
+
[ "$STATUS" = "pending" ] || break
|
|
1026
|
+
done
|
|
968
1027
|
done
|
|
969
1028
|
|
|
970
|
-
echo "::
|
|
971
|
-
exit 1
|
|
1029
|
+
echo "::warning::${ALIAS} is still serving $(served_version /tmp/cdn_alias.js) rather than ${VER}. That is the fallback path only: injector.js pins to ${PINNED}, verified above, and uses the alias just when the npm registry is unreachable. jsDelivr caches its idea of \"latest\" for up to twelve hours and this clears on its own; purge by hand at https://www.jsdelivr.com/tools/purge to hurry it."
|
|
972
1030
|
|
|
973
1031
|
- name: Cache purge complete
|
|
974
1032
|
if: steps.confirm_publish.outputs.confirmed == 'true'
|
|
@@ -82,6 +82,12 @@ on:
|
|
|
82
82
|
workflow_run:
|
|
83
83
|
workflows: ['Build, publish and cleanup old npm versions']
|
|
84
84
|
types: [completed]
|
|
85
|
+
# The branch the triggering run was on, which for a pull-request build is
|
|
86
|
+
# the feature branch. Without this, every pull request started a run here
|
|
87
|
+
# that the job-level `if` below immediately skipped: real runs, listed in
|
|
88
|
+
# the Actions tab, queued and accounted for, that could never do anything.
|
|
89
|
+
# Filtering at the trigger means they are never created.
|
|
90
|
+
branches: ['main']
|
|
85
91
|
push:
|
|
86
92
|
tags:
|
|
87
93
|
- 'v*.*.*'
|
|
@@ -100,8 +106,10 @@ jobs:
|
|
|
100
106
|
# Only proceed on a successful npm-publish run that was itself triggered by
|
|
101
107
|
# a push to main (build-publish-cleanup.yml's job is skipped entirely for
|
|
102
108
|
# pull_request runs, which can still report an overall "success" — checking
|
|
103
|
-
# .workflow_run.event too avoids firing off of those).
|
|
104
|
-
#
|
|
109
|
+
# .workflow_run.event too avoids firing off of those). The branches filter
|
|
110
|
+
# on the trigger now stops those runs from being created at all; this stays
|
|
111
|
+
# as the second check, since it also covers a publish run dispatched by
|
|
112
|
+
# hand off main. Tag pushes and manual dispatch always proceed.
|
|
105
113
|
if: >
|
|
106
114
|
github.event_name != 'workflow_run' ||
|
|
107
115
|
(github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push')
|
|
@@ -1,44 +1,55 @@
|
|
|
1
|
-
name: "CodeQL"
|
|
2
|
-
|
|
3
|
-
on:
|
|
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
|
-
|
|
1
|
+
name: "CodeQL"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Pushes to main and the weekly sweep, but deliberately not pull_request.
|
|
5
|
+
#
|
|
6
|
+
# Every change arrives through a pull request that is then fast-forwarded
|
|
7
|
+
# onto main, so analysing both meant analysing the same tree twice: half of
|
|
8
|
+
# this repository's CodeQL runs were duplicates of the other half.
|
|
9
|
+
#
|
|
10
|
+
# Keeping the push side rather than the pull_request side is the deliberate
|
|
11
|
+
# half of that choice. Code scanning treats analyses of the default branch
|
|
12
|
+
# as the state of the project, which is what the Security tab lists and what
|
|
13
|
+
# gets fixed from; a pull_request-only setup leaves that state to the weekly
|
|
14
|
+
# cron. The cost is that a newly introduced alert shows up just after a merge
|
|
15
|
+
# instead of just before, which is how the alerts in this repository have
|
|
16
|
+
# actually been found and fixed.
|
|
17
|
+
push:
|
|
18
|
+
branches: ["main"]
|
|
19
|
+
schedule:
|
|
20
|
+
- cron: '23 3 * * 1'
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
analyze:
|
|
24
|
+
name: Analyze (${{ matrix.language }})
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
permissions:
|
|
27
|
+
actions: read
|
|
28
|
+
contents: read
|
|
29
|
+
security-events: write
|
|
30
|
+
|
|
31
|
+
strategy:
|
|
32
|
+
fail-fast: false
|
|
33
|
+
matrix:
|
|
34
|
+
language: ["javascript-typescript"]
|
|
35
|
+
|
|
36
|
+
steps:
|
|
37
|
+
- name: Checkout repository
|
|
38
|
+
uses: actions/checkout@v6
|
|
39
|
+
|
|
40
|
+
- name: Initialize CodeQL
|
|
41
|
+
uses: github/codeql-action/init@v4
|
|
42
|
+
with:
|
|
43
|
+
languages: ${{ matrix.language }}
|
|
44
|
+
queries: security-extended,security-and-quality
|
|
45
|
+
config: |
|
|
46
|
+
paths-ignore:
|
|
47
|
+
- dist/**
|
|
48
|
+
|
|
49
|
+
- name: Autobuild
|
|
50
|
+
uses: github/codeql-action/autobuild@v4
|
|
51
|
+
|
|
52
|
+
- name: Perform CodeQL Analysis
|
|
53
|
+
uses: github/codeql-action/analyze@v4
|
|
54
|
+
with:
|
|
44
55
|
category: "/language:${{matrix.language}}"
|