create-grist-widget 0.2.21 → 0.2.23
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.
package/package.json
CHANGED
|
@@ -5,6 +5,19 @@ name: Deploy widget to GitHub Pages
|
|
|
5
5
|
# /<repo>/v<version>/ + mutable /<repo>/latest/.
|
|
6
6
|
# Rebuilt only when package.json's version has no v<version> dir yet, so
|
|
7
7
|
# re-pushing main without a version bump is a no-op deploy.
|
|
8
|
+
# A push that *creates* the main ref, authored by GitHub's own web-flow
|
|
9
|
+
# bot -- fired by "Use this template" copying this repo onto a brand-new
|
|
10
|
+
# ref -- is skipped entirely instead: it would otherwise publish
|
|
11
|
+
# whatever boilerplate version package.json happens to have checked in
|
|
12
|
+
# and permanently spend the first-release override before anyone's done
|
|
13
|
+
# real work. (Checking github.event.created alone isn't enough: a CLI
|
|
14
|
+
# scaffold's own first `git push -u origin main` also creates that ref
|
|
15
|
+
# for the first time, but is a real user's genuine first release and
|
|
16
|
+
# must not be skipped -- the web-flow committer check tells the two
|
|
17
|
+
# apart.) That skipped run still clears any foreign content the copy
|
|
18
|
+
# brought along (stray v<version>/ dirs, a root/latest/ still pointing
|
|
19
|
+
# at the source repo's own path) via `cleanup-foreign`, so root/latest/
|
|
20
|
+
# aren't left blank until the widget's real first release.
|
|
8
21
|
# - push to dev -> dev channel: mutable /<repo>/dev/
|
|
9
22
|
# with version.json + a self-reload snippet, for live review inside Grist.
|
|
10
23
|
#
|
|
@@ -91,7 +104,8 @@ jobs:
|
|
|
91
104
|
--site site --repo "$REPO_NAME" \
|
|
92
105
|
--event "${{ github.event_name }}" \
|
|
93
106
|
--ref "${{ github.ref }}" \
|
|
94
|
-
${{ github.event.inputs.force == 'true' && '--force' || '' }}
|
|
107
|
+
${{ github.event.inputs.force == 'true' && '--force' || '' }} \
|
|
108
|
+
${{ github.event.created == true && github.event.head_commit.committer.email == 'noreply@github.com' && '--created' || '' }})
|
|
95
109
|
echo "Plan: $PLAN"
|
|
96
110
|
node -e '
|
|
97
111
|
const p = JSON.parse(process.argv[1]);
|
|
@@ -99,6 +113,7 @@ jobs:
|
|
|
99
113
|
const out = process.env.GITHUB_OUTPUT;
|
|
100
114
|
fs.appendFileSync(out, `context=${p.context}\n`);
|
|
101
115
|
fs.appendFileSync(out, `skip=${p.skip ? "true" : "false"}\n`);
|
|
116
|
+
fs.appendFileSync(out, `reason=${p.reason || ""}\n`);
|
|
102
117
|
fs.appendFileSync(out, `version=${p.version || ""}\n`);
|
|
103
118
|
fs.appendFileSync(out, `base=${p.base}\n`);
|
|
104
119
|
fs.appendFileSync(out, `firstRelease=${p.firstRelease ? "true" : "false"}\n`);
|
|
@@ -123,9 +138,19 @@ jobs:
|
|
|
123
138
|
--sha "$SHA" --ref "${{ github.ref }}"
|
|
124
139
|
|
|
125
140
|
- name: Skip (already published)
|
|
126
|
-
if: steps.plan.outputs.skip == 'true'
|
|
141
|
+
if: steps.plan.outputs.skip == 'true' && steps.plan.outputs.reason != 'ref-created'
|
|
127
142
|
run: echo "== skip — v${{ steps.plan.outputs.version }} already published"
|
|
128
143
|
|
|
144
|
+
# The ref-created push never reaches Build/Place, so it's the only
|
|
145
|
+
# path where cleanupForeignVersionsIfFirstRelease (normally a side
|
|
146
|
+
# effect of Place) needs to run standalone -- otherwise foreign
|
|
147
|
+
# content from "Use this template" (stray v<version>/ dirs, a
|
|
148
|
+
# root/latest/ pointing at the source repo's own path) sits untouched
|
|
149
|
+
# until the widget's real first release.
|
|
150
|
+
- name: Clean foreign content (ref-created push published nothing)
|
|
151
|
+
if: steps.plan.outputs.reason == 'ref-created'
|
|
152
|
+
run: node scripts/deploy.mjs cleanup-foreign --site site --repo "$REPO_NAME"
|
|
153
|
+
|
|
129
154
|
- name: Finalize (versions.json + commit + push)
|
|
130
155
|
run: |
|
|
131
156
|
UPDATE_VERSIONS=""
|
package/template/README.md
CHANGED
|
@@ -111,6 +111,18 @@ automatically.
|
|
|
111
111
|
> only ever apply before your *first* genuine release — once one exists,
|
|
112
112
|
> they're permanently a no-op, so it's still safest to never manually
|
|
113
113
|
> re-seed `gh-pages` again after that point.
|
|
114
|
+
>
|
|
115
|
+
> "Use this template" also immediately fires this workflow once on its own,
|
|
116
|
+
> the moment the repo is created — before you've cloned it, let alone
|
|
117
|
+
> changed anything. That run is recognized (GitHub's own web-flow bot
|
|
118
|
+
> creating the `main` ref) and skipped entirely: nothing gets published,
|
|
119
|
+
> and it doesn't count as your first release, so the `0.0.1` override above
|
|
120
|
+
> still applies in full once you actually push real changes. If you also
|
|
121
|
+
> checked "Include all branches", that same skipped run still clears out
|
|
122
|
+
> whatever foreign content came along with it — stray `v<version>/` dirs,
|
|
123
|
+
> and a root/`latest/` still pointing at the *source* repo's own path
|
|
124
|
+
> (which would otherwise render blank until your real first release) —
|
|
125
|
+
> without needing to publish anything of its own to do so.
|
|
114
126
|
|
|
115
127
|
**One-time setup** (the workflow can't do this part for you):
|
|
116
128
|
|
|
@@ -19,15 +19,27 @@
|
|
|
19
19
|
//
|
|
20
20
|
// Subcommands:
|
|
21
21
|
// plan --site <dir> --repo <name> --event <push|workflow_dispatch>
|
|
22
|
-
// --ref <ref> [--force]
|
|
22
|
+
// --ref <ref> [--force] [--created]
|
|
23
23
|
// Prints JSON { context: "release"|"dev", version?, base, skip }.
|
|
24
24
|
// Release is skipped when v<version> already exists on gh-pages
|
|
25
25
|
// (idempotence: re-pushing main without a version bump is a no-op).
|
|
26
|
+
// --created additionally skips unconditionally, without consuming the
|
|
27
|
+
// first-release version override -- see plan()'s own comment. Callers
|
|
28
|
+
// must only pass --created for GitHub's own server-side "Use this
|
|
29
|
+
// template" push, never a real user push that merely happens to create
|
|
30
|
+
// a ref for the first time (e.g. a CLI scaffold's first `git push -u
|
|
31
|
+
// origin main`) -- see deploy.yml's wiring for the distinguishing check.
|
|
26
32
|
//
|
|
27
33
|
// place --site <dir> --repo <name> --channel <release|dev>
|
|
28
34
|
// [--version <v>] --dist <dir> --sha <sha> [--ref <ref>]
|
|
29
35
|
// Copies a freshly built dist into the gh-pages tree.
|
|
30
36
|
//
|
|
37
|
+
// cleanup-foreign --site <dir> --repo <name>
|
|
38
|
+
// Standalone entry point for `cleanupForeignVersionsIfFirstRelease` --
|
|
39
|
+
// used on a skipped ref-created push (see `plan`), which never reaches
|
|
40
|
+
// `place` (the only other caller of this cleanup) so foreign content
|
|
41
|
+
// from "Use this template" would otherwise sit untouched indefinitely.
|
|
42
|
+
//
|
|
31
43
|
// remove --site <dir>
|
|
32
44
|
// Removes dev/ from the gh-pages tree (retire the dev URL when the `dev`
|
|
33
45
|
// branch is deleted). Never touches a release or latest/.
|
|
@@ -101,7 +113,7 @@ function hasGenuineRelease(siteDir, repo) {
|
|
|
101
113
|
* genuinely published by this repo before (unless force), so re-pushing main
|
|
102
114
|
* without a version bump is a no-op.
|
|
103
115
|
*/
|
|
104
|
-
export function plan(siteDir, repo, event, ref, { force = false } = {}) {
|
|
116
|
+
export function plan(siteDir, repo, event, ref, { force = false, created = false } = {}) {
|
|
105
117
|
const isRelease = event === "workflow_dispatch" || ref === "refs/heads/main" || ref === "main"
|
|
106
118
|
if (!isRelease) {
|
|
107
119
|
return { context: "dev", base: basePathFor(repo, "dev") }
|
|
@@ -118,6 +130,28 @@ export function plan(siteDir, repo, event, ref, { force = false } = {}) {
|
|
|
118
130
|
const version = firstRelease ? "0.0.1" : pkg.version
|
|
119
131
|
if (!version) throw new Error("package.json has no version")
|
|
120
132
|
const versionDir = join(siteDir, `v${version}`)
|
|
133
|
+
// GitHub's "Use this template" copies the source repo's main branch onto a
|
|
134
|
+
// brand-new ref, which fires this same push-to-main event itself --
|
|
135
|
+
// before anyone has done any real work. Without this check, that event
|
|
136
|
+
// would consume the first-release override above on whatever unmodified
|
|
137
|
+
// boilerplate happens to be checked in, so the widget's *actual* first
|
|
138
|
+
// release (once someone merges real content) no longer counts as
|
|
139
|
+
// firstRelease and publishes under that boilerplate's version verbatim
|
|
140
|
+
// instead of a clean 0.0.1 -- found live (a monorepo widget moved into its
|
|
141
|
+
// own repo this way published its real first release as "v0.2.21").
|
|
142
|
+
// Skipping this event entirely (never placing anything, never touching
|
|
143
|
+
// gh-pages) keeps hasGenuineRelease() false, so the override survives
|
|
144
|
+
// intact for whenever a real release actually happens.
|
|
145
|
+
if (created && event === "push") {
|
|
146
|
+
return {
|
|
147
|
+
context: "release",
|
|
148
|
+
version,
|
|
149
|
+
base: basePathFor(repo, "release", version),
|
|
150
|
+
skip: true,
|
|
151
|
+
reason: "ref-created",
|
|
152
|
+
firstRelease,
|
|
153
|
+
}
|
|
154
|
+
}
|
|
121
155
|
const exists = isGenuineRelease(versionDir, repo)
|
|
122
156
|
return {
|
|
123
157
|
context: "release",
|
|
@@ -212,21 +246,28 @@ function replaceDir(dest, srcDist) {
|
|
|
212
246
|
|
|
213
247
|
/**
|
|
214
248
|
* If this repo has never genuinely published a release before (no
|
|
215
|
-
* v<version>/ directory whose showcase-meta.json matches this repo),
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
249
|
+
* v<version>/ directory whose showcase-meta.json matches this repo), *every*
|
|
250
|
+
* top-level entry except `dev/` (the mutable dev channel, legitimately this
|
|
251
|
+
* repo's own regardless of release history) and a small set of
|
|
252
|
+
* pipeline-managed files is provably inherited noise -- e.g. from copying
|
|
253
|
+
* this template repo including its gh-pages branch (GitHub's "Use this
|
|
254
|
+
* template" -> "Include all branches"): stray `v<version>/` directories,
|
|
255
|
+
* but also a root `index.html`/`latest/` still referencing the *source*
|
|
256
|
+
* repo's own base path (found live: a fresh copy's root and `latest/`
|
|
257
|
+
* pointed at `/grist-widget-template/v0.2.22/assets/...`, 404ing on this
|
|
258
|
+
* repo's own Pages site -- a blank page -- because the ref-created push
|
|
259
|
+
* that used to overwrite them with this repo's own build is now skipped
|
|
260
|
+
* entirely, see `plan()`). Safe to clear unconditionally: a repo with zero
|
|
261
|
+
* genuine releases can't have any of its own history to lose. Once a
|
|
262
|
+
* genuine release exists for this repo, buildVersionsManifest is non-empty
|
|
263
|
+
* and this is permanently a no-op.
|
|
224
264
|
*/
|
|
225
265
|
export function cleanupForeignVersionsIfFirstRelease(siteDir, repo) {
|
|
226
266
|
if (hasGenuineRelease(siteDir, repo)) return { cleaned: [] }
|
|
267
|
+
const PROTECTED = new Set([".nojekyll", "dev", "versions.json", ".git"])
|
|
227
268
|
const cleaned = []
|
|
228
269
|
for (const name of existsSync(siteDir) ? readdirSync(siteDir) : []) {
|
|
229
|
-
if (
|
|
270
|
+
if (PROTECTED.has(name)) continue
|
|
230
271
|
rmSync(join(siteDir, name), { recursive: true, force: true })
|
|
231
272
|
cleaned.push(name)
|
|
232
273
|
}
|
|
@@ -382,7 +423,10 @@ function main() {
|
|
|
382
423
|
|
|
383
424
|
switch (cmd) {
|
|
384
425
|
case "plan": {
|
|
385
|
-
const result = plan(args.site, args.repo, args.event, args.ref, {
|
|
426
|
+
const result = plan(args.site, args.repo, args.event, args.ref, {
|
|
427
|
+
force: !!args.force,
|
|
428
|
+
created: !!args.created,
|
|
429
|
+
})
|
|
386
430
|
process.stdout.write(JSON.stringify(result))
|
|
387
431
|
break
|
|
388
432
|
}
|
|
@@ -404,6 +448,11 @@ function main() {
|
|
|
404
448
|
console.log("remove:", JSON.stringify(res))
|
|
405
449
|
break
|
|
406
450
|
}
|
|
451
|
+
case "cleanup-foreign": {
|
|
452
|
+
const res = cleanupForeignVersionsIfFirstRelease(args.site, args.repo)
|
|
453
|
+
console.log("cleanup-foreign:", JSON.stringify(res))
|
|
454
|
+
break
|
|
455
|
+
}
|
|
407
456
|
case "finalize": {
|
|
408
457
|
const res = finalize({
|
|
409
458
|
siteDir: args.site,
|