-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcloud-publish-workflow.yml
More file actions
177 lines (157 loc) · 7.58 KB
/
Copy pathcloud-publish-workflow.yml
File metadata and controls
177 lines (157 loc) · 7.58 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
# Headless publish to the cloud backend (htmlbin.dev) from GitHub Actions.
#
# For @htmlbin/cli >= 0.2.0, prefer cloud-upsert-workflow.yml: the
# --upsert flag + metadata tagging replaces the find-by-title dance
# below with one publish call and gives you a stable URL per PR.
# This workflow stays useful if you're pinned to 0.1.x or want to
# look up drops by --title rather than by metadata tags.
#
# Use this when:
# - You have HTML to share publicly (test reports, coverage, demos,
# PR previews) and don't need org-internal SSO gating
# - You don't want to set up gh-pages or Cloudflare Pages
# - You want the fastest possible "CI emits a URL" flow
#
# This is the simplest backend story: no repo permissions, no Pages
# setup, no infra. One secret ($HTMLBIN_TOKEN) and you get a public URL
# per PR. The find-by-title pattern below handles cleanup so re-pushes
# don't accumulate stale drops, and the teardown job deletes everything
# when the PR closes.
#
# For org-internal HTML that must stay behind SAML SSO, use
# `gh-pages` (see preview-workflow.yml / agent-preview-workflow.yml)
# or Cloudflare Pages + Access instead.
#
# **Prerequisites** (one-time):
# 1. Run `htmlbin login` on your laptop (device-code flow with GitHub)
# 2. Copy the minted token: `cat ~/.config/htmlbin/token`
# 3. Add it as a repo secret named `HTMLBIN_TOKEN`
# 4. Replace the "Build the HTML" step below with whatever produces
# your HTML — `npm run build && cp dist/index.html ./preview.html`,
# a coverage report, a Storybook export, an agent-generated page,
# whatever. The publish step only cares that ./preview.html exists.
name: PR preview (cloud)
on:
pull_request:
types: [opened, synchronize, reopened, closed]
permissions:
pull-requests: write # to post the sticky comment
concurrency:
group: pr-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true
# A deterministic title lets us find and delete prior drops for this PR
# without storing slug state anywhere. The cloud backend generates a fresh
# slug per publish; the title is the stable handle we control.
env:
PREVIEW_TITLE: "PR #${{ github.event.pull_request.number }} preview"
jobs:
# ---------------------------------------------------------------------
# Publish on open / synchronize / reopen
# ---------------------------------------------------------------------
publish:
if: github.event.action != 'closed'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
# --- Step 1: produce ./preview.html ----------------------------------
# Replace this with your real build. For a Storybook/Vite/Astro repo
# it's typically `npm ci && npm run build && cp dist/index.html ./preview.html`.
- name: Build the HTML
run: |
npm ci
npm run build
# Adjust the path: whatever file you want to publish.
cp dist/index.html ./preview.html
# --- Step 2: delete any previous drop for this PR --------------------
# The cloud backend generates a fresh slug per publish — pre-deleting
# any drop with the same title keeps re-pushes from piling up.
- name: Clean up previous preview
run: |
npx -y @htmlbin/cli@latest list --output json \
| jq -r --arg t "$PREVIEW_TITLE" '.[] | select(.title == $t) | .slug' \
| xargs -I {} npx -y @htmlbin/cli@latest delete {} || true
env:
HTMLBIN_TOKEN: ${{ secrets.HTMLBIN_TOKEN }}
# --- Step 3: publish to htmlbin.dev ----------------------------------
# --title locks the title to a deterministic value so the find-by-title
# cleanup above (and the teardown job below) can locate prior drops.
# --output json gives a tight envelope we can pipe through jq.
- name: Publish preview
id: publish
run: |
npx -y @htmlbin/cli@latest publish ./preview.html \
--title "$PREVIEW_TITLE" \
--output json > drop.json
echo "url=$(jq -r .url drop.json)" >> $GITHUB_OUTPUT
echo "slug=$(jq -r .slug drop.json)" >> $GITHUB_OUTPUT
echo "size_kb=$(du -k ./preview.html | cut -f1)" >> $GITHUB_OUTPUT
echo "short_sha=${HEAD_SHA:0:7}" >> $GITHUB_OUTPUT
env:
HTMLBIN_TOKEN: ${{ secrets.HTMLBIN_TOKEN }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
# --- Step 4: sticky comment ------------------------------------------
# The URL changes per push (slug is server-generated), so the comment
# updates with the new URL each time. The sticky-comment action edits
# the existing comment in place rather than appending new ones.
- name: Post preview URL
if: success()
uses: marocchino/sticky-pull-request-comment@v2
with:
header: htmlbin-preview
message: |
### 🔗 htmlbin preview
| | |
|---|---|
| **Status** | ✅ Live |
| **URL** | ${{ steps.publish.outputs.url }} |
| **Slug** | `${{ steps.publish.outputs.slug }}` |
| **Commit** | [`${{ steps.publish.outputs.short_sha }}`](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.event.pull_request.head.sha }}) |
| **Size** | ${{ steps.publish.outputs.size_kb }} KB |
| **Updated** | just now (run [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})) |
<sub>Regenerates on every push · Auto-deleted when this PR closes · Powered by <a href="https://github.com/utsengar/htmlbin-cli">@htmlbin/cli</a></sub>
- name: Post failure notice
if: failure()
uses: marocchino/sticky-pull-request-comment@v2
with:
header: htmlbin-preview
message: |
### ❌ htmlbin preview — build failed
| | |
|---|---|
| **Status** | ❌ Failed |
| **Commit** | [`${{ steps.publish.outputs.short_sha || 'unknown' }}`](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.event.pull_request.head.sha }}) |
| **Logs** | [run #${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) |
<sub>This comment auto-updates on the next push.</sub>
# ---------------------------------------------------------------------
# Tear down on close — public URLs shouldn't outlive the PR
# ---------------------------------------------------------------------
teardown:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Delete preview
# Find by title and delete. `|| true` so a PR that never had a
# preview (or one already deleted) doesn't fail the workflow.
run: |
npx -y @htmlbin/cli@latest list --output json \
| jq -r --arg t "$PREVIEW_TITLE" '.[] | select(.title == $t) | .slug' \
| xargs -I {} npx -y @htmlbin/cli@latest delete {} || true
env:
HTMLBIN_TOKEN: ${{ secrets.HTMLBIN_TOKEN }}
- name: Mark comment as torn down
uses: marocchino/sticky-pull-request-comment@v2
with:
header: htmlbin-preview
message: |
### 🗑 htmlbin preview — torn down
| | |
|---|---|
| **Status** | 🗑 Deleted |
| **Reason** | PR closed |
<sub>Reopening this PR will republish the preview.</sub>