hd-garden 0.8.0 → 0.8.2
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/.agents/skills/garden-ui/SKILL.md +2 -2
- package/.env.en.example +67 -0
- package/README.en.md +2 -2
- package/README.md +2 -2
- package/app/a2/[slug]/page.tsx +4 -3
- package/app/a2/page.tsx +4 -3
- package/app/about/page.tsx +8 -9
- package/app/admin/page.tsx +7 -6
- package/app/admin/preview/[...path]/page.tsx +2 -1
- package/app/admin/ui/blocks/page.tsx +2 -1
- package/app/admin/ui/catalog/page.tsx +2 -1
- package/app/admin/ui/evals/page.tsx +2 -1
- package/app/admin/ui/page.tsx +2 -1
- package/app/blog/[...path]/page.tsx +7 -6
- package/app/blog/page.tsx +4 -2
- package/app/columns/[column]/[...path]/page.tsx +8 -7
- package/app/columns/page.tsx +12 -8
- package/app/components/AdminUiShell.tsx +4 -3
- package/app/components/ArticleMeasure.tsx +6 -3
- package/app/components/ArticleReferences.tsx +4 -1
- package/app/components/ArticleTags.tsx +3 -2
- package/app/components/BlogArchive.tsx +20 -16
- package/app/components/Comments.tsx +16 -10
- package/app/components/ContentEmptyState.tsx +29 -28
- package/app/components/ExternalEmbed.tsx +15 -14
- package/app/components/GardenContentGuide.tsx +10 -2
- package/app/components/GardenDocsNav.tsx +4 -2
- package/app/components/GiscusComments.tsx +2 -1
- package/app/components/GithubLiveOverview.tsx +10 -8
- package/app/components/GithubProfile.tsx +31 -21
- package/app/components/HandbookLangSwitch.tsx +8 -4
- package/app/components/HandbookView.tsx +92 -9
- package/app/components/MarkdownArticle.tsx +31 -7
- package/app/components/MermaidDiagram.tsx +4 -3
- package/app/components/SiteChrome.tsx +3 -3
- package/app/components/SiteFooter.tsx +1 -1
- package/app/components/SiteHeader.tsx +13 -4
- package/app/components/ThoughtCard.tsx +16 -14
- package/app/components/UiBlock.tsx +3 -2
- package/app/components/Webmentions.tsx +11 -11
- package/app/components/WidgetChart.tsx +8 -6
- package/app/components/garden/FilePreview.tsx +2 -2
- package/app/components/garden/GardenBlock.tsx +7 -0
- package/app/components/garden/GardenFile.tsx +2 -2
- package/app/components/garden/RefDemo.tsx +62 -0
- package/app/components/garden/blocks.tsx +56 -8
- package/app/components/garden/patterns.tsx +497 -0
- package/app/garden/[...slug]/page.tsx +3 -2
- package/app/garden/en/page.tsx +7 -7
- package/app/garden/page.tsx +3 -2
- package/app/globals.css +49 -1
- package/app/lib/a2-meta.ts +26 -3
- package/app/lib/content.ts +2 -2
- package/app/lib/garden-docs-meta.ts +24 -0
- package/app/lib/github-id.mjs +8 -0
- package/app/lib/handbook-switch.mjs +12 -0
- package/app/lib/i18n.ts +401 -2
- package/app/lib/rehype-field-tables.mjs +47 -0
- package/app/lib/remark-a2.mjs +18 -8
- package/app/lib/remark-link-card.mjs +22 -0
- package/app/lib/remark-ref-demos.mjs +42 -0
- package/app/lib/tag-filter.ts +9 -2
- package/app/not-found.tsx +32 -4
- package/app/page.tsx +17 -14
- package/app/rss.xml/route.ts +2 -1
- package/app/styles/a2.css +338 -0
- package/app/styles/shell.css +15 -2
- package/app/tags/page.tsx +7 -5
- package/app/thoughts/[slug]/page.tsx +2 -1
- package/app/thoughts/page/[n]/page.tsx +1 -1
- package/app/thoughts/page.tsx +2 -1
- package/app/ui-parity/page.tsx +38 -22
- package/bin/garden.mjs +129 -19
- package/docs/handbook/ai-writing.md +2 -2
- package/docs/handbook/assets/reading-layout-en.svg +26 -0
- package/docs/handbook/components/card.md +43 -22
- package/docs/handbook/components/chart.md +10 -26
- package/docs/handbook/components/choice.md +42 -0
- package/docs/handbook/components/compare.md +32 -17
- package/docs/handbook/components/figure.md +33 -46
- package/docs/handbook/components/file.md +10 -15
- package/docs/handbook/components/html.md +10 -30
- package/docs/handbook/components/interactive.md +9 -35
- package/docs/handbook/components/list.md +65 -0
- package/docs/handbook/components/relations.md +95 -0
- package/docs/handbook/components/stat.md +10 -28
- package/docs/handbook/components/timeline.md +13 -28
- package/docs/handbook/components.md +210 -19
- package/docs/handbook/config.md +5 -3
- package/docs/handbook/deploy.md +1 -1
- package/docs/handbook/design.md +20 -12
- package/docs/handbook/en/ai-writing.md +2 -2
- package/docs/handbook/en/components/card.md +42 -21
- package/docs/handbook/en/components/chart.md +10 -26
- package/docs/handbook/en/components/choice.md +42 -0
- package/docs/handbook/en/components/compare.md +30 -15
- package/docs/handbook/en/components/figure.md +29 -42
- package/docs/handbook/en/components/file.md +9 -14
- package/docs/handbook/en/components/html.md +9 -29
- package/docs/handbook/en/components/interactive.md +8 -34
- package/docs/handbook/en/components/list.md +65 -0
- package/docs/handbook/en/components/relations.md +95 -0
- package/docs/handbook/en/components/stat.md +9 -27
- package/docs/handbook/en/components/timeline.md +9 -24
- package/docs/handbook/en/components.md +211 -19
- package/docs/handbook/en/config.md +32 -30
- package/docs/handbook/en/deploy.md +12 -12
- package/docs/handbook/en/design.md +19 -12
- package/docs/handbook/en/index.md +2 -2
- package/docs/handbook/en/reference/card.md +85 -0
- package/docs/handbook/en/reference/chart.md +68 -0
- package/docs/handbook/en/reference/choice.md +69 -0
- package/docs/handbook/en/reference/compare.md +59 -0
- package/docs/handbook/en/reference/figure.md +84 -0
- package/docs/handbook/en/reference/file/checklist.md +17 -0
- package/docs/handbook/en/reference/file.md +50 -0
- package/docs/handbook/en/reference/html.md +62 -0
- package/docs/handbook/en/reference/interactive.md +71 -0
- package/docs/handbook/en/reference/list.md +72 -0
- package/docs/handbook/en/reference/relations.md +113 -0
- package/docs/handbook/en/reference/stat.md +60 -0
- package/docs/handbook/en/reference/timeline.md +56 -0
- package/docs/handbook/en/reference.md +26 -0
- package/docs/handbook/en/start.md +2 -2
- package/docs/handbook/en/workflow.md +6 -5
- package/docs/handbook/en/writing.md +3 -2
- package/docs/handbook/index.md +1 -1
- package/docs/handbook/reference/card.md +85 -0
- package/docs/handbook/reference/chart.md +68 -0
- package/docs/handbook/reference/choice.md +69 -0
- package/docs/handbook/reference/compare.md +59 -0
- package/docs/handbook/reference/figure.md +84 -0
- package/docs/handbook/reference/file/checklist.md +17 -0
- package/docs/handbook/reference/file.md +50 -0
- package/docs/handbook/reference/html.md +62 -0
- package/docs/handbook/reference/interactive.md +71 -0
- package/docs/handbook/reference/list.md +72 -0
- package/docs/handbook/reference/relations.md +113 -0
- package/docs/handbook/reference/stat.md +60 -0
- package/docs/handbook/reference/timeline.md +56 -0
- package/docs/handbook/reference.md +26 -0
- package/docs/handbook/start.md +1 -1
- package/docs/handbook/workflow.md +6 -5
- package/docs/handbook/writing.md +3 -2
- package/next.config.ts +6 -0
- package/package.json +2 -1
- package/public/images/garden/ref-card-book.svg +1 -0
- package/public/images/garden/ref-card-lamp.svg +1 -0
- package/scripts/build-content.mjs +37 -16
- package/scripts/favicon-ico.mjs +9 -6
- package/scripts/file-preview.mjs +10 -7
- package/scripts/handbook-allowlist.mjs +18 -0
- package/scripts/handbook-facts.mjs +305 -11
- package/scripts/link-assets.mjs +7 -0
- package/scripts/new-post.mjs +18 -9
- package/scripts/prepare-pages-output.mjs +30 -18
- package/scripts/redirects.mjs +17 -6
- package/templates/garden-blocks.md +67 -0
- package/templates/garden-snippets.plist +61 -0
- package/templates/site/Makefile.en +45 -0
- package/templates/site/README.en.md +15 -0
- package/templates/site/site.config.en.yaml +55 -0
- package/templates/skills-en/garden-interactive-chart/SKILL.md +84 -0
- package/templates/skills-en/garden-interactive-chart/references/shell.html +49 -0
- package/templates/skills-en/garden-interactive-chart/references/style.md +61 -0
- package/templates/skills-en/garden-post-review/SKILL.md +63 -0
- package/templates/skills-en/garden-ui/SKILL.md +118 -0
- package/templates/workflows/pages.en.yml +195 -0
- package/templates/workflows/pages.yml +195 -0
- package/ui/garden/catalog.mjs +205 -4
- package/ui/garden/check.mjs +6 -0
- package/ui/garden/file-block.mjs +8 -7
- package/ui/garden/html-lang.mjs +73 -1
- package/ui/garden/markdown-links.mjs +7 -4
- package/ui/garden/parse.mjs +45 -0
- package/ui/garden/relations.mjs +252 -0
- package/ui/garden/search-index.mjs +6 -4
- package/ui/garden/source-icon.mjs +54 -0
- package/ui/parity-fixtures.mjs +77 -0
- package/ui/preview/dist/garden-ui.esm.js +41 -4
- package/ui/preview/dist/garden-ui.iife.js +41 -4
- package/ui/prompt/rules.md +28 -1
- package/ui/react/components/chart.tsx +1 -1
- package/ui/react/components/display.tsx +1 -1
- package/ui/react/lang.tsx +4 -0
- package/ui/react/parity.tsx +8 -6
- package/worker/index.ts +8 -2
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Garden chart visuals
|
|
2
|
+
|
|
3
|
+
Follow the tokens in the site's `app/globals.css`, not the dark green glow of whatever article you are referencing.
|
|
4
|
+
|
|
5
|
+
## Tokens
|
|
6
|
+
|
|
7
|
+
```css
|
|
8
|
+
:root {
|
|
9
|
+
--paper: #f8f8f6;
|
|
10
|
+
--paper-deep: #eeeeeb;
|
|
11
|
+
--card: #ffffff;
|
|
12
|
+
--ink: #202124;
|
|
13
|
+
--ink-soft: #34383d;
|
|
14
|
+
--muted: #65707d;
|
|
15
|
+
--faint: #a1a6ad;
|
|
16
|
+
--line: #deded9;
|
|
17
|
+
--line-strong: #c9c9c2;
|
|
18
|
+
--accent: #d82d48;
|
|
19
|
+
--accent-soft: #f9e8eb;
|
|
20
|
+
--new: #1f7a4d;
|
|
21
|
+
--new-soft: #e5f4ec;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
:root[data-theme="dark"] {
|
|
25
|
+
--paper: #171819;
|
|
26
|
+
--paper-deep: #202224;
|
|
27
|
+
--card: #1e2022;
|
|
28
|
+
--ink: #ededeb;
|
|
29
|
+
--ink-soft: #d8d8d4;
|
|
30
|
+
--muted: #a6adb6;
|
|
31
|
+
--faint: #747b84;
|
|
32
|
+
--line: #35383b;
|
|
33
|
+
--line-strong: #4b4f54;
|
|
34
|
+
--accent: #ff5d76;
|
|
35
|
+
--accent-soft: #3b242a;
|
|
36
|
+
--new: #5ee0a0;
|
|
37
|
+
--new-soft: #1a3a2c;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Use the accent on one or two focal points at most. Newly computed uses `--new`, waste or repetition uses `--accent`, cached uses `--muted`.
|
|
42
|
+
|
|
43
|
+
## Type and density
|
|
44
|
+
|
|
45
|
+
```css
|
|
46
|
+
font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
|
|
47
|
+
font-size: 13px;
|
|
48
|
+
line-height: 1.5;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Do not add Google Fonts. The text column is about 700px wide; draw for 640–680. Use multiples of 4 for control heights and spacing. No shadows, no large radii (4px at most on cells).
|
|
52
|
+
|
|
53
|
+
## Semantic colors
|
|
54
|
+
|
|
55
|
+
| Marker | Use |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| `new` / `append` | Cells newly computed at this beat |
|
|
58
|
+
| `waste` | Past tokens that are recomputed |
|
|
59
|
+
| `cached` | Read from the cache, not projected again |
|
|
60
|
+
| `idle` | Placeholder, visually gone |
|
|
61
|
+
| `repeat` / `unique` | Repeated vs unique in an inspect grid |
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: garden-post-review
|
|
3
|
+
description: >-
|
|
4
|
+
Reviews one specified Garden post in three steps: fix script-reported
|
|
5
|
+
structure errors, fix widgets with the chart skill, then suggest prose
|
|
6
|
+
improvements without editing. Use when the user asks to review or
|
|
7
|
+
proofread a Garden blog post.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Review a Garden post
|
|
11
|
+
|
|
12
|
+
Review only the post the user named. Do the three steps in order; each step sees the post as the previous step left it.
|
|
13
|
+
|
|
14
|
+
Before you start, run `npx garden ui scan content/posts/path.md`. If any block has `status` `uncompiled`, `stale` or `error`, handle it with [garden-ui](../garden-ui/SKILL.md) first, then go to step 1.
|
|
15
|
+
|
|
16
|
+
Hard check command (from the site root):
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx garden check content/posts/path.md
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
stdout is JSON. It passes only when `ok` is true. Do not re-check titles, dates or the reference list yourself.
|
|
23
|
+
|
|
24
|
+
## 1. The script reports errors; fix only those
|
|
25
|
+
|
|
26
|
+
Run `garden check`. If there are `errors`, change only those entries, then run the same command again until `ok` is true.
|
|
27
|
+
|
|
28
|
+
- Touch only the places the errors point to.
|
|
29
|
+
- Do not fix structural issues the script did not report.
|
|
30
|
+
- `references` is recommended further reading. It does not have to match the links in the body one to one. Do not add an entry because the body has a link, and do not remove one because the body never mentions it.
|
|
31
|
+
- `reference-heading`: move the flagged reference-list heading into `references` and delete the heading.
|
|
32
|
+
- If a widget file is missing, only fix a mistyped `src`. Do not build a new chart in this step.
|
|
33
|
+
|
|
34
|
+
## 2. Review and fix charts with the chart skill
|
|
35
|
+
|
|
36
|
+
Do this step only when the post has a `widget`. Read [garden-interactive-chart](../garden-interactive-chart/SKILL.md) first.
|
|
37
|
+
|
|
38
|
+
You may change the HTML in the same-name directory and the `caption` of its fence. Leave the surrounding prose alone. `caption` must be a one-sentence claim.
|
|
39
|
+
|
|
40
|
+
Run `garden check` again afterwards, until it passes.
|
|
41
|
+
|
|
42
|
+
Skip this step when there is no `widget`.
|
|
43
|
+
|
|
44
|
+
## 3. Read the whole post; suggestions only
|
|
45
|
+
|
|
46
|
+
`garden check` passes and the charts are fixed. Read the whole post. Do not change any file.
|
|
47
|
+
|
|
48
|
+
There is one goal: does the post start from first principles, stay consistent, and close the loop on one point? After reading, the reader should be able to say what this is, why it has to be this way, and how that "why" lands in a piece of practice. Practice means code, an incident, a measurement, or a derivation put to work. It verifies the same chain; it is not a separate tutorial.
|
|
49
|
+
|
|
50
|
+
First principles means reasoning up from facts, constraints or invariants that cannot be broken down further, not from "everyone does it this way" or a metaphor. After taking it apart, put it back together: listing the holes in existing approaches without reaching a conclusion is not finished. Analogies and industry practice may appear, but only as a foil for the derivation, never as a substitute for it.
|
|
51
|
+
|
|
52
|
+
Write a suggestion only when:
|
|
53
|
+
|
|
54
|
+
- The opening stands on a term, a convention or a metaphor, and the reader cannot see which fact constrains the problem
|
|
55
|
+
- A later mechanism, term or conclusion cannot be derived from the earlier facts, or the same word means different things in different places
|
|
56
|
+
- A point stops at "what it is": there is no why, or the why never lands in practice that can be checked
|
|
57
|
+
- The practice and the principles talk past each other and are not the same chain
|
|
58
|
+
- The post spreads across several neighbouring topics without bringing one of them home. One point explained fully beats many points touched lightly
|
|
59
|
+
- Numbers, comparisons or "usually" claims do not grow out of the derivation, the practice or a source
|
|
60
|
+
|
|
61
|
+
Each suggestion gives: the heading it is under, where the loop breaks, and how it could be closed. If there are none, say so. Do not turn the post into a problem–solution template, and do not ask for a "does not apply" note on every paragraph. If a translation already restates the original's derivation, do not ask the author to invent exercises.
|
|
62
|
+
|
|
63
|
+
This step must not change the post, the charts or the front matter.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: garden-ui
|
|
3
|
+
description: >-
|
|
4
|
+
Compiles the `garden` idea blocks in one Garden post into garden components
|
|
5
|
+
(garden interactive, or card / stat / compare / ... , or prose, or garden
|
|
6
|
+
html), fixes broken garden interactive blocks, and suggests where a post could
|
|
7
|
+
use interaction. Older intent / ui blocks are handled the same way. Use when
|
|
8
|
+
the user says compile this post / compile ideas / recompile <id> / where could
|
|
9
|
+
this post use interaction, or pastes a garden ui check fix prompt.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Compile Garden interactive blocks
|
|
13
|
+
|
|
14
|
+
The author writes a one-sentence idea in an unnamed `garden` fence. This skill turns it into `garden interactive` or another `garden` component. The interactive components and design rules are in the output of `npx garden ui prompt`. The purpose and examples of the 12 `garden` components are in `node_modules/hd-garden/templates/garden-blocks.md` (in the engine repo, `templates/garden-blocks.md`). Treat those two as the source of truth; never write components from memory.
|
|
15
|
+
|
|
16
|
+
When the author commits, the pre-commit hook runs the same `npx garden ui check`. The commands you use to find blocks, write them back and self-check are the same ones that stop the author's commit.
|
|
17
|
+
|
|
18
|
+
Run every command from the site root. If no post path was given, ask only for the path; do not scan the whole repo.
|
|
19
|
+
|
|
20
|
+
## Triggers and scope
|
|
21
|
+
|
|
22
|
+
| The user says | Blocks to handle |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| Compile this post: `<path>`, compile ideas | Blocks with status `uncompiled`, `stale` or `error` |
|
|
25
|
+
| Recompile `<id>` | Only this block, whatever its status |
|
|
26
|
+
| Pastes a `garden ui check` fix prompt | The blocks listed in the prompt |
|
|
27
|
+
| Where could this post use interaction | Read-only suggestion mode, see the end; do not edit the post |
|
|
28
|
+
|
|
29
|
+
## Workflow
|
|
30
|
+
|
|
31
|
+
1. Scan:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx garden ui scan content/posts/path.md
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
stdout is JSON. `lang` is `garden-idea` (an idea), `garden-interactive`, or the older `intent` / `ui`. Each block has `lang`, `id`, `status`, `startLine`, `hash` (hash of the whole fence, used as `--base` on write-back), `intentHash` (hash of the author's words), `intent` (the author's words), `caption`, `section` (the heading it sits under) and `diagnostics`. Do not find fences yourself with regular expressions.
|
|
38
|
+
|
|
39
|
+
2. Read the rules:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx garden ui prompt
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
It contains the component catalog, recipes and design rules. Follow the recipe skeletons; do not invent components or properties that are not in the catalog.
|
|
46
|
+
|
|
47
|
+
3. For each block, read the author's words and its section, then pick one:
|
|
48
|
+
- **Write it back as prose**: when a sentence, a table or a Mermaid diagram says it clearly.
|
|
49
|
+
- **Write `garden interactive`**: when the reader needs to drag, click or step through it to understand.
|
|
50
|
+
- **Write a `diff`**: when the idea follows a complete code block and is about "what changed since the last version". Write the diff the words describe as plain Markdown (just this one `diff` fence). Once written back it sits right after that code, and the page turns them into a "code / compare with previous" toggle. New lines in the diff must match the complete code above.
|
|
51
|
+
- **Write another `garden` component**: one or more resource cards (`card` / `cards`), a few metrics (`stat`), two approaches side by side or a good/bad comparison (`compare` / `verdict: good|bad`), a timeline (`timeline`), a static chart (`chart`), a labelled structure diagram (`figure`), a downloadable file (`file`), a relationship diagram of 3–6 elements (`relations`), a compact icon list or step list (`list`), or a choice card with two or three options (`choice`). Fields and validation rules are in `npx garden ui prompt` and `templates/garden-blocks.md`.
|
|
52
|
+
- **Write `garden html`**: canvas animation, audio, physics simulations and anything else the catalog cannot express. Write the HTML in the same-name directory following [garden-interactive-chart](../garden-interactive-chart/SKILL.md), and put the claim in `title`.
|
|
53
|
+
|
|
54
|
+
4. When writing `garden interactive`:
|
|
55
|
+
- Format: the fence header is `garden interactive #<id>`. Above `---` go `caption`, `intent` and an optional `expect`; below `---` goes the component tree from `npx garden ui prompt`.
|
|
56
|
+
- Put the author's words into `intent` verbatim; do not change a single character.
|
|
57
|
+
- `caption` takes the claim from the author's words. If there is no claim, write one from the section and say so in your reply.
|
|
58
|
+
- Known points in the words ("512 MiB at batch 1") go into `expect`.
|
|
59
|
+
- Data lives in the block. Use `Data` references only when the words mention a data file that already exists in the same-name directory.
|
|
60
|
+
- If a block gets too big, split it into two, each placed next to the paragraph it explains. Do not move it to another file.
|
|
61
|
+
|
|
62
|
+
5. Write each block back with `apply`, passing the new content on standard input:
|
|
63
|
+
|
|
64
|
+
````bash
|
|
65
|
+
npx garden ui apply content/posts/path.md --id <id> --base <hash> <<'GARDEN_UI'
|
|
66
|
+
```garden interactive #id
|
|
67
|
+
caption: ...
|
|
68
|
+
intent: |
|
|
69
|
+
...
|
|
70
|
+
---
|
|
71
|
+
...
|
|
72
|
+
```
|
|
73
|
+
GARDEN_UI
|
|
74
|
+
````
|
|
75
|
+
|
|
76
|
+
- Idea blocks have no id; locate them with `--intent-hash <intentHash>`, or `--at <startLine>` when the words repeat.
|
|
77
|
+
- The new content can be one `garden` component fence (interactive, card, stat, …) or plain Markdown (when writing it back as prose). Old `ui` blocks may also be written back in their original format.
|
|
78
|
+
- The new content must not contain any uncompiled ideas.
|
|
79
|
+
- On success stdout is `{"ok":true,...}`. On failure stderr is JSON; act on `code`:
|
|
80
|
+
- `apply-invalid`: the new content failed validation. Fix it from `diagnostics` and write again.
|
|
81
|
+
- `apply-base`: the block changed after the scan. Run `scan` again and use the new `hash`.
|
|
82
|
+
- `apply-not-found` / `apply-ambiguous`: the block was not found or not unique. Run `scan` again and locate it another way.
|
|
83
|
+
- Line numbers shift after each write-back, so run `scan` again before the next block.
|
|
84
|
+
|
|
85
|
+
6. When everything is written:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx garden ui check content/posts/path.md
|
|
89
|
+
npx garden check content/posts/path.md
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The first is the pre-commit check and must pass; the second must report `ok` true. If the same block fails three times in a row, stop and report the diagnostics to the user as they are.
|
|
93
|
+
|
|
94
|
+
7. Reply with a table:
|
|
95
|
+
|
|
96
|
+
| id | choice | recipe | assumptions | expect |
|
|
97
|
+
| --- | --- | --- | --- | --- |
|
|
98
|
+
| kv-memory | garden interactive | param bench | default sequence is 4K | 512 MiB at batch 1 |
|
|
99
|
+
|
|
100
|
+
"Assumptions" lists what the author's words did not say and you decided for them (defaults, ranges, an added caption). Write "none" if there are none.
|
|
101
|
+
|
|
102
|
+
## Don't
|
|
103
|
+
|
|
104
|
+
- Edit the post file directly. The post changes only through `apply`; HTML files referenced by `garden html` may be created directly.
|
|
105
|
+
- Invent numbers the author did not give. If a number is needed and missing, compute it from a formula in the words or ask the author.
|
|
106
|
+
- Use remote URLs (images, scripts, data).
|
|
107
|
+
- Change prose outside the target blocks.
|
|
108
|
+
|
|
109
|
+
## Suggestion mode: where could this post use interaction
|
|
110
|
+
|
|
111
|
+
Read-only; do not edit the post. Run `npx garden ui prompt` to read the design rules, then read the whole post and pick paragraphs that plain text or a static image cannot explain well:
|
|
112
|
+
|
|
113
|
+
- A formula or numbers that change with parameters (param bench, converter)
|
|
114
|
+
- A multi-step process (stepper, flow)
|
|
115
|
+
- The difference between two approaches (comparison)
|
|
116
|
+
- A set of cells, bytes or a memory layout (grid)
|
|
117
|
+
|
|
118
|
+
For each, give: the section, why text is not enough, and a draft `garden` idea block that can be pasted right after that paragraph. The draft says only what the reader does and sees, plus numbers already in the post; do not name components. Five at most; if none fit, say so.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
name: Verify and publish blog
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: publish-blog
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
if: github.event.repository.name == format('{0}.github.io', github.repository_owner) || vars.SITE_URL != '' || vars.PAGES_REPOSITORY != ''
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v7
|
|
21
|
+
|
|
22
|
+
- uses: actions/setup-node@v7
|
|
23
|
+
with:
|
|
24
|
+
node-version: 22
|
|
25
|
+
cache: npm
|
|
26
|
+
|
|
27
|
+
- run: npm ci
|
|
28
|
+
|
|
29
|
+
- name: Resolve the public URL
|
|
30
|
+
env:
|
|
31
|
+
SITE_URL_OVERRIDE: ${{ vars.SITE_URL }}
|
|
32
|
+
ADMIN_URL_OVERRIDE: ${{ vars.ADMIN_URL }}
|
|
33
|
+
GISCUS_REPO: ${{ vars.GISCUS_REPO }}
|
|
34
|
+
GISCUS_REPO_ID: ${{ vars.GISCUS_REPO_ID }}
|
|
35
|
+
GISCUS_CATEGORY: ${{ vars.GISCUS_CATEGORY }}
|
|
36
|
+
GISCUS_CATEGORY_ID: ${{ vars.GISCUS_CATEGORY_ID }}
|
|
37
|
+
GISCUS_DISABLED: ${{ vars.GISCUS_DISABLED }}
|
|
38
|
+
WEBMENTION_IO_DOMAIN: ${{ vars.WEBMENTION_IO_DOMAIN }}
|
|
39
|
+
ANALYTICS_DOMAIN: ${{ vars.ANALYTICS_DOMAIN }}
|
|
40
|
+
ANALYTICS_SCRIPT: ${{ vars.ANALYTICS_SCRIPT }}
|
|
41
|
+
run: |
|
|
42
|
+
owner="$GITHUB_REPOSITORY_OWNER"
|
|
43
|
+
default_url="https://$owner.github.io"
|
|
44
|
+
giscus_ready=1
|
|
45
|
+
if [ -z "$GISCUS_REPO" ] || [ "$GISCUS_REPO" = "owner/repository" ]; then giscus_ready=0; fi
|
|
46
|
+
if [ -z "$GISCUS_REPO_ID" ] || [ "$GISCUS_REPO_ID" = "R_xxxxxxxxxx" ]; then giscus_ready=0; fi
|
|
47
|
+
if [ -z "$GISCUS_CATEGORY" ]; then giscus_ready=0; fi
|
|
48
|
+
if [ -z "$GISCUS_CATEGORY_ID" ] || [ "$GISCUS_CATEGORY_ID" = "DIC_xxxxxxxxxx" ]; then giscus_ready=0; fi
|
|
49
|
+
if [ "$giscus_ready" != 1 ]; then
|
|
50
|
+
if [ "$GISCUS_DISABLED" = "1" ]; then
|
|
51
|
+
GISCUS_REPO=
|
|
52
|
+
GISCUS_REPO_ID=
|
|
53
|
+
GISCUS_CATEGORY=
|
|
54
|
+
GISCUS_CATEGORY_ID=
|
|
55
|
+
echo "GISCUS_DISABLED=1; building without comments."
|
|
56
|
+
else
|
|
57
|
+
echo "Comments are not configured yet; stopping the build."
|
|
58
|
+
echo "1. Prepare a public GitHub repository and enable Discussions."
|
|
59
|
+
echo "2. Open https://giscus.app, install the Giscus App, and pick the repository and category."
|
|
60
|
+
echo "3. Under Settings -> Secrets and variables -> Actions -> Variables, set:"
|
|
61
|
+
echo " GISCUS_REPO, GISCUS_REPO_ID, GISCUS_CATEGORY, GISCUS_CATEGORY_ID"
|
|
62
|
+
echo "To build without comments, set GISCUS_DISABLED to 1. Empty values and the placeholder owner/repository will not pass."
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
fi
|
|
66
|
+
{
|
|
67
|
+
echo "SITE_URL=${SITE_URL_OVERRIDE:-$default_url}"
|
|
68
|
+
echo "NEXT_PUBLIC_SITE_URL=${SITE_URL_OVERRIDE:-$default_url}"
|
|
69
|
+
echo "ADMIN_URL=$ADMIN_URL_OVERRIDE"
|
|
70
|
+
echo "GISCUS_REPO=$GISCUS_REPO"
|
|
71
|
+
echo "GISCUS_REPO_ID=$GISCUS_REPO_ID"
|
|
72
|
+
echo "GISCUS_CATEGORY=$GISCUS_CATEGORY"
|
|
73
|
+
echo "GISCUS_CATEGORY_ID=$GISCUS_CATEGORY_ID"
|
|
74
|
+
echo "NEXT_PUBLIC_GISCUS_REPO=$GISCUS_REPO"
|
|
75
|
+
echo "NEXT_PUBLIC_GISCUS_REPO_ID=$GISCUS_REPO_ID"
|
|
76
|
+
echo "NEXT_PUBLIC_GISCUS_CATEGORY=$GISCUS_CATEGORY"
|
|
77
|
+
echo "NEXT_PUBLIC_GISCUS_CATEGORY_ID=$GISCUS_CATEGORY_ID"
|
|
78
|
+
echo "WEBMENTION_IO_DOMAIN=$WEBMENTION_IO_DOMAIN"
|
|
79
|
+
echo "NEXT_PUBLIC_ANALYTICS_DOMAIN=$ANALYTICS_DOMAIN"
|
|
80
|
+
echo "NEXT_PUBLIC_ANALYTICS_SCRIPT=$ANALYTICS_SCRIPT"
|
|
81
|
+
echo "STATIC_EXPORT=1"
|
|
82
|
+
} >> "$GITHUB_ENV"
|
|
83
|
+
|
|
84
|
+
- name: Build the public site
|
|
85
|
+
env:
|
|
86
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
87
|
+
run: npm run build
|
|
88
|
+
|
|
89
|
+
- name: Validate the static output
|
|
90
|
+
run: npm run pages:validate
|
|
91
|
+
|
|
92
|
+
- name: Configure GitHub Pages
|
|
93
|
+
if: ${{ vars.PAGES_REPOSITORY == '' }}
|
|
94
|
+
uses: actions/configure-pages@v6
|
|
95
|
+
|
|
96
|
+
- name: Upload the GitHub Pages artifact
|
|
97
|
+
if: ${{ vars.PAGES_REPOSITORY == '' }}
|
|
98
|
+
uses: actions/upload-pages-artifact@v5
|
|
99
|
+
with:
|
|
100
|
+
path: dist/client
|
|
101
|
+
|
|
102
|
+
- name: Upload the public-repository artifact
|
|
103
|
+
if: ${{ vars.PAGES_REPOSITORY != '' }}
|
|
104
|
+
uses: actions/upload-artifact@v7
|
|
105
|
+
with:
|
|
106
|
+
name: static-site
|
|
107
|
+
path: dist/client
|
|
108
|
+
include-hidden-files: true
|
|
109
|
+
if-no-files-found: error
|
|
110
|
+
retention-days: 1
|
|
111
|
+
|
|
112
|
+
deploy-pages:
|
|
113
|
+
if: ${{ vars.PAGES_REPOSITORY == '' }}
|
|
114
|
+
needs: build
|
|
115
|
+
permissions:
|
|
116
|
+
pages: write
|
|
117
|
+
id-token: write
|
|
118
|
+
environment:
|
|
119
|
+
name: github-pages
|
|
120
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
121
|
+
runs-on: ubuntu-latest
|
|
122
|
+
steps:
|
|
123
|
+
- name: Deploy the GitHub Pages artifact
|
|
124
|
+
id: deployment
|
|
125
|
+
uses: actions/deploy-pages@v5
|
|
126
|
+
|
|
127
|
+
publish-repository:
|
|
128
|
+
if: ${{ vars.PAGES_REPOSITORY != '' }}
|
|
129
|
+
needs: build
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/checkout@v7
|
|
133
|
+
|
|
134
|
+
- uses: actions/setup-node@v7
|
|
135
|
+
with:
|
|
136
|
+
node-version: 22
|
|
137
|
+
cache: npm
|
|
138
|
+
|
|
139
|
+
- run: npm ci
|
|
140
|
+
|
|
141
|
+
- name: Check the split-repository configuration
|
|
142
|
+
env:
|
|
143
|
+
PAGES_DEPLOY_KEY: ${{ secrets.PAGES_DEPLOY_KEY }}
|
|
144
|
+
TARGET_REPOSITORY: ${{ vars.PAGES_REPOSITORY }}
|
|
145
|
+
run: |
|
|
146
|
+
test -n "$PAGES_DEPLOY_KEY" || { echo "Missing PAGES_DEPLOY_KEY secret"; exit 1; }
|
|
147
|
+
[[ "$TARGET_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] || {
|
|
148
|
+
echo "Invalid PAGES_REPOSITORY format"
|
|
149
|
+
exit 1
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
- uses: actions/download-artifact@v8
|
|
153
|
+
with:
|
|
154
|
+
name: static-site
|
|
155
|
+
path: static-site
|
|
156
|
+
|
|
157
|
+
- name: Check out the public output repository
|
|
158
|
+
uses: actions/checkout@v7
|
|
159
|
+
with:
|
|
160
|
+
repository: ${{ vars.PAGES_REPOSITORY }}
|
|
161
|
+
ssh-key: ${{ secrets.PAGES_DEPLOY_KEY }}
|
|
162
|
+
path: pages-repository
|
|
163
|
+
fetch-depth: 1
|
|
164
|
+
|
|
165
|
+
- name: Start a clean rolling deployment
|
|
166
|
+
working-directory: pages-repository
|
|
167
|
+
env:
|
|
168
|
+
TARGET_REPOSITORY: ${{ vars.PAGES_REPOSITORY }}
|
|
169
|
+
run: |
|
|
170
|
+
expected_remote="git@github.com:$TARGET_REPOSITORY.git"
|
|
171
|
+
actual_remote="$(git remote get-url origin)"
|
|
172
|
+
test "$actual_remote" = "$expected_remote" || {
|
|
173
|
+
echo "Refusing to publish to unexpected repository: $actual_remote"
|
|
174
|
+
exit 1
|
|
175
|
+
}
|
|
176
|
+
echo "PAGES_PREVIOUS_TREE=$(git rev-parse 'HEAD^{tree}')" >> "$GITHUB_ENV"
|
|
177
|
+
git checkout --orphan pages-deploy
|
|
178
|
+
git rm -q -r -f .
|
|
179
|
+
|
|
180
|
+
- name: Prepare generated-only repository contents
|
|
181
|
+
run: npx garden pages:prepare static-site pages-repository
|
|
182
|
+
|
|
183
|
+
- name: Publish the rolling deployment commit
|
|
184
|
+
working-directory: pages-repository
|
|
185
|
+
run: |
|
|
186
|
+
git config user.name "github-actions[bot]"
|
|
187
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
188
|
+
git add -A
|
|
189
|
+
new_tree="$(git write-tree)"
|
|
190
|
+
if [ "$new_tree" = "$PAGES_PREVIOUS_TREE" ]; then
|
|
191
|
+
echo "Static output is unchanged; skipping publish"
|
|
192
|
+
exit 0
|
|
193
|
+
fi
|
|
194
|
+
git commit -m "Deploy ${GITHUB_SHA}"
|
|
195
|
+
git push --force origin HEAD:main
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
name: Verify and publish blog
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: publish-blog
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
if: github.event.repository.name == format('{0}.github.io', github.repository_owner) || vars.SITE_URL != '' || vars.PAGES_REPOSITORY != ''
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v7
|
|
21
|
+
|
|
22
|
+
- uses: actions/setup-node@v7
|
|
23
|
+
with:
|
|
24
|
+
node-version: 22
|
|
25
|
+
cache: npm
|
|
26
|
+
|
|
27
|
+
- run: npm ci
|
|
28
|
+
|
|
29
|
+
- name: Resolve the public URL
|
|
30
|
+
env:
|
|
31
|
+
SITE_URL_OVERRIDE: ${{ vars.SITE_URL }}
|
|
32
|
+
ADMIN_URL_OVERRIDE: ${{ vars.ADMIN_URL }}
|
|
33
|
+
GISCUS_REPO: ${{ vars.GISCUS_REPO }}
|
|
34
|
+
GISCUS_REPO_ID: ${{ vars.GISCUS_REPO_ID }}
|
|
35
|
+
GISCUS_CATEGORY: ${{ vars.GISCUS_CATEGORY }}
|
|
36
|
+
GISCUS_CATEGORY_ID: ${{ vars.GISCUS_CATEGORY_ID }}
|
|
37
|
+
GISCUS_DISABLED: ${{ vars.GISCUS_DISABLED }}
|
|
38
|
+
WEBMENTION_IO_DOMAIN: ${{ vars.WEBMENTION_IO_DOMAIN }}
|
|
39
|
+
ANALYTICS_DOMAIN: ${{ vars.ANALYTICS_DOMAIN }}
|
|
40
|
+
ANALYTICS_SCRIPT: ${{ vars.ANALYTICS_SCRIPT }}
|
|
41
|
+
run: |
|
|
42
|
+
owner="$GITHUB_REPOSITORY_OWNER"
|
|
43
|
+
default_url="https://$owner.github.io"
|
|
44
|
+
giscus_ready=1
|
|
45
|
+
if [ -z "$GISCUS_REPO" ] || [ "$GISCUS_REPO" = "owner/repository" ]; then giscus_ready=0; fi
|
|
46
|
+
if [ -z "$GISCUS_REPO_ID" ] || [ "$GISCUS_REPO_ID" = "R_xxxxxxxxxx" ]; then giscus_ready=0; fi
|
|
47
|
+
if [ -z "$GISCUS_CATEGORY" ]; then giscus_ready=0; fi
|
|
48
|
+
if [ -z "$GISCUS_CATEGORY_ID" ] || [ "$GISCUS_CATEGORY_ID" = "DIC_xxxxxxxxxx" ]; then giscus_ready=0; fi
|
|
49
|
+
if [ "$giscus_ready" != 1 ]; then
|
|
50
|
+
if [ "$GISCUS_DISABLED" = "1" ]; then
|
|
51
|
+
GISCUS_REPO=
|
|
52
|
+
GISCUS_REPO_ID=
|
|
53
|
+
GISCUS_CATEGORY=
|
|
54
|
+
GISCUS_CATEGORY_ID=
|
|
55
|
+
echo "GISCUS_DISABLED=1,本次构建不开放评论。"
|
|
56
|
+
else
|
|
57
|
+
echo "评论还没有配置,构建已停止。"
|
|
58
|
+
echo "1. 准备一个公开 GitHub 仓库,并开启 Discussions。"
|
|
59
|
+
echo "2. 打开 https://giscus.app/zh-CN ,安装 Giscus App,选中该仓库和分类。"
|
|
60
|
+
echo "3. 在 Settings → Secrets and variables → Actions → Variables 写入:"
|
|
61
|
+
echo " GISCUS_REPO、GISCUS_REPO_ID、GISCUS_CATEGORY、GISCUS_CATEGORY_ID"
|
|
62
|
+
echo "确定不开放评论时,把 GISCUS_DISABLED 设为 1。留空和示例值 owner/repository 都不会通过。"
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
fi
|
|
66
|
+
{
|
|
67
|
+
echo "SITE_URL=${SITE_URL_OVERRIDE:-$default_url}"
|
|
68
|
+
echo "NEXT_PUBLIC_SITE_URL=${SITE_URL_OVERRIDE:-$default_url}"
|
|
69
|
+
echo "ADMIN_URL=$ADMIN_URL_OVERRIDE"
|
|
70
|
+
echo "GISCUS_REPO=$GISCUS_REPO"
|
|
71
|
+
echo "GISCUS_REPO_ID=$GISCUS_REPO_ID"
|
|
72
|
+
echo "GISCUS_CATEGORY=$GISCUS_CATEGORY"
|
|
73
|
+
echo "GISCUS_CATEGORY_ID=$GISCUS_CATEGORY_ID"
|
|
74
|
+
echo "NEXT_PUBLIC_GISCUS_REPO=$GISCUS_REPO"
|
|
75
|
+
echo "NEXT_PUBLIC_GISCUS_REPO_ID=$GISCUS_REPO_ID"
|
|
76
|
+
echo "NEXT_PUBLIC_GISCUS_CATEGORY=$GISCUS_CATEGORY"
|
|
77
|
+
echo "NEXT_PUBLIC_GISCUS_CATEGORY_ID=$GISCUS_CATEGORY_ID"
|
|
78
|
+
echo "WEBMENTION_IO_DOMAIN=$WEBMENTION_IO_DOMAIN"
|
|
79
|
+
echo "NEXT_PUBLIC_ANALYTICS_DOMAIN=$ANALYTICS_DOMAIN"
|
|
80
|
+
echo "NEXT_PUBLIC_ANALYTICS_SCRIPT=$ANALYTICS_SCRIPT"
|
|
81
|
+
echo "STATIC_EXPORT=1"
|
|
82
|
+
} >> "$GITHUB_ENV"
|
|
83
|
+
|
|
84
|
+
- name: Build the public site
|
|
85
|
+
env:
|
|
86
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
87
|
+
run: npm run build
|
|
88
|
+
|
|
89
|
+
- name: Validate the static output
|
|
90
|
+
run: npm run pages:validate
|
|
91
|
+
|
|
92
|
+
- name: Configure GitHub Pages
|
|
93
|
+
if: ${{ vars.PAGES_REPOSITORY == '' }}
|
|
94
|
+
uses: actions/configure-pages@v6
|
|
95
|
+
|
|
96
|
+
- name: Upload the GitHub Pages artifact
|
|
97
|
+
if: ${{ vars.PAGES_REPOSITORY == '' }}
|
|
98
|
+
uses: actions/upload-pages-artifact@v5
|
|
99
|
+
with:
|
|
100
|
+
path: dist/client
|
|
101
|
+
|
|
102
|
+
- name: Upload the public-repository artifact
|
|
103
|
+
if: ${{ vars.PAGES_REPOSITORY != '' }}
|
|
104
|
+
uses: actions/upload-artifact@v7
|
|
105
|
+
with:
|
|
106
|
+
name: static-site
|
|
107
|
+
path: dist/client
|
|
108
|
+
include-hidden-files: true
|
|
109
|
+
if-no-files-found: error
|
|
110
|
+
retention-days: 1
|
|
111
|
+
|
|
112
|
+
deploy-pages:
|
|
113
|
+
if: ${{ vars.PAGES_REPOSITORY == '' }}
|
|
114
|
+
needs: build
|
|
115
|
+
permissions:
|
|
116
|
+
pages: write
|
|
117
|
+
id-token: write
|
|
118
|
+
environment:
|
|
119
|
+
name: github-pages
|
|
120
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
121
|
+
runs-on: ubuntu-latest
|
|
122
|
+
steps:
|
|
123
|
+
- name: Deploy the GitHub Pages artifact
|
|
124
|
+
id: deployment
|
|
125
|
+
uses: actions/deploy-pages@v5
|
|
126
|
+
|
|
127
|
+
publish-repository:
|
|
128
|
+
if: ${{ vars.PAGES_REPOSITORY != '' }}
|
|
129
|
+
needs: build
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/checkout@v7
|
|
133
|
+
|
|
134
|
+
- uses: actions/setup-node@v7
|
|
135
|
+
with:
|
|
136
|
+
node-version: 22
|
|
137
|
+
cache: npm
|
|
138
|
+
|
|
139
|
+
- run: npm ci
|
|
140
|
+
|
|
141
|
+
- name: Check the split-repository configuration
|
|
142
|
+
env:
|
|
143
|
+
PAGES_DEPLOY_KEY: ${{ secrets.PAGES_DEPLOY_KEY }}
|
|
144
|
+
TARGET_REPOSITORY: ${{ vars.PAGES_REPOSITORY }}
|
|
145
|
+
run: |
|
|
146
|
+
test -n "$PAGES_DEPLOY_KEY" || { echo "缺少 PAGES_DEPLOY_KEY Secret"; exit 1; }
|
|
147
|
+
[[ "$TARGET_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] || {
|
|
148
|
+
echo "PAGES_REPOSITORY 格式无效"
|
|
149
|
+
exit 1
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
- uses: actions/download-artifact@v8
|
|
153
|
+
with:
|
|
154
|
+
name: static-site
|
|
155
|
+
path: static-site
|
|
156
|
+
|
|
157
|
+
- name: Check out the public output repository
|
|
158
|
+
uses: actions/checkout@v7
|
|
159
|
+
with:
|
|
160
|
+
repository: ${{ vars.PAGES_REPOSITORY }}
|
|
161
|
+
ssh-key: ${{ secrets.PAGES_DEPLOY_KEY }}
|
|
162
|
+
path: pages-repository
|
|
163
|
+
fetch-depth: 1
|
|
164
|
+
|
|
165
|
+
- name: Start a clean rolling deployment
|
|
166
|
+
working-directory: pages-repository
|
|
167
|
+
env:
|
|
168
|
+
TARGET_REPOSITORY: ${{ vars.PAGES_REPOSITORY }}
|
|
169
|
+
run: |
|
|
170
|
+
expected_remote="git@github.com:$TARGET_REPOSITORY.git"
|
|
171
|
+
actual_remote="$(git remote get-url origin)"
|
|
172
|
+
test "$actual_remote" = "$expected_remote" || {
|
|
173
|
+
echo "拒绝发布到非目标仓库:$actual_remote"
|
|
174
|
+
exit 1
|
|
175
|
+
}
|
|
176
|
+
echo "PAGES_PREVIOUS_TREE=$(git rev-parse 'HEAD^{tree}')" >> "$GITHUB_ENV"
|
|
177
|
+
git checkout --orphan pages-deploy
|
|
178
|
+
git rm -q -r -f .
|
|
179
|
+
|
|
180
|
+
- name: Prepare generated-only repository contents
|
|
181
|
+
run: npx garden pages:prepare static-site pages-repository
|
|
182
|
+
|
|
183
|
+
- name: Publish the rolling deployment commit
|
|
184
|
+
working-directory: pages-repository
|
|
185
|
+
run: |
|
|
186
|
+
git config user.name "github-actions[bot]"
|
|
187
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
188
|
+
git add -A
|
|
189
|
+
new_tree="$(git write-tree)"
|
|
190
|
+
if [ "$new_tree" = "$PAGES_PREVIOUS_TREE" ]; then
|
|
191
|
+
echo "静态产物没有变化,无需发布"
|
|
192
|
+
exit 0
|
|
193
|
+
fi
|
|
194
|
+
git commit -m "Deploy ${GITHUB_SHA}"
|
|
195
|
+
git push --force origin HEAD:main
|