mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 21:38:38 +00:00
Simplify release install process
Fix install on startup
This commit is contained in:
parent
09a2f769c3
commit
4a8845e578
@ -48,6 +48,10 @@ public static class Constants
|
||||
/// The full path to the Artemis logs folder
|
||||
/// </summary>
|
||||
public static readonly string LogsFolder = Path.Combine(DataFolder, "Logs");
|
||||
/// <summary>
|
||||
/// The full path to the Artemis logs folder
|
||||
/// </summary>
|
||||
public static readonly string UpdatingFolder = Path.Combine(DataFolder, "updating");
|
||||
|
||||
/// <summary>
|
||||
/// The full path to the Artemis plugins folder
|
||||
|
||||
@ -21,6 +21,7 @@ public static class Utilities
|
||||
CreateAccessibleDirectory(Constants.DataFolder);
|
||||
CreateAccessibleDirectory(Constants.PluginsFolder);
|
||||
CreateAccessibleDirectory(Constants.LayoutsFolder);
|
||||
CreateAccessibleDirectory(Constants.UpdatingFolder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -7,15 +7,5 @@ public class ReleaseEntity
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Version { get; set; }
|
||||
public string ReleaseId { get; set; }
|
||||
public ReleaseEntityStatus Status { get; set; }
|
||||
public DateTimeOffset? InstalledAt { get; set; }
|
||||
}
|
||||
|
||||
public enum ReleaseEntityStatus
|
||||
{
|
||||
Queued,
|
||||
Installed,
|
||||
Historical,
|
||||
Unknown
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Storage.Entities.General;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using LiteDB;
|
||||
@ -14,63 +13,25 @@ public class ReleaseRepository : IReleaseRepository
|
||||
{
|
||||
_repository = repository;
|
||||
_repository.Database.GetCollection<ReleaseEntity>().EnsureIndex(s => s.Version, true);
|
||||
_repository.Database.GetCollection<ReleaseEntity>().EnsureIndex(s => s.Status);
|
||||
}
|
||||
|
||||
public ReleaseEntity GetQueuedVersion()
|
||||
public void SaveVersionInstallDate(string version)
|
||||
{
|
||||
return _repository.Query<ReleaseEntity>().Where(r => r.Status == ReleaseEntityStatus.Queued).FirstOrDefault();
|
||||
}
|
||||
ReleaseEntity release = _repository.Query<ReleaseEntity>().Where(r => r.Version == version).FirstOrDefault();
|
||||
if (release != null)
|
||||
return;
|
||||
|
||||
public ReleaseEntity GetInstalledVersion()
|
||||
{
|
||||
return _repository.Query<ReleaseEntity>().Where(r => r.Status == ReleaseEntityStatus.Installed).FirstOrDefault();
|
||||
_repository.Insert(new ReleaseEntity {Version = version, InstalledAt = DateTimeOffset.UtcNow});
|
||||
}
|
||||
|
||||
public ReleaseEntity GetPreviousInstalledVersion()
|
||||
{
|
||||
return _repository.Query<ReleaseEntity>().Where(r => r.Status == ReleaseEntityStatus.Historical).OrderByDescending(r => r.InstalledAt).FirstOrDefault();
|
||||
}
|
||||
|
||||
public void QueueInstallation(string version, string releaseId)
|
||||
{
|
||||
// Mark release as queued and add if missing
|
||||
ReleaseEntity release = _repository.Query<ReleaseEntity>().Where(r => r.Version == version).FirstOrDefault() ?? new ReleaseEntity {Version = version, ReleaseId = releaseId};
|
||||
release.Status = ReleaseEntityStatus.Queued;
|
||||
_repository.Upsert(release);
|
||||
}
|
||||
|
||||
public void FinishInstallation(string version)
|
||||
{
|
||||
// Mark release as installed and add if missing
|
||||
ReleaseEntity release = _repository.Query<ReleaseEntity>().Where(r => r.Version == version).FirstOrDefault() ?? new ReleaseEntity {Version = version};
|
||||
release.Status = ReleaseEntityStatus.Installed;
|
||||
release.InstalledAt = DateTimeOffset.UtcNow;
|
||||
_repository.Upsert(release);
|
||||
|
||||
// Mark other releases as historical
|
||||
List<ReleaseEntity> oldReleases = _repository.Query<ReleaseEntity>().Where(r => r.Version != version && r.Status != ReleaseEntityStatus.Historical).ToList();
|
||||
foreach (ReleaseEntity oldRelease in oldReleases)
|
||||
oldRelease.Status = ReleaseEntityStatus.Historical;
|
||||
_repository.Update<ReleaseEntity>(oldReleases);
|
||||
}
|
||||
|
||||
public void DequeueInstallation()
|
||||
{
|
||||
// Mark all queued releases as unknown, until FinishInstallation is called we don't know the status
|
||||
List<ReleaseEntity> queuedReleases = _repository.Query<ReleaseEntity>().Where(r => r.Status == ReleaseEntityStatus.Queued).ToList();
|
||||
foreach (ReleaseEntity queuedRelease in queuedReleases)
|
||||
queuedRelease.Status = ReleaseEntityStatus.Unknown;
|
||||
_repository.Update<ReleaseEntity>(queuedReleases);
|
||||
return _repository.Query<ReleaseEntity>().OrderByDescending(r => r.InstalledAt).Skip(1).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IReleaseRepository : IRepository
|
||||
{
|
||||
ReleaseEntity GetQueuedVersion();
|
||||
ReleaseEntity GetInstalledVersion();
|
||||
void SaveVersionInstallDate(string version);
|
||||
ReleaseEntity GetPreviousInstalledVersion();
|
||||
void QueueInstallation(string version, string releaseId);
|
||||
void FinishInstallation(string version);
|
||||
void DequeueInstallation();
|
||||
}
|
||||
@ -43,9 +43,9 @@ public class App : Application
|
||||
{
|
||||
if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || Design.IsDesignMode || _shutDown)
|
||||
return;
|
||||
|
||||
ArtemisBootstrapper.Initialize();
|
||||
|
||||
_applicationStateManager = new ApplicationStateManager(_container!, desktop.Args);
|
||||
ArtemisBootstrapper.Initialize();
|
||||
RegisterProviders(_container!);
|
||||
}
|
||||
|
||||
|
||||
@ -99,8 +99,8 @@ public class ApplicationStateManager
|
||||
argsList.Add("--autorun");
|
||||
|
||||
// Retain startup arguments after update by providing them to the script
|
||||
string script = $"\"{Path.Combine(Constants.DataFolder, "updating", "pending", "scripts", "update.ps1")}\"";
|
||||
string source = $"-sourceDirectory \"{Path.Combine(Constants.DataFolder, "updating", "pending")}\"";
|
||||
string script = $"\"{Path.Combine(Constants.UpdatingFolder, "installing", "scripts", "update.ps1")}\"";
|
||||
string source = $"-sourceDirectory \"{Path.Combine(Constants.UpdatingFolder, "installing")}\"";
|
||||
string destination = $"-destinationDirectory \"{Constants.ApplicationFolder}\"";
|
||||
string args = argsList.Any() ? $"-artemisArgs \"{string.Join(',', argsList)}\"" : "";
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ using Artemis.UI.Screens.Settings;
|
||||
using Artemis.UI.Services.Updating;
|
||||
using Artemis.UI.Shared.Services.MainWindow;
|
||||
using Avalonia.Threading;
|
||||
using DryIoc.ImTools;
|
||||
using Microsoft.Toolkit.Uwp.Notifications;
|
||||
using ReactiveUI;
|
||||
|
||||
@ -16,7 +17,7 @@ namespace Artemis.UI.Windows.Providers;
|
||||
|
||||
public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
{
|
||||
private readonly Func<string, ReleaseInstaller> _getReleaseInstaller;
|
||||
private readonly Func<Guid, ReleaseInstaller> _getReleaseInstaller;
|
||||
private readonly Func<IScreen, SettingsViewModel> _getSettingsViewModel;
|
||||
private readonly IMainWindowService _mainWindowService;
|
||||
private readonly IUpdateService _updateService;
|
||||
@ -25,7 +26,7 @@ public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
public WindowsUpdateNotificationProvider(IMainWindowService mainWindowService,
|
||||
IUpdateService updateService,
|
||||
Func<IScreen, SettingsViewModel> getSettingsViewModel,
|
||||
Func<string, ReleaseInstaller> getReleaseInstaller)
|
||||
Func<Guid, ReleaseInstaller> getReleaseInstaller)
|
||||
{
|
||||
_mainWindowService = mainWindowService;
|
||||
_updateService = updateService;
|
||||
@ -37,7 +38,7 @@ public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
private async void ToastNotificationManagerCompatOnOnActivated(ToastNotificationActivatedEventArgsCompat e)
|
||||
{
|
||||
ToastArguments args = ToastArguments.Parse(e.Argument);
|
||||
string releaseId = args.Get("releaseId");
|
||||
Guid releaseId = Guid.Parse(args.Get("releaseId"));
|
||||
string releaseVersion = args.Get("releaseVersion");
|
||||
string action = "view-changes";
|
||||
if (args.Contains("action"))
|
||||
@ -53,7 +54,7 @@ public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
_updateService.RestartForUpdate(false);
|
||||
}
|
||||
|
||||
public void ShowNotification(string releaseId, string releaseVersion)
|
||||
public void ShowNotification(Guid releaseId, string releaseVersion)
|
||||
{
|
||||
GetBuilderForRelease(releaseId, releaseVersion)
|
||||
.AddText("Update available")
|
||||
@ -62,10 +63,10 @@ public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
.SetContent("Install")
|
||||
.AddArgument("action", "install").SetAfterActivationBehavior(ToastAfterActivationBehavior.PendingUpdate))
|
||||
.AddButton(new ToastButton().SetContent("View changes").AddArgument("action", "view-changes"))
|
||||
.Show(t => t.Tag = releaseId);
|
||||
.Show(t => t.Tag = releaseId.ToString());
|
||||
}
|
||||
|
||||
private void ViewRelease(string releaseId)
|
||||
private void ViewRelease(Guid releaseId)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
@ -87,7 +88,7 @@ public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
});
|
||||
}
|
||||
|
||||
private async Task InstallRelease(string releaseId, string releaseVersion)
|
||||
private async Task InstallRelease(Guid releaseId, string releaseVersion)
|
||||
{
|
||||
ReleaseInstaller installer = _getReleaseInstaller(releaseId);
|
||||
void InstallerOnPropertyChanged(object? sender, PropertyChangedEventArgs e) => UpdateInstallProgress(releaseId, installer);
|
||||
@ -104,7 +105,7 @@ public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
.AddButton(new ToastButton().SetContent("Cancel").AddArgument("action", "cancel"))
|
||||
.Show(t =>
|
||||
{
|
||||
t.Tag = releaseId;
|
||||
t.Tag = releaseId.ToString();
|
||||
t.Data = GetDataForInstaller(installer);
|
||||
});
|
||||
|
||||
@ -127,26 +128,23 @@ public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
installer.PropertyChanged -= InstallerOnPropertyChanged;
|
||||
}
|
||||
|
||||
// Queue an update in case the user interrupts the process after everything has been prepared
|
||||
_updateService.QueueUpdate(releaseVersion, releaseId);
|
||||
|
||||
GetBuilderForRelease(releaseId, releaseVersion)
|
||||
.AddAudio(new ToastAudio {Silent = true})
|
||||
.AddText("Update ready")
|
||||
.AddText($"Artemis version {releaseVersion} is ready to be applied")
|
||||
.AddButton(new ToastButton().SetContent("Restart Artemis").AddArgument("action", "restart-for-update"))
|
||||
.AddButton(new ToastButton().SetContent("Later").AddArgument("action", "postpone-update"))
|
||||
.Show(t => t.Tag = releaseId);
|
||||
.Show(t => t.Tag = releaseId.ToString());
|
||||
}
|
||||
|
||||
private void UpdateInstallProgress(string releaseId, ReleaseInstaller installer)
|
||||
private void UpdateInstallProgress(Guid releaseId, ReleaseInstaller installer)
|
||||
{
|
||||
ToastNotificationManagerCompat.CreateToastNotifier().Update(GetDataForInstaller(installer), releaseId);
|
||||
ToastNotificationManagerCompat.CreateToastNotifier().Update(GetDataForInstaller(installer), releaseId.ToString());
|
||||
}
|
||||
|
||||
private ToastContentBuilder GetBuilderForRelease(string releaseId, string releaseVersion)
|
||||
private ToastContentBuilder GetBuilderForRelease(Guid releaseId, string releaseVersion)
|
||||
{
|
||||
return new ToastContentBuilder().AddArgument("releaseId", releaseId).AddArgument("releaseVersion", releaseVersion);
|
||||
return new ToastContentBuilder().AddArgument("releaseId", releaseId.ToString()).AddArgument("releaseVersion", releaseVersion);
|
||||
}
|
||||
|
||||
private NotificationData GetDataForInstaller(ReleaseInstaller installer)
|
||||
|
||||
@ -480,7 +480,7 @@ public class ScriptVmFactory : IScriptVmFactory
|
||||
|
||||
public interface IReleaseVmFactory : IVmFactory
|
||||
{
|
||||
ReleaseViewModel ReleaseListViewModel(string releaseId, string version, DateTimeOffset createdAt);
|
||||
ReleaseViewModel ReleaseListViewModel(Guid releaseId, string version, DateTimeOffset createdAt);
|
||||
}
|
||||
public class ReleaseVmFactory : IReleaseVmFactory
|
||||
{
|
||||
@ -491,7 +491,7 @@ public class ReleaseVmFactory : IReleaseVmFactory
|
||||
_container = container;
|
||||
}
|
||||
|
||||
public ReleaseViewModel ReleaseListViewModel(string releaseId, string version, DateTimeOffset createdAt)
|
||||
public ReleaseViewModel ReleaseListViewModel(Guid releaseId, string version, DateTimeOffset createdAt)
|
||||
{
|
||||
return _container.Resolve<ReleaseViewModel>(new object[] { releaseId, version, createdAt });
|
||||
}
|
||||
|
||||
@ -64,6 +64,9 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi
|
||||
Router.CurrentViewModel.Subscribe(UpdateTitleBarViewModel);
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (_updateService.Initialize())
|
||||
return;
|
||||
|
||||
coreService.Initialize();
|
||||
registrationService.RegisterBuiltInDataModelDisplays();
|
||||
registrationService.RegisterBuiltInDataModelInputs();
|
||||
|
||||
@ -61,7 +61,7 @@ public class ReleasesTabViewModel : ActivatableViewModelBase
|
||||
|
||||
public ReadOnlyObservableCollection<ReleaseViewModel> ReleaseViewModels { get; }
|
||||
public string Channel { get; }
|
||||
public string? PreselectId { get; set; }
|
||||
public Guid? PreselectId { get; set; }
|
||||
|
||||
public ReleaseViewModel? SelectedReleaseViewModel
|
||||
{
|
||||
|
||||
@ -36,7 +36,7 @@ public class ReleaseViewModel : ActivatableViewModelBase
|
||||
private bool _loading = true;
|
||||
private bool _retrievedDetails;
|
||||
|
||||
public ReleaseViewModel(string releaseId,
|
||||
public ReleaseViewModel(Guid releaseId,
|
||||
string version,
|
||||
DateTimeOffset createdAt,
|
||||
ILogger logger,
|
||||
@ -79,7 +79,7 @@ public class ReleaseViewModel : ActivatableViewModelBase
|
||||
});
|
||||
}
|
||||
|
||||
public string ReleaseId { get; }
|
||||
public Guid ReleaseId { get; }
|
||||
|
||||
private void ExecuteRestart()
|
||||
{
|
||||
@ -158,7 +158,6 @@ public class ReleaseViewModel : ActivatableViewModelBase
|
||||
{
|
||||
InstallationInProgress = true;
|
||||
await ReleaseInstaller.InstallAsync(_installerCts.Token);
|
||||
_updateService.QueueUpdate(Version, ReleaseId);
|
||||
InstallationFinished = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Artemis.UI.Services.Updating;
|
||||
|
||||
public interface IUpdateNotificationProvider
|
||||
{
|
||||
void ShowNotification(string releaseId, string releaseVersion);
|
||||
void ShowNotification(Guid releaseId, string releaseVersion);
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.UI.Services.Interfaces;
|
||||
using Artemis.WebClient.Updating;
|
||||
@ -6,14 +7,47 @@ namespace Artemis.UI.Services.Updating;
|
||||
|
||||
public interface IUpdateService : IArtemisUIService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the current update channel.
|
||||
/// </summary>
|
||||
string Channel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version number of the previous release that was installed, if any.
|
||||
/// </summary>
|
||||
string? PreviousVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The latest cached release, can be updated by calling <see cref="CachedLatestRelease" />.
|
||||
/// </summary>
|
||||
IGetNextRelease_NextPublishedRelease? CachedLatestRelease { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously caches the latest release.
|
||||
/// </summary>
|
||||
Task CacheLatestRelease();
|
||||
Task<bool> CheckForUpdate();
|
||||
void QueueUpdate(string version, string releaseId);
|
||||
|
||||
ReleaseInstaller GetReleaseInstaller(string releaseId);
|
||||
/// <summary>
|
||||
/// Asynchronously checks whether an update is available on the current <see cref="Channel" />.
|
||||
/// </summary>
|
||||
Task<bool> CheckForUpdate();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a release installed for a release with the provided ID.
|
||||
/// </summary>
|
||||
/// <param name="releaseId">The ID of the release to create the installer for.</param>
|
||||
/// <returns>The resulting release installer.</returns>
|
||||
ReleaseInstaller GetReleaseInstaller(Guid releaseId);
|
||||
|
||||
/// <summary>
|
||||
/// Restarts the application to install a pending update.
|
||||
/// </summary>
|
||||
/// <param name="silent">A boolean indicating whether to perform a silent install of the update.</param>
|
||||
void RestartForUpdate(bool silent);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the update service.
|
||||
/// </summary>
|
||||
/// <returns>A boolean indicating whether a restart will occur to install a pending update.</returns>
|
||||
bool Initialize();
|
||||
}
|
||||
@ -23,7 +23,7 @@ public class InAppUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
_getSettingsViewModel = getSettingsViewModel;
|
||||
}
|
||||
|
||||
private void ShowInAppNotification(string releaseId, string releaseVersion)
|
||||
private void ShowInAppNotification(Guid releaseId, string releaseVersion)
|
||||
{
|
||||
_notification?.Invoke();
|
||||
_notification = _notificationService.CreateNotification()
|
||||
@ -35,7 +35,7 @@ public class InAppUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
.Show();
|
||||
}
|
||||
|
||||
private void ViewRelease(string releaseId)
|
||||
private void ViewRelease(Guid releaseId)
|
||||
{
|
||||
_notification?.Invoke();
|
||||
|
||||
@ -56,7 +56,7 @@ public class InAppUpdateNotificationProvider : IUpdateNotificationProvider
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ShowNotification(string releaseId, string releaseVersion)
|
||||
public void ShowNotification(Guid releaseId, string releaseVersion)
|
||||
{
|
||||
if (_mainWindowService.IsMainWindowOpen)
|
||||
ShowInAppNotification(releaseId, releaseVersion);
|
||||
|
||||
@ -22,24 +22,26 @@ namespace Artemis.UI.Services.Updating;
|
||||
/// </summary>
|
||||
public class ReleaseInstaller : CorePropertyChanged
|
||||
{
|
||||
private readonly string _dataFolder;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger _logger;
|
||||
private readonly string _releaseId;
|
||||
private readonly Guid _releaseId;
|
||||
private readonly Platform _updatePlatform;
|
||||
private readonly IUpdatingClient _updatingClient;
|
||||
private readonly Progress<float> _progress = new();
|
||||
|
||||
private IGetReleaseById_PublishedRelease _release = null!;
|
||||
private IGetReleaseById_PublishedRelease_Artifacts _artifact = null!;
|
||||
|
||||
private Progress<float> _stepProgress = new();
|
||||
private string _status = string.Empty;
|
||||
private float _progress1;
|
||||
private float _floatProgress;
|
||||
|
||||
public ReleaseInstaller(string releaseId, ILogger logger, IUpdatingClient updatingClient, HttpClient httpClient)
|
||||
public ReleaseInstaller(Guid releaseId, ILogger logger, IUpdatingClient updatingClient, HttpClient httpClient)
|
||||
{
|
||||
_releaseId = releaseId;
|
||||
_logger = logger;
|
||||
_updatingClient = updatingClient;
|
||||
_httpClient = httpClient;
|
||||
_dataFolder = Path.Combine(Constants.DataFolder, "updating");
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
_updatePlatform = Platform.Windows;
|
||||
@ -50,9 +52,6 @@ public class ReleaseInstaller : CorePropertyChanged
|
||||
else
|
||||
throw new PlatformNotSupportedException("Cannot auto update on the current platform");
|
||||
|
||||
if (!Directory.Exists(_dataFolder))
|
||||
Directory.CreateDirectory(_dataFolder);
|
||||
|
||||
_progress.ProgressChanged += (_, f) => Progress = f;
|
||||
}
|
||||
|
||||
@ -64,8 +63,8 @@ public class ReleaseInstaller : CorePropertyChanged
|
||||
|
||||
public float Progress
|
||||
{
|
||||
get => _progress1;
|
||||
set => SetAndNotify(ref _progress1, value);
|
||||
get => _floatProgress;
|
||||
set => SetAndNotify(ref _floatProgress, value);
|
||||
}
|
||||
|
||||
public async Task InstallAsync(CancellationToken cancellationToken)
|
||||
@ -79,24 +78,24 @@ public class ReleaseInstaller : CorePropertyChanged
|
||||
IOperationResult<IGetReleaseByIdResult> result = await _updatingClient.GetReleaseById.ExecuteAsync(_releaseId, cancellationToken);
|
||||
result.EnsureNoErrors();
|
||||
|
||||
IGetReleaseById_PublishedRelease? release = result.Data?.PublishedRelease;
|
||||
if (release == null)
|
||||
_release = result.Data?.PublishedRelease!;
|
||||
if (_release == null)
|
||||
throw new Exception($"Could not find release with ID {_releaseId}");
|
||||
|
||||
IGetReleaseById_PublishedRelease_Artifacts? artifact = release.Artifacts.FirstOrDefault(a => a.Platform == _updatePlatform);
|
||||
if (artifact == null)
|
||||
_artifact = _release.Artifacts.FirstOrDefault(a => a.Platform == _updatePlatform)!;
|
||||
if (_artifact == null)
|
||||
throw new Exception("Found the release but it has no artifact for the current platform");
|
||||
|
||||
((IProgress<float>) _progress).Report(10);
|
||||
|
||||
// Determine whether the last update matches our local version, then we can download the delta
|
||||
if (release.PreviousRelease != null && File.Exists(Path.Combine(_dataFolder, $"{release.PreviousRelease}.zip")) && artifact.DeltaFileInfo.DownloadSize != 0)
|
||||
await DownloadDelta(artifact, Path.Combine(_dataFolder, $"{release.PreviousRelease}.zip"), cancellationToken);
|
||||
if (_release.PreviousRelease != null && File.Exists(Path.Combine(Constants.UpdatingFolder, $"{_release.PreviousRelease.Version}.zip")) && _artifact.DeltaFileInfo.DownloadSize != 0)
|
||||
await DownloadDelta(Path.Combine(Constants.UpdatingFolder, $"{_release.PreviousRelease.Version}.zip"), cancellationToken);
|
||||
else
|
||||
await Download(artifact, cancellationToken);
|
||||
await Download(cancellationToken);
|
||||
}
|
||||
|
||||
private async Task DownloadDelta(IGetReleaseById_PublishedRelease_Artifacts artifact, string previousRelease, CancellationToken cancellationToken)
|
||||
private async Task DownloadDelta(string previousRelease, CancellationToken cancellationToken)
|
||||
{
|
||||
// 10 - 50%
|
||||
_stepProgress.ProgressChanged += StepProgressOnProgressChanged;
|
||||
@ -104,20 +103,20 @@ public class ReleaseInstaller : CorePropertyChanged
|
||||
|
||||
Status = "Downloading...";
|
||||
await using MemoryStream stream = new();
|
||||
await _httpClient.DownloadDataAsync($"https://updating.artemis-rgb.com/api/artifacts/{artifact.ArtifactId}/delta", stream, _stepProgress, cancellationToken);
|
||||
await _httpClient.DownloadDataAsync($"https://updating.artemis-rgb.com/api/artifacts/{_artifact.ArtifactId}/delta", stream, _stepProgress, cancellationToken);
|
||||
|
||||
_stepProgress.ProgressChanged -= StepProgressOnProgressChanged;
|
||||
await PatchDelta(stream, previousRelease, artifact, cancellationToken);
|
||||
await PatchDelta(stream, previousRelease, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task PatchDelta(Stream deltaStream, string previousRelease, IGetReleaseById_PublishedRelease_Artifacts artifact, CancellationToken cancellationToken)
|
||||
private async Task PatchDelta(Stream deltaStream, string previousRelease, CancellationToken cancellationToken)
|
||||
{
|
||||
// 50 - 60%
|
||||
_stepProgress.ProgressChanged += StepProgressOnProgressChanged;
|
||||
void StepProgressOnProgressChanged(object? sender, float e) => ((IProgress<float>) _progress).Report(50f + e * 0.1f);
|
||||
|
||||
Status = "Patching...";
|
||||
await using FileStream newFileStream = new(Path.Combine(_dataFolder, $"{_releaseId}.zip"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
|
||||
await using FileStream newFileStream = new(Path.Combine(Constants.UpdatingFolder, $"{_release.Version}.zip"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
|
||||
await using (FileStream baseStream = File.OpenRead(previousRelease))
|
||||
{
|
||||
deltaStream.Seek(0, SeekOrigin.Begin);
|
||||
@ -132,23 +131,23 @@ public class ReleaseInstaller : CorePropertyChanged
|
||||
|
||||
_stepProgress.ProgressChanged -= StepProgressOnProgressChanged;
|
||||
|
||||
await ValidateArchive(newFileStream, artifact, cancellationToken);
|
||||
await ValidateArchive(newFileStream, cancellationToken);
|
||||
await Extract(newFileStream, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task Download(IGetReleaseById_PublishedRelease_Artifacts artifact, CancellationToken cancellationToken)
|
||||
private async Task Download(CancellationToken cancellationToken)
|
||||
{
|
||||
// 10 - 60%
|
||||
_stepProgress.ProgressChanged += StepProgressOnProgressChanged;
|
||||
void StepProgressOnProgressChanged(object? sender, float e) => ((IProgress<float>) _progress).Report(10f + e * 0.5f);
|
||||
|
||||
Status = "Downloading...";
|
||||
await using FileStream stream = new(Path.Combine(_dataFolder, $"{_releaseId}.zip"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
|
||||
await _httpClient.DownloadDataAsync($"https://updating.artemis-rgb.com/api/artifacts/{artifact.ArtifactId}", stream, _stepProgress, cancellationToken);
|
||||
await using FileStream stream = new(Path.Combine(Constants.UpdatingFolder, $"{_release.Version}.zip"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
|
||||
await _httpClient.DownloadDataAsync($"https://updating.artemis-rgb.com/api/artifacts/{_artifact.ArtifactId}", stream, _stepProgress, cancellationToken);
|
||||
|
||||
_stepProgress.ProgressChanged -= StepProgressOnProgressChanged;
|
||||
|
||||
await ValidateArchive(stream, artifact, cancellationToken);
|
||||
await ValidateArchive(stream, cancellationToken);
|
||||
await Extract(stream, cancellationToken);
|
||||
}
|
||||
|
||||
@ -160,7 +159,7 @@ public class ReleaseInstaller : CorePropertyChanged
|
||||
|
||||
Status = "Extracting...";
|
||||
// Ensure the directory is empty
|
||||
string extractDirectory = Path.Combine(_dataFolder, "pending");
|
||||
string extractDirectory = Path.Combine(Constants.UpdatingFolder, "pending");
|
||||
if (Directory.Exists(extractDirectory))
|
||||
Directory.Delete(extractDirectory, true);
|
||||
Directory.CreateDirectory(extractDirectory);
|
||||
@ -176,12 +175,12 @@ public class ReleaseInstaller : CorePropertyChanged
|
||||
_stepProgress.ProgressChanged -= StepProgressOnProgressChanged;
|
||||
}
|
||||
|
||||
private async Task ValidateArchive(Stream archiveStream, IGetReleaseById_PublishedRelease_Artifacts artifact, CancellationToken cancellationToken)
|
||||
private async Task ValidateArchive(Stream archiveStream, CancellationToken cancellationToken)
|
||||
{
|
||||
using MD5 md5 = MD5.Create();
|
||||
archiveStream.Seek(0, SeekOrigin.Begin);
|
||||
string hash = BitConverter.ToString(await md5.ComputeHashAsync(archiveStream, cancellationToken)).Replace("-", "");
|
||||
if (hash != artifact.FileInfo.Md5Hash)
|
||||
throw new ArtemisUIException($"Update file hash mismatch, expected \"{artifact.FileInfo.Md5Hash}\" but got \"{hash}\"");
|
||||
if (hash != _artifact.FileInfo.Md5Hash)
|
||||
throw new ArtemisUIException($"Update file hash mismatch, expected \"{_artifact.FileInfo.Md5Hash}\" but got \"{hash}\"");
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Storage.Entities.General;
|
||||
using Artemis.Storage.Repositories;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Shared.Services.MainWindow;
|
||||
using Artemis.WebClient.Updating;
|
||||
using Serilog;
|
||||
@ -20,7 +21,7 @@ public class UpdateService : IUpdateService
|
||||
private const double UPDATE_CHECK_INTERVAL = 3_600_000; // once per hour
|
||||
private readonly PluginSetting<bool> _autoCheck;
|
||||
private readonly PluginSetting<bool> _autoInstall;
|
||||
private readonly Func<string, ReleaseInstaller> _getReleaseInstaller;
|
||||
private readonly Func<Guid, ReleaseInstaller> _getReleaseInstaller;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private readonly IReleaseRepository _releaseRepository;
|
||||
@ -36,7 +37,7 @@ public class UpdateService : IUpdateService
|
||||
IUpdatingClient updatingClient,
|
||||
IReleaseRepository releaseRepository,
|
||||
Lazy<IUpdateNotificationProvider> updateNotificationProvider,
|
||||
Func<string, ReleaseInstaller> getReleaseInstaller)
|
||||
Func<Guid, ReleaseInstaller> getReleaseInstaller)
|
||||
{
|
||||
_logger = logger;
|
||||
_updatingClient = updatingClient;
|
||||
@ -66,39 +67,21 @@ public class UpdateService : IUpdateService
|
||||
Timer timer = new(UPDATE_CHECK_INTERVAL);
|
||||
timer.Elapsed += HandleAutoUpdateEvent;
|
||||
timer.Start();
|
||||
|
||||
_logger.Information("Update service initialized for {Channel} channel", Channel);
|
||||
ProcessReleaseStatus();
|
||||
}
|
||||
|
||||
private void ProcessReleaseStatus()
|
||||
{
|
||||
// If an update is queued, don't bother with anything else
|
||||
ReleaseEntity? queued = _releaseRepository.GetQueuedVersion();
|
||||
if (queued != null)
|
||||
{
|
||||
// Remove the queued installation, in case something goes wrong then at least we don't end up in a loop
|
||||
_logger.Information("Installing queued version {Version}", queued.Version);
|
||||
RestartForUpdate(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If a different version was installed, mark it as such
|
||||
ReleaseEntity? installed = _releaseRepository.GetInstalledVersion();
|
||||
if (installed?.Version != Constants.CurrentVersion)
|
||||
_releaseRepository.FinishInstallation(Constants.CurrentVersion);
|
||||
|
||||
string currentVersion = Constants.CurrentVersion;
|
||||
_releaseRepository.SaveVersionInstallDate(currentVersion);
|
||||
PreviousVersion = _releaseRepository.GetPreviousInstalledVersion()?.Version;
|
||||
|
||||
if (!Directory.Exists(Path.Combine(Constants.DataFolder, "updating")))
|
||||
if (!Directory.Exists(Constants.UpdatingFolder))
|
||||
return;
|
||||
|
||||
// Clean up the update folder, leaving only the last ZIP
|
||||
foreach (string file in Directory.GetFiles(Path.Combine(Constants.DataFolder, "updating")))
|
||||
foreach (string file in Directory.GetFiles(Constants.UpdatingFolder))
|
||||
{
|
||||
if (Path.GetExtension(file) != ".zip")
|
||||
continue;
|
||||
if (installed != null && Path.GetFileName(file) == $"{installed.ReleaseId}.zip")
|
||||
if (Path.GetExtension(file) != ".zip" || Path.GetFileName(file) == $"{currentVersion}.zip")
|
||||
continue;
|
||||
|
||||
try
|
||||
@ -140,8 +123,13 @@ public class UpdateService : IUpdateService
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Channel { get; }
|
||||
public string? PreviousVersion { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? PreviousVersion { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IGetNextRelease_NextPublishedRelease? CachedLatestRelease { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -158,6 +146,7 @@ public class UpdateService : IUpdateService
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> CheckForUpdate()
|
||||
{
|
||||
IOperationResult<IGetNextReleaseResult> result = await _updatingClient.GetNextRelease.ExecuteAsync(Constants.CurrentVersion, Channel, _updatePlatform);
|
||||
@ -183,13 +172,7 @@ public class UpdateService : IUpdateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void QueueUpdate(string version, string releaseId)
|
||||
{
|
||||
_releaseRepository.QueueInstallation(version, releaseId);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReleaseInstaller GetReleaseInstaller(string releaseId)
|
||||
public ReleaseInstaller GetReleaseInstaller(Guid releaseId)
|
||||
{
|
||||
return _getReleaseInstaller(releaseId);
|
||||
}
|
||||
@ -197,7 +180,33 @@ public class UpdateService : IUpdateService
|
||||
/// <inheritdoc />
|
||||
public void RestartForUpdate(bool silent)
|
||||
{
|
||||
_releaseRepository.DequeueInstallation();
|
||||
if (!Directory.Exists(Path.Combine(Constants.UpdatingFolder, "pending")))
|
||||
throw new ArtemisUIException("Cannot install update, none is pending.");
|
||||
|
||||
Directory.Move(Path.Combine(Constants.UpdatingFolder, "pending"), Path.Combine(Constants.UpdatingFolder, "installing"));
|
||||
Utilities.ApplyUpdate(silent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Initialize()
|
||||
{
|
||||
// There should never be an installing folder
|
||||
if (Directory.Exists(Path.Combine(Constants.UpdatingFolder, "installing")))
|
||||
{
|
||||
_logger.Warning("Cleaning up leftover installing folder, did an update go wrong?");
|
||||
Directory.Delete(Path.Combine(Constants.UpdatingFolder, "installing"));
|
||||
}
|
||||
|
||||
// If an update is pending, don't bother with anything else
|
||||
if (Directory.Exists(Path.Combine(Constants.UpdatingFolder, "pending")))
|
||||
{
|
||||
_logger.Information("Installing pending update");
|
||||
RestartForUpdate(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
ProcessReleaseStatus();
|
||||
_logger.Information("Update service initialized for {Channel} channel", Channel);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -22,12 +22,14 @@ query GetReleases($branch: String!, $platform: Platform!, $take: Int!, $after: S
|
||||
}
|
||||
|
||||
|
||||
query GetReleaseById($id: String!) {
|
||||
query GetReleaseById($id: UUID!) {
|
||||
publishedRelease(id: $id) {
|
||||
branch
|
||||
commit
|
||||
version
|
||||
previousRelease
|
||||
previousRelease {
|
||||
version
|
||||
}
|
||||
changelog
|
||||
artifacts {
|
||||
platform
|
||||
|
||||
@ -5,33 +5,6 @@ schema {
|
||||
mutation: Mutation
|
||||
}
|
||||
|
||||
"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`."
|
||||
directive @defer(
|
||||
"Deferred when true."
|
||||
if: Boolean,
|
||||
"If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to."
|
||||
label: String
|
||||
) on FRAGMENT_SPREAD | INLINE_FRAGMENT
|
||||
|
||||
"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`."
|
||||
directive @stream(
|
||||
"Streamed when true."
|
||||
if: Boolean,
|
||||
"The initial elements that shall be send down to the consumer."
|
||||
initialCount: Int! = 0,
|
||||
"If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to."
|
||||
label: String
|
||||
) on FIELD
|
||||
|
||||
directive @authorize(
|
||||
"Defines when when the resolver shall be executed.By default the resolver is executed after the policy has determined that the current user is allowed to access the field."
|
||||
apply: ApplyPolicy! = BEFORE_RESOLVER,
|
||||
"The name of the authorization policy that determines access to the annotated resource."
|
||||
policy: String,
|
||||
"Roles that are allowed to access the annotated resource."
|
||||
roles: [String!]
|
||||
) on SCHEMA | OBJECT | FIELD_DEFINITION
|
||||
|
||||
type ArtemisChannel {
|
||||
branch: String!
|
||||
releases: Int!
|
||||
@ -41,15 +14,25 @@ type Artifact {
|
||||
artifactId: Long!
|
||||
deltaFileInfo: ArtifactFileInfo!
|
||||
fileInfo: ArtifactFileInfo!
|
||||
id: UUID!
|
||||
platform: Platform!
|
||||
}
|
||||
|
||||
type ArtifactFileInfo {
|
||||
downloadSize: Long!
|
||||
downloads: Long!
|
||||
id: UUID!
|
||||
md5Hash: String
|
||||
}
|
||||
|
||||
"Information about the offset pagination."
|
||||
type CollectionSegmentInfo {
|
||||
"Indicates whether more items exist following the set defined by the clients arguments."
|
||||
hasNextPage: Boolean!
|
||||
"Indicates whether more items exist prior the set defined by the clients arguments."
|
||||
hasPreviousPage: Boolean!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
updateReleaseChangelog(input: UpdateReleaseChangelogInput!): UpdateReleaseChangelogPayload!
|
||||
}
|
||||
@ -74,6 +57,7 @@ type PublishedReleasesConnection {
|
||||
nodes: [Release!]
|
||||
"Information to aid in pagination."
|
||||
pageInfo: PageInfo!
|
||||
"Identifies the total count of items in the connection."
|
||||
totalCount: Int!
|
||||
}
|
||||
|
||||
@ -90,7 +74,7 @@ type Query {
|
||||
channels: [ArtemisChannel!]!
|
||||
nextPublishedRelease(branch: String!, platform: Platform!, version: String): Release
|
||||
publishedChannels: [String!]!
|
||||
publishedRelease(id: String!): Release
|
||||
publishedRelease(id: UUID!): Release
|
||||
publishedReleases(
|
||||
"Returns the elements in the list that come after the specified cursor."
|
||||
after: String,
|
||||
@ -103,20 +87,9 @@ type Query {
|
||||
order: [ReleaseSortInput!],
|
||||
where: ReleaseFilterInput
|
||||
): PublishedReleasesConnection
|
||||
release(id: String!): Release
|
||||
release(id: UUID!): Release
|
||||
releaseStatistics(order: [ReleaseStatisticSortInput!], where: ReleaseStatisticFilterInput): [ReleaseStatistic!]!
|
||||
releases(
|
||||
"Returns the elements in the list that come after the specified cursor."
|
||||
after: String,
|
||||
"Returns the elements in the list that come before the specified cursor."
|
||||
before: String,
|
||||
"Returns the first _n_ elements from the list."
|
||||
first: Int,
|
||||
"Returns the last _n_ elements from the list."
|
||||
last: Int,
|
||||
order: [ReleaseSortInput!],
|
||||
where: ReleaseFilterInput
|
||||
): ReleasesConnection
|
||||
releases(order: [ReleaseSortInput!], skip: Int, take: Int, where: ReleaseFilterInput): ReleasesCollectionSegment
|
||||
}
|
||||
|
||||
type Release {
|
||||
@ -125,9 +98,9 @@ type Release {
|
||||
changelog: String!
|
||||
commit: String!
|
||||
createdAt: DateTime!
|
||||
id: String!
|
||||
id: UUID!
|
||||
isDraft: Boolean!
|
||||
previousRelease: String
|
||||
previousRelease: Release
|
||||
version: String!
|
||||
workflowRunId: Long!
|
||||
}
|
||||
@ -136,30 +109,20 @@ type ReleaseStatistic {
|
||||
count: Int!
|
||||
lastReportedUsage: DateTime!
|
||||
linuxCount: Int!
|
||||
oSXCount: Int!
|
||||
releaseId: String!
|
||||
osxCount: Int!
|
||||
releaseId: UUID!
|
||||
windowsCount: Int!
|
||||
}
|
||||
|
||||
"A connection to a list of items."
|
||||
type ReleasesConnection {
|
||||
"A list of edges."
|
||||
edges: [ReleasesEdge!]
|
||||
"A flattened list of the nodes."
|
||||
nodes: [Release!]
|
||||
"A segment of a collection."
|
||||
type ReleasesCollectionSegment {
|
||||
"A flattened list of the items."
|
||||
items: [Release!]
|
||||
"Information to aid in pagination."
|
||||
pageInfo: PageInfo!
|
||||
pageInfo: CollectionSegmentInfo!
|
||||
totalCount: Int!
|
||||
}
|
||||
|
||||
"An edge in a connection."
|
||||
type ReleasesEdge {
|
||||
"A cursor for use in pagination."
|
||||
cursor: String!
|
||||
"The item at the end of the edge."
|
||||
node: Release!
|
||||
}
|
||||
|
||||
type UpdateReleaseChangelogPayload {
|
||||
release: Release
|
||||
}
|
||||
@ -167,6 +130,7 @@ type UpdateReleaseChangelogPayload {
|
||||
enum ApplyPolicy {
|
||||
AFTER_RESOLVER
|
||||
BEFORE_RESOLVER
|
||||
VALIDATION
|
||||
}
|
||||
|
||||
enum Platform {
|
||||
@ -186,19 +150,23 @@ scalar DateTime
|
||||
"The `Long` scalar type represents non-fractional signed whole 64-bit numeric values. Long can represent values between -(2^63) and 2^63 - 1."
|
||||
scalar Long
|
||||
|
||||
scalar UUID
|
||||
|
||||
input ArtifactFileInfoFilterInput {
|
||||
and: [ArtifactFileInfoFilterInput!]
|
||||
downloadSize: ComparableInt64OperationFilterInput
|
||||
downloads: ComparableInt64OperationFilterInput
|
||||
downloadSize: LongOperationFilterInput
|
||||
downloads: LongOperationFilterInput
|
||||
id: UuidOperationFilterInput
|
||||
md5Hash: StringOperationFilterInput
|
||||
or: [ArtifactFileInfoFilterInput!]
|
||||
}
|
||||
|
||||
input ArtifactFilterInput {
|
||||
and: [ArtifactFilterInput!]
|
||||
artifactId: ComparableInt64OperationFilterInput
|
||||
artifactId: LongOperationFilterInput
|
||||
deltaFileInfo: ArtifactFileInfoFilterInput
|
||||
fileInfo: ArtifactFileInfoFilterInput
|
||||
id: UuidOperationFilterInput
|
||||
or: [ArtifactFilterInput!]
|
||||
platform: PlatformOperationFilterInput
|
||||
}
|
||||
@ -208,51 +176,36 @@ input BooleanOperationFilterInput {
|
||||
neq: Boolean
|
||||
}
|
||||
|
||||
input ComparableDateTimeOffsetOperationFilterInput {
|
||||
input DateTimeOperationFilterInput {
|
||||
eq: DateTime
|
||||
gt: DateTime
|
||||
gte: DateTime
|
||||
in: [DateTime!]
|
||||
in: [DateTime]
|
||||
lt: DateTime
|
||||
lte: DateTime
|
||||
neq: DateTime
|
||||
ngt: DateTime
|
||||
ngte: DateTime
|
||||
nin: [DateTime!]
|
||||
nin: [DateTime]
|
||||
nlt: DateTime
|
||||
nlte: DateTime
|
||||
}
|
||||
|
||||
input ComparableInt32OperationFilterInput {
|
||||
input IntOperationFilterInput {
|
||||
eq: Int
|
||||
gt: Int
|
||||
gte: Int
|
||||
in: [Int!]
|
||||
in: [Int]
|
||||
lt: Int
|
||||
lte: Int
|
||||
neq: Int
|
||||
ngt: Int
|
||||
ngte: Int
|
||||
nin: [Int!]
|
||||
nin: [Int]
|
||||
nlt: Int
|
||||
nlte: Int
|
||||
}
|
||||
|
||||
input ComparableInt64OperationFilterInput {
|
||||
eq: Long
|
||||
gt: Long
|
||||
gte: Long
|
||||
in: [Long!]
|
||||
lt: Long
|
||||
lte: Long
|
||||
neq: Long
|
||||
ngt: Long
|
||||
ngte: Long
|
||||
nin: [Long!]
|
||||
nlt: Long
|
||||
nlte: Long
|
||||
}
|
||||
|
||||
input ListFilterInputTypeOfArtifactFilterInput {
|
||||
all: ArtifactFilterInput
|
||||
any: Boolean
|
||||
@ -260,6 +213,21 @@ input ListFilterInputTypeOfArtifactFilterInput {
|
||||
some: ArtifactFilterInput
|
||||
}
|
||||
|
||||
input LongOperationFilterInput {
|
||||
eq: Long
|
||||
gt: Long
|
||||
gte: Long
|
||||
in: [Long]
|
||||
lt: Long
|
||||
lte: Long
|
||||
neq: Long
|
||||
ngt: Long
|
||||
ngte: Long
|
||||
nin: [Long]
|
||||
nlt: Long
|
||||
nlte: Long
|
||||
}
|
||||
|
||||
input PlatformOperationFilterInput {
|
||||
eq: Platform
|
||||
in: [Platform!]
|
||||
@ -273,13 +241,13 @@ input ReleaseFilterInput {
|
||||
branch: StringOperationFilterInput
|
||||
changelog: StringOperationFilterInput
|
||||
commit: StringOperationFilterInput
|
||||
createdAt: ComparableDateTimeOffsetOperationFilterInput
|
||||
id: StringOperationFilterInput
|
||||
createdAt: DateTimeOperationFilterInput
|
||||
id: UuidOperationFilterInput
|
||||
isDraft: BooleanOperationFilterInput
|
||||
or: [ReleaseFilterInput!]
|
||||
previousRelease: StringOperationFilterInput
|
||||
previousRelease: ReleaseFilterInput
|
||||
version: StringOperationFilterInput
|
||||
workflowRunId: ComparableInt64OperationFilterInput
|
||||
workflowRunId: LongOperationFilterInput
|
||||
}
|
||||
|
||||
input ReleaseSortInput {
|
||||
@ -289,27 +257,27 @@ input ReleaseSortInput {
|
||||
createdAt: SortEnumType
|
||||
id: SortEnumType
|
||||
isDraft: SortEnumType
|
||||
previousRelease: SortEnumType
|
||||
previousRelease: ReleaseSortInput
|
||||
version: SortEnumType
|
||||
workflowRunId: SortEnumType
|
||||
}
|
||||
|
||||
input ReleaseStatisticFilterInput {
|
||||
and: [ReleaseStatisticFilterInput!]
|
||||
count: ComparableInt32OperationFilterInput
|
||||
lastReportedUsage: ComparableDateTimeOffsetOperationFilterInput
|
||||
linuxCount: ComparableInt32OperationFilterInput
|
||||
oSXCount: ComparableInt32OperationFilterInput
|
||||
count: IntOperationFilterInput
|
||||
lastReportedUsage: DateTimeOperationFilterInput
|
||||
linuxCount: IntOperationFilterInput
|
||||
or: [ReleaseStatisticFilterInput!]
|
||||
releaseId: StringOperationFilterInput
|
||||
windowsCount: ComparableInt32OperationFilterInput
|
||||
osxCount: IntOperationFilterInput
|
||||
releaseId: UuidOperationFilterInput
|
||||
windowsCount: IntOperationFilterInput
|
||||
}
|
||||
|
||||
input ReleaseStatisticSortInput {
|
||||
count: SortEnumType
|
||||
lastReportedUsage: SortEnumType
|
||||
linuxCount: SortEnumType
|
||||
oSXCount: SortEnumType
|
||||
osxCount: SortEnumType
|
||||
releaseId: SortEnumType
|
||||
windowsCount: SortEnumType
|
||||
}
|
||||
@ -331,6 +299,21 @@ input StringOperationFilterInput {
|
||||
|
||||
input UpdateReleaseChangelogInput {
|
||||
changelog: String!
|
||||
id: String!
|
||||
id: UUID!
|
||||
isDraft: Boolean!
|
||||
}
|
||||
|
||||
input UuidOperationFilterInput {
|
||||
eq: UUID
|
||||
gt: UUID
|
||||
gte: UUID
|
||||
in: [UUID]
|
||||
lt: UUID
|
||||
lte: UUID
|
||||
neq: UUID
|
||||
ngt: UUID
|
||||
ngte: UUID
|
||||
nin: [UUID]
|
||||
nlt: UUID
|
||||
nlte: UUID
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user