feat: make testing opt-in per plugin

This commit is contained in:
goat 2022-10-29 14:45:52 +02:00
parent ce8b4702b6
commit 505e37fd28
No known key found for this signature in database
GPG key ID: 49E2AA8C6A76498B
6 changed files with 109 additions and 32 deletions

View file

@ -337,6 +337,11 @@ namespace Dalamud.Configuration.Internal
/// </summary> /// </summary>
public string LastFeedbackContactDetails { get; set; } = string.Empty; public string LastFeedbackContactDetails { get; set; } = string.Empty;
/// <summary>
/// Gets or sets a list of plugins that testing builds should be downloaded for.
/// </summary>
public List<PluginTestingOptIn>? PluginTestingOptIns { get; set; }
/// <summary> /// <summary>
/// Load a configuration from the provided path. /// Load a configuration from the provided path.
/// </summary> /// </summary>

View file

@ -0,0 +1,24 @@
namespace Dalamud.Configuration.Internal;
public record PluginTestingOptIn
{
/// <summary>
/// Initializes a new instance of the <see cref="PluginTestingOptIn"/> class.
/// </summary>
/// <param name="internalName">The internal name of the plugin.</param>
public PluginTestingOptIn(string internalName)
{
this.InternalName = internalName;
this.Branch = "testing-live"; // TODO: make these do something, needs work in plogon
}
/// <summary>
/// Gets the internal name of the plugin to test.
/// </summary>
public string InternalName { get; private set; }
/// <summary>
/// Gets the testing branch to use.
/// </summary>
public string Branch { get; private set; }
}

View file

@ -513,7 +513,7 @@ namespace Dalamud.Interface.Internal.Windows
isThirdParty = true; isThirdParty = true;
} }
var useTesting = PluginManager.UseTesting(manifest); var useTesting = Service<PluginManager>.Get().UseTesting(manifest);
var url = this.GetPluginIconUrl(manifest, isThirdParty, useTesting); var url = this.GetPluginIconUrl(manifest, isThirdParty, useTesting);
if (url.IsNullOrEmpty()) if (url.IsNullOrEmpty())
@ -599,7 +599,7 @@ namespace Dalamud.Interface.Internal.Windows
isThirdParty = true; isThirdParty = true;
} }
var useTesting = PluginManager.UseTesting(manifest); var useTesting = Service<PluginManager>.Get().UseTesting(manifest);
var urls = this.GetPluginImageUrls(manifest, isThirdParty, useTesting); var urls = this.GetPluginImageUrls(manifest, isThirdParty, useTesting);
urls = urls?.Where(x => !string.IsNullOrEmpty(x)).ToList(); urls = urls?.Where(x => !string.IsNullOrEmpty(x)).ToList();
if (urls?.Any() != true) if (urls?.Any() != true)

View file

@ -1637,7 +1637,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
var notifications = Service<NotificationManager>.Get(); var notifications = Service<NotificationManager>.Get();
var pluginManager = Service<PluginManager>.Get(); var pluginManager = Service<PluginManager>.Get();
var useTesting = PluginManager.UseTesting(manifest); var useTesting = pluginManager.UseTesting(manifest);
var wasSeen = this.WasPluginSeen(manifest.InternalName); var wasSeen = this.WasPluginSeen(manifest.InternalName);
var isOutdated = manifest.DalamudApiLevel < PluginManager.DalamudApiLevel; var isOutdated = manifest.DalamudApiLevel < PluginManager.DalamudApiLevel;
@ -1653,7 +1653,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
var label = manifest.Name; var label = manifest.Name;
// Testing // Testing
if (useTesting) if (useTesting || manifest.IsTestingExclusive)
{ {
label += Locs.PluginTitleMod_TestingVersion; label += Locs.PluginTitleMod_TestingVersion;
} }
@ -1710,7 +1710,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
this.installStatus = OperationStatus.InProgress; this.installStatus = OperationStatus.InProgress;
this.loadingIndicatorKind = LoadingIndicatorKind.Installing; this.loadingIndicatorKind = LoadingIndicatorKind.Installing;
Task.Run(() => pluginManager.InstallPluginAsync(manifest, useTesting, PluginLoadReason.Installer)) Task.Run(() => pluginManager.InstallPluginAsync(manifest, useTesting || manifest.IsTestingExclusive, PluginLoadReason.Installer))
.ContinueWith(task => .ContinueWith(task =>
{ {
// There is no need to set as Complete for an individual plugin installation // There is no need to set as Complete for an individual plugin installation
@ -1803,6 +1803,8 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
var configuration = Service<DalamudConfiguration>.Get(); var configuration = Service<DalamudConfiguration>.Get();
var commandManager = Service<CommandManager>.Get(); var commandManager = Service<CommandManager>.Get();
var testingOptIn =
configuration.PluginTestingOptIns?.FirstOrDefault(x => x.InternalName == plugin.Manifest.InternalName);
var trouble = false; var trouble = false;
// Name // Name
@ -1820,6 +1822,11 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
label += Locs.PluginTitleMod_TestingVersion; label += Locs.PluginTitleMod_TestingVersion;
} }
if (plugin.Manifest.IsAvailableForTesting && configuration.DoPluginTest && testingOptIn == null)
{
label += Locs.PluginTitleMod_TestingAvailable;
}
// Freshly installed // Freshly installed
if (showInstalled) if (showInstalled)
{ {
@ -1904,7 +1911,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
ImGui.PushID($"installed{index}{plugin.Manifest.InternalName}"); ImGui.PushID($"installed{index}{plugin.Manifest.InternalName}");
var hasChangelog = !plugin.Manifest.Changelog.IsNullOrEmpty(); var hasChangelog = !plugin.Manifest.Changelog.IsNullOrEmpty();
if (this.DrawPluginCollapsingHeader(label, plugin, plugin.Manifest, plugin.Manifest.IsThirdParty, trouble, availablePluginUpdate != default, false, false, () => this.DrawInstalledPluginContextMenu(plugin), index)) if (this.DrawPluginCollapsingHeader(label, plugin, plugin.Manifest, plugin.Manifest.IsThirdParty, trouble, availablePluginUpdate != default, false, false, () => this.DrawInstalledPluginContextMenu(plugin, testingOptIn), index))
{ {
if (!this.WasPluginSeen(plugin.Manifest.InternalName)) if (!this.WasPluginSeen(plugin.Manifest.InternalName))
configuration.SeenPluginInternalName.Add(plugin.Manifest.InternalName); configuration.SeenPluginInternalName.Add(plugin.Manifest.InternalName);
@ -2038,13 +2045,35 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
ImGui.PopStyleColor(2); ImGui.PopStyleColor(2);
} }
private void DrawInstalledPluginContextMenu(LocalPlugin plugin) private void DrawInstalledPluginContextMenu(LocalPlugin plugin, PluginTestingOptIn? optIn)
{ {
var pluginManager = Service<PluginManager>.Get(); var pluginManager = Service<PluginManager>.Get();
var configuration = Service<DalamudConfiguration>.Get();
if (ImGui.BeginPopupContextItem("InstalledItemContextMenu")) if (ImGui.BeginPopupContextItem("InstalledItemContextMenu"))
{ {
if (ImGui.Selectable(Locs.PluginContext_DeletePluginConfigReload)) var repoManifest = this.pluginListAvailable.FirstOrDefault(x => x.InternalName == plugin.Manifest.InternalName);
if (repoManifest?.IsTestingExclusive == true)
ImGui.BeginDisabled();
if (ImGui.MenuItem(Locs.PluginContext_TestingOptIn, string.Empty, optIn != null))
{
if (optIn != null)
{
configuration.PluginTestingOptIns!.Remove(optIn);
}
else
{
configuration.PluginTestingOptIns!.Add(new PluginTestingOptIn(plugin.Manifest.InternalName));
}
configuration.Save();
}
if (repoManifest?.IsTestingExclusive == true)
ImGui.EndDisabled();
if (ImGui.MenuItem(Locs.PluginContext_DeletePluginConfigReload))
{ {
Log.Debug($"Deleting config for {plugin.Manifest.InternalName}"); Log.Debug($"Deleting config for {plugin.Manifest.InternalName}");
@ -2751,6 +2780,8 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
public static string PluginTitleMod_TestingVersion => Loc.Localize("InstallerTestingVersion", " (testing version)"); public static string PluginTitleMod_TestingVersion => Loc.Localize("InstallerTestingVersion", " (testing version)");
public static string PluginTitleMod_TestingAvailable => Loc.Localize("InstallerTestingAvailable", " (available for testing)");
public static string PluginTitleMod_DevPlugin => Loc.Localize("InstallerDevPlugin", " (dev plugin)"); public static string PluginTitleMod_DevPlugin => Loc.Localize("InstallerDevPlugin", " (dev plugin)");
public static string PluginTitleMod_UpdateFailed => Loc.Localize("InstallerUpdateFailed", " (update failed)"); public static string PluginTitleMod_UpdateFailed => Loc.Localize("InstallerUpdateFailed", " (update failed)");
@ -2773,6 +2804,8 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller
#region Plugin context menu #region Plugin context menu
public static string PluginContext_TestingOptIn => Loc.Localize("InstallerTestingOptIn", "Receive plugin testing versions");
public static string PluginContext_MarkAllSeen => Loc.Localize("InstallerMarkAllSeen", "Mark all as seen"); public static string PluginContext_MarkAllSeen => Loc.Localize("InstallerMarkAllSeen", "Mark all as seen");
public static string PluginContext_HidePlugin => Loc.Localize("InstallerHidePlugin", "Hide from installer"); public static string PluginContext_HidePlugin => Loc.Localize("InstallerHidePlugin", "Hide from installer");

View file

@ -118,11 +118,13 @@ Thanks and have fun!";
throw new InvalidDataException("Couldn't deserialize banned plugins manifest."); throw new InvalidDataException("Couldn't deserialize banned plugins manifest.");
} }
this.openInstallerWindowPluginChangelogsLink = Service<ChatGui>.Get().AddChatLinkHandler("Dalamud", 1003, (i, m) => this.openInstallerWindowPluginChangelogsLink = Service<ChatGui>.Get().AddChatLinkHandler("Dalamud", 1003, (_, _) =>
{ {
Service<DalamudInterface>.GetNullable()?.OpenPluginInstallerPluginChangelogs(); Service<DalamudInterface>.GetNullable()?.OpenPluginInstallerPluginChangelogs();
}); });
this.configuration.PluginTestingOptIns ??= new List<PluginTestingOptIn>();
this.ApplyPatches(); this.ApplyPatches();
} }
@ -186,6 +188,23 @@ Thanks and have fun!";
/// </summary> /// </summary>
public bool LoadBannedPlugins { get; set; } public bool LoadBannedPlugins { get; set; }
/// <summary>
/// Gets a value indicating whether the given repo manifest should be visible to the user.
/// </summary>
/// <param name="manifest">Repo manifest.</param>
/// <returns>If the manifest is visible.</returns>
public static bool IsManifestVisible(RemotePluginManifest manifest)
{
var configuration = Service<DalamudConfiguration>.Get();
// Hidden by user
if (configuration.HiddenPluginInternalName.Contains(manifest.InternalName))
return false;
// Hidden by manifest
return !manifest.IsHide;
}
/// <summary> /// <summary>
/// Print to chat any plugin updates and whether they were successful. /// Print to chat any plugin updates and whether they were successful.
/// </summary> /// </summary>
@ -236,11 +255,12 @@ Thanks and have fun!";
/// </summary> /// </summary>
/// <param name="manifest">Manifest to check.</param> /// <param name="manifest">Manifest to check.</param>
/// <returns>A value indicating whether testing should be used.</returns> /// <returns>A value indicating whether testing should be used.</returns>
public static bool UseTesting(PluginManifest manifest) public bool UseTesting(PluginManifest manifest)
{ {
var configuration = Service<DalamudConfiguration>.Get(); if (!this.configuration.DoPluginTest)
return false;
if (!configuration.DoPluginTest) if (this.configuration.PluginTestingOptIns!.All(x => x.InternalName != manifest.InternalName))
return false; return false;
if (manifest.IsTestingExclusive) if (manifest.IsTestingExclusive)
@ -258,25 +278,6 @@ Thanks and have fun!";
return false; return false;
} }
/// <summary>
/// Gets a value indicating whether the given repo manifest should be visible to the user.
/// </summary>
/// <param name="manifest">Repo manifest.</param>
/// <returns>If the manifest is visible.</returns>
public static bool IsManifestVisible(RemotePluginManifest manifest)
{
var configuration = Service<DalamudConfiguration>.Get();
// Hidden by user
if (configuration.HiddenPluginInternalName.Contains(manifest.InternalName))
return false;
return true; // TODO temporary
// Hidden by manifest
return !manifest.IsHide;
}
/// <inheritdoc/> /// <inheritdoc/>
public void Dispose() public void Dispose()
{ {
@ -687,6 +688,13 @@ Thanks and have fun!";
{ {
Log.Debug($"Installing plugin {repoManifest.Name} (testing={useTesting})"); Log.Debug($"Installing plugin {repoManifest.Name} (testing={useTesting})");
// Ensure that we have a testing opt-in for this plugin if we are installing a testing version
if (useTesting && this.configuration.PluginTestingOptIns!.All(x => x.InternalName != repoManifest.InternalName))
{
this.configuration.PluginTestingOptIns.Add(new PluginTestingOptIn(repoManifest.InternalName));
this.configuration.Save();
}
var downloadUrl = useTesting ? repoManifest.DownloadLinkTesting : repoManifest.DownloadLinkInstall; var downloadUrl = useTesting ? repoManifest.DownloadLinkTesting : repoManifest.DownloadLinkInstall;
var version = useTesting ? repoManifest.TestingAssemblyVersion : repoManifest.AssemblyVersion; var version = useTesting ? repoManifest.TestingAssemblyVersion : repoManifest.AssemblyVersion;
@ -961,6 +969,7 @@ Thanks and have fun!";
versionDir.Delete(true); versionDir.Delete(true);
continue; continue;
} }
var dllFile = new FileInfo(Path.Combine(versionDir.FullName, $"{pluginDir.Name}.dll")); var dllFile = new FileInfo(Path.Combine(versionDir.FullName, $"{pluginDir.Name}.dll"));
if (!dllFile.Exists) if (!dllFile.Exists)
{ {
@ -1008,6 +1017,7 @@ Thanks and have fun!";
/// <summary> /// <summary>
/// Update all non-dev plugins. /// Update all non-dev plugins.
/// </summary> /// </summary>
/// <param name="ignoreDisabled">Ignore disabled plugins.</param>
/// <param name="dryRun">Perform a dry run, don't install anything.</param> /// <param name="dryRun">Perform a dry run, don't install anything.</param>
/// <returns>Success or failure and a list of updated plugin metadata.</returns> /// <returns>Success or failure and a list of updated plugin metadata.</returns>
public async Task<List<PluginUpdateStatus>> UpdatePluginsAsync(bool ignoreDisabled, bool dryRun) public async Task<List<PluginUpdateStatus>> UpdatePluginsAsync(bool ignoreDisabled, bool dryRun)
@ -1265,7 +1275,7 @@ Thanks and have fun!";
.Where(remoteManifest => remoteManifest.DalamudApiLevel == DalamudApiLevel) .Where(remoteManifest => remoteManifest.DalamudApiLevel == DalamudApiLevel)
.Select(remoteManifest => .Select(remoteManifest =>
{ {
var useTesting = UseTesting(remoteManifest); var useTesting = this.UseTesting(remoteManifest);
var candidateVersion = useTesting var candidateVersion = useTesting
? remoteManifest.TestingAssemblyVersion ? remoteManifest.TestingAssemblyVersion
: remoteManifest.AssemblyVersion; : remoteManifest.AssemblyVersion;

View file

@ -50,6 +50,11 @@ internal record LocalPluginManifest : PluginManifest
/// </summary> /// </summary>
public Version EffectiveVersion => this.Testing && this.TestingAssemblyVersion != null ? this.TestingAssemblyVersion : this.AssemblyVersion; public Version EffectiveVersion => this.Testing && this.TestingAssemblyVersion != null ? this.TestingAssemblyVersion : this.AssemblyVersion;
/// <summary>
/// Gets a value indicating whether this plugin is eligible for testing.
/// </summary>
public bool IsAvailableForTesting => this.TestingAssemblyVersion != null && this.TestingAssemblyVersion > this.AssemblyVersion;
/// <summary> /// <summary>
/// Save a plugin manifest to file. /// Save a plugin manifest to file.
/// </summary> /// </summary>