Prepare v6.0.5 RC1 release packet
Some checks are pending
Build and Test / Secret Scan (push) Waiting to run
Build and Test / Frontend & Backend (push) Waiting to run
Canonical Governance / governance (push) Waiting to run
Helm CI / Lint and Render Chart (push) Waiting to run
Core E2E Tests / Playwright Core E2E (push) Waiting to run

Refs #1530

Refs #1531

Refs #1471
This commit is contained in:
rcourtman 2026-07-07 00:12:09 +01:00
parent 4b669ad9b5
commit dded079297
13 changed files with 180 additions and 67 deletions

View file

@ -1 +1 @@
6.0.5
6.0.5-rc.1

View file

@ -2,9 +2,9 @@ apiVersion: v2
name: pulse
description: Helm chart for deploying the Pulse hub and optional Docker monitoring agent.
type: application
version: 6.0.5
appVersion: "6.0.5"
icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.0.5/docs/images/pulse-logo.svg
version: 6.0.5-rc.1
appVersion: "6.0.5-rc.1"
icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.0.5-rc.1/docs/images/pulse-logo.svg
keywords:
- monitoring
- proxmox
@ -32,7 +32,7 @@ annotations:
description: Smoke tests with kind cluster deployment
artifacthub.io/links: |
- name: Documentation
url: https://github.com/rcourtman/Pulse/blob/v6.0.5/docs/KUBERNETES.md
url: https://github.com/rcourtman/Pulse/blob/v6.0.5-rc.1/docs/KUBERNETES.md
- name: Support
url: https://github.com/rcourtman/Pulse/discussions
artifacthub.io/maintainers: |

View file

@ -1,6 +1,6 @@
# pulse
![Version: 6.0.5](https://img.shields.io/badge/Version-6.0.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 6.0.5](https://img.shields.io/badge/AppVersion-6.0.5-informational?style=flat-square)
![Version: 6.0.5-rc.1](https://img.shields.io/badge/Version-6.0.5--rc.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 6.0.5-rc.1](https://img.shields.io/badge/AppVersion-6.0.5--rc.1-informational?style=flat-square)
Helm chart for deploying the Pulse hub and optional Docker monitoring agent.

View file

@ -2,7 +2,7 @@ version: '3.8'
services:
pulse:
image: ${PULSE_IMAGE:-rcourtman/pulse:6.0.5}
image: ${PULSE_IMAGE:-rcourtman/pulse:6.0.5-rc.1}
container_name: pulse
restart: unless-stopped
logging:

View file

@ -6,9 +6,11 @@ Pulse release notes live on GitHub:
For historical v4 notes that previously lived in this repo, see:
`docs/releases/RELEASE_NOTES_v4.md`
For the current v6 support release candidate packet, see:
- `docs/releases/RELEASE_NOTES_v6.0.5-rc.1.md`
- `docs/releases/V6_CHANGELOG_v6.0.5-rc.1.md`
For the current stable v6 patch packet, see:
- `docs/releases/RELEASE_NOTES_v6.0.5.md`
- `docs/releases/V6_CHANGELOG_v6.0.5.md`
- `docs/releases/RELEASE_NOTES_v6.0.4.md`
- `docs/releases/V6_CHANGELOG_v6.0.4.md`
- `docs/releases/RELEASE_NOTES_v6.0.3.md`

View file

@ -2,10 +2,13 @@
This guide covers practical upgrade steps for existing Pulse installs moving to v6.
For the current v6 support release candidate packet, see:
- `docs/releases/RELEASE_NOTES_v6.0.5-rc.1.md`
- `docs/releases/V6_CHANGELOG_v6.0.5-rc.1.md`
For the current stable v6 packet and rollout references, see:
- `docs/releases/RELEASE_NOTES_v6.0.5.md`
- `docs/releases/V6_CHANGELOG_v6.0.5.md`
- `docs/releases/RELEASE_NOTES_v6.0.4.md`
- `docs/releases/V6_CHANGELOG_v6.0.4.md`
- `docs/releases/RELEASE_NOTES_v6.0.3.md`

View file

@ -811,13 +811,16 @@ TLS floor in the dynamic config.
## Current State
The active stable `v6.0.5` cut sets the repo-root `VERSION`,
The active support prerelease `v6.0.5-rc.1` cut sets the repo-root `VERSION`,
repo-root `docker-compose.yml` image default, `scripts/install-docker.sh`
fallback, and Helm chart release metadata to the same `6.0.5` release version.
This patch release uses the stable hotfix path with `rollback_version=v6.0.4`,
`hotfix_exception=true`, a release-owner reason, and no fabricated same-version
RC tag. It advances the v6.0.4 stable line with customer-support fixes for
Gemini Patrol tool-call readiness and remembered-login submit persistence.
fallback, and Helm chart release metadata to the same `6.0.5-rc.1` release
version. This support prerelease keeps `rollback_version=v6.0.4`, publishes a
versioned public GitHub prerelease plus versioned Docker and Helm artifacts,
and does not move stable/latest install pointers or stable semver aliases. It
queues the v6.0.4 stable line's customer-support fixes for Gemini Patrol
tool-call readiness, remembered-login submit persistence, and Proxmox
SATA/SAT SMART temperature fallback behind RC validation instead of publishing
another same-day stable patch.
The initial GA promotion
metadata remains
`promoted_from_tag=v6.0.0-rc.7`, `rollback_version=v5.1.35`,
@ -871,10 +874,11 @@ compose image default, standalone installer fallback constant, and packaged
Helm metadata. A draft release workflow failure caused by stale image or chart
pins is a release-packet blocker until the defaults, tests, and evidence
record are refreshed from the new branch head.
For the active stable `v6.0.5` cut, the repo-root compose default and
`scripts/install-docker.sh` fallback must both pin `6.0.5`. The stable
promotion guard remains in force by rejecting leftover `-rc.` defaults when
the governed `VERSION` is a stable release.
For the active support prerelease `v6.0.5-rc.1` cut, the repo-root compose
default and `scripts/install-docker.sh` fallback must both pin `6.0.5-rc.1`
until the next governed stable cut moves them forward. The stable promotion
guard remains in force by rejecting leftover `-rc.` defaults when the governed
`VERSION` is a stable release.
The RC7 packet refresh records `fc10de9b5477613316473267b72b05b6b2b7aaff`
as the current validation-risk commit. That head includes the earlier
Docker-default correction plus the follow-on capacity-forecast and Patrol

View file

@ -1,9 +1,9 @@
# Pulse v6.0.5 Release Notes
# Pulse v6.0.5-rc.1 Release Notes
`v6.0.5` is a stable patch release for the Pulse v6 line. It follows
`v6.0.4` and bundles support fixes for Patrol Gemini model readiness and
remembered-login submit persistence, plus a Proxmox SMART temperature fallback
for direct SATA/SAT disks.
`v6.0.5-rc.1` is a release candidate for the next Pulse v6 patch line. It
follows stable `v6.0.4` and packages support fixes for Patrol Gemini model
readiness and remembered-login submit persistence, plus a Proxmox SMART
temperature fallback for direct SATA/SAT disks.
## Fixes
@ -14,13 +14,14 @@ for direct SATA/SAT disks.
- Fixed Proxmox SMART temperature collection for direct SATA/SAT disks where
smartctl auto-detection returned disk health but no temperature until retried
with an explicit SAT probe.
- Refreshed Docker, Helm, installer, and release-helper metadata for the stable
patch line.
- Refreshed Docker, Helm, installer, and release-helper metadata for the
release candidate.
## Upgrade Notes
Use the normal v6 install or update flow for `v6.0.5`. The rollback target for
this patch release is `v6.0.4`.
Use the normal v6 install or update flow for `v6.0.5-rc.1` only when you are
comfortable testing an RC. The rollback target for this release candidate is
`v6.0.4`.
Paid Pulse Pro, Relay, and eligible legacy customers should continue to use the
private download page and private runtime image for paid runtime features.

View file

@ -1,7 +1,7 @@
# Pulse v6.0.5
# Pulse v6.0.5-rc.1
_This changelog describes the stable `v6.0.5` patch release compared with
`v6.0.4`._
_This changelog describes the `v6.0.5-rc.1` release candidate compared with
stable `v6.0.4`._
## Fixed
@ -13,10 +13,10 @@ _This changelog describes the stable `v6.0.5` patch release compared with
explicit SAT probe when smartctl auto-detection returns health but no
temperature.
- Docker, Helm, installer, and release-helper metadata now track the active
stable patch version.
release candidate version.
## Release Metadata
- Version: `v6.0.5`
- Version: `v6.0.5-rc.1`
- Rollback target: `v6.0.4`
- Promotion path: stable patch hotfix from `main`
- Promotion path: release candidate from `main`

View file

@ -6,7 +6,7 @@ set -euo pipefail
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
DOCKER_IMAGE_REPO="${DOCKER_IMAGE_REPO:-rcourtman/pulse}"
CANONICAL_DEFAULT_PULSE_VERSION="6.0.5"
CANONICAL_DEFAULT_PULSE_VERSION="6.0.5-rc.1"
resolve_default_pulse_version() {
if [ -n "${PULSE_IMAGE_VERSION:-}" ]; then

View file

@ -308,6 +308,71 @@ func TestCurrentStablePatchReleasePacketTracksInstallMetadata(t *testing.T) {
)
}
func TestCurrentSupportPrereleasePacketTracksInstallMetadata(t *testing.T) {
version := currentReleaseVersion(t)
if !isPrereleaseVersion(version) {
t.Skip("current release is stable")
}
previous, ok := previousStableForPrereleaseVersion(version)
if !ok {
t.Skip("current prerelease does not have a previous stable patch")
}
releaseNotesPath := repoFile("docs", "releases", "RELEASE_NOTES_v"+version+".md")
changelogPath := repoFile("docs", "releases", "V6_CHANGELOG_v"+version+".md")
assertFileContainsAllNormalized(t, releaseNotesPath,
"`v"+version+"` is a release candidate",
"stable `v"+previous+"`",
"Patrol Gemini model readiness",
"remembered-login submit persistence",
"Proxmox SMART temperature fallback",
"direct SATA/SAT disks",
"rollback target for this release candidate is `v"+previous+"`",
)
assertFileContainsAll(t, changelogPath,
"Version: `v"+version+"`",
"Rollback target: `v"+previous+"`",
"Promotion path: release candidate from `main`",
"Gemini tool-call capability",
"Remembered-login state now persists",
"Proxmox SMART temperature collection",
"explicit SAT probe",
)
assertFileContainsAll(t, repoFile("docs", "RELEASE_NOTES.md"),
"docs/releases/RELEASE_NOTES_v"+version+".md",
"docs/releases/V6_CHANGELOG_v"+version+".md",
"current v6 support release candidate packet",
)
assertFileContainsAll(t, repoFile("docs", "UPGRADE_v6.md"),
"docs/releases/RELEASE_NOTES_v"+version+".md",
"docs/releases/V6_CHANGELOG_v"+version+".md",
"current v6 support release candidate packet",
)
assertFileContainsAll(t, repoFile("deploy", "helm", "pulse", "Chart.yaml"),
"version: "+version,
`appVersion: "`+version+`"`,
"raw.githubusercontent.com/rcourtman/Pulse/v"+version+"/docs/images/pulse-logo.svg",
"blob/v"+version+"/docs/KUBERNETES.md",
)
assertFileContainsAll(t, repoFile("deploy", "helm", "pulse", "README.md"),
"Version-"+shieldsBadgeMessage(version)+"-informational",
"AppVersion-"+shieldsBadgeMessage(version)+"-informational",
"Autogenerated from chart metadata using [helm-docs v1.14.2]",
)
assertFileContainsAll(t, repoFile("docker-compose.yml"),
"image: ${PULSE_IMAGE:-rcourtman/pulse:"+version+"}",
)
assertFileContainsAll(t, repoFile("scripts", "install-docker.sh"),
`CANONICAL_DEFAULT_PULSE_VERSION="`+version+`"`,
)
assertFileContainsAllNormalized(t, repoFile("docs", "release-control", "v6", "internal", "subsystems", "deployment-installability.md"),
"The active support prerelease `v"+version+"` cut sets the repo-root `VERSION`, repo-root `docker-compose.yml` image default, `scripts/install-docker.sh` fallback, and Helm chart release metadata to the same `"+version+"` release version.",
"This support prerelease keeps `rollback_version=v"+previous+"`, publishes a versioned public GitHub prerelease plus versioned Docker and Helm artifacts, and does not move stable/latest install pointers or stable semver aliases.",
"For the active support prerelease `v"+version+"` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `"+version+"` until the next governed stable cut moves them forward.",
)
}
func TestBackfillReleaseWorkflowRepairsPublishedAssetsWithoutRebuilds(t *testing.T) {
scriptBytes, err := os.ReadFile(repoFile("scripts", "backfill-release-assets.sh"))
if err != nil {

View file

@ -228,7 +228,7 @@ func TestInstallDockerProofTracksSupportPrereleaseContract(t *testing.T) {
assertFileContainsAllNormalized(t, repoFile("docs", "release-control", "v6", "internal", "subsystems", "deployment-installability.md"),
"The active support prerelease `v"+version+"` cut sets the repo-root `VERSION`, repo-root `docker-compose.yml` image default, `scripts/install-docker.sh` fallback, and Helm chart release metadata to the same `"+version+"` release version.",
"This support prerelease uses the private Pro support image path with a stable rollback reference `v"+previous+"`, no `latest` movement, no stable semver tag movement, no R2 manifest promotion, no broker download metadata promotion, and no public `rcourtman/pulse` image publication.",
"This support prerelease keeps `rollback_version=v"+previous+"`, publishes a versioned public GitHub prerelease plus versioned Docker and Helm artifacts, and does not move stable/latest install pointers or stable semver aliases.",
"For the active support prerelease `v"+version+"` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `"+version+"` until the next governed stable cut moves them forward.",
)
}

View file

@ -78,6 +78,18 @@ def rc_packet_paths_for_version(version: str) -> tuple[str, str, str] | None:
)
def support_prerelease_packet_paths_for_version(version: str) -> tuple[str, str] | None:
"""Return release-notes and changelog paths for post-GA support RC versions."""
if not re.match(r"^6\.\d+\.\d+-rc\.\d+$", version):
return None
if version.startswith("6.0.0-rc."):
return None
return (
f"docs/releases/RELEASE_NOTES_v{version}.md",
f"docs/releases/V6_CHANGELOG_v{version}.md",
)
def stable_packet_paths_for_version(version: str) -> tuple[str, str] | None:
"""Return the stable release-notes and changelog packet paths for a v6 stable VERSION."""
if not re.match(r"^6\.\d+\.\d+$", version):
@ -350,25 +362,40 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
self.assertIn(f"Pulse v{current_version}", changelog)
else:
packet_paths = rc_packet_paths_for_version(current_version)
self.assertIsNotNone(
packet_paths,
f"VERSION={current_version} does not match the 6.0.0-rc.N pattern",
support_packet_paths = support_prerelease_packet_paths_for_version(current_version)
self.assertTrue(
packet_paths is not None or support_packet_paths is not None,
f"VERSION={current_version} does not match a governed v6 prerelease packet pattern",
)
release_notes_path, changelog_path, operator_pack_path = packet_paths
if packet_paths is not None:
release_notes_path, changelog_path, operator_pack_path = packet_paths
release_notes = read(release_notes_path)
changelog = read(changelog_path)
operator_pack = read(operator_pack_path)
release_notes = read(release_notes_path)
changelog = read(changelog_path)
operator_pack = read(operator_pack_path)
self.assertIn(f"current in-repo v6 `rc.{current_version.rsplit('.', 1)[1]}` draft packet", release_index)
self.assertIn(release_notes_path, release_index)
self.assertIn(changelog_path, release_index)
self.assertIn(operator_pack_path, release_index)
self.assertNotIn("current stable v6 release packet", release_index)
self.assertIn(f"Pulse v{current_version} Draft Release Notes", release_notes)
self.assertIn(f"`v{current_version}`", release_notes)
self.assertIn(f"Pulse v{current_version} Draft Changelog", changelog)
self.assertIn(f"`v{current_version}`", operator_pack)
self.assertIn(f"current in-repo v6 `rc.{current_version.rsplit('.', 1)[1]}` draft packet", release_index)
self.assertIn(release_notes_path, release_index)
self.assertIn(changelog_path, release_index)
self.assertIn(operator_pack_path, release_index)
self.assertNotIn("current stable v6 release packet", release_index)
self.assertIn(f"Pulse v{current_version} Draft Release Notes", release_notes)
self.assertIn(f"`v{current_version}`", release_notes)
self.assertIn(f"Pulse v{current_version} Draft Changelog", changelog)
self.assertIn(f"`v{current_version}`", operator_pack)
else:
assert support_packet_paths is not None
release_notes_path, changelog_path = support_packet_paths
release_notes = read(release_notes_path)
changelog = read(changelog_path)
self.assertIn("current v6 support release candidate packet", release_index)
self.assertIn(release_notes_path, release_index)
self.assertIn(changelog_path, release_index)
self.assertIn(f"Pulse v{current_version} Release Notes", release_notes)
self.assertIn(f"`v{current_version}`", release_notes)
self.assertIn(f"Pulse v{current_version}", changelog)
def test_upgrade_guide_points_at_current_rc_support_pack(self) -> None:
upgrade_guide = read("docs/UPGRADE_v6.md")
@ -400,17 +427,27 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
self.assertNotIn("docs/releases/V6_RC_OPERATOR_SUPPORT_PACK.md", upgrade_guide)
else:
packet_paths = rc_packet_paths_for_version(current_version)
self.assertIsNotNone(
packet_paths,
f"VERSION={current_version} does not match the 6.0.0-rc.N pattern",
support_packet_paths = support_prerelease_packet_paths_for_version(current_version)
self.assertTrue(
packet_paths is not None or support_packet_paths is not None,
f"VERSION={current_version} does not match a governed v6 prerelease packet pattern",
)
current_support_pack = packet_paths[2]
self.assertIn(current_support_pack, upgrade_guide)
for _, _, _, support_pack in discover_rc_draft_packets():
if support_pack == current_support_pack:
continue
self.assertNotIn(support_pack, upgrade_guide)
self.assertNotIn("docs/releases/V6_RC_OPERATOR_SUPPORT_PACK.md", upgrade_guide)
if packet_paths is not None:
current_support_pack = packet_paths[2]
self.assertIn(current_support_pack, upgrade_guide)
for _, _, _, support_pack in discover_rc_draft_packets():
if support_pack == current_support_pack:
continue
self.assertNotIn(support_pack, upgrade_guide)
self.assertNotIn("docs/releases/V6_RC_OPERATOR_SUPPORT_PACK.md", upgrade_guide)
else:
assert support_packet_paths is not None
release_notes_path, changelog_path = support_packet_paths
self.assertIn(release_notes_path, upgrade_guide)
self.assertIn(changelog_path, upgrade_guide)
for _, _, _, support_pack in discover_rc_draft_packets():
self.assertNotIn(support_pack, upgrade_guide)
self.assertNotIn("docs/releases/V6_RC_OPERATOR_SUPPORT_PACK.md", upgrade_guide)
def test_prerelease_feedback_template_uses_generic_current_rc_wording(self) -> None:
template = read(".github/ISSUE_TEMPLATE/v6_rc_feedback.yml")
@ -855,9 +892,10 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
if current_version != "6.0.0":
self.assertNotIn(f"VERSION={current_version}", blocked)
else:
self.assertIsNotNone(
rc_packet_paths_for_version(current_version),
f"VERSION={current_version} does not match the 6.0.0-rc.N pattern",
self.assertTrue(
rc_packet_paths_for_version(current_version) is not None
or support_prerelease_packet_paths_for_version(current_version) is not None,
f"VERSION={current_version} does not match a governed v6 prerelease packet pattern",
)
self.assertIn("VERSION=6.0.0", blocked)
self.assertNotIn(f"VERSION={current_version}", blocked)