mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-05-07 02:03:55 -05:00
Lays foundation for unified release versioning across MLSysBook publishable artifacts. Pure additions — no existing builds, configs, or sources are touched. scripts/version/release.py Python CLI with helpers: - compute-id: semver bump from previous tag (patch/minor/major/none/explicit) - compute-hash: deterministic SHA-256 over input directories with per-file index - emit-release: writes releases/<project>-<id>/release.json (canonical artifact) - emit-manifest: writes the build-time manifest the deployable bundles Tier A (citable) emits per-file Merkle index; Tier B (lite) is flat. scripts/version/schema.json JSON Schema for release.json. Validates project/tier/release_id/release_hash + Tier A's files[] index. Used by validators in CI. shared/release/release-pill.html Footer snippet — fetches deployable manifest at runtime, renders "v0.1.0 · Apr 26, 2026" pill. Configured per-project via <meta name="release-manifest"> tag. Silent on any fetch failure. shared/release/release-card.html About-page snippet — fuller release-identity card with click-to-copy hash. Same fetch + meta-tag conventions. shared/release/README.md Operator-facing contract documentation. .github/workflows/_release-prepare.yml Reusable workflow_call. Validates confirm == "PUBLISH", computes new_release_id from previous tag + bump (delegates to release.py for canonical math). Outputs new_release_id/new_tag/previous_* for caller's downstream build and finalize steps. Refuses to re-tag existing releases (citation integrity). Caller workflows still own their build commands and tag/release creation; this only standardizes the input shape and version math.
120 lines
3.9 KiB
HTML
120 lines
3.9 KiB
HTML
<!--
|
|
MLSysBook release-card — fuller release-identity card for About pages.
|
|
|
|
Like release-pill.html but bigger: shows release_id, build date, and
|
|
full hash with a click-to-copy button. Use on About pages, citation
|
|
contexts, or anywhere users may want to copy the release identity for
|
|
reference. Same manifest-fetch and meta-tag conventions as the pill.
|
|
|
|
Per-project setup is identical to release-pill.html — set the
|
|
<meta name="release-manifest"> tag once in _quarto.yml; embed
|
|
this snippet on the About page only.
|
|
-->
|
|
|
|
<section class="release-card" data-release-card aria-label="Release identity"></section>
|
|
|
|
<style>
|
|
.release-card {
|
|
display: block;
|
|
padding: 1rem;
|
|
border: 1px solid var(--bs-border-color, #dee2e6);
|
|
border-radius: 0.5rem;
|
|
background: var(--bs-tertiary-bg, #f8f9fa);
|
|
font-size: 0.875rem;
|
|
margin: 1rem 0;
|
|
}
|
|
.release-card-empty { display: none; }
|
|
.release-card-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem 1.5rem;
|
|
align-items: baseline;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
.release-card-version {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
font-weight: 600;
|
|
font-size: 1rem;
|
|
}
|
|
.release-card-meta {
|
|
color: var(--bs-secondary, #6c757d);
|
|
font-size: 0.8rem;
|
|
}
|
|
.release-card-hash {
|
|
display: inline-flex;
|
|
align-items: baseline;
|
|
gap: 0.5rem;
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
font-size: 0.7rem;
|
|
color: var(--bs-secondary, #6c757d);
|
|
margin-top: 0.5rem;
|
|
word-break: break-all;
|
|
}
|
|
.release-card-copy {
|
|
cursor: pointer;
|
|
border: 1px solid var(--bs-border-color, #dee2e6);
|
|
background: var(--bs-body-bg, #fff);
|
|
color: inherit;
|
|
padding: 0.125rem 0.5rem;
|
|
border-radius: 0.25rem;
|
|
font-size: 0.65rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
.release-card-copy:hover {
|
|
border-color: var(--bs-link-color, #0d6efd);
|
|
color: var(--bs-link-color, #0d6efd);
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
(function () {
|
|
var el = document.querySelector('[data-release-card]');
|
|
if (!el) return;
|
|
|
|
var meta = document.querySelector('meta[name="release-manifest"]');
|
|
var manifestPath =
|
|
el.getAttribute('data-manifest') ||
|
|
(meta && meta.getAttribute('content')) ||
|
|
'./release-manifest.json';
|
|
|
|
fetch(manifestPath, { cache: 'no-store' })
|
|
.then(function (res) { return res.ok ? res.json() : null; })
|
|
.then(function (m) {
|
|
if (!m || !m.releaseId || !m.releaseHash) {
|
|
el.classList.add('release-card-empty');
|
|
return;
|
|
}
|
|
var date = m.buildDate
|
|
? new Date(m.buildDate).toLocaleDateString('en-US',
|
|
{ year: 'numeric', month: 'long', day: 'numeric' })
|
|
: '';
|
|
var project = m.project || 'Release';
|
|
var html =
|
|
'<div class="release-card-row">' +
|
|
'<span class="release-card-version">' + project + ' v' + m.releaseId + '</span>' +
|
|
(date ? '<span class="release-card-meta">built ' + date + '</span>' : '') +
|
|
(m.tier ? '<span class="release-card-meta">tier ' + m.tier + '</span>' : '') +
|
|
'</div>' +
|
|
'<div class="release-card-hash" id="release-card-hash">' +
|
|
'<span>hash <span data-hash>' + m.releaseHash + '</span></span>' +
|
|
'<button type="button" class="release-card-copy" data-copy>copy</button>' +
|
|
'</div>';
|
|
el.id = 'release';
|
|
el.innerHTML = html;
|
|
var btn = el.querySelector('[data-copy]');
|
|
if (btn && navigator.clipboard) {
|
|
btn.addEventListener('click', function () {
|
|
navigator.clipboard.writeText(m.releaseHash).then(function () {
|
|
btn.textContent = 'copied';
|
|
setTimeout(function () { btn.textContent = 'copy'; }, 1500);
|
|
});
|
|
});
|
|
}
|
|
})
|
|
.catch(function () {
|
|
el.classList.add('release-card-empty');
|
|
});
|
|
})();
|
|
</script>
|