Skip to content

feat(docs): trunk-based versioning with permanent next/ directory#495

Merged
myasnikovdaniil merged 15 commits intomainfrom
feat/trunk-based-next
Apr 21, 2026
Merged

feat(docs): trunk-based versioning with permanent next/ directory#495
myasnikovdaniil merged 15 commits intomainfrom
feat/trunk-based-next

Conversation

@myasnikovdaniil
Copy link
Copy Markdown
Contributor

@myasnikovdaniil myasnikovdaniil commented Apr 17, 2026

Summary

Replaces the hardcoded v1.3 draft-directory approach from #493 with a permanent content/en/docs/next/ trunk for upcoming/unreleased Cozystack docs. The next release version is no longer assumed at write-time — next/ is promoted to vX.Y/ when the upstream release workflow fires make release-next RELEASE_TAG=vX.Y.Z.

  • Permanent content/en/docs/next/ trunk (198 files, seeded from v1.2), excluded from production via config/production/hugo.yaml, visible in local dev and Netlify deploy previews.
  • Makefile routing by RELEASE_TAG: patch releases of an existing registered version update in-place; everything else accumulates in next/.
  • New scripts: hack/release_next.sh (promote next/vX.Y/), hack/register_version.sh (manage hugo.yaml entries).
  • Version switcher and landing page filter hidden: true entries at build time — no manual edits to add a new version to the dropdown/table.
  • Closes out feat(docs): version lifecycle management with hidden/draft support #493 (please close it manually after this merges).

Design

Problem

PR #493 introduced version lifecycle management by creating a draft v1.3 directory. This hardcodes an assumption about what the next release will be. The actual next version could be v1.5, v2.0, or anything else. Docs written ahead of a release should not be tied to a specific version number until the release actually happens.

Core Concept

A permanent content/en/docs/next/ directory serves as a version-agnostic trunk. Docs for upcoming features accumulate here. When a cozystack release is cut, next/ is copied out to the actual version directory and registered.

Directory Structure

content/en/docs/next/ is a full content tree — a copy of the latest released version plus manual edits for upcoming features.

  • Internal links use /docs/next/ paths (rewritten to the actual version at release time)
  • _index.md title: "Cozystack Next (unreleased)" with a draft banner
  • Always present in the repo (never deleted)

Version Registration in hugo.yaml

params:
  latest_version_id: "v1.2"
  versions:
    - version: "next"
      url: "/docs/next/"
      id: "next"
      order: 999
      hidden: true
      label: "Next (unreleased)"
    - version: "v1.2"
      url: "/docs/v1.2/"
      id: "v1.2"
      order: 4
    # ... older versions

hidden: true + content mount exclusion (- '! docs/next/**') excludes next/ from production builds.

Build Integration

Production (GitHub Pages): next/ excluded via config/production/hugo.yaml, which duplicates the full module block from base hugo.yaml (Hugo replaces arrays wholesale during config merge) with - '! docs/next/**' added to the content mount. download_openapi.sh iterates v*/ — naturally skips next/.

Deploy previews (Netlify) & local dev: next/ is visible at /docs/next/. Netlify's [context.deploy-preview] sets HUGO_ENV=preview so deploy previews skip the production override. Version switcher hides the entry (label Next (unreleased)) from the dropdown but is aware of it for tooling.

Makefile Routing Logic

When RELEASE_TAG is set, derive DOC_VERSION (e.g., v1.3.0v1.3). Then:

  1. If content/en/docs/$DOC_VERSION/ exists and is registered as non-hidden in hugo.yaml → target $DOC_VERSION (patch release, update in place)
  2. Otherwise → target next

Without RELEASE_TAG → target next, BRANCH=main.

Scenario Target
make update-all (no tag) next/
make update-all RELEASE_TAG=v1.1.8 (v1.1 exists) v1.1/
make update-all RELEASE_TAG=v1.3.0-rc1 (v1.3 doesn't exist) next/
make update-all RELEASE_TAG=v1.3.0 (v1.3 doesn't exist) next/
make release-next RELEASE_TAG=v1.3.0 copies next/v1.3/
make update-all RELEASE_TAG=v1.3.1 (v1.3 now exists) v1.3/

Makefile Targets

Target Description
make update-all Updates target directory (routed by logic above)
make release-next RELEASE_TAG=vX.Y.Z Copies next/vX.Y/, registers version
make init-next (Re)creates next/ from latest released version
make show-target Debug: prints resolved DOC_VERSION/BRANCH

release-next Flow (hack/release_next.sh)

  1. Validate: next/ exists and is non-empty; RELEASE_TAG is set; derived DOC_VERSION doesn't already exist as a released directory. Fail hard on any validation error.
  2. Copy: cp -a content/en/docs/next/ content/en/docs/$DOC_VERSION/
  3. Rewrite links: sed pass over all .md files in $DOC_VERSION//docs/next//docs/$DOC_VERSION/, "docs/next/"docs/$DOC_VERSION/
  4. Update _index.md: title → Cozystack $DOC_VERSION Documentation, remove the {{% warning %}}…{{% /warning %}} draft banner, set weight: 10
  5. Register version: register_version.sh --release $DOC_VERSION (unhides if already present, or inserts a new entry with auto-computed order)

next/ is never modified during release.

Upstream Workflow Contract

The upstream cozystack/cozystack tags.yaml workflow:

  • Always calls: make update-all RELEASE_TAG=vX.Y.Z
  • Explicitly calls for new minor/major releases only: make release-next RELEASE_TAG=vX.Y.Z
    Upstream PR ci(docs): promote next/ trunk on new minor/major releases cozystack#2433
    The upstream workflow owns the decision of when to call release-next. No automatic detection — explicit conditional logic on the upstream side.

release-next validates and fails hard if preconditions aren't met (no silent no-ops).

Changes vs PR #493

Keep:

  • hidden: true field on version entries in hugo.yaml
  • Content mount exclusion pattern for hidden versions
  • register_version.sh (with modifications)
  • init_version.sh (for edge cases)
  • Dynamic docs landing page
  • Removal of navbar-version-selector.html
  • Weight normalization in _index.md files

Remove / replace:

  • content/en/docs/v1.3/ → replaced by content/en/docs/next/
  • make add-draft → replaced by make init-next
  • "Auto draft-next on make update-all" behavior → replaced by routing logic
  • The concept of numbered draft versions is gone — only next

New:

  • content/en/docs/next/ directory
  • hack/release_next.sh script
  • make release-next and make init-next targets
  • Routing logic in Makefile

Additional build-config details

  • Bumped Hugo to 0.160.1 (netlify.toml, .github/workflows/hugo.yaml) — required for the files: mount-filter syntax, which replaces the deprecated excludeFiles:.
  • yq v4+ is now required for hack/register_version.sh and the Makefile routing conditional.

Test plan

  • Netlify deploy preview renders /docs/next/ with the "Cozystack Next (unreleased)" draft banner
  • Netlify deploy preview version-switcher dropdown does not show next (hidden), /docs/ landing table does not list it
  • Production build (HUGO_ENV=production hugo --gc --minify) produces no public/docs/next/ directory — verified locally ✅
  • Preview build (HUGO_ENV=preview hugo --gc --minify) produces public/docs/next/ populated from the trunk — verified locally ✅
  • make show-target prints correct routing:
    • No tag → DOC_VERSION=next, BRANCH=main
    • RELEASE_TAG=v1.2.9DOC_VERSION=v1.2 (v1.2 is non-hidden)
    • RELEASE_TAG=v1.3.0DOC_VERSION=next (v1.3 doesn't exist)
  • make init-next wipes content/en/docs/next/ and repopulates from the latest released version with the draft banner prepended
  • make release-next RELEASE_TAG=v1.3.0 (dry-run in a throwaway branch) copies next/v1.3/, rewrites links, strips banner, registers the version, leaves next/ intact
  • Spot-check a rewritten link in a newly released directory (e.g., /docs/next/install//docs/v1.3/install/)
  • /docs/ landing page table reflects all non-hidden versions with "Latest (stable)" marker on latest_version_id

Notes

🤖 Generated with Claude Code

Hugo v0.153.0+ replaced the deprecated excludeFiles module-mount key with
files (which supports negative patterns like `! docs/next/**`). The
upcoming trunk-based versioning change uses this syntax to exclude the
new next/ directory from production builds, so bump both netlify.toml
and the GitHub Pages workflow to 0.160.1.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Add the permanent content/en/docs/next/ directory as a version-agnostic
trunk for upcoming/unreleased docs. The content is a copy of v1.2/ with
internal /docs/v1.2/ links rewritten to /docs/next/, and _index.md
retitled "Cozystack Next (unreleased)" with a draft-banner shortcode.

Subsequent commits wire up mount/switcher/makefile support so next/ is
visible in local dev and Netlify deploy previews, excluded from the
GitHub Pages production build, and can be promoted to a released
vX.Y/ directory via hack/release_next.sh.

Replaces the hardcoded v1.3 draft-directory approach from #493.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Adds the `next` version entry (hidden, order 999) so the version switcher
and release tooling know about it, and migrates the content mount from the
deprecated `excludeFiles` to the new `files` syntax (Hugo 0.160+).

Production builds exclude docs/next/** via config/production/hugo.yaml,
which duplicates the full module.mounts list (Hugo replaces arrays
wholesale during config merge). Local dev and Netlify deploy previews
render next/ — the preview context sets HUGO_ENV=preview to skip the
production override.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Version entries with `hidden: true` (like `next`) are now skipped in the
dropdown but remain known to tooling and build configuration.

navbar-version-selector.html duplicated the same logic and is removed;
the dropdown in version-switcher.html is the single source of truth.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Introduces layouts/docs/docs-landing.html, a landing template that iterates
Site.Params.versions at build time. It filters out hidden entries (next),
labels latest_version_id as "Latest (stable)", and links each version's
docs root. Removes the hardcoded version references from the body.

With this, releasing a new version (via release-next/register_version.sh)
requires no edits to the landing page.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Orders version landing pages so newer versions sort above older ones in
Hugo's sidebar/navigation:
  next → 5, v1.2 → 10 (unchanged), v1.1 → 30, v1.0 → 40, v0 → 50

v1.2 stays at weight 10 as the current latest.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Script used by hack/release_next.sh to register a new version (or unhide
an existing hidden one) in hugo.yaml and set it as latest_version_id.

Order is auto-computed from non-hidden entries so new versions slot in
above older ones. The 'next' entry is never touched.

Requires yq v4+.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Given a RELEASE_TAG (e.g., v1.3.0), derives the target minor version
(v1.3), copies content/en/docs/next/ to content/en/docs/v1.3/, rewrites
/docs/next/ links to /docs/v1.3/, strips the draft-banner shortcode
from _index.md, and calls register_version.sh to register v1.3 as the
new latest in hugo.yaml.

Validates preconditions (next/ non-empty, target dir doesn't exist) and
fails hard — there is no silent no-op. next/ itself is never modified,
so the trunk stays in place for the next release cycle.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
When --version=next, the script now rewrites the title/linkTitle to the
unreleased form, sets weight=5, prepends the draft-banner warning
shortcode (idempotently), and skips the usual "Cozystack vX.Y → vX.Y"
rename (no source version appears in next/'s content).

This is what `make init-next` calls to (re)initialize the trunk from the
latest released version.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
RELEASE_TAG drives the routing:
  - no tag                         → next/ (trunk), BRANCH=main
  - tag for released minor (v1.2/) → v1.2/ in place, BRANCH=tag
  - tag for unreleased minor       → next/ (still accumulating), BRANCH=tag

Detection checks both that the target directory exists AND that its
entry in hugo.yaml is non-hidden (via yq). Falls back to directory-only
when yq is absent; `next` is excluded by design as it's always hidden.

Adds new targets:
  - init-next     — rm -rf + reinit next/ from latest released version
  - release-next  — promote next/ to vX.Y/ (requires RELEASE_TAG)
  - show-target   — debug: prints resolved DOC_VERSION/BRANCH

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Replaces the "Creating a new version" section with the trunk-based
workflow (init-next / release-next), documents the RELEASE_TAG routing
table, and notes Hugo 0.160.1 / yq v4+ as new tool requirements.

Also notes next/ behavior in dev and deploy previews (visible) vs
production (excluded via config/production/hugo.yaml) and updates the
upstream release-workflow contract to include release-next for new
minors.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, reopen this pull request to trigger a review.

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 17, 2026

Deploy Preview for cozystack ready!

Name Link
🔨 Latest commit db84d06
🔍 Latest deploy log https://app.netlify.com/projects/cozystack/deploys/69e747a72561b90007b11296
😎 Deploy Preview https://deploy-preview-495--cozystack.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 17, 2026

Important

Review skipped

Too many files!

This PR contains 203 files, which is 53 over the limit of 150.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 48d2003f-506c-4d5f-ae02-c0196f0bda67

📥 Commits

Reviewing files that changed from the base of the PR and between 1e6d68e and db84d06.

⛔ Files ignored due to path filters (13)
  • content/en/docs/next/guides/platform-stack/cozystack-layers.png is excluded by !**/*.png
  • content/en/docs/next/guides/tenants/tenants1.png is excluded by !**/*.png
  • content/en/docs/next/guides/tenants/tenants2.png is excluded by !**/*.png
  • content/en/docs/next/install/providers/servers-com/img/l2_segments1.png is excluded by !**/*.png
  • content/en/docs/next/install/providers/servers-com/img/l2_segments2.png is excluded by !**/*.png
  • content/en/docs/next/install/providers/servers-com/img/l2_segments3.png is excluded by !**/*.png
  • content/en/docs/next/install/providers/servers-com/img/public_ip.png is excluded by !**/*.png
  • content/en/docs/next/install/providers/servers-com/img/ssh_gpg_keys1.png is excluded by !**/*.png
  • content/en/docs/next/install/providers/servers-com/img/ssh_gpg_keys2.png is excluded by !**/*.png
  • content/en/docs/next/install/providers/servers-com/img/ssh_gpg_keys3.png is excluded by !**/*.png
  • content/en/docs/next/install/providers/servers-com/img/type_native.png is excluded by !**/*.png
  • content/en/docs/next/operations/vpc/vm-subnets.png is excluded by !**/*.png
  • content/en/docs/next/operations/vpc/vpc-subnets.png is excluded by !**/*.png
📒 Files selected for processing (203)
  • .github/workflows/hugo.yaml
  • CLAUDE.md
  • CONTRIBUTING.md
  • Makefile
  • config/production/hugo.yaml
  • content/en/docs/_index.md
  • content/en/docs/next/.gitkeep
  • content/en/docs/next/_index.md
  • content/en/docs/next/applications/_include/clickhouse.md
  • content/en/docs/next/applications/_include/foundationdb.md
  • content/en/docs/next/applications/_include/harbor.md
  • content/en/docs/next/applications/_include/kafka.md
  • content/en/docs/next/applications/_include/mariadb.md
  • content/en/docs/next/applications/_include/mongodb.md
  • content/en/docs/next/applications/_include/nats.md
  • content/en/docs/next/applications/_include/openbao.md
  • content/en/docs/next/applications/_include/postgres.md
  • content/en/docs/next/applications/_include/qdrant.md
  • content/en/docs/next/applications/_include/rabbitmq.md
  • content/en/docs/next/applications/_include/redis.md
  • content/en/docs/next/applications/_include/tenant.md
  • content/en/docs/next/applications/_index.md
  • content/en/docs/next/applications/clickhouse.md
  • content/en/docs/next/applications/external.md
  • content/en/docs/next/applications/foundationdb.md
  • content/en/docs/next/applications/harbor.md
  • content/en/docs/next/applications/kafka.md
  • content/en/docs/next/applications/mariadb.md
  • content/en/docs/next/applications/mongodb.md
  • content/en/docs/next/applications/nats.md
  • content/en/docs/next/applications/openbao.md
  • content/en/docs/next/applications/postgres.md
  • content/en/docs/next/applications/qdrant.md
  • content/en/docs/next/applications/rabbitmq.md
  • content/en/docs/next/applications/redis.md
  • content/en/docs/next/applications/tenant.md
  • content/en/docs/next/cozystack-api/_index.md
  • content/en/docs/next/cozystack-api/application-definitions.md
  • content/en/docs/next/cozystack-api/go-types.md
  • content/en/docs/next/cozystack-api/rest.md
  • content/en/docs/next/development.md
  • content/en/docs/next/getting-started/_index.md
  • content/en/docs/next/getting-started/create-tenant.md
  • content/en/docs/next/getting-started/deploy-app.md
  • content/en/docs/next/getting-started/install-cozystack.md
  • content/en/docs/next/getting-started/install-kubernetes.md
  • content/en/docs/next/getting-started/install-talos.md
  • content/en/docs/next/getting-started/requirements.md
  • content/en/docs/next/guides/_index.md
  • content/en/docs/next/guides/concepts.md
  • content/en/docs/next/guides/platform-stack/_index.md
  • content/en/docs/next/guides/resource-management/_index.md
  • content/en/docs/next/guides/talos.md
  • content/en/docs/next/guides/tenants/_index.md
  • content/en/docs/next/guides/use-cases/_index.md
  • content/en/docs/next/guides/use-cases/kubernetes-distribution.md
  • content/en/docs/next/guides/use-cases/private-cloud.md
  • content/en/docs/next/guides/use-cases/public-cloud.md
  • content/en/docs/next/install/_include/hardware-config-tabs.md
  • content/en/docs/next/install/_index.md
  • content/en/docs/next/install/ansible.md
  • content/en/docs/next/install/cozystack/_index.md
  • content/en/docs/next/install/cozystack/kubernetes-distribution.md
  • content/en/docs/next/install/cozystack/platform.md
  • content/en/docs/next/install/hardware-requirements.md
  • content/en/docs/next/install/how-to/_index.md
  • content/en/docs/next/install/how-to/bonding.md
  • content/en/docs/next/install/how-to/hugepages.md
  • content/en/docs/next/install/how-to/kubespan.md
  • content/en/docs/next/install/how-to/public-ip.md
  • content/en/docs/next/install/how-to/single-disk.md
  • content/en/docs/next/install/kubernetes/_index.md
  • content/en/docs/next/install/kubernetes/air-gapped.md
  • content/en/docs/next/install/kubernetes/generic.md
  • content/en/docs/next/install/kubernetes/talm.md
  • content/en/docs/next/install/kubernetes/talos-bootstrap.md
  • content/en/docs/next/install/kubernetes/talosctl.md
  • content/en/docs/next/install/kubernetes/troubleshooting.md
  • content/en/docs/next/install/providers/_index.md
  • content/en/docs/next/install/providers/hetzner.md
  • content/en/docs/next/install/providers/oracle-cloud.md
  • content/en/docs/next/install/providers/servers-com/_index.md
  • content/en/docs/next/install/resource-planning.md
  • content/en/docs/next/install/talos/_index.md
  • content/en/docs/next/install/talos/boot-to-talos.md
  • content/en/docs/next/install/talos/iso.md
  • content/en/docs/next/install/talos/pxe.md
  • content/en/docs/next/introduction/_index.md
  • content/en/docs/next/kubernetes/_include/_index.md
  • content/en/docs/next/kubernetes/_index.md
  • content/en/docs/next/kubernetes/relocate-etcd.md
  • content/en/docs/next/networking/_include/http-cache.md
  • content/en/docs/next/networking/_include/tcp-balancer.md
  • content/en/docs/next/networking/_include/vpc.md
  • content/en/docs/next/networking/_include/vpn.md
  • content/en/docs/next/networking/_index.md
  • content/en/docs/next/networking/architecture.md
  • content/en/docs/next/networking/http-cache.md
  • content/en/docs/next/networking/tcp-balancer.md
  • content/en/docs/next/networking/virtual-router.md
  • content/en/docs/next/networking/vpc.md
  • content/en/docs/next/networking/vpn.md
  • content/en/docs/next/operations/_index.md
  • content/en/docs/next/operations/cluster/_index.md
  • content/en/docs/next/operations/cluster/rotate-ca.md
  • content/en/docs/next/operations/cluster/scaling.md
  • content/en/docs/next/operations/cluster/upgrade.md
  • content/en/docs/next/operations/configuration/_index.md
  • content/en/docs/next/operations/configuration/components.md
  • content/en/docs/next/operations/configuration/platform-package.md
  • content/en/docs/next/operations/configuration/telemetry.md
  • content/en/docs/next/operations/configuration/variants.md
  • content/en/docs/next/operations/configuration/white-labeling.md
  • content/en/docs/next/operations/faq/_index.md
  • content/en/docs/next/operations/faq/generate-kubeconfig.md
  • content/en/docs/next/operations/faq/serviceaccount-api-access.md
  • content/en/docs/next/operations/multi-location/_index.md
  • content/en/docs/next/operations/multi-location/autoscaling/_index.md
  • content/en/docs/next/operations/multi-location/autoscaling/azure.md
  • content/en/docs/next/operations/multi-location/autoscaling/hetzner.md
  • content/en/docs/next/operations/multi-location/local-ccm.md
  • content/en/docs/next/operations/multi-location/networking-mesh.md
  • content/en/docs/next/operations/oidc/_index.md
  • content/en/docs/next/operations/oidc/enable_oidc.md
  • content/en/docs/next/operations/oidc/identity_providers/_index.md
  • content/en/docs/next/operations/oidc/identity_providers/gitlab.md
  • content/en/docs/next/operations/oidc/identity_providers/google.md
  • content/en/docs/next/operations/oidc/self-signed-certificates.md
  • content/en/docs/next/operations/oidc/users_and_roles.md
  • content/en/docs/next/operations/scheduling-classes.md
  • content/en/docs/next/operations/services/_include/bootbox.md
  • content/en/docs/next/operations/services/_include/etcd.md
  • content/en/docs/next/operations/services/_include/ingress.md
  • content/en/docs/next/operations/services/_include/monitoring-overview.md
  • content/en/docs/next/operations/services/_include/monitoring.md
  • content/en/docs/next/operations/services/_include/parameters.md
  • content/en/docs/next/operations/services/_include/seaweedfs.md
  • content/en/docs/next/operations/services/_index.md
  • content/en/docs/next/operations/services/bootbox.md
  • content/en/docs/next/operations/services/etcd.md
  • content/en/docs/next/operations/services/ingress.md
  • content/en/docs/next/operations/services/monitoring/_index.md
  • content/en/docs/next/operations/services/monitoring/alerting.md
  • content/en/docs/next/operations/services/monitoring/custom-metrics.md
  • content/en/docs/next/operations/services/monitoring/dashboards.md
  • content/en/docs/next/operations/services/monitoring/logs.md
  • content/en/docs/next/operations/services/monitoring/parameters.md
  • content/en/docs/next/operations/services/monitoring/setup.md
  • content/en/docs/next/operations/services/object-storage/_index.md
  • content/en/docs/next/operations/services/object-storage/buckets.md
  • content/en/docs/next/operations/services/object-storage/storage-pools.md
  • content/en/docs/next/operations/services/seaweedfs.md
  • content/en/docs/next/operations/services/velero-backup-configuration.md
  • content/en/docs/next/operations/stretched/_index.md
  • content/en/docs/next/operations/stretched/drbd-tuning.md
  • content/en/docs/next/operations/stretched/etcd.md
  • content/en/docs/next/operations/stretched/kubeSchedulerConfiguration.md
  • content/en/docs/next/operations/stretched/labels.md
  • content/en/docs/next/operations/stretched/linstor-dedicated-network.md
  • content/en/docs/next/operations/stretched/seaweedfs-multidc.md
  • content/en/docs/next/operations/troubleshooting/_index.md
  • content/en/docs/next/operations/troubleshooting/etcd.md
  • content/en/docs/next/operations/troubleshooting/flux-cd.md
  • content/en/docs/next/operations/troubleshooting/kube-ovn.md
  • content/en/docs/next/operations/troubleshooting/linstor-controller.md
  • content/en/docs/next/operations/troubleshooting/linstor-database.md
  • content/en/docs/next/operations/troubleshooting/monitoring-troubleshooting.md
  • content/en/docs/next/operations/troubleshooting/piraeus-custom-resources.md
  • content/en/docs/next/operations/upgrades/_index.md
  • content/en/docs/next/operations/vpc/_index.md
  • content/en/docs/next/roadmap.html
  • content/en/docs/next/storage/_index.md
  • content/en/docs/next/storage/dedicated-network.md
  • content/en/docs/next/storage/disk-encryption.md
  • content/en/docs/next/storage/disk-preparation.md
  • content/en/docs/next/storage/drbd-tuning.md
  • content/en/docs/next/storage/nfs.md
  • content/en/docs/next/virtualization/_include/virtual-machine.md
  • content/en/docs/next/virtualization/_include/vm-disk.md
  • content/en/docs/next/virtualization/_include/vm-instance.md
  • content/en/docs/next/virtualization/_index.md
  • content/en/docs/next/virtualization/backup-and-recovery.md
  • content/en/docs/next/virtualization/cloneable-vms.md
  • content/en/docs/next/virtualization/gpu.md
  • content/en/docs/next/virtualization/mikrotik.md
  • content/en/docs/next/virtualization/proxmox-migration.md
  • content/en/docs/next/virtualization/resources.md
  • content/en/docs/next/virtualization/vm-disk.md
  • content/en/docs/next/virtualization/vm-image.md
  • content/en/docs/next/virtualization/vm-instance.md
  • content/en/docs/next/virtualization/windows.md
  • content/en/docs/v0/_index.md
  • content/en/docs/v1.0/_index.md
  • content/en/docs/v1.1/_index.md
  • content/en/docs/v1.2/_index.md
  • hack/init_version.sh
  • hack/register_version.sh
  • hack/release_next.sh
  • hugo.yaml
  • layouts/docs/docs-landing.html
  • layouts/partials/navbar-version-selector.html
  • layouts/partials/version-switcher.html
  • netlify.toml

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/trunk-based-next

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@myasnikovdaniil myasnikovdaniil self-assigned this Apr 17, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a permanent next/ documentation trunk for Cozystack, providing a version-agnostic space for upcoming release documentation. The changes include a comprehensive suite of new guides covering architecture, multi-location clusters, cloud-specific installations, and advanced operations like OIDC and scheduling classes. The feedback identifies a broken link to a missing file, a typo in a CLI flag, and the use of a deprecated Kubernetes API version. Additionally, there are several instances of inconsistent Talos version numbers across the new documentation examples that should be unified.

own etcd (only applicable when the tenant was created with
`etcd: true`).

See [Tenant `isolated` flag removed]({{% ref "/docs/next/operations/upgrades#tenant-isolated-flag-removed" %}})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The link points to /docs/next/operations/upgrades#tenant-isolated-flag-removed, but the file operations/upgrades.md appears to be missing from the next/ directory in this pull request. This will result in a broken link. Please ensure the file is included or update the link to the correct destination.

Copy link
Copy Markdown
Contributor Author

@myasnikovdaniil myasnikovdaniil Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The link is valid. content/en/docs/next/operations/upgrades/_index.md exists and contains the heading "Tenant isolated flag removed" at line 137. With autoHeadingIDType: github in hugo.yaml, Hugo auto-generates the anchor #tenant-isolated-flag-removed, and the ref shortcode resolves the directory index correctly. No change needed.


```bash
talm template -f nodes/node1.yaml -I
talm apply -f nodes/node1.yaml
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Typo in talm flag: -I should be -i (lowercase) to specify the insecure mode when applying the template.

Suggested change
talm apply -f nodes/node1.yaml
talm template -f nodes/node1.yaml -i

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-I is the intended flag — it is --in-place (re-template and overwrite generated files), not a typo for -i (--insecure). talm template --help lists both: -I, --in-place and -i, --insecure. The doc describes re-rendering generated files after editing _helpers.tpl, which is exactly what --in-place does.

cluster:
...
scheduler:
config:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The KubeSchedulerConfiguration version v1beta3 is deprecated. Since this documentation targets upcoming releases (likely Kubernetes 1.31+), it should be updated to v1 to ensure compatibility with modern clusters.

Suggested change
config:
apiVersion: kubescheduler.config.k8s.io/v1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid tech-debt point — v1beta3 graduated to v1 in Kubernetes 1.25. However, this file is a verbatim copy from content/en/docs/v1.2/ (introduced by cp -a when seeding the next/ trunk); this PR does not touch its content. I'd rather land this as a separate content PR that updates both v1.2/ and next/, so the API version stays consistent across published versions.

```console
$ boot-to-talos
Target disk [/dev/sda]:
Talos installer image [ghcr.io/cozystack/cozystack/talos:v1.10.5]:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Talos version in this example (v1.10.5) is inconsistent with other parts of the documentation (e.g., boot-to-talos.md mentions v1.12.6). It is recommended to use a consistent version across all examples in the next/ trunk.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted. The Talos version here is byte-identical to content/en/docs/v1.2/getting-started/install-talos.md (diff shows only path rewrites in links/aliases). The wider inconsistency already exists in v1.2/ across multiple files (v1.9.5, v1.10.3, v1.10.5, v1.11.6, v1.12.6). A consistency sweep should pick a canonical version and update both v1.2/ and next/ in a dedicated content PR — out of scope for this trunk-mechanism change.

- name: vfio_pci
- name: vfio_iommu_type1
install:
image: ghcr.io/cozystack/cozystack/talos:v1.10.3
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Talos version in this configuration snippet (v1.10.3) is inconsistent with other examples in the documentation. Please use a consistent version (e.g., v1.12.6) throughout the next/ trunk.

Suggested change
image: ghcr.io/cozystack/cozystack/talos:v1.10.3
image: ghcr.io/cozystack/cozystack/talos:v1.12.6

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the thread on install-talos.md: this is a verbatim copy from v1.2/. A consistency sweep picking a canonical Talos version should land as a separate content PR touching both v1.2/ and next/. Not introducing content edits in this infrastructure PR.

- name: vfio_pci
- name: vfio_iommu_type1
install:
image: ghcr.io/cozystack/cozystack/talos:v1.10.3
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Talos version in this configuration snippet (v1.10.3) is inconsistent with other examples in the documentation. Please use a consistent version (e.g., v1.12.6) throughout the next/ trunk.

Suggested change
image: ghcr.io/cozystack/cozystack/talos:v1.10.3
image: ghcr.io/cozystack/cozystack/talos:v1.12.6

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same reasoning as the other Talos-version threads — this file is byte-identical to v1.2/install/kubernetes/talos-bootstrap.md. Deferring to a follow-up content PR so the canonical version is aligned across all published docs versions at once.

release_next.sh set the new version's _index.md weight to 10 but left
older versions untouched — so the outgoing latest (also weight 10) would
collide with the incoming one, making sidebar ordering undefined.

register_version.sh now owns weight normalization: after every release
registration it walks all non-hidden version entries sorted by `order`
descending and rewrites each _index.md weight to 10, 20, 30, …. The
permanent `next` trunk stays at weight 5 (set by init_version.sh) and
is not touched. The redundant weight sed is removed from release_next.sh.

Verified end-to-end with a simulated v1.3 release:
  next → 5, v1.3 → 10, v1.2 → 20, v1.1 → 30, v1.0 → 40, v0 → 50.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Explains the versioning model (independent per-minor directories, no
auto-backport), why `next/` exists (writing upcoming-release docs
without committing to a version number), where to make each kind of
change, how autogenerated content sync works, and the full release
lifecycle including `release-next` and `init-next`.

Mirrors CLAUDE.md's reference material but in a narrative form aimed at
human contributors — CLAUDE.md stays as the terse machine-readable
reference.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Copy link
Copy Markdown
Contributor

@lexfrei lexfrei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the design and the routing/lifecycle scripts with a focus on completeness and release-time correctness. Overall the design is sound (permanent next/ trunk, production exclusion via a dedicated config, Makefile routing, version registration in hugo.yaml). Commits are atomic and CONTRIBUTING.md is excellent.

Two gaps in the end-to-end flow are worth closing before merge, plus one content-hygiene item and a few nits.

Blocking

1. aliases: - /docs/v1/ does not move between latest versions

v1.2/_index.md carries aliases: - /docs/v1/. Hugo aliases are server-side redirects, so after release-next promotes next/ to v1.3, /docs/v1/ still points at the now-stale v1.2. The JS fallback in layouts/404.html does not help — Hugo's alias wins with a 200 redirect before the 404 renders.

hack/release_next.sh should: (a) strip the /docs/v<major>/ alias from the previous latest_version_id _index.md, and (b) add it to the new one. Otherwise every new minor release quietly breaks the short path.

2. Upstream workflow contract is not linked

The design delegates "when to call release-next vs update-all" to cozystack/cozystack tags.yaml. There's no companion PR referenced in this one. Until that lands upstream, release-next is never invoked and the flow is not actually end-to-end. Please link the companion upstream PR (or explicitly mark it as a required follow-up in the PR description).

Content hygiene (not blocking, but should land before the next release)

3. release_next.sh rewrites URLs, not prose

The sed pass only rewrites /docs/next//docs/vX.Y/. Version references in prose are promoted verbatim:

  • next/install/talos/boot-to-talos.md:27 — "For Cozystack v1.2.x the pinned Talos version is v1.12.6"
  • next/install/talos/boot-to-talos.md:36 — "Cozystack v1.2.x … Talos v1.11"
  • next/cozystack-api/go-types.md:16go get …@v1.2.0
  • next/operations/scheduling-classes.md:35 — "Cozystack v1.2+"

These are inherited from v1.2, but at the release boundary they become factually wrong on the v1.3 pages. At minimum, add a release checklist item to CONTRIBUTING.md ("audit version-specific prose before release-next"). Ideally the script does a targeted sed pass for known patterns (Cozystack v<prev>, @v<prev>.0).

Nits

  • make init-next is destructive and manual. It silently rm -rfs content/en/docs/next/ and re-initializes. After release-next the trunk still holds a stale copy, and the moment init-next runs is left to a human. Consider either chaining init-next at the end of release-next, or guarding against a dirty tree inside next/.
  • release_next.sh:47 accepts pre-release tags. The regex ^v([0-9]+)\.([0-9]+)\.([0-9]+).*$ happily matches v1.3.0-rc1 and would promote next/ from an RC. The PR description says release-next is "for new minor/major releases only" — the script should enforce that.
  • register_version.sh uses non-portable sed -i. Lines 67, 72, 78, 80 use sed -i "..." without an extension (GNU-only). The neighbouring release_next.sh uses the portable sed -i.bak idiom. Fine on Linux CI, but inconsistent.
  • label: "Next (unreleased)" in hugo.yaml:126 is unused. Neither version-switcher.html nor docs-landing.html reads .label. On a /docs/next/ preview page the switcher button shows next (from .version). Either wire label into the switcher for hidden entries, or drop the field.
  • release_next.sh:98-99 comment is misleading. The comment says "Collapse any double blank lines", but '/./,/^$/!d' actually strips leading/trailing blank lines. The effect is correct for this input shape, but the comment will mislead the next reader.

Strengths

  • Clean separation: trunk vs production override vs Makefile routing.
  • release_next.sh fail-fast preconditions (non-empty next/, target directory absent) are the right shape.
  • CONTRIBUTING.md is thorough; decision table + command reference make contributor onboarding easy.
  • [context.deploy-preview.environment] HUGO_ENV=preview is a tidy way to opt previews into the trunk.
  • Verified locally: next/ has the same 198 files as v1.2/, and no stray /docs/v1.2/ link slipped into next/.

- release_next.sh: reject pre-release RELEASE_TAGs (v1.3.0-rc1 etc.) so only
  final releases can promote next/ → vX.Y/
- release_next.sh: tighten the comment on the post-banner cleanup sed to
  describe what it actually does (trims leading/trailing blanks, collapses
  runs of blanks), instead of the inaccurate "collapse double blank lines"
- v1.2/_index.md: drop stale "aliases: - /docs/v1/". The 404 JS fallback in
  layouts/404.html already redirects /docs/v<major>/... to the current latest
  dynamically via Site.Params.latest_version_id, so a Hugo alias is both
  unnecessary and actively harmful (it shadows the fallback and pins the
  short path at whichever version last held the alias)
- register_version.sh: use portable "sed -i.bak" with a single trailing
  cleanup, matching the existing pattern in release_next.sh
- hugo.yaml: drop unused "label: Next (unreleased)" from the next version
  entry — no layout reads .label
- CONTRIBUTING.md: add a "Pre-release audit" subsection with grep patterns
  that catch version-specific prose inherited from the previous release
  (release_next.sh rewrites URL paths but not body text)
- CONTRIBUTING.md: promote "make init-next" from "common practice" to a
  mandatory final step of every release, so the trunk never lingers with
  already-released content

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@myasnikovdaniil
Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review — addressed all eight items; next/ stays untouched as designed. Fixes land in d7a0008. Summary per item:

Blocking

  1. /docs/v1/ redirect — dropped the stale aliases: - /docs/v1/ from v1.2/_index.md instead of moving it. The JS fallback in layouts/404.html already computes the major prefix from Site.Params.latest_version_id and redirects subpaths to the current latest, so with no Hugo alias shadowing it, the 404 fires and the redirect resolves to whatever the registered latest is at the time. register_version.sh updates latest_version_id during release, so this tracks automatically — no release-time alias shuffling, and no per-major bookkeeping in release_next.sh.
  2. Upstream workflow contract — the companion change in cozystack/cozystack is planned but not yet submitted, so no PR to link. Until it lands, release-next is a no-op in CI; website-side behaviour is unchanged. Will reference the upstream PR in the description once it's up.

Content hygiene

  1. Added a "Pre-release audit" subsection to CONTRIBUTING.md with the grep patterns that catch the prose stragglers (Cozystack v[0-9], @v[0-9], talos:v[0-9]). Opted for a checklist over a sed pass — automated rewriting of prose is too easy to get wrong on pinned image tags and "since vX.Y" phrasing.

Nits

  1. Tightened the "Resetting the trunk after release" section in CONTRIBUTING.md to make make init-next a mandatory final step rather than "common practice". Not chaining into release-next itself — keeps the script scoped to the copy/register step.
  2. Regex is now ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ — rejects -rc1/-beta suffixes. Pre-release tags still accumulate in next/ via update-all, per the routing table.
  3. register_version.sh uses sed -i.bak with a single cleanup rm -f after the block, matching release_next.sh.
  4. Dropped the unused label: field from the next entry in hugo.yaml.
  5. Tightened the blank-line comment to describe what /./,/^$/!d actually does (strips leading/trailing blanks, collapses runs of blanks to one).

@myasnikovdaniil
Copy link
Copy Markdown
Contributor Author

Added upstream PR
cozystack/cozystack#2433

Copy link
Copy Markdown
Contributor

@lexfrei lexfrei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All review points from the previous round are addressed in d7a0008.

Blockers resolved

  • aliases: - /docs/v1/ was dropped from v1.2/_index.md; the short path is now handled dynamically by layouts/404.html via Site.Params.latest_version_id, so no release-time alias shuffling is needed. The script header documents this decision.
  • Companion upstream PR cozystack/cozystack#2433 is linked in the PR body, so the end-to-end flow has a landing target.

Content hygiene

  • CONTRIBUTING.md gained a "Pre-release audit" section with ready-to-run grep patterns (Cozystack v[0-9], @v[0-9], talos:v[0-9]) — good compromise short of automating prose rewrites in the script.

Nits cleaned up

  • release_next.sh regex tightened to ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ (no pre-release suffix), with a clear error.
  • register_version.sh standardized on sed -i.bak + cleanup, matching release_next.sh.
  • Unused label: field removed from hugo.yaml.
  • '/./,/^$/!d' comment rewritten to describe actual behavior.
  • init-next section in CONTRIBUTING.md promoted to "Run this as the final step of every release" with rationale — documentation-only, but explicit enough.

One minor follow-up (not blocking): netlify.toml:26-29 still hardcodes /docs/v1/* → /docs/v1.2/:splat, which will go stale when latest_version_id moves to v1.3. Preview-only and pre-existing, so fine to pick up separately.

LGTM.

@myasnikovdaniil myasnikovdaniil merged commit 6a684d0 into main Apr 21, 2026
6 checks passed
@myasnikovdaniil myasnikovdaniil deleted the feat/trunk-based-next branch April 21, 2026 09:47
myasnikovdaniil added a commit to cozystack/cozystack that referenced this pull request Apr 21, 2026
## What this PR does

Updates the `update-website-docs` job in `.github/workflows/tags.yaml`
to match the new docs-versioning contract introduced in
cozystack/website#495.

The website repo replaces the old "pre-create `vX.Y/` draft directory"
scheme with a permanent `content/en/docs/next/` trunk. Released version
directories are no longer implicitly pre-created — the upstream release
workflow owns the explicit decision of when to promote `next/` →
`vX.Y/`.

### Changes

- **New step `Determine if this release promotes next/`** — parses the
tag and only sets `promote=true` for final `vX.Y.Z` tags where
`content/en/docs/vX.Y/` does not already exist. Prereleases
(`vX.Y.Z-rc.N`, etc.) and patch releases skip promotion.
- **New step `Promote next/ to released version`** — gated on
`promote=true`; runs `make release-next RELEASE_TAG=<tag>`.
- **Step order**: `release-next` runs **before** `update-all`. This way
`update-all` routes into the freshly-created `vX.Y/` directory (per the
website Makefile's routing logic), and `next/` stays untouched as the
trunk for the following release.
- **`git add content hugo.yaml`** — `release-next` registers the new
version in `hugo.yaml` via `register_version.sh`, so the commit step
must stage it.
- Converted the existing `update-all` step to use `env:` vars for
consistency with the new step and workflow-injection hardening.

### Behaviour by tag

| Tag | `release-next`? | `update-all` targets |
|-----|-----------------|----------------------|
| `v1.3.0` (v1.3 does not exist) | yes — promotes next/ → v1.3/ | v1.3/
|
| `v1.3.1` (v1.3 exists) | no — skipped | v1.3/ |
| `v1.3.0-rc.1` | no — skipped (prerelease) | next/ |
| `v2.0.0` (v2.0 does not exist) | yes — promotes next/ → v2.0/ | v2.0/
|

### Release note

```release-note
Release tagging now promotes the website's `next/` docs trunk to `vX.Y/` when cutting a new minor or major release (requires cozystack/website#495 to be merged first).
```

### Dependency

Must not merge until cozystack/website#495 is merged on `main` of the
website repo, otherwise `make release-next` won't exist there and
new-minor release tags will fail.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated release automation to apply conditional logic for version
promotion based on tag patterns and documentation availability. Modified
documentation staging behavior in release workflows.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
pull Bot pushed a commit to medampudi/cozystack that referenced this pull request Apr 21, 2026
The website repo is switching to a permanent `content/en/docs/next/`
trunk (cozystack/website#495). Released version directories are no
longer pre-created — the upstream release workflow is now responsible
for explicitly promoting `next/` → `vX.Y/` on new minor/major releases
via `make release-next`.

Update the `update-website-docs` job to match that contract:

- New `Determine if this release promotes next/` step parses the tag
  and only enables promotion for final `vX.Y.Z` tags where
  `content/en/docs/vX.Y/` does not already exist. Prereleases and
  patch releases keep the old behaviour (target routing is handled
  by the website Makefile on its own).
- New `Promote next/ to released version` step runs
  `make release-next RELEASE_TAG=...` before `make update-all`, so
  the subsequent `update-all` routes into the freshly-created
  `vX.Y/` directory and `next/` stays untouched as the trunk for
  the following release.
- `git add content hugo.yaml` to pick up the version registration
  that `release-next` writes via `register_version.sh`.
- Convert the existing `update-all` step to use `env:` vars,
  matching the new step and addressing the workflow-injection
  hardening guidance.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants