mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-28 23:01:37 +00:00
ADD - check GitHub releases on startup (#10)
Compare the fxmanifest version against the latest published sky_phone release tag and report update, current, ahead, and failure states without blocking resource startup. Document the startup check and cover the HTTP and version comparison behavior with a focused Lua test.
This commit is contained in:
@@ -249,6 +249,11 @@ When enabled, Sky Phone prints debug and informational messages. Warnings and er
|
|||||||
|
|
||||||
The short LB Phone detection notice also remains visible when debug mode is disabled.
|
The short LB Phone detection notice also remains visible when debug mode is disabled.
|
||||||
|
|
||||||
|
On every resource start, Sky Phone compares the `version` in `fxmanifest.lua` with the tag of the
|
||||||
|
latest published [GitHub release](https://github.com/sky-systems/sky_phone/releases/latest). The
|
||||||
|
server console reports whether the installed version is current and shows the release link when an
|
||||||
|
update is available. A failed GitHub request is reported but does not prevent the phone from starting.
|
||||||
|
|
||||||
## Security values
|
## Security values
|
||||||
|
|
||||||
Sky Phone ships with stable generated defaults in `Config.Server`:
|
Sky Phone ships with stable generated defaults in `Config.Server`:
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ server_scripts {
|
|||||||
'config/media.lua',
|
'config/media.lua',
|
||||||
'config/locales/en.lua',
|
'config/locales/en.lua',
|
||||||
'config/locales/de.lua',
|
'config/locales/de.lua',
|
||||||
|
'source/server/update_check.lua',
|
||||||
'source/bridge/server/database.lua',
|
'source/bridge/server/database.lua',
|
||||||
'source/bridge/server/migrations.lua',
|
'source/bridge/server/migrations.lua',
|
||||||
'source/bridge/server/callbacks.lua',
|
'source/bridge/server/callbacks.lua',
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
local RELEASE_API_URL = "https://api.github.com/repos/sky-systems/sky_phone/releases/latest"
|
||||||
|
local RELEASE_PAGE_URL = "https://github.com/sky-systems/sky_phone/releases/latest"
|
||||||
|
|
||||||
|
local function parse_version(version)
|
||||||
|
if type(version) ~= "string" then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local major, minor, patch = version:match("^v?(%d+)%.(%d+)%.(%d+)$")
|
||||||
|
if not major then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return tonumber(major), tonumber(minor), tonumber(patch)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compare_versions(installed_version, release_version)
|
||||||
|
local installed_major, installed_minor, installed_patch = parse_version(installed_version)
|
||||||
|
local release_major, release_minor, release_patch = parse_version(release_version)
|
||||||
|
if not installed_major or not release_major then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if installed_major ~= release_major then
|
||||||
|
return installed_major < release_major and -1 or 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if installed_minor ~= release_minor then
|
||||||
|
return installed_minor < release_minor and -1 or 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if installed_patch ~= release_patch then
|
||||||
|
return installed_patch < release_patch and -1 or 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local function print_update_notice(installed_version, release_version)
|
||||||
|
local border = "======================================================================"
|
||||||
|
print(([[
|
||||||
|
^1%s^0
|
||||||
|
^1 SKY PHONE UPDATE AVAILABLE ^0
|
||||||
|
^1%s^0
|
||||||
|
^3 Installed version: ^1%s^0
|
||||||
|
^3 Latest release: ^2%s^0
|
||||||
|
|
||||||
|
^5 Download: %s^0
|
||||||
|
^1%s^0]]):format(border, border, installed_version, release_version, RELEASE_PAGE_URL, border))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function check_for_update()
|
||||||
|
local resource_name = GetCurrentResourceName()
|
||||||
|
local installed_version = GetResourceMetadata(resource_name, "version", 0)
|
||||||
|
if not parse_version(installed_version) then
|
||||||
|
print(("^3[sky_phone] Update check skipped because fxmanifest.lua has an invalid version: %s.^0")
|
||||||
|
:format(tostring(installed_version)))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
PerformHttpRequest(RELEASE_API_URL, function(status_code, response_body)
|
||||||
|
if status_code ~= 200 then
|
||||||
|
print(("^3[sky_phone] GitHub update check failed with HTTP %s.^0"):format(tostring(status_code)))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local decoded, release = pcall(json.decode, response_body)
|
||||||
|
local release_version = decoded and type(release) == "table" and release.tag_name or nil
|
||||||
|
local comparison = compare_versions(installed_version, release_version)
|
||||||
|
if not comparison then
|
||||||
|
print(("^3[sky_phone] GitHub update check returned an invalid release tag: %s.^0")
|
||||||
|
:format(tostring(release_version)))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if comparison < 0 then
|
||||||
|
print_update_notice(installed_version, release_version)
|
||||||
|
elseif comparison > 0 then
|
||||||
|
print(("^3[sky_phone] Installed version %s is newer than the latest GitHub release %s.^0")
|
||||||
|
:format(installed_version, release_version))
|
||||||
|
else
|
||||||
|
print(("^2[sky_phone] Version %s is up to date.^0"):format(installed_version))
|
||||||
|
end
|
||||||
|
end, "GET", "", {
|
||||||
|
["Accept"] = "application/vnd.github+json",
|
||||||
|
["User-Agent"] = "sky_phone-update-check",
|
||||||
|
["X-GitHub-Api-Version"] = "2022-11-28",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
CreateThread(check_for_update)
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
local source_path = "sky_phone/source/server/update_check.lua"
|
||||||
|
local original_print = print
|
||||||
|
|
||||||
|
local function run_check(installed_version, status_code, release_version)
|
||||||
|
local output = {}
|
||||||
|
local request
|
||||||
|
|
||||||
|
print = function(message)
|
||||||
|
output[#output + 1] = tostring(message)
|
||||||
|
end
|
||||||
|
GetCurrentResourceName = function()
|
||||||
|
return "sky_phone"
|
||||||
|
end
|
||||||
|
GetResourceMetadata = function(resource_name, key, index)
|
||||||
|
assert(resource_name == "sky_phone", "update check must read its own resource metadata")
|
||||||
|
assert(key == "version" and index == 0, "update check must read the fxmanifest version")
|
||||||
|
return installed_version
|
||||||
|
end
|
||||||
|
PerformHttpRequest = function(url, callback, method, body, headers)
|
||||||
|
request = {
|
||||||
|
url = url,
|
||||||
|
callback = callback,
|
||||||
|
method = method,
|
||||||
|
body = body,
|
||||||
|
headers = headers,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
CreateThread = function(callback)
|
||||||
|
callback()
|
||||||
|
end
|
||||||
|
json = {
|
||||||
|
decode = function()
|
||||||
|
return { tag_name = release_version }
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
dofile(source_path)
|
||||||
|
|
||||||
|
if request then
|
||||||
|
assert(request.url == "https://api.github.com/repos/sky-systems/sky_phone/releases/latest")
|
||||||
|
assert(request.method == "GET" and request.body == "", "update check must use a read-only GET request")
|
||||||
|
assert(request.headers["Accept"] == "application/vnd.github+json")
|
||||||
|
assert(request.headers["User-Agent"] == "sky_phone-update-check")
|
||||||
|
request.callback(status_code, "{}")
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat(output, "\n"), request
|
||||||
|
end
|
||||||
|
|
||||||
|
local current_output = run_check("0.1.0", 200, "0.1.0")
|
||||||
|
assert(current_output:find("Version 0.1.0 is up to date", 1, true), "matching versions must report up to date")
|
||||||
|
|
||||||
|
local outdated_output = run_check("0.1.0", 200, "0.2.0")
|
||||||
|
assert(outdated_output:find("SKY PHONE UPDATE AVAILABLE", 1, true), "newer releases must show an update notice")
|
||||||
|
assert(outdated_output:find("Installed version: ^10.1.0", 1, true), "notice must show the manifest version")
|
||||||
|
assert(outdated_output:find("Latest release: ^20.2.0", 1, true), "notice must show the release tag")
|
||||||
|
|
||||||
|
local ahead_output = run_check("1.0.0", 200, "0.9.9")
|
||||||
|
assert(ahead_output:find("newer than the latest GitHub release", 1, true), "ahead versions must be distinguished")
|
||||||
|
|
||||||
|
local invalid_output, invalid_request = run_check("development", 200, "0.1.0")
|
||||||
|
assert(not invalid_request, "invalid manifest versions must not make an HTTP request")
|
||||||
|
assert(invalid_output:find("fxmanifest.lua has an invalid version", 1, true), "invalid manifests must be visible")
|
||||||
|
|
||||||
|
local failed_output = run_check("0.1.0", 429, "0.1.0")
|
||||||
|
assert(failed_output:find("GitHub update check failed with HTTP 429", 1, true), "HTTP failures must be visible")
|
||||||
|
|
||||||
|
print = original_print
|
||||||
|
io.write("Sky Phone update check tests passed\n")
|
||||||
Reference in New Issue
Block a user