Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions PluginVersion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;

namespace RomM
{
/// <summary>
/// The plugin's own version, as reported to RomM whenever this client registers itself (QR
/// pairing, save sync device registration). Read from the assembly -- built from Version in
/// RomM.csproj -- so the registration paths cannot report different versions from one another;
/// PluginVersionTests ties that version to the one the addon manifests declare.
/// </summary>
internal static class PluginVersion
{
/// <summary>
/// Major.minor.patch, matching the Version in extension.yaml. Assemblies always carry a
/// four-part version ("0.9.0.0"), and the revision is never set here, so it is dropped.
/// </summary>
public static string Current { get; } = Format(typeof(PluginVersion).Assembly.GetName().Version);

internal static string Format(Version version)
{
if (version == null)
return "0.0.0";

// Build is -1, not 0, when the version was declared with two parts.
return $"{version.Major}.{version.Minor}.{Math.Max(version.Build, 0)}";
}
}
}
67 changes: 67 additions & 0 deletions RomM.Tests/PluginVersionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Xunit;

namespace RomM.Tests
{
/// <summary>
/// The version this client reports to RomM comes from the assembly, which is built from Version
/// in RomM.csproj, while the addon manifests declare their own. Nothing in the compiler or the
/// packaging step ties the two together, so a release that bumped one and forgot the other would
/// ship a plugin identifying itself as the wrong version, silently. These tests are that tie.
/// </summary>
public class PluginVersionTests
{
[Fact]
public void Project_version_matches_the_extension_manifest()
{
Assert.Equal(ExtensionVersion(), ProjectVersion());
}

[Fact]
public void Installer_manifest_carries_a_package_for_the_current_version()
{
var packaged = Regex.Matches(ReadDeclaration("installer.yaml"), @"(?m)^\s*-\s*Version:\s*(\S+)\s*$")
.Cast<Match>()
.Select(m => m.Groups[1].Value)
.ToList();

Assert.Contains(ExtensionVersion(), packaged);
}

[Theory]
[InlineData("0.9.0.0", "0.9.0")]
[InlineData("1.2.3.4", "1.2.3")]
[InlineData("0.9", "0.9.0")] // Build is -1 when only two parts were declared.
public void Format_drops_the_revision_the_plugin_never_sets(string assemblyVersion, string expected)
{
Assert.Equal(expected, PluginVersion.Format(new Version(assemblyVersion)));
}

[Fact]
public void Format_survives_an_assembly_with_no_version()
{
Assert.Equal("0.0.0", PluginVersion.Format(null));
}

private static string ProjectVersion() =>
Declaration("RomM.csproj.txt", @"<Version>\s*([^<\s]+)\s*</Version>");

private static string ExtensionVersion() =>
Declaration("extension.yaml", @"(?m)^?Version:\s*(\S+)\s*$");

private static string Declaration(string file, string pattern)
{
var match = Regex.Match(ReadDeclaration(file), pattern);
Assert.True(match.Success, $"No version declaration found in {file}.");
return match.Groups[1].Value;
}

// RomM.Tests.csproj copies these three next to the test assembly; the project file keeps a
// .txt suffix there so nothing mistakes the copy for a project it should build.
private static string ReadDeclaration(string file) =>
File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Declarations", file));
}
}
12 changes: 11 additions & 1 deletion RomM.Tests/RomM.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PlayniteSDK" Version="6.16.0" />
<PackageReference Include="PlayniteSDK" Version="6.17.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="protobuf-net" Version="2.0.0.668" />
</ItemGroup>
Expand All @@ -41,6 +41,7 @@
<Compile Include="..\Models\**\*.cs" Exclude="..\Models\**\GameInstallInfo.cs">
<Link>Linked\Models\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\PluginVersion.cs" Link="Linked\PluginVersion.cs" />
<Compile Include="..\Games\RomMGameId.cs" Link="Linked\Games\RomMGameId.cs" />
<Compile Include="..\Games\RomMGameInfo.cs" Link="Linked\Games\RomMGameInfo.cs" />
<Compile Include="..\Games\RomMMetadataMapper.cs" Link="Linked\Games\RomMMetadataMapper.cs" />
Expand All @@ -61,4 +62,13 @@
<Compile Include="..\Saves\Handlers\SaveHandlerRegistry.cs" Link="Linked\Saves\Handlers\SaveHandlerRegistry.cs" />
</ItemGroup>

<!-- The version declarations PluginVersionTests compares. Copied rather than read from the
repo so the check does not depend on where the test assembly ends up; the project file
lands as .txt so nothing mistakes the copy for a project it should build. -->
<ItemGroup>
<None Include="..\extension.yaml" Link="Declarations\extension.yaml" CopyToOutputDirectory="PreserveNewest" />
<None Include="..\manifests\installer.yaml" Link="Declarations\installer.yaml" CopyToOutputDirectory="PreserveNewest" />
<None Include="..\RomM.csproj" Link="Declarations\RomM.csproj.txt" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions RomM.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>RomM</RootNamespace>
<AssemblyName>RomM</AssemblyName>
<!-- Keep in sync with extension.yaml; save sync reports it as the client version. -->
<Version>0.9.0</Version>
<TargetFramework>net462</TargetFramework>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
Expand Down
5 changes: 2 additions & 3 deletions Saves/SaveSyncService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Newtonsoft.Json;
using Newtonsoft.Json;
using Playnite.SDK;
using Playnite.SDK.Models;
using RomM.Games;
Expand All @@ -13,7 +13,6 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Threading;

Expand Down Expand Up @@ -391,7 +390,7 @@ private string EnsureDeviceRegistered(CancellationToken ct)
Name = Environment.MachineName,
Platform = "Windows",
Client = DeviceClient,
ClientVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(),
ClientVersion = PluginVersion.Current,
};

var url = RomMUrl.Combine(host, "api/devices");
Expand Down
3 changes: 1 addition & 2 deletions Settings/SettingsView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ private async void Click_LoginViaQR(object sender, RoutedEventArgs e)
name = $"Playnite-{Environment.MachineName}",
client = "Playnite Plugin",
platform = "Windows",
client_version = "0.8.0", // This should be probably be changed to reading the extension.yaml at runtime or
// adding a plugin version to the main file that devs change every update
client_version = PluginVersion.Current,
requested_scopes = new List<string>
{
"me.read", "me.write",
Expand Down
2 changes: 1 addition & 1 deletion extension.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Id: RomM_9700aa21-447d-41b4-a989-acd38f407d9f
Name: RomM Library Importer
Author: The RomM Team
Version: 0.8.0
Version: 0.9.0
Module: RomM.dll
Type: GameLibrary
Icon: icon.png
Expand Down
9 changes: 9 additions & 0 deletions manifests/installer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,12 @@ Packages:
- Better error message when no mapping found by @gantoine
- Derive install paths from RomM folder (fs_name) for folder-based ROMs by @gantoine
- Keep nested ROM paths and contain untrusted paths in the install root by @gantoine
- Version: 0.9.0
RequiredApiVersion: 6.17.0
ReleaseDate: 2026-09-16
PackageUrl: https://github.com/rommapp/playnite-plugin/releases/download/0.9.0/RomM_9700aa21-447d-41b4-a989-acd38f407d9f_0_9_0.pext
Changelog:
- Sync RetroArch saves with RomM, downloading the newest save before launch and uploading after play by @LxKnsy
- Add option to install ROMs flat, without per-game folders by @matthew-pye
- Fix typos in comments, README, and addon manifests by @Avicennasis
- Bump PlayniteSDK from 6.16.0 to 6.17.0 by @dependabot
Loading