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
20 changes: 14 additions & 6 deletions .github/workflows/version-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,28 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
let mainVersion, stagingVersion, failureReason;
let mainVersion, prBranchVersion, failureReason;
try {
mainVersion = fs.readFileSync('main/pyproject.toml', 'utf8')
.match(/^version\s*=\s*["']([^"']+)["']/m)[1];
stagingVersion = fs.readFileSync('staging/pyproject.toml', 'utf8')
.match(/^version\s*=\s*["']([^"']+)["']/m)[1];
} catch (e) {
console.error('Failed to read main version:', e.message);
mainVersion = 'unknown';
stagingVersion = 'unknown';
}

try {
prBranchVersion = fs.readFileSync('pr-branch/pyproject.toml', 'utf8')
.match(/^version\s*=\s*["']([^"']+)["']/m)[1];
} catch (e) {
console.error('Failed to read PR branch version:', e.message);
prBranchVersion = 'unknown';
}

// Get failure reason from step output
failureReason = '${{ steps.failure_reason.outputs.reason }}' || '';

const prBranch = context.payload.pull_request.head.ref;

let body = `❌ **Version Check Failed**\n\n`;

if (failureReason) {
Expand All @@ -215,13 +223,13 @@ jobs:

body += `**Version Bump:**\n` +
`- Main version: \`${mainVersion}\`\n` +
`- Staging version: \`${stagingVersion}\`\n\n` +
`- PR branch (\`${prBranch}\`) version: \`${prBranchVersion}\`\n\n` +
`Please update the version in **BOTH** files before merging to main:\n\n` +
`1. \`pyproject.toml\` (under \`[project]\` section)\n` +
`2. \`cartha_validator/__init__.py\` (fallback \`__version__\`)\n\n` +
`**Requirements:**\n` +
`- Both files must have the **same version**\n` +
`- The staging version must be **greater** than the main version\n` +
`- The PR branch version must be **greater** than the main version\n` +
`- Use semantic versioning: \`major.minor.patch\`\n` +
`- Repository version_key must be >= subnet weights_version (netuid 35)\n\n` +
`Check the workflow logs above for detailed error messages.`;
Expand Down
2 changes: 1 addition & 1 deletion cartha_validator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Validator tooling for Cartha."""

__version__ = "1.0.1"
__version__ = "1.0.2"

# Convert version string (e.g., "1.0.0") to spec_version integer (e.g., 1000)
# Format: 1000 * major + 10 * minor + 1 * patch
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "cartha-subnet-validator"
version = "1.0.1"
version = "1.0.2"
description = "Cartha subnet validator reference implementation."
requires-python = ">=3.11,<3.12"
authors = [
Expand Down
78 changes: 77 additions & 1 deletion scripts/validator_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,73 @@ def initialize_validator_uid(
)
return False

def get_running_validator_version(self) -> str | None:
"""
Extract the running validator version from its logs.

Returns:
Version string if found, None otherwise
"""
try:
# Get recent logs from PM2
logs = self.pm2_manager.get_logs(lines=200)

# Look for version pattern: "Validator version: 1.0.1" or "__version__ = 1.0.1"
import re
patterns = [
r'Validator version:\s*([\d.]+)',
r'__version__\s*=\s*["\']([\d.]+)["\']',
r'version_key=(\d+)', # Fallback: extract from version_key
]

for pattern in patterns:
match = re.search(pattern, logs)
if match:
version = match.group(1)
# If we got version_key, convert it back (e.g., 1001 -> 1.0.1)
if pattern == patterns[2] and len(version) == 4:
major = int(version[0])
minor = int(version[1:3])
patch = int(version[3])
return f"{major}.{minor}.{patch}"
return version

return None
except Exception as e:
print(f"Warning: Could not extract running validator version: {e}", file=sys.stderr)
return None

def check_running_version_mismatch(self) -> bool:
"""
Check if running validator version differs from local code version.
This handles cases where code was updated but validator wasn't restarted.

Returns:
True if versions don't match and restart is needed, False otherwise
"""
try:
local_version = get_version_from_pyproject()
running_version = self.get_running_validator_version()

if running_version is None:
# Can't determine running version, assume it's fine
return False

if local_version != running_version:
print(
f"⚠ Version mismatch detected!\n"
f" Local code version: {local_version}\n"
f" Running validator version: {running_version}\n"
f" Restarting validator to sync versions...",
file=sys.stderr
)
return True

return False
except Exception as e:
print(f"Warning: Could not check version mismatch: {e}", file=sys.stderr)
return False

def check_for_updates(self) -> tuple[bool, str | None]:
"""
Check if a new release is available on GitHub.
Expand Down Expand Up @@ -384,7 +451,16 @@ def run_update_loop(self) -> None:

while True:
try:
# Check for updates
# First, check if running validator version matches local code version
# This handles cases where code was updated but validator wasn't restarted
if self.check_running_version_mismatch():
print("Restarting validator to sync with local code version...")
self.pm2_manager.restart_validator()
time.sleep(5) # Wait for restart
if not self.pm2_manager.is_running():
print("Warning: Validator failed to restart after version sync", file=sys.stderr)

# Check for updates from GitHub
update_available, latest_version = self.check_for_updates()

if update_available:
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading