Skip to content

Commit 1d93688

Browse files
authored
Merge pull request #33 from jdarcyryan/jdr/pages
jdr/pages
2 parents 29cf627 + 59d49bd commit 1d93688

1 file changed

Lines changed: 133 additions & 18 deletions

File tree

.github/workflows/pages.yml

Lines changed: 133 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,80 @@ on:
44
push:
55
branches: ["main"]
66
workflow_dispatch:
7+
repository_dispatch:
8+
types: [visibility_changed]
79

810
permissions:
911
contents: read
1012
pages: write
1113
id-token: write
14+
deployments: write
1215

1316
concurrency:
1417
group: "pages"
1518
cancel-in-progress: false
1619

1720
jobs:
21+
# ── Guard: check repo visibility ────────────────────────────────
22+
check-visibility:
23+
runs-on: ubuntu-latest
24+
outputs:
25+
is_private: ${{ steps.check.outputs.is_private }}
26+
steps:
27+
- name: Check repo visibility
28+
id: check
29+
run: |
30+
if [ "${{ github.event.repository.private }}" = "true" ]; then
31+
echo "is_private=true" >> "$GITHUB_OUTPUT"
32+
echo "::warning::Repository is private — Pages deployment will be skipped"
33+
else
34+
echo "is_private=false" >> "$GITHUB_OUTPUT"
35+
fi
36+
37+
# ── Teardown: remove Pages if repo is private ───────────────────
38+
teardown:
39+
runs-on: ubuntu-latest
40+
needs: check-visibility
41+
if: needs.check-visibility.outputs.is_private == 'true'
42+
steps:
43+
- name: Remove GitHub Pages deployments
44+
env:
45+
GH_TOKEN: ${{ github.token }}
46+
REPO: ${{ github.repository }}
47+
run: |
48+
echo "Repository is private — removing existing Pages deployments"
49+
50+
# List all deployments in the github-pages environment
51+
DEPLOYMENTS=$(gh api "repos/${REPO}/deployments?environment=github-pages&per_page=100" --jq '.[].id' 2>/dev/null || true)
52+
53+
if [ -z "$DEPLOYMENTS" ]; then
54+
echo "No existing Pages deployments found"
55+
exit 0
56+
fi
57+
58+
# Mark each deployment as inactive, then delete it
59+
for ID in $DEPLOYMENTS; do
60+
echo "Deactivating deployment ${ID}..."
61+
gh api \
62+
--method POST \
63+
-H "Accept: application/vnd.github+json" \
64+
"repos/${REPO}/deployments/${ID}/statuses" \
65+
-f state=inactive 2>/dev/null || true
66+
67+
echo "Deleting deployment ${ID}..."
68+
gh api \
69+
--method DELETE \
70+
-H "Accept: application/vnd.github+json" \
71+
"repos/${REPO}/deployments/${ID}" 2>/dev/null || true
72+
done
73+
74+
echo "All Pages deployments removed"
75+
76+
# ── Build (only if public) ──────────────────────────────────────
1877
build:
1978
runs-on: ubuntu-latest
79+
needs: check-visibility
80+
if: needs.check-visibility.outputs.is_private == 'false'
2081
steps:
2182
- name: Checkout
2283
uses: actions/checkout@v4
@@ -197,10 +258,6 @@ jobs:
197258
fi
198259
199260
# ── Fix relative links for Jekyll ─────────────────────────────
200-
# Jekyll with permalink:pretty changes paths, so relative links
201-
# like [X](CONTRIBUTING.md) or [X](LICENSE) would 404.
202-
# Point them at their Jekyll permalinks instead.
203-
# Only targets known community files in root-level markdown.
204261
for f in *.md; do
205262
[ -f "$f" ] || continue
206263
[ -f "CONTRIBUTING.md" ] && sed -i 's|\](CONTRIBUTING\.md)|\](contributing/)|g' "$f"
@@ -250,7 +307,6 @@ jobs:
250307
fi
251308
252309
# ── Releases page ─────────────────────────────────────────────
253-
# Write the JS to a separate file to avoid heredoc escaping issues
254310
mkdir -p _includes
255311
cat > _includes/releases.js << 'JSEOF'
256312
(async function() {
@@ -262,6 +318,29 @@ jobs:
262318
var data = await res.json();
263319
if (!data.length) { c.innerHTML = '<p>No releases found.</p>'; return; }
264320
321+
function inline(s) {
322+
var codes = [];
323+
s = s.replace(/`([^`]+)`/g, function(m, code) {
324+
codes.push(code.replace(/</g,'&lt;').replace(/>/g,'&gt;'));
325+
return '\x00CODE' + (codes.length - 1) + '\x00';
326+
});
327+
s = s
328+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>')
329+
.replace(/(https?:\/\/[^\s<)]+)/g, function(m, url, offset, str) {
330+
if (str.charAt(offset - 1) === '"' || str.charAt(offset - 1) === '>' || str.substring(offset - 6, offset) === 'href="') return m;
331+
return '<a href="' + url + '">' + url + '</a>';
332+
})
333+
.replace(/(^|[\s(])@([a-zA-Z0-9_-]+)/g, function(m, pre, user) {
334+
return pre + '<a href="https://github.com/' + user + '">@' + user + '</a>';
335+
})
336+
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
337+
.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, '<em>$1</em>');
338+
s = s.replace(/\x00CODE(\d+)\x00/g, function(m, idx) {
339+
return '<code>' + codes[parseInt(idx)] + '</code>';
340+
});
341+
return s;
342+
}
343+
265344
function md(s) {
266345
if (!s) return '';
267346
var lines = s.split('\n');
@@ -272,29 +351,29 @@ jobs:
272351
var h3 = line.match(/^### (.+)$/);
273352
var h2 = line.match(/^## (.+)$/);
274353
var li = line.match(/^\* (.+)$/);
275-
var cb = line.match(/^```/);
354+
var cb = line.match(/^```(.*)$/);
276355
if (cb) {
277356
if (inList) { html += '</ul>'; inList = false; }
357+
var lang = cb[1].trim();
278358
var code = '';
279359
i++;
280360
while (i < lines.length && !lines[i].match(/^```/)) { code += lines[i] + '\n'; i++; }
281-
html += '<pre><code>' + code + '</code></pre>';
361+
var langLabel = lang ? '<div style="font-size:11px;color:var(--text-muted);padding:4px 12px;border-bottom:1px solid var(--border);font-family:IBM Plex Mono,monospace">' + lang + '</div>' : '';
362+
html += '<div style="border:1px solid var(--border);border-radius:6px;overflow:hidden;margin:8px 0 16px">' + langLabel + '<pre style="margin:0;border:none;border-radius:0"><code>' + code.replace(/</g,'&lt;').replace(/>/g,'&gt;') + '</code></pre></div>';
282363
} else if (h2) {
283364
if (inList) { html += '</ul>'; inList = false; }
284-
html += '<h2>' + h2[1] + '</h2>';
365+
html += '<h2>' + inline(h2[1]) + '</h2>';
285366
} else if (h3) {
286367
if (inList) { html += '</ul>'; inList = false; }
287-
html += '<h3>' + h3[1] + '</h3>';
368+
html += '<h3>' + inline(h3[1]) + '</h3>';
288369
} else if (li) {
289370
if (!inList) { html += '<ul>'; inList = true; }
290-
var text = li[1].replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
291-
html += '<li>' + text + '</li>';
371+
html += '<li>' + inline(li[1]) + '</li>';
292372
} else {
293373
if (inList) { html += '</ul>'; inList = false; }
294374
if (line.trim() === '---') { html += '<hr>'; }
295375
else if (line.trim()) {
296-
var text = line.replace(/`([^`]+)`/g, '<code>$1</code>').replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>').replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
297-
html += '<p>' + text + '</p>';
376+
html += '<p>' + inline(line) + '</p>';
298377
}
299378
}
300379
}
@@ -306,16 +385,52 @@ jobs:
306385
var d = new Date(r.published_at).toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' });
307386
var latest = i === 0 ? '<span class="release-latest">latest</span>' : '';
308387
var openAttr = i === 0 ? ' open' : '';
388+
389+
// Commit SHA
390+
var sha = r.target_commitish || '';
391+
var shortSha = sha.substring(0, 7);
392+
var shaHtml = '';
393+
if (sha.length >= 7) {
394+
shaHtml = '<div style="margin-top:12px;padding-top:12px;border-top:1px solid var(--border);font-size:13px;color:var(--text-muted)">'
395+
+ '<a href="https://github.com/' + repo + '/commit/' + sha + '" style="font-family:IBM Plex Mono,monospace;font-size:12px">' + shortSha + '</a>'
396+
+ '</div>';
397+
}
398+
399+
// Assets
309400
var assets = '';
310401
if (r.assets.length) {
311-
assets = '<details class="release-assets"><summary>Assets (' + r.assets.length + ')</summary>';
402+
var hashMap = {};
403+
var mainAssets = [];
312404
for (var j = 0; j < r.assets.length; j++) {
313405
var a = r.assets[j];
314-
assets += '<div class="release-asset">' + a.name + ' <span style="color:var(--text-muted)">' + (a.size / 1024).toFixed(1) + ' KB</span></div>';
406+
if (a.name.match(/\.(sha256|sha512|md5|sha1)$/i)) {
407+
var base = a.name.replace(/\.(sha256|sha512|md5|sha1)$/i, '');
408+
hashMap[base] = a;
409+
} else {
410+
mainAssets.push(a);
411+
}
412+
}
413+
414+
var srcZip = 'https://github.com/' + repo + '/archive/refs/tags/' + r.tag_name + '.zip';
415+
var srcTar = 'https://github.com/' + repo + '/archive/refs/tags/' + r.tag_name + '.tar.gz';
416+
var totalAssets = mainAssets.length + 2;
417+
418+
assets = '<details class="release-assets"><summary>Assets (' + totalAssets + ')</summary>';
419+
for (var j = 0; j < mainAssets.length; j++) {
420+
var a = mainAssets[j];
421+
var hash = hashMap[a.name];
422+
var hashHtml = '';
423+
if (hash) {
424+
hashHtml = ' <span style="font-size:11px;color:var(--text-muted)">(' + hash.name.split('.').pop() + ')</span>';
425+
}
426+
assets += '<div class="release-asset"><a href="' + a.browser_download_url + '">' + a.name + '</a> <span style="color:var(--text-muted)">' + (a.size / 1024).toFixed(1) + ' KB</span>' + hashHtml + '</div>';
315427
}
428+
assets += '<div class="release-asset"><a href="' + srcZip + '">Source code</a> <span style="color:var(--text-muted)">(zip)</span></div>';
429+
assets += '<div class="release-asset"><a href="' + srcTar + '">Source code</a> <span style="color:var(--text-muted)">(tar.gz)</span></div>';
316430
assets += '</details>';
317431
}
318-
return '<details class="release"' + openAttr + '><summary><span class="release-tag">' + r.tag_name + '</span>' + latest + '<span class="release-date">' + d + '</span></summary><div class="release-body">' + md(r.body) + assets + '</div></details>';
432+
433+
return '<details class="release"' + openAttr + '><summary><span class="release-tag">' + r.tag_name + '</span>' + latest + '<span class="release-date">' + d + '</span></summary><div class="release-body">' + md(r.body) + assets + shaHtml + '</div></details>';
319434
}).join('');
320435
} catch(e) {
321436
c.innerHTML = '<p>Unable to load releases. Visit <a href="https://github.com/' + repo + '/releases">GitHub</a> directly.</p>';
@@ -344,7 +459,6 @@ jobs:
344459
done
345460
346461
if [ -n "$LICENSE_SRC" ]; then
347-
# Create LICENSE.md with front matter + full license text
348462
if ! ([ -f "LICENSE.md" ] && head -1 LICENSE.md | grep -q '^\-\-\-'); then
349463
TEMP=$(mktemp)
350464
printf -- '---\nlayout: default\ntitle: License\npermalink: /license/\n---\n\n# License\n\n```\n' > "$TEMP"
@@ -354,7 +468,6 @@ jobs:
354468
echo "Created LICENSE.md from ${LICENSE_SRC}"
355469
fi
356470
elif [ -f "LICENSE.md" ] && ! head -1 LICENSE.md | grep -q '^\-\-\-'; then
357-
# LICENSE.md exists but has no front matter
358471
TEMP=$(mktemp)
359472
printf -- '---\nlayout: default\ntitle: License\npermalink: /license/\n---\n\n' > "$TEMP"
360473
cat LICENSE.md >> "$TEMP"
@@ -397,12 +510,14 @@ jobs:
397510
- name: Upload artifact
398511
uses: actions/upload-pages-artifact@v3
399512

513+
# ── Deploy (only if build succeeded) ────────────────────────────
400514
deploy:
401515
environment:
402516
name: github-pages
403517
url: ${{ steps.deployment.outputs.page_url }}
404518
runs-on: ubuntu-latest
405519
needs: build
520+
if: needs.build.result == 'success'
406521
steps:
407522
- name: Deploy to GitHub Pages
408523
id: deployment

0 commit comments

Comments
 (0)