Skip to content

Refactor docs versions to major.minor variants#477

Merged
myasnikovdaniil merged 4 commits intomainfrom
feat/refactor-versioning
Apr 15, 2026
Merged

Refactor docs versions to major.minor variants#477
myasnikovdaniil merged 4 commits intomainfrom
feat/refactor-versioning

Conversation

@myasnikovdaniil
Copy link
Copy Markdown
Contributor

@myasnikovdaniil myasnikovdaniil commented Apr 9, 2026

Summary

Refactors the docs versioning structure from v0/v1 to per-minor-version directories (v0, v1.0, v1.1, v1.2), making the site compatible with the push-based docs update pipeline from cozystack/cozystack#2214.

What changed

Docs structure:

  • Renamed content/en/docs/v1/v1.0/
  • Bootstrapped v1.1 and v1.2 from v1.0, then pulled actual content from release-1.1 and release-1.2 branches
  • Added 301 redirect /docs/v1/*/docs/v1.0/:splat in netlify.toml for backward compatibility

Version-aware Makefile:

  • RELEASE_TAG=v1.2.1 automatically derives DOC_VERSION=v1.2, BRANCH=release-1.2
  • override BRANCH fixes the mismatch where cozystack passes BRANCH=release-1.2.1 but the actual branch is release-1.2
  • New targets: init-version (bootstrap new version dir), download-openapi, download-openapi-all

OpenAPI spec out of git:

  • v0 and v1.0 keep api.json in-repo (no release asset available for those versions)
  • v1.1 also keeps a copy in-repo (v1.1.x releases predate the openapi.json artifact)
  • v1.2+ downloads openapi.json from GitHub releases at Netlify build time via hack/download_openapi.sh
  • static/docs/*/cozystack-api/ added to .gitignore

Version switcher UI:

  • Refactored from inline buttons to a Bootstrap dropdown — scales cleanly as versions grow
  • Fixed version-banner.html — replaced int() cast (breaks on v1.0) with index-based comparison

GitHub workflow:

  • update-managed-apps.yaml now accepts RELEASE_TAG via dispatch payload or workflow input
  • Daily sync targets latest version (read from hugo.yaml)
  • Per-version PR branches: update-managed-apps-v1.2

New scripts

  • hack/init_version.sh — copies content from previous version, updates all internal refs, removes api.json
  • hack/download_openapi.sh — downloads openapi.json from GitHub releases at build time (works without gh CLI)

Note for cozystack/cozystack#2214

The update-website-docs job passes BRANCH=release-X.Y.Z (full version) but cozystack release branches are release-X.Y (major.minor). This PR handles the mismatch via override BRANCH in the Makefile, but ideally the cozystack workflow should also be fixed to pass BRANCH=release-X.Y.

🤖 Generated with Claude Code

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 9, 2026

Deploy Preview for cozystack ready!

Name Link
🔨 Latest commit 332bf33
🔍 Latest deploy log https://app.netlify.com/projects/cozystack/deploys/69de5cdc3e17a10007087090
😎 Deploy Preview https://deploy-preview-477--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 9, 2026

Important

Review skipped

Too many files!

This PR contains 276 files, which is 126 over the limit of 150.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9db6561f-0186-4002-a217-07c597b1287c

📥 Commits

Reviewing files that changed from the base of the PR and between 1d856cd and 332bf33.

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

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/refactor-versioning

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.

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 implements a versioned documentation structure, organizing content into version-specific directories and updating the build system to support version derivation from release tags. Key changes include Makefile updates for automated versioning and OpenAPI spec management, a redesign of the sidebar version switcher into a dropdown menu, and a comprehensive update of internal documentation links. Feedback focuses on correcting link formatting in the new documentation files to ensure absolute paths and versioned references are used correctly.

- `./packages/apps`: Helm charts for applications that can be installed from the dashboard.

Just like standard Cozystack applications, this external application package is using Helm and FluxCD.
To learn more about developing application packages, read Cozystack [Developer Guide](/docs/development/)
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 link to the Developer Guide is a root-relative link (/docs/development/) which might not resolve correctly within the versioned documentation structure. To ensure it points to the correct versioned guide, please use the ref shortcode with an absolute path, similar to other links in the documentation.

Suggested change
To learn more about developing application packages, read Cozystack [Developer Guide](/docs/development/)
To learn more about developing application packages, read Cozystack [Developer Guide]({{% ref "/docs/v1.1/development" %}})

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.

Replaced the plain /docs/development/ link with a Hugo ref shortcode pointing to the versioned development page. Applied across v1.0, v1.1, and v1.2. Fixed in f8abb15.

Comment thread content/en/docs/v1.1/guides/concepts.md Outdated
Comment on lines +41 to +81
Read more: [Tenant System]({{% ref "docs/v1.1/guides/tenants" %}}).

## Tenant Cluster

Users can deploy separate Kubernetes clusters in their own tenants.
These are not namespaces of the management cluster, but complete Kubernetes-in-Kubernetes clusters.

Tenant clusters are what many cloud providers call "managed Kubernetes".
They are used as development, testing, and production environments.

Read more: [tenant Kubernetes clusters]({{% ref "docs/v1.1/kubernetes" %}}).

## Managed Applications

Cozystack comes with a catalog of **managed applications** (services) that can be deployed on the platform with minimal effort.
These include relational databases (PostgreSQL, MySQL/MariaDB), NoSQL/queues (Redis, NATS, Kafka, RabbitMQ), HTTP cache, load balancer, and others.

Tenants, tenant Kubernetes clusters, and VMs are also managed applications in terms of Cozystack.
They are created with the same user workflow and are managed with Helm and Flux, just as other applications.

Read more: [managed applications]({{% ref "/docs/v1.1/applications" %}}).

## Cozystack API

Instead of a proprietary API or UI-only management, Cozystack exposes its functionality through
[Kubernetes Custom Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)
and the standard Kubernetes API, accessible via REST API, `kubectl` client, and the Cozystack dashboard.

This approach combines well with role-based access control.
Non-administrative users can use `kubectl` to access the management cluster,
but their kubeconfig will authorize them only to create custom resources in their tenants.

Read more: [Cozystack API]({{% ref "/docs/v1.1/cozystack-api" %}}).

## Variants

Variants are pre-defined configurations of Cozystack that determine which bundles and components are enabled.
Each variant is tested, versioned, and guaranteed to work as a unit.
They simplify installation, reduce the risk of misconfiguration, and make it easier to choose the right set of features for your deployment.

Read more: [Variants]({{% ref "/docs/v1.1/operations/configuration/variants" %}}).
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

Several links in this document are missing a leading slash / in the ref shortcode path. This will cause them to be treated as relative links and likely fail to resolve. Please add a leading slash to make them absolute paths from the content root.

This applies to the following links:

  • [Tenant System]({{% ref "docs/v1.1/guides/tenants" %}}) on line 41
  • [tenant Kubernetes clusters]({{% ref "docs/v1.1/kubernetes" %}}) on line 51
  • [managed applications]({{% ref "docs/v1.1/applications" %}}) on line 61
  • [Cozystack API]({{% ref "docs/v1.1/cozystack-api" %}}) on line 73
  • [Variants]({{% ref "docs/v1.1/operations/configuration/variants" %}}) on line 81

For example, the link on line 41 should be:
[Tenant System]({{% ref "/docs/v1.1/guides/tenants" %}})

Read more: [Tenant System]({{% ref "/docs/v1.1/guides/tenants" %}}).

## Tenant Cluster

Users can deploy separate Kubernetes clusters in their own tenants.
These are not namespaces of the management cluster, but complete Kubernetes-in-Kubernetes clusters.

Tenant clusters are what many cloud providers call "managed Kubernetes".
They are used as development, testing, and production environments.

Read more: [tenant Kubernetes clusters]({{% ref "/docs/v1.1/kubernetes" %}}).

## Managed Applications

Cozystack comes with a catalog of **managed applications** (services) that can be deployed on the platform with minimal effort.
These include relational databases (PostgreSQL, MySQL/MariaDB), NoSQL/queues (Redis, NATS, Kafka, RabbitMQ), HTTP cache, load balancer, and others.

Tenants, tenant Kubernetes clusters, and VMs are also managed applications in terms of Cozystack.
They are created with the same user workflow and are managed with Helm and Flux, just as other applications.

Read more: [managed applications]({{% ref "/docs/v1.1/applications" %}}).

## Cozystack API

Instead of a proprietary API or UI-only management, Cozystack exposes its functionality through 
[Kubernetes Custom Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) 
and the standard Kubernetes API, accessible via REST API, `kubectl` client, and the Cozystack dashboard.

This approach combines well with role-based access control.
Non-administrative users can use `kubectl` to access the management cluster, 
but their kubeconfig will authorize them only to create custom resources in their tenants.

Read more: [Cozystack API]({{% ref "/docs/v1.1/cozystack-api" %}}).

## Variants

Variants are pre-defined configurations of Cozystack that determine which bundles and components are enabled.
Each variant is tested, versioned, and guaranteed to work as a unit.
They simplify installation, reduce the risk of misconfiguration, and make it easier to choose the right set of features for your deployment.

Read more: [Variants]({{% ref "/docs/v1.1/operations/configuration/variants" %}}).

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.

Added leading / to ref shortcode paths that were missing it. Also fixed the same issue in hetzner.md, monitoring/logs.md, monitoring/alerting.md, monitoring/dashboards.md, and operations/services/_index.md across all versions. Fixed in dc7476d.

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.

Major refactor of docs versioning into per-minor-version directories. The UI, redirects, and build-time OpenAPI download all work on the deploy preview. However, the sync automation has three blocking issues that will ship incorrect content to production.

Blocker 1: v1.1 api.json is a byte-for-byte copy of the v1.0 spec

content/en/docs/v1.1/cozystack-api/api.json has md5 6476e14adf822b931aa52dd481b1a3e6 and size 1818459 bytes — identical to content/en/docs/v1.0/cozystack-api/api.json. The v1.1 swagger UI will silently serve the v1.0 schema. Per v1.1.0 release notes, v1.1 introduces OpenBAO, tiered object storage user model, RabbitMQ version selection, and MongoDB dashboards — none of which appear in the v1.0 spec.

Since v1.1.x releases don't ship an openapi.json asset and hack/download_openapi.sh:38 skips versions with api.json already in content/, this will never be auto-corrected.

Fix: extract the real v1.1 spec from a running v1.1.x cluster (kubectl get --raw '/openapi/v3/apis/apps.cozystack.io/v1alpha1') and commit it.

(GitHub rejected an inline comment on api.json because the diff is too large; see Makefile:13 and the workflow comment for the other two blockers.)

Blocker 2: daily/manual sync without RELEASE_TAG overwrites stable v1.2 docs with main

See inline on Makefile:13.

Blocker 3: shell injection in release_tag

See inline on .github/workflows/update-managed-apps.yaml:36.

Extra observation: .github/workflows/hugo.yaml skips the OpenAPI download

Production cozystack.io (Netlify) is fine — netlify.toml calls ./hack/download_openapi.sh before hugo. But this workflow (contributor forks deploying to personal GitHub Pages) does not, so the v1.2 swagger UI will 404 on fork previews. Either add make download-openapi-all before Build with Hugo, or delete the workflow if unused. (Not commented inline because the file isn't modified in this PR.)

Non-blocking observations and suggestions are inline.

Comment thread Makefile
override BRANCH := release-$(_major).$(_minor)
else
DOC_VERSION ?= v1.2
BRANCH ?= main
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.

Blocker: BRANCH fallback silently overwrites v1.2 docs with main.

When RELEASE_TAG is absent, BRANCH defaults to main. The scheduled daily run and manual dispatch without a tag enter this branch: the workflow reads LATEST=v1.2 from hugo.yaml, then calls make update-all DOC_VERSION=v1.2. hack/update_apps.sh then fetches READMEs from raw.githubusercontent.com/cozystack/cozystack/main/... and stamps source: links pointing to main, overwriting the curated v1.2 docs with unreleased content.

Fix: derive BRANCH from DOC_VERSION when no release tag is given, e.g. BRANCH ?= release-$(DOC_VERSION:v%=%) (with a v0main special case), or pass BRANCH explicitly from the workflow's "latest" path.

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.

This will be addressed by cozystack/cozystack#2214, which moves the website docs pipeline from pull-based (daily schedule) to push-based (triggered on release). The daily schedule and the fallback path will be removed entirely once that lands.

id: version
run: |
# Get release tag from dispatch payload, workflow input, or default to empty
RELEASE_TAG="${{ github.event.client_payload.release_tag || github.event.inputs.release_tag || '' }}"
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.

Blocker: shell injection in release_tag.

${{ ... }} expands before the shell runs. A payload like v1.2.1"; touch /tmp/pwn; # becomes RELEASE_TAG="v1.2.1"; touch /tmp/pwn; #" on the runner. repository_dispatch requires a PAT, but this is still the standard hardening pattern called out in GitHub's Actions security guide.

Fix: pass via env:, then validate format before use:

env:
  RELEASE_TAG_INPUT: ${{ github.event.client_payload.release_tag || github.event.inputs.release_tag || '' }}
run: |
  if [[ -n "$RELEASE_TAG_INPUT" && ! "$RELEASE_TAG_INPUT" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    echo "Invalid release tag format" >&2; exit 1
  fi
  RELEASE_TAG="$RELEASE_TAG_INPUT"

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.

Fixed — release_tag is now passed via env: and validated against ^v[0-9]+\.[0-9]+\.[0-9]+$ before use. All other ${{ steps.* }} references in run: blocks were also moved to env:. See ef4648f.

Comment thread Makefile Outdated
_major := $(word 1,$(subst ., ,$(_ver)))
_minor := $(word 2,$(subst ., ,$(_ver)))
DOC_VERSION := $(if $(filter 0,$(_major)),v0,v$(_major).$(_minor))
override BRANCH := release-$(_major).$(_minor)
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.

Observation (non-blocking): RELEASE_TAG does not pin to the tag.

override BRANCH := release-$(_major).$(_minor) fetches from the rolling release-1.2 branch, not from the tag. After v1.2.1 is tagged, later patches can land on release-1.2 before v1.2.2, so re-running make update-all RELEASE_TAG=v1.2.1 produces different output over time. raw.githubusercontent.com accepts tags as refs, so BRANCH := $(RELEASE_TAG) would give reproducible builds.

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.

Good catch — changed override BRANCH from release-$(_major).$(_minor) to $(RELEASE_TAG) so builds are pinned to the exact tag. See ef4648f.

Comment thread hack/init_version.sh Outdated
find "$TARGET_DIR" -name 'api.json' -delete

# Update internal doc references (both /docs/vX.Y/ URLs and "docs/vX.Y/" Hugo refs)
find "$TARGET_DIR" -name '*.md' -exec sed -i \
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.

Observation (non-blocking): GNU sed -i is not portable.

sed -i without a backup suffix works on GNU sed (Linux CI) but fails on BSD sed (macOS). Maintainers running make init-version locally on Mac get an error. Either use sed -i.bak ... && find -name '*.bak' -delete, branch on uname, or switch to Perl/Python.

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.

Switched to sed -i.bak with subsequent cleanup across all sed invocations in the script. See ef4648f.

Comment thread hack/download_openapi.sh
}

# Fetch all releases once (up to 100)
RELEASES_JSON=$(curl_gh "${API_BASE}/releases?per_page=100")
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.

Observation (non-blocking): unauthenticated GitHub API per build.

curl_gh "${API_BASE}/releases?per_page=100" runs on every Netlify build, deploy preview, and branch deploy without a token by default (60 req/hr/IP). Preview-heavy periods from the shared Netlify egress pool can exhaust the quota and make builds flaky. Provision a GITHUB_TOKEN env in Netlify, or pin release tags in repo metadata and skip the API entirely.

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.

The script already supports GITHUB_TOKEN when set (lines 16–19) — it adds the Authorization header to all curl_gh calls. The remaining piece is provisioning the token in Netlify site settings, which is an ops configuration change outside this PR.

Comment thread Makefile
update-api:
kubectl get --raw '/openapi/v3/apis/apps.cozystack.io/v1alpha1' > content/en/docs/cozystack-api/api.json
# Download openapi.json for a specific version from GitHub release
download-openapi:
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.

Observation (non-blocking): silent no-op without RELEASE_TAG.

Without RELEASE_TAG, this target produces no output and exits 0 — looks successful. Add $(error RELEASE_TAG is required) in an else branch, or only expose download-openapi-all publicly.

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.

Added $(error RELEASE_TAG is required ...) via ifndef RELEASE_TAG so the target fails loudly instead of silently succeeding. See ef4648f.

{{- with site.GetPage $trimmed -}}
{{- $targetPath = .RelPermalink -}}
<div class="version-switcher dropdown">
<button class="version-switcher__toggle dropdown-toggle" type="button"
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.

Observation (non-blocking): accessibility and single-version rendering.

The button has no id, so the menu cannot use aria-labelledby (compare layouts/partials/navbar-version-selector.html:9-19). The dropdown also renders even when only one version exists. Short-circuit to plain text when len .Site.Params.versions <= 1 and add the id/aria-labelledby pair.

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.

Added id="versionSwitcherButton" and aria-labelledby="versionSwitcherButton" to match navbar-version-selector.html. The dropdown now short-circuits to plain text when only one version exists. See ef4648f.

Comment thread layouts/partials/version-banner.html Outdated
{{- /* Use index in versions list (ordered newest-first) to compare */ -}}
{{- $currentIdx := -1 -}}
{{- $latestIdx := -1 -}}
{{- range $i, $v := .Site.Params.versions -}}
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.

Observation (non-blocking): index-based comparison is order-dependent.

The new logic computes "newer/older" from position in .Site.Params.versions. It only works because that list happens to be newest-first in hugo.yaml. A future reorder or non-chronological insertion would silently flip the "beta" and "older release" banners. Either compare the version string as semver or add an explicit order field.

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.

Added an explicit order field to each entry in hugo.yaml versions list. The banner template now compares order values instead of array indices — safe against reordering. See ef4648f.

Comment thread package-lock.json
@@ -1,5 +1,5 @@
{
"name": "cozystack.io",
"name": "website",
"lockfileVersion": 2,
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.

Observation (non-blocking): unrelated change.

"name" changed from "cozystack.io" to "website", unrelated to the versioning refactor. Revert or split into a separate PR.

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.

Reverted — name is back to "cozystack.io". See ef4648f.

Comment thread content/en/docs/_index.md Outdated
**Additional Resources:**
- [Release notes](https://github.com/cozystack/cozystack/releases)
- [v0 to v1 upgrade guide](/docs/v1/operations/upgrades/)
- [v0 to v1 upgrade guide](/docs/v1.2/operations/upgrades/)
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.

Observation (non-blocking): link text says "v1", points to v1.2.

- [v0 to v1 upgrade guide](/docs/v1.2/operations/upgrades/)

Rename to "v0 to v1.x upgrade guide" for consistency.

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.

Changed to "v0 to v1.x upgrade guide". See ef4648f.

@myasnikovdaniil myasnikovdaniil force-pushed the feat/refactor-versioning branch from ba18305 to dc7476d Compare April 14, 2026 15:04
myasnikovdaniil and others added 4 commits April 14, 2026 20:25
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
- Fix shell injection: pass release_tag via env + validate format
- Pin BRANCH to exact tag for reproducible builds
- Add explicit order field to versions config for banner comparison
- Add error for download-openapi without RELEASE_TAG
- Make sed portable (BSD/macOS) in init_version.sh
- Add id/aria-labelledby to version-switcher, skip dropdown for single version
- Revert unrelated package-lock.json name change
- Fix "v1" → "v1.x" in upgrade guide link text
- Fix stale /docs/v1/ refs from rebase (new upstream content)
- Distribute application-definitions.md to v1.0, v1.1, v1.2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Address review feedback from gemini-code-assist on
content/en/docs/v1.1/applications/external.md:26:
replace plain /docs/development/ link (404s in versioned docs) with
Hugo ref shortcode pointing to the versioned development page.
Applied across v1.0, v1.1, v1.2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Address review feedback from gemini-code-assist on
content/en/docs/v1.1/guides/concepts.md:41:
ref shortcodes without leading / are relative paths; add / to make
them absolute from the content root. Applied across all affected
files in v1.0, v1.1, v1.2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@myasnikovdaniil myasnikovdaniil force-pushed the feat/refactor-versioning branch from dc7476d to 332bf33 Compare April 14, 2026 15:26
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.

Fixes in 00720fb, 475a8a9, and 332bf33 address the shell injection blocker and all non-blocking observations from the previous review — nice work.

My previous blocker (v1.1 api.json is a byte-for-byte copy of v1.0) remains unresolved.


Observation (non-blocking): content/en/docs/v0/_index.md:8 has weight: 20, same as v1.1. Hugo resolves ties alphabetically by title, which places "v0" before "v1.1" in the sidebar. Expected order: v1.2 → v1.1 → v1.0 → v0 (newest first). Setting v0’s weight to 40 would fix the ordering.

@myasnikovdaniil
Copy link
Copy Markdown
Contributor Author

Re: Blocker 1 — v1.1 api.json byte-for-byte copy of v1.0.

We're going to leave this as-is; it's not a regression introduced by this PR.

  • Before this refactor, the 1.x docs lived under a single unified /docs/v1/ tree with one shared api.json. Splitting that tree into per-minor directories (v1.0/, v1.1/, v1.2/) copies that same spec into both v1.0 and v1.1 — so what you see in v1.1 is what the unified tree already served.
  • The build-time OpenAPI pipeline (hack/download_openapi.sh fetching the per-release openapi.json asset) is new and starts at v1.2.x; earlier releases don't ship that asset.
  • Reconstructing a "real" v1.1 spec from a running v1.1 cluster is out of scope here. v1.1 docs remain intentionally stale for the OpenAPI surface, same as before this PR. If we want to backfill a correct v1.1 spec later, it can be done in a follow-up — it's independent of this refactor.

@myasnikovdaniil myasnikovdaniil merged commit b299b57 into main Apr 15, 2026
6 checks passed
@myasnikovdaniil myasnikovdaniil deleted the feat/refactor-versioning branch April 15, 2026 13:45
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.

2 participants