[PR #1408] [MERGED] PR-4b: Per-volume book versioning (vol1-v* / vol2-v* independent tag spaces) #8175

Closed
opened 2026-04-27 17:28:49 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/harvard-edge/cs249r_book/pull/1408
Author: @profvjreddi
Created: 4/19/2026
Status: Merged
Merged: 4/19/2026
Merged by: @profvjreddi

Base: devHead: release-prep/book-versioning


📝 Commits (1)

  • ed98b62 feat(book-publish): per-volume versioning (vol1-v* / vol2-v* tags)

📊 Changes

2 files changed (+218 additions, -102 deletions)

View changed files

📝 .github/workflows/book-publish-live.yml (+217 -101)
📝 book/quarto/contents/vol2/index.qmd (+1 -1)

📄 Description

Summary

Refactor book-publish-live.yml so Volume I and Volume II evolve on
independent semver lifecycles instead of sharing one book-v* tag
namespace. Required so we can ship Volume II at v0.1.0 while Volume I
continues from v0.5.1 → v0.6.0 → ... without one volume's bump
implicitly relabeling the other.

Why now

Two real problems with the current workflow that block the staged
launch:

  1. All three index.qmd files were stuck at doi: \"v0.5.1\"
    (root + vol1 + vol2). The publish step only sed'd the root
    index.qmd, so the per-volume Quarto title blocks displayed a stale
    version after every release.
  2. A single book-v* tag space couldn't represent two
    independently-versioned volumes
    — bumping for a Vol II content
    change would have implied a Vol I release too, which is wrong.

What changed

.github/workflows/book-publish-live.yml:

  • New per-volume outputs from validate-inputs:
    new_vol1_version, new_vol2_version, previous_vol1_version,
    previous_vol2_version. The legacy new_version /
    previous_version outputs are retained as a backwards-compatible
    summary string (e.g. vol1-v0.6.0+vol2-v0.1.0) for the ~50
    downstream references that just want a printable version label.

  • Calculate Next Version step rewritten with two helpers:

    • bump <prefix> <prev_full_tag> — applies major/minor/patch to
      the numeric portion. Each local declaration is on its own line
      (bundled local a=\$1 b=\$2 c=\${b#x} silently breaks c).
    • latest_for <prefix> [fallback] — finds the latest
      <prefix>-v* tag, with a fallback for the very first release.

    Logic:

    • vol1: seed from latest book-v* (so v0.5.1 → v0.6.0 line
      is preserved across the rename). Subsequent bumps come from
      vol1-v* tags.
    • vol2: seed from vol2-v0.0.0 so the FIRST publish with
      release_type=minor lands at vol2-v0.1.0.
    • The deploy_target input (vol1 / vol2 / all) decides
      which volume(s) get bumped on a given run.
  • Update per-volume version in index.qmd step now updates
    contents/vol1/index.qmd and/or contents/vol2/index.qmd based
    on deploy_target. Strips the volX- prefix when writing the
    doi: field (readers see "v0.6.0", the tag is "vol1-v0.6.0").
    Legacy root index.qmd is intentionally untouched — it's the
    unified landing, not a volume.

  • Create per-volume release tag(s) step creates vol1-v*
    and/or vol2-v* tags independently. Refuses to overwrite an
    existing tag (no --force-with-lease on a remote tag — that would
    silently overwrite a previously-shipped release).

  • previous_version input description updated: when
    deploy_target=all, the input is ignored and both versions are
    auto-detected; when targeting a single volume, the input applies
    to that volume.

book/quarto/contents/vol2/index.qmd:

  • Set doi: \"v0.1.0-pre\" to establish a clear pre-release baseline
    for Volume II so the rendered title block stops claiming v0.5.1
    before the workflow ever runs.

Risk surface

  • The new logic is workflow-internal; doesn't change the rendered
    pages until a publish runs.
  • Refusal-to-retag is a hard fail: if a maintainer manually creates a
    conflicting tag, the next publish will error with a clear message
    and require manual intervention. This is intentional — the
    alternative (silent overwrite) corrupts release history.
  • Backwards compat: downstream steps that read new_version /
    previous_version continue to work; they just see a richer string.

Verification

  • Bash helpers tested locally with edge cases (no existing tags,
    legacy book-v* only, both vol1-v* and vol2-v* present).
  • python3 -c \"import yaml; yaml.safe_load(open('.github/workflows/book-publish-live.yml'))\" parses clean.
  • CI: book-validate-dev runs.
  • Manual (post-merge): dispatch book-publish-live.yml with
    deploy_target=vol2, release_type=minor in TESTING MODE;
    observe the computed versions in the workflow logs (should be
    vol2-v0.0.0vol2-v0.1.0, with vol1 untouched).
  • Manual: same but deploy_target=vol1, release_type=minor;
    should be vol1-v0.5.1vol1-v0.6.0 (seeded from the
    legacy book-v0.5.1 tag).

Rollout sequence

When merged: the FIRST live publish should be a deploy_target=vol1
to establish vol1-v0.6.0, then deploy_target=vol2 to establish
vol2-v0.1.0. After both tags exist, deploy_target=all will work
for joint releases.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/harvard-edge/cs249r_book/pull/1408 **Author:** [@profvjreddi](https://github.com/profvjreddi) **Created:** 4/19/2026 **Status:** ✅ Merged **Merged:** 4/19/2026 **Merged by:** [@profvjreddi](https://github.com/profvjreddi) **Base:** `dev` ← **Head:** `release-prep/book-versioning` --- ### 📝 Commits (1) - [`ed98b62`](https://github.com/harvard-edge/cs249r_book/commit/ed98b6206e42aaa063b8c654a4c683c472633856) feat(book-publish): per-volume versioning (vol1-v* / vol2-v* tags) ### 📊 Changes **2 files changed** (+218 additions, -102 deletions) <details> <summary>View changed files</summary> 📝 `.github/workflows/book-publish-live.yml` (+217 -101) 📝 `book/quarto/contents/vol2/index.qmd` (+1 -1) </details> ### 📄 Description ## Summary Refactor `book-publish-live.yml` so Volume I and Volume II evolve on independent semver lifecycles instead of sharing one `book-v*` tag namespace. Required so we can ship Volume II at v0.1.0 while Volume I continues from v0.5.1 → v0.6.0 → ... without one volume's bump implicitly relabeling the other. ### Why now Two real problems with the current workflow that block the staged launch: 1. **All three `index.qmd` files were stuck at `doi: \"v0.5.1\"`** (root + vol1 + vol2). The publish step only sed'd the root index.qmd, so the per-volume Quarto title blocks displayed a stale version after every release. 2. **A single `book-v*` tag space couldn't represent two independently-versioned volumes** — bumping for a Vol II content change would have implied a Vol I release too, which is wrong. ### What changed `.github/workflows/book-publish-live.yml`: - **New per-volume outputs from `validate-inputs`**: `new_vol1_version`, `new_vol2_version`, `previous_vol1_version`, `previous_vol2_version`. The legacy `new_version` / `previous_version` outputs are retained as a backwards-compatible *summary string* (e.g. `vol1-v0.6.0+vol2-v0.1.0`) for the ~50 downstream references that just want a printable version label. - **`Calculate Next Version` step rewritten** with two helpers: - `bump <prefix> <prev_full_tag>` — applies major/minor/patch to the numeric portion. Each `local` declaration is on its own line (bundled `local a=\$1 b=\$2 c=\${b#x}` silently breaks `c`). - `latest_for <prefix> [fallback]` — finds the latest `<prefix>-v*` tag, with a fallback for the very first release. Logic: - **vol1**: seed from latest `book-v*` (so v0.5.1 → v0.6.0 line is preserved across the rename). Subsequent bumps come from `vol1-v*` tags. - **vol2**: seed from `vol2-v0.0.0` so the FIRST publish with `release_type=minor` lands at `vol2-v0.1.0`. - The `deploy_target` input (`vol1` / `vol2` / `all`) decides which volume(s) get bumped on a given run. - **`Update per-volume version in index.qmd` step** now updates `contents/vol1/index.qmd` and/or `contents/vol2/index.qmd` based on `deploy_target`. Strips the `volX-` prefix when writing the `doi:` field (readers see \"v0.6.0\", the tag is \"vol1-v0.6.0\"). Legacy root `index.qmd` is intentionally untouched — it's the unified landing, not a volume. - **`Create per-volume release tag(s)` step** creates `vol1-v*` and/or `vol2-v*` tags independently. Refuses to overwrite an existing tag (no `--force-with-lease` on a remote tag — that would silently overwrite a previously-shipped release). - **`previous_version` input** description updated: when `deploy_target=all`, the input is ignored and both versions are auto-detected; when targeting a single volume, the input applies to that volume. `book/quarto/contents/vol2/index.qmd`: - Set `doi: \"v0.1.0-pre\"` to establish a clear pre-release baseline for Volume II so the rendered title block stops claiming v0.5.1 before the workflow ever runs. ### Risk surface - The new logic is workflow-internal; doesn't change the rendered pages until a publish runs. - Refusal-to-retag is a hard fail: if a maintainer manually creates a conflicting tag, the next publish will error with a clear message and require manual intervention. This is intentional — the alternative (silent overwrite) corrupts release history. - Backwards compat: downstream steps that read `new_version` / `previous_version` continue to work; they just see a richer string. ### Verification - [ ] Bash helpers tested locally with edge cases (no existing tags, legacy `book-v*` only, both `vol1-v*` and `vol2-v*` present). - [ ] `python3 -c \"import yaml; yaml.safe_load(open('.github/workflows/book-publish-live.yml'))\"` parses clean. - [ ] CI: book-validate-dev runs. - [ ] Manual (post-merge): dispatch `book-publish-live.yml` with `deploy_target=vol2`, `release_type=minor` in TESTING MODE; observe the computed versions in the workflow logs (should be `vol2-v0.0.0` → `vol2-v0.1.0`, with vol1 untouched). - [ ] Manual: same but `deploy_target=vol1`, `release_type=minor`; should be `vol1-v0.5.1` → `vol1-v0.6.0` (seeded from the legacy `book-v0.5.1` tag). ### Rollout sequence When merged: the FIRST live publish should be a `deploy_target=vol1` to establish `vol1-v0.6.0`, then `deploy_target=vol2` to establish `vol2-v0.1.0`. After both tags exist, `deploy_target=all` will work for joint releases. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-27 17:28:49 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/cs249r_book#8175