5 Commits

Author SHA1 Message Date
d4977a8708 Добавлено закрытие приложения
All checks were successful
CI / build-test (push) Successful in 25s
Release / pack-and-publish (release) Successful in 25s
2025-11-25 09:34:10 +03:00
6a01813602 Добавлена задержка перед обновлением 2025-11-25 09:32:09 +03:00
60a3ec4dc7 Добавлена настройка пути updater.exe
All checks were successful
CI / build-test (push) Successful in 28s
Release / pack-and-publish (release) Successful in 29s
2025-11-25 08:28:30 +03:00
fb83e2d060 ci
All checks were successful
CI / build-test (push) Successful in 30s
2025-11-25 08:19:37 +03:00
a5055f7f26 readme
Some checks failed
CI / build-test (push) Failing after 36s
2025-11-25 08:18:07 +03:00
6 changed files with 26 additions and 16 deletions

View File

@@ -20,14 +20,14 @@ jobs:
dotnet-version: |
8.0.x
- name: Restore
run: dotnet restore
- name: Restore ReleaseUpdater
run: dotnet restore ReleaseUpdater
- name: Build
run: dotnet build --no-restore -c Release
- name: Build ReleaseUpdater
run: dotnet build ReleaseUpdater --no-restore -c Release
- name: Test
run: dotnet test --no-build -c Release --collect:"XPlat Code Coverage" --logger "trx;LogFileName=test-results.trx"
- name: Test ReleaseUpdater
run: dotnet test ReleaseUpdater --no-build -c Release --collect:"XPlat Code Coverage" --logger "trx;LogFileName=test-results.trx"
- name: Upload test results
if: always()

View File

@@ -1,4 +1,5 @@
# Updater
![Workflow](https://git.frigat.duckdns.org/FrigaT/ReleaseUpdater/actions/workflows/release-package.yaml/badge.svg?branch=master&style=flat)
## 📖 Описание
`Updater` — это инструмент для безопасного обновления приложений.

View File

@@ -6,7 +6,7 @@ namespace ReleaseUpdater;
/// <summary>
/// Провайдер для получения информации о релизах из Github / Gitea API.
/// </summary>
public sealed class GiteaReleaseProvider
public sealed class ReleaseProvider
{
private static readonly JsonSerializerOptions JsonOpts = new(JsonSerializerDefaults.Web);

View File

@@ -29,7 +29,7 @@ public static class ReleaseUpdaterFacade
/// </summary>
public static async Task<IReadOnlyList<string>> GetVersionsAsync(string apiUrl, string? token = null)
{
var provider = new GiteaReleaseProvider();
var provider = new ReleaseProvider();
var releases = await provider.GetReleasesAsync(apiUrl, token);
return releases.Select(r => r.TagName).ToList();
}
@@ -42,7 +42,7 @@ public static class ReleaseUpdaterFacade
{
try
{
var provider = new GiteaReleaseProvider();
var provider = new ReleaseProvider();
var release = await provider.FindReleaseAsync(apiUrl, versionOrLatest, token)
?? throw new Exception("Release not found");
@@ -72,11 +72,11 @@ public static class ReleaseUpdaterFacade
/// Обновление через внешний Updater.exe.
/// </summary>
public static async Task UpdateWithExternalAsync(
string apiUrl, string? token, string installPath, string appExe, string versionOrLatest = "latest")
string apiUrl, string? token, string installPath, string appExe, string versionOrLatest = "latest", string? updaterExePath = null, bool exitCurrentApp = false)
{
try
{
var provider = new GiteaReleaseProvider();
var provider = new ReleaseProvider();
var release = await provider.FindReleaseAsync(apiUrl, versionOrLatest, token)
?? throw new Exception("Release not found");
@@ -88,17 +88,19 @@ public static class ReleaseUpdaterFacade
BeforeInstall?.Invoke();
var updaterExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Updater.exe");
if (updaterExePath == null) updaterExePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Updater.exe");
var args = $"--zip \"{zipPath}\" --installPath \"{installPath}\" --appExe \"{appExe}\"";
var process = Process.Start(new ProcessStartInfo
{
FileName = updaterExe,
FileName = updaterExePath,
Arguments = args,
UseShellExecute = true,
WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory
});
if (exitCurrentApp) { Environment.Exit(0); }
process?.WaitForExit();
if (process?.ExitCode == 0)

View File

@@ -12,11 +12,14 @@ public sealed class Options
/// <summary>Имя исполняемого файла приложения для перезапуска (e.g., MyBot.exe).</summary>
public required string AppExe { get; init; }
/// <summary>Необязательно: подождите миллисекунды перед перезапуском (льготный период).</summary>
/// <summary>Необязательно: подождите миллисекунды перед перезапуском.</summary>
public int RestartDelayMs { get; init; } = 500;
/// <summary>Необязательно: подождите миллисекунды перед запуском обновления.</summary>
public int UpdateDelayMs { get; init; } = 500;
public static string Usage =>
"Usage: Updater.exe --zip <path.zip> --installPath <dir> --appExe <file.exe> [--restartDelayMs <int>]";
"Usage: Updater.exe --zip <path.zip> --installPath <dir> --appExe <file.exe> [--restartDelayMs <int>] [--updateDelayMs <int>]";
/// <summary>Папрсинг CLI аргументов в Options.</summary>
public static Options Parse(string[] args)
@@ -42,7 +45,8 @@ public sealed class Options
ZipPath = Path.GetFullPath(zip),
InstallPath = Path.GetFullPath(install),
AppExe = exe,
RestartDelayMs = dict.TryGetValue("restartDelayMs", out var d) && int.TryParse(d, out var n) ? n : 500
RestartDelayMs = dict.TryGetValue("restartDelayMs", out var d) && int.TryParse(d, out var n) ? n : 500,
UpdateDelayMs = dict.TryGetValue("updateDelayMs", out var d2) && int.TryParse(d2, out var n2) ? n2 : 500
};
}

View File

@@ -19,6 +19,9 @@ internal sealed class Program
return ExitCodes.InvalidArgs;
}
Thread.Sleep(options.UpdateDelayMs);
var extractor = new ZipExtractor(logger);
var installer = new SafeFileInstaller(logger);
var procMgr = new ProcessManager(logger);