Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/migration/vibemon-install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@ $ErrorActionPreference = "Stop"
$DefaultServer = if ($env:VIBEMON_SYNC_URL) { $env:VIBEMON_SYNC_URL } else { "https://sync.vibemon.dev" }
if ($Server -eq "") { $Server = $DefaultServer }
$Server = $Server.TrimEnd("/")
# 0.2.11 configures local OTel collection with the agent hooks.
# A newer `attempt` already on the machine is kept.
$AttemptVersion = if ($env:ATTEMPTDB_VERSION) { $env:ATTEMPTDB_VERSION } else { "0.2.11" }
$InstallerVersion = "0.2.11+install.1"
# 0.2.13 knows the `messages` sync profile the connect step asks for; an
# older binary rejects `-Profile messages` and pairing fails. tests/installers
# pins this to the workspace version. A newer `attempt` already on the
# machine is kept.
$AttemptVersion = if ($env:ATTEMPTDB_VERSION) { $env:ATTEMPTDB_VERSION } else { "0.2.13" }
$InstallerVersion = "0.2.13+install.1"
$env:ATTEMPTDB_VERSION = $AttemptVersion
$Installer = if ($env:ATTEMPTDB_INSTALLER) { $env:ATTEMPTDB_INSTALLER } else { "https://raw.githubusercontent.com/nullarch/attemptdb/v$AttemptVersion/install.ps1" }
$BinDir = if ($env:ATTEMPTDB_BIN_DIR) { $env:ATTEMPTDB_BIN_DIR } else { Join-Path $env:LOCALAPPDATA "AttemptDB\bin" }
Expand Down
13 changes: 8 additions & 5 deletions docs/migration/vibemon-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,14 @@ AUTO_MIGRATE=0
RUNTIME=service
INSTALL_TMP=""
# The installer hotfix and the binary have independent immutable pins.
# 0.2.11 configures local OTel collection with the agent hooks.
# A newer `attempt` already on the machine is kept.
ATTEMPTDB_VERSION="${ATTEMPTDB_VERSION:-0.2.11}"
INSTALLER_VERSION="0.2.11+install.1"
INSTALLER_REF="v0.2.11"
# 0.2.13 knows the `messages` sync profile the connect step asks for (and
# reads flushed conversation content back with the key); an older binary
# rejects `--profile messages` and pairing fails. tests/installers pins
# ATTEMPTDB_VERSION to the workspace version so a release cannot leave it
# behind again. A newer `attempt` already on the machine is kept.
ATTEMPTDB_VERSION="${ATTEMPTDB_VERSION:-0.2.13}"
INSTALLER_VERSION="0.2.13+install.1"
INSTALLER_REF="install-2026-09-09.1"
ATTEMPTDB_INSTALLER="${ATTEMPTDB_INSTALLER:-https://raw.githubusercontent.com/nullarch/attemptdb/v${ATTEMPTDB_VERSION}/install.sh}"
export ATTEMPTDB_VERSION

Expand Down
45 changes: 45 additions & 0 deletions tests/installers/test_pins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""The installers' binary pin follows the workspace version.

The connect step passes `--profile messages`, which only 0.2.12+ binaries
know. On 2026-09-09 the 0.2.12 and 0.2.13 releases shipped installer scripts
that still downloaded 0.2.11, so every new install failed at pairing with
`unknown profile messages` (install report #86). A release that bumps
Cargo.toml must bump both scripts with it; this test is the reminder.
"""

import re
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parents[2]


def workspace_version() -> str:
text = (ROOT / "Cargo.toml").read_text()
match = re.search(r'^version = "([0-9]+\.[0-9]+\.[0-9]+)"', text, re.M)
assert match, "workspace version not found in Cargo.toml"
return match.group(1)


class PinTests(unittest.TestCase):
def test_shell_installer_pins_the_workspace_version(self):
text = (ROOT / "docs/migration/vibemon-install.sh").read_text()
version = workspace_version()
self.assertIn(f'ATTEMPTDB_VERSION="${{ATTEMPTDB_VERSION:-{version}}}"', text)
self.assertRegex(text, rf'(?m)^INSTALLER_VERSION="{re.escape(version)}\+install\.[0-9]+"$')

def test_powershell_installer_pins_the_workspace_version(self):
text = (ROOT / "docs/migration/vibemon-install.ps1").read_text()
version = workspace_version()
self.assertIn(f'else {{ "{version}" }}', text)
self.assertRegex(text, rf'(?m)^\$InstallerVersion = "{re.escape(version)}\+install\.[0-9]+"$')

def test_messages_profile_needs_a_binary_that_knows_it(self):
sh = (ROOT / "docs/migration/vibemon-install.sh").read_text()
self.assertIn('PROFILE="messages"', sh)
major, minor, patch = (int(n) for n in workspace_version().split("."))
self.assertGreaterEqual((major, minor, patch), (0, 2, 12))


if __name__ == "__main__":
unittest.main()
4 changes: 3 additions & 1 deletion tests/installers/test_reports.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Full PowerShell installer failures against a loopback report receiver."""
import re
import http.server
import json
import os
Expand Down Expand Up @@ -73,7 +74,8 @@ def test_unhandled_download_exception_reports_the_stage_once(self):
self.assertEqual((reports[0]["ok"], reports[0]["step"]), (False, "binary"))
self.assertTrue(reports[0]["error"])
self.assertTrue(reports[0]["unattended"])
self.assertEqual(reports[0]["installer_version"], "0.2.11+install.1")
pinned = re.search(r'^\$InstallerVersion = "([^"]+)"', SCRIPT.read_text(), re.M).group(1)
self.assertEqual(reports[0]["installer_version"], pinned)

def test_explicit_failure_is_not_reported_twice_by_the_trap(self):
code, reports = self.invoke(preflight=410)
Expand Down
12 changes: 11 additions & 1 deletion tests/installers/test_vibemon_install.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Installer regressions with stubbed commands; no network or host changes."""
import re
import json
import os
from pathlib import Path
Expand All @@ -20,7 +21,7 @@
elif name in ("systemctl", "launchctl"):
sys.exit(int(os.environ.get("SERVICE_EXIT", "0")))
elif name == "attempt":
if args == ["--version"]: print("attempt 0.2.11")
if args == ["--version"]: print("attempt __WORKSPACE_VERSION__")
elif args == ["sync", "status", "--json"]: print(json.dumps({"connected": os.environ.get("CONNECTED") == "1"}))
elif args[:2] == ["daemon", "status"]:
print(json.dumps({"endpoint": "unix:/fixture/daemon.sock", "running": True}))
Expand All @@ -46,6 +47,15 @@
elif name == "powershell.exe": sys.exit(int(os.environ.get("NATIVE_EXIT", "0")))
'''

# The fake `attempt` reports the workspace version — the same one the script
# pins — so the "present and recent enough; keeping it" path is exercised.
WORKSPACE_VERSION = re.search(
r'^version = "([0-9]+\.[0-9]+\.[0-9]+)"',
(Path(__file__).resolve().parents[2] / "Cargo.toml").read_text(),
re.M,
).group(1)
STUB = STUB.replace("__WORKSPACE_VERSION__", WORKSPACE_VERSION)


class MigrationTests(unittest.TestCase):
def run_install(self, args=(), legacy=False, missing=(), **settings):
Expand Down
Loading