diff --git a/Data/Server/WebUI/src/Devices/Device_List.jsx b/Data/Server/WebUI/src/Devices/Device_List.jsx index faf415a..07ed381 100644 --- a/Data/Server/WebUI/src/Devices/Device_List.jsx +++ b/Data/Server/WebUI/src/Devices/Device_List.jsx @@ -127,7 +127,7 @@ export default function DeviceList({ onSelectDevice }) { const fetchLatestRepoHash = useCallback(async () => { try { const params = new URLSearchParams({ repo: "bunny-lab-io/Borealis", branch: "main" }); - const resp = await fetch(`/api/agent/repo_hash?${params.toString()}`); + const resp = await fetch(`/api/repo/current_hash?${params.toString()}`); const json = await resp.json(); const sha = (json?.sha || "").trim(); if (!resp.ok || !sha) { diff --git a/Data/Server/server.py b/Data/Server/server.py index fbf3bdb..d185b3b 100644 --- a/Data/Server/server.py +++ b/Data/Server/server.py @@ -356,8 +356,8 @@ def health(): return jsonify({"status": "ok"}) -@app.route("/api/agent/repo_hash", methods=["GET"]) -def api_agent_repo_hash(): +@app.route("/api/repo/current_hash", methods=["GET"]) +def api_repo_current_hash(): try: repo = (request.args.get('repo') or _DEFAULT_REPO).strip() branch = (request.args.get('branch') or _DEFAULT_BRANCH).strip() @@ -390,130 +390,141 @@ def api_agent_repo_hash(): return jsonify(payload) return jsonify(payload), 503 except Exception as exc: - _write_service_log('server', f'/api/agent/repo_hash error: {exc}') + _write_service_log('server', f'/api/repo/current_hash error: {exc}') return jsonify({"error": "internal error"}), 500 -@app.route("/api/agent/update_check", methods=["POST"]) -def api_agent_update_check(): - data = request.get_json(silent=True) or {} - agent_id = (data.get("agent_id") or "").strip() +def _lookup_agent_hash_record(agent_id: str) -> Optional[Dict[str, Any]]: + agent_id = (agent_id or '').strip() if not agent_id: - return jsonify({"error": "agent_id required"}), 400 + return None - repo_info = _refresh_default_repo_hash() - repo_sha = (repo_info.get("sha") or "").strip() - if not repo_sha: - payload = { - "error": repo_info.get("error") or "repository hash unavailable", - "repo_source": repo_info.get("source"), + info = registered_agents.get(agent_id) or {} + candidate = (info.get('agent_hash') or '').strip() + hostname = (info.get('hostname') or '').strip() + if candidate: + payload: Dict[str, Any] = { + 'agent_id': agent_id, + 'agent_hash': candidate, + 'source': 'memory', } - return jsonify(payload), 503 + if hostname: + payload['hostname'] = hostname + return payload - registry_info = registered_agents.get(agent_id) or {} - hostname = (registry_info.get("hostname") or "").strip() or None - stored_hash: Optional[str] = (registry_info.get("agent_hash") or "").strip() or None conn = None try: conn = _db_conn() cur = conn.cursor() rows = _device_rows_for_agent(cur, agent_id) - except Exception: - rows = [] + effective_hostname = hostname or None + if rows: + if not effective_hostname: + effective_hostname = rows[0].get('hostname') or effective_hostname + for row in rows: + if row.get('matched'): + normalized_hash = (row.get('agent_hash') or '').strip() + if not normalized_hash: + details = row.get('details') or {} + try: + normalized_hash = ((details.get('summary') or {}).get('agent_hash') or '').strip() + except Exception: + normalized_hash = '' + if normalized_hash: + payload = { + 'agent_id': agent_id, + 'agent_hash': normalized_hash, + 'hostname': row.get('hostname') or effective_hostname, + 'source': 'database', + } + return payload + first = rows[0] + fallback_hash = (first.get('agent_hash') or '').strip() + if not fallback_hash: + details = first.get('details') or {} + try: + fallback_hash = ((details.get('summary') or {}).get('agent_hash') or '').strip() + except Exception: + fallback_hash = '' + if fallback_hash: + payload = { + 'agent_id': agent_id, + 'agent_hash': fallback_hash, + 'hostname': first.get('hostname') or effective_hostname, + 'source': 'database', + } + return payload + cur.execute('SELECT hostname, agent_hash, details FROM device_details') + for host, db_hash, details_json in cur.fetchall(): + try: + data = json.loads(details_json or '{}') + except Exception: + data = {} + summary = data.get('summary') or {} + summary_agent_id = (summary.get('agent_id') or '').strip() + if summary_agent_id != agent_id: + continue + summary_hash = (summary.get('agent_hash') or '').strip() + normalized_hash = (db_hash or '').strip() or summary_hash + if normalized_hash: + return { + 'agent_id': agent_id, + 'agent_hash': normalized_hash, + 'hostname': host, + 'source': 'database', + } finally: if conn: try: conn.close() except Exception: pass - - if rows: - hostname = rows[0].get("hostname") or hostname - for row in rows: - if row.get("matched"): - hostname = row.get("hostname") or hostname - candidate = (row.get("agent_hash") or "").strip() - if not candidate: - summary = row.get("details") or {} - try: - candidate = (summary.get("summary") or {}).get("agent_hash") or "" - except Exception: - candidate = "" - candidate = candidate.strip() - stored_hash = candidate or None - break - if stored_hash is None: - first = rows[0] - candidate = (first.get("agent_hash") or "").strip() - if not candidate: - details = first.get("details") or {} - try: - candidate = (details.get("summary") or {}).get("agent_hash") or "" - except Exception: - candidate = "" - candidate = candidate.strip() - stored_hash = candidate or None - - update_available = (not stored_hash) or (stored_hash.strip() != repo_sha) - - payload = { - "agent_id": agent_id, - "hostname": hostname, - "repo_hash": repo_sha, - "agent_hash": stored_hash, - "update_available": bool(update_available), - "repo_source": repo_info.get("source"), - } - if repo_info.get("cached") is not None: - payload["cached"] = bool(repo_info.get("cached")) - if repo_info.get("age_seconds") is not None: - payload["age_seconds"] = repo_info.get("age_seconds") - if repo_info.get("error"): - payload["repo_error"] = repo_info.get("error") - return jsonify(payload) + return None -@app.route("/api/agent/agent_hash", methods=["POST"]) -def api_agent_agent_hash_post(): - data = request.get_json(silent=True) or {} - agent_id = (data.get("agent_id") or "").strip() - agent_hash = (data.get("agent_hash") or "").strip() +def _apply_agent_hash_update(agent_id: str, agent_hash: str) -> Tuple[Dict[str, Any], int]: + agent_id = (agent_id or '').strip() + agent_hash = (agent_hash or '').strip() if not agent_id or not agent_hash: - return jsonify({"error": "agent_id and agent_hash required"}), 400 + return {'error': 'agent_id and agent_hash required'}, 400 conn = None hostname = None + response_payload: Optional[Dict[str, Any]] = None + status_code = 200 try: conn = _db_conn() cur = conn.cursor() rows = _device_rows_for_agent(cur, agent_id) target = None for row in rows: - if row.get("matched"): + if row.get('matched'): target = row break if not target: - if conn: - conn.close() - return jsonify({"status": "ignored"}), 200 - - hostname = target.get("hostname") - details = target.get("details") or {} - summary = details.setdefault("summary", {}) - summary["agent_hash"] = agent_hash - cur.execute( - "UPDATE device_details SET agent_hash=?, details=? WHERE hostname=?", - (agent_hash, json.dumps(details), hostname), - ) - conn.commit() + response_payload = { + 'status': 'ignored', + 'agent_id': agent_id, + 'agent_hash': agent_hash, + } + else: + hostname = target.get('hostname') + details = target.get('details') or {} + summary = details.setdefault('summary', {}) + summary['agent_hash'] = agent_hash + cur.execute( + 'UPDATE device_details SET agent_hash=?, details=? WHERE hostname=?', + (agent_hash, json.dumps(details), hostname), + ) + conn.commit() except Exception as exc: if conn: try: conn.rollback() except Exception: pass - _write_service_log('server', f'/api/agent/agent_hash error: {exc}') - return jsonify({"error": "internal error"}), 500 + _write_service_log('server', f'/api/agent/hash error: {exc}') + return {'error': 'internal error'}, 500 finally: if conn: try: @@ -521,22 +532,53 @@ def api_agent_agent_hash_post(): except Exception: pass + if response_payload is not None: + return response_payload, status_code + normalized_hash = agent_hash if agent_id in registered_agents: - registered_agents[agent_id]["agent_hash"] = normalized_hash + registered_agents[agent_id]['agent_hash'] = normalized_hash try: for aid, rec in registered_agents.items(): - if rec.get("hostname") and hostname and rec["hostname"] == hostname: - rec["agent_hash"] = normalized_hash + if rec.get('hostname') and hostname and rec['hostname'] == hostname: + rec['agent_hash'] = normalized_hash except Exception: pass - return jsonify({ - "status": "ok", - "agent_id": agent_id, - "hostname": hostname, - "agent_hash": agent_hash, - }) + payload: Dict[str, Any] = { + 'status': 'ok', + 'agent_id': agent_id, + 'agent_hash': agent_hash, + } + if hostname: + payload['hostname'] = hostname + return payload, 200 + + +@app.route("/api/agent/hash", methods=["GET", "POST"]) +def api_agent_hash(): + if request.method == 'GET': + agent_id = (request.args.get('agent_id') or request.args.get('id') or '').strip() + if not agent_id: + data = request.get_json(silent=True) or {} + agent_id = (data.get('agent_id') or '').strip() + if not agent_id: + return jsonify({'error': 'agent_id required'}), 400 + try: + record = _lookup_agent_hash_record(agent_id) + except Exception as exc: + _write_service_log('server', f'/api/agent/hash lookup error: {exc}') + return jsonify({'error': 'internal error'}), 500 + if record: + return jsonify(record) + return jsonify({'error': 'agent hash not found'}), 404 + + data = request.get_json(silent=True) or {} + agent_id = (data.get('agent_id') or '').strip() + agent_hash = (data.get('agent_hash') or '').strip() + payload, status = _apply_agent_hash_update(agent_id, agent_hash) + return jsonify(payload), status + # --------------------------------------------- # Server Time Endpoint @@ -3342,92 +3384,6 @@ def set_device_description(hostname: str): return jsonify({"error": str(e)}), 500 -@app.route("/api/agent/hash/", methods=["GET"]) -def get_agent_hash(agent_id: str): - """Return the last known repository hash for a specific agent.""" - - agent_id = (agent_id or "").strip() - if not agent_id: - return jsonify({"error": "invalid agent id"}), 400 - - # Prefer the in-memory registry (updated on every heartbeat/details post). - info = registered_agents.get(agent_id) or {} - candidate = (info.get("agent_hash") or "").strip() - hostname = (info.get("hostname") or "").strip() - - if candidate: - return jsonify({ - "agent_id": agent_id, - "agent_hash": candidate, - "source": "memory", - }) - - # Fall back to the persisted device_details row, if any. - try: - conn = _db_conn() - cur = conn.cursor() - rows = _device_rows_for_agent(cur, agent_id) - if rows: - if not hostname: - hostname = rows[0].get("hostname") or hostname - for row in rows: - if row.get("matched"): - normalized_hash = (row.get("agent_hash") or "").strip() - if not normalized_hash: - details = row.get("details") or {} - try: - normalized_hash = ((details.get("summary") or {}).get("agent_hash") or "").strip() - except Exception: - normalized_hash = "" - if normalized_hash: - effective_hostname = row.get("hostname") or hostname - return jsonify({ - "agent_id": agent_id, - "agent_hash": normalized_hash, - "hostname": effective_hostname, - "source": "database", - }) - first = rows[0] - fallback_hash = (first.get("agent_hash") or "").strip() - if not fallback_hash: - details = first.get("details") or {} - try: - fallback_hash = ((details.get("summary") or {}).get("agent_hash") or "").strip() - except Exception: - fallback_hash = "" - if fallback_hash: - effective_hostname = first.get("hostname") or hostname - return jsonify({ - "agent_id": agent_id, - "agent_hash": fallback_hash, - "hostname": effective_hostname, - "source": "database", - }) - - # As a final fallback, scan the table for any matching agent_id in case hostname inference failed. - cur.execute("SELECT hostname, agent_hash, details FROM device_details") - for host, db_hash, details_json in cur.fetchall(): - try: - data = json.loads(details_json or "{}") - except Exception: - data = {} - summary = data.get("summary") or {} - summary_agent_id = (summary.get("agent_id") or "").strip() - if summary_agent_id != agent_id: - continue - summary_hash = (summary.get("agent_hash") or "").strip() - normalized_hash = (db_hash or "").strip() or summary_hash - if normalized_hash: - effective_hostname = host or summary.get("hostname") or hostname - return jsonify({ - "agent_id": agent_id, - "agent_hash": normalized_hash, - "hostname": effective_hostname, - "source": "database", - }) - conn.close() - - return jsonify({"error": "agent hash not found"}), 404 except Exception as e: return jsonify({"error": str(e)}), 500 diff --git a/Update.ps1 b/Update.ps1 index 854fc36..f6f7929 100644 --- a/Update.ps1 +++ b/Update.ps1 @@ -137,45 +137,40 @@ function Get-AgentServiceId { return '' } -function Invoke-AgentUpdateCheck { - param( - [Parameter(Mandatory = $true)] - [string]$ServerBaseUrl, - - [Parameter(Mandatory = $true)] - [string]$AgentId - ) - - if ([string]::IsNullOrWhiteSpace($ServerBaseUrl)) { - throw 'Server URL is blank; cannot perform update check.' - } - - $base = $ServerBaseUrl.TrimEnd('/') - $uri = "$base/api/agent/update_check" - $payload = @{ agent_id = $AgentId } | ConvertTo-Json -Depth 3 - $headers = @{ 'User-Agent' = 'borealis-agent-updater' } - - $resp = Invoke-WebRequest -Uri $uri -Method Post -Headers $headers -Body $payload -ContentType 'application/json' -UseBasicParsing -ErrorAction Stop - $json = $resp.Content | ConvertFrom-Json - - if ($resp.StatusCode -ne 200) { - $message = $json.error - if (-not $message) { $message = "HTTP $($resp.StatusCode)" } - throw "Borealis server responded with an error: $message" - } - - return $json -} - function Get-RepositoryCommitHash { param( [Parameter(Mandatory = $true)] - [string]$ProjectRoot + [string]$ProjectRoot, + + [string]$AgentRoot ) - $candidates = @($ProjectRoot) - $agentRootCandidate = Join-Path $ProjectRoot 'Agent\Borealis' - if (Test-Path $agentRootCandidate -PathType Container) { $candidates += $agentRootCandidate } + $candidates = @() + if ($ProjectRoot -and ($candidates -notcontains $ProjectRoot)) { $candidates += $ProjectRoot } + if ($AgentRoot -and ($candidates -notcontains $AgentRoot)) { $candidates += $AgentRoot } + if ($ProjectRoot) { + $agentRootCandidate = Join-Path $ProjectRoot 'Agent\Borealis' + if (Test-Path $agentRootCandidate -PathType Container -and ($candidates -notcontains $agentRootCandidate)) { + $candidates += $agentRootCandidate + } + } + + foreach ($root in $candidates) { + try { + $gitDir = Join-Path $root '.git' + $fetchHead = Join-Path $gitDir 'FETCH_HEAD' + if (-not (Test-Path $fetchHead -PathType Leaf)) { continue } + foreach ($line in Get-Content -Path $fetchHead -ErrorAction Stop) { + $trim = ($line).Trim() + if (-not $trim -or $trim.StartsWith('#')) { continue } + $split = $trim.Split(@("`t", ' '), [StringSplitOptions]::RemoveEmptyEntries) + if ($split.Count -gt 0) { + $candidate = $split[0].Trim() + if ($candidate) { return $candidate } + } + } + } catch {} + } foreach ($root in $candidates) { try { @@ -216,22 +211,14 @@ function Get-RepositoryCommitHash { if ($candidate) { return $candidate } } } - - $fetchHead = Join-Path $gitDir 'FETCH_HEAD' - if (Test-Path $fetchHead -PathType Leaf) { - foreach ($line in Get-Content -Path $fetchHead -ErrorAction Stop) { - $trim = ($line).Trim() - if (-not $trim -or $trim.StartsWith('#')) { continue } - $split = $trim.Split(@("`t", ' '), [StringSplitOptions]::RemoveEmptyEntries) - if ($split.Count -gt 0) { - $candidate = $split[0].Trim() - if ($candidate) { return $candidate } - } - } - } } catch {} } + if ($AgentRoot) { + $stored = Get-StoredAgentHash -AgentRoot $AgentRoot + if ($stored) { return $stored } + } + return '' } @@ -272,7 +259,28 @@ function Set-StoredAgentHash { } catch {} } -function Get-ServerRepositoryHash { +function Set-GitFetchHeadHash { + param( + [string]$ProjectRoot, + [string]$CommitHash, + [string]$BranchName = 'main' + ) + + if ([string]::IsNullOrWhiteSpace($ProjectRoot) -or [string]::IsNullOrWhiteSpace($CommitHash)) { return } + + try { + $gitDir = Join-Path $ProjectRoot '.git' + if (-not (Test-Path $gitDir -PathType Container)) { + New-Item -ItemType Directory -Force -Path $gitDir | Out-Null + } + $fetchHead = Join-Path $gitDir 'FETCH_HEAD' + $branchSegment = if ([string]::IsNullOrWhiteSpace($BranchName)) { '' } else { "`tbranch '$BranchName'" } + $content = "{0}{1}" -f ($CommitHash.Trim()), $branchSegment + Set-Content -Path $fetchHead -Value $content -Encoding UTF8 + } catch {} +} + +function Get-ServerCurrentRepoHash { param( [Parameter(Mandatory = $true)] [string]$ServerBaseUrl @@ -281,7 +289,7 @@ function Get-ServerRepositoryHash { if ([string]::IsNullOrWhiteSpace($ServerBaseUrl)) { return $null } $base = $ServerBaseUrl.TrimEnd('/') - $uri = "$base/api/agent/repo_hash" + $uri = "$base/api/repo/current_hash" $headers = @{ 'User-Agent' = 'borealis-agent-updater' } try { @@ -310,7 +318,7 @@ function Submit-AgentHash { } $base = $ServerBaseUrl.TrimEnd('/') - $uri = "$base/api/agent/agent_hash" + $uri = "$base/api/agent/hash" $payload = @{ agent_id = $AgentId; agent_hash = $AgentHash } | ConvertTo-Json -Depth 3 $headers = @{ 'User-Agent' = 'borealis-agent-updater' } @@ -325,15 +333,22 @@ function Submit-AgentHash { function Sync-AgentHashRecord { param( + [string]$ProjectRoot, [string]$AgentRoot, [string]$AgentHash, [string]$ServerBaseUrl, - [string]$AgentId + [string]$AgentId, + [string]$BranchName = 'main' ) if ([string]::IsNullOrWhiteSpace($AgentHash)) { return } - Set-StoredAgentHash -AgentRoot $AgentRoot -AgentHash $AgentHash + if ($ProjectRoot) { + Set-GitFetchHeadHash -ProjectRoot $ProjectRoot -CommitHash $AgentHash -BranchName $BranchName + } + if ($AgentRoot) { + Set-StoredAgentHash -AgentRoot $AgentRoot -AgentHash $AgentHash + } if ([string]::IsNullOrWhiteSpace($ServerBaseUrl)) { return } @@ -426,48 +441,25 @@ function Invoke-BorealisAgentUpdate { } } - $currentHash = Get-RepositoryCommitHash -ProjectRoot $scriptDir - if ($currentHash) { - Set-StoredAgentHash -AgentRoot $agentRoot -AgentHash $currentHash - } else { - $storedHash = Get-StoredAgentHash -AgentRoot $agentRoot - if ($storedHash) { $currentHash = $storedHash } - } - + $currentHash = Get-RepositoryCommitHash -ProjectRoot $scriptDir -AgentRoot $agentRoot $serverBaseUrl = Get-BorealisServerUrl -AgentRoot $agentRoot $agentId = Get-AgentServiceId -AgentRoot $agentRoot - $serverRepoInfo = Get-ServerRepositoryHash -ServerBaseUrl $serverBaseUrl + $serverRepoInfo = Get-ServerCurrentRepoHash -ServerBaseUrl $serverBaseUrl $serverHash = '' + $serverBranch = 'main' if ($serverRepoInfo) { try { $serverHash = (($serverRepoInfo.sha) -as [string]).Trim() } catch { $serverHash = '' } + try { + $branchCandidate = (($serverRepoInfo.branch) -as [string]).Trim() + if ($branchCandidate) { $serverBranch = $branchCandidate } + } catch { $serverBranch = 'main' } } $updateMode = $env:update_mode if ($updateMode) { $updateMode = $updateMode.ToLowerInvariant() } else { $updateMode = 'update' } $forceUpdate = $updateMode -eq 'force_update' - $updateInfo = $null - $shouldUpdate = $forceUpdate - - if (-not $forceUpdate) { - if (-not $agentId) { - Write-Host "Agent ID unavailable; cannot request update status from server." -ForegroundColor Yellow - Write-Host "⚠️ Borealis update aborted." - return - } - - try { - $updateInfo = Invoke-AgentUpdateCheck -ServerBaseUrl $serverBaseUrl -AgentId $agentId - $shouldUpdate = [bool]($updateInfo.update_available) - if (-not $serverHash -and $updateInfo.repo_hash) { $serverHash = ($updateInfo.repo_hash).ToString().Trim() } - } catch { - Write-Host ("Failed to contact Borealis server for update status: {0}" -f $_.Exception.Message) -ForegroundColor Yellow - Write-Host "⚠️ Borealis update aborted." - return - } - } - if ($currentHash) { Write-Host ("Local Agent Hash: {0}" -f $currentHash) } else { @@ -483,31 +475,21 @@ function Invoke-BorealisAgentUpdate { $normalizedLocalHash = if ($currentHash) { $currentHash.Trim().ToLowerInvariant() } else { '' } $normalizedServerHash = if ($serverHash) { $serverHash.Trim().ToLowerInvariant() } else { '' } $hashesMatch = ($normalizedLocalHash -and $normalizedServerHash -and ($normalizedLocalHash -eq $normalizedServerHash)) + $needsUpdate = $forceUpdate -or (-not $hashesMatch) if ($forceUpdate) { - Write-Host "Server update check bypassed (force update requested)." - } elseif ($updateInfo) { - if ($shouldUpdate) { - Write-Host "Server reports agent hash mismatch (update required)." - } else { - Write-Host "Server reports agent is current." -ForegroundColor Green - if ($serverHash) { - Set-StoredAgentHash -AgentRoot $agentRoot -AgentHash $serverHash - } - Write-Host "✅ Borealis - Automation Platform Already Up-to-Date" - return - } - } else { - Write-Host "Server response unavailable; cannot continue." -ForegroundColor Yellow + Write-Host "Force update requested; skipping hash comparison." -ForegroundColor Yellow + } elseif (-not $serverHash) { + Write-Host "Borealis server hash unavailable; cannot continue." -ForegroundColor Yellow Write-Host "⚠️ Borealis update aborted." return - } - - if (-not $forceUpdate -and $updateInfo -and $shouldUpdate -and $hashesMatch) { - Write-Host "Local agent files already match the server repository hash; skipping update while syncing server state." -ForegroundColor Green - Sync-AgentHashRecord -AgentRoot $agentRoot -AgentHash $serverHash -ServerBaseUrl $serverBaseUrl -AgentId $agentId + } elseif (-not $needsUpdate) { + Write-Host "Local agent files already match the server repository hash." -ForegroundColor Green + Sync-AgentHashRecord -ProjectRoot $scriptDir -AgentRoot $agentRoot -AgentHash $serverHash -ServerBaseUrl $serverBaseUrl -AgentId $agentId -BranchName $serverBranch Write-Host "✅ Borealis - Automation Platform Already Up-to-Date" return + } else { + Write-Host "Repository hash mismatch detected; update required." } $mutex = $null @@ -555,25 +537,25 @@ function Invoke-BorealisAgentUpdate { throw 'Borealis update failed.' } - $newHash = Get-RepositoryCommitHash -ProjectRoot $scriptDir - if (-not $newHash -and $updateInfo -and $updateInfo.repo_hash) { - $newHash = ($updateInfo.repo_hash).ToString().Trim() - } - if (-not $newHash -and $agentId) { + $postUpdateInfo = Get-ServerCurrentRepoHash -ServerBaseUrl $serverBaseUrl + if ($postUpdateInfo) { try { - $postUpdateInfo = Invoke-AgentUpdateCheck -ServerBaseUrl $serverBaseUrl -AgentId $agentId - if ($postUpdateInfo -and $postUpdateInfo.repo_hash) { - $newHash = ($postUpdateInfo.repo_hash).ToString().Trim() - } - } catch { - Write-Verbose ("Post-update hash retrieval failed: {0}" -f $_.Exception.Message) - } + $refreshedSha = (($postUpdateInfo.sha) -as [string]).Trim() + if ($refreshedSha) { $serverHash = $refreshedSha } + } catch {} + try { + $branchCandidate = (($postUpdateInfo.branch) -as [string]).Trim() + if ($branchCandidate) { $serverBranch = $branchCandidate } + } catch {} + } + + $newHash = Get-RepositoryCommitHash -ProjectRoot $scriptDir -AgentRoot $agentRoot + if (-not $newHash -and $serverHash) { + $newHash = $serverHash } if ($newHash) { - Sync-AgentHashRecord -AgentRoot $agentRoot -AgentHash $newHash -ServerBaseUrl $serverBaseUrl -AgentId $agentId - } elseif ($serverHash) { - Sync-AgentHashRecord -AgentRoot $agentRoot -AgentHash $serverHash -ServerBaseUrl $serverBaseUrl -AgentId $agentId + Sync-AgentHashRecord -ProjectRoot $scriptDir -AgentRoot $agentRoot -AgentHash $newHash -ServerBaseUrl $serverBaseUrl -AgentId $agentId -BranchName $serverBranch } else { Write-Host "Unable to determine repository hash for submission; server hash not updated." -ForegroundColor DarkYellow } @@ -585,4 +567,4 @@ function Invoke-BorealisAgentUpdate { } } -Invoke-BorealisAgentUpdate \ No newline at end of file +Invoke-BorealisAgentUpdate