Add plugin update support in Plugins settings tab - #4595
Conversation
- Auto-check for updates silently when navigating to Plugins tab - Show update badge (v1.0.0 → v2.0.0) on plugin cards with available updates - Add per-plugin "Update" button in the plugin display header - Add "Check for updates" button in Plugins tab toolbar - Add "Update All" button that appears when updates are available
📝 WalkthroughWalkthroughThe plugin settings page now checks plugin manifests, tracks available updates, displays version differences, and provides per-plugin and bulk update commands. Silent checking starts when the settings page is opened. ChangesPlugin update workflow
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant SettingsPanePluginsViewModel
participant PluginInstaller
participant PluginViewModel
participant PluginUpdateWindow
SettingsPanePluginsViewModel->>PluginInstaller: refresh plugin manifest
SettingsPanePluginsViewModel->>PluginViewModel: set UpdateInfo
SettingsPanePluginsViewModel->>PluginUpdateWindow: open plugins with updates
PluginViewModel->>PluginInstaller: update plugin and check restart
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs`:
- Around line 250-251: Replace the lexicographic comparison in the update check
around PluginModified with a semantic-version comparer that correctly orders
numeric components and prerelease versions. Apply the same comparer consistently
to all plugin version comparisons in PluginInstaller.cs and PluginsManager.cs,
preserving the existing update and modification conditions.
In `@Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml.cs`:
- Line 35: Update the silent update-check path around
CheckForUpdatesSilentlyAsync so failures from its asynchronous manifest I/O are
observed, caught, and logged rather than discarded. Preserve the existing
session guard, and explicitly handle whether that guard is cleared when the
silent check fails so the retry behavior is intentional.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 31639003-6e6b-4776-8338-bdfc6881ede1
📒 Files selected for processing (5)
Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xamlFlow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.csFlow.Launcher/SettingPages/Views/SettingsPanePlugins.xamlFlow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml.csFlow.Launcher/ViewModel/PluginViewModel.cs
| if (string.Compare(currentVersion, newVersion, StringComparison.InvariantCulture) < 0 | ||
| && !PublicApi.Instance.PluginModified(vm.PluginPair.Metadata.ID)) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find existing version parsing/comparison conventions before adding a new one.
rg -n -C 3 -g '*.cs' '\b(NuGetVersion|SemanticVersion|Version\.(TryParse|Parse)|CompareTo)\b' .
rg -n -g '*.json' '"[Vv]ersion"\s*:' .Repository: Flow-Launcher/Flow.Launcher
Length of output: 5858
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## Candidate file outline"
ast-grep outline Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs --view compact || true
echo "## Relevant SettingsPanePluginsViewModel section"
sed -n '220,270p' Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs | cat -n
echo "## Relevant PluginManager version methods"
sed -n '860,900p' Flow.Launcher.Core/Plugin/PluginManager.cs | cat -n
sed -n '1145,1170p' Flow.Launcher.Core/Plugin/PluginManager.cs | cat -n
echo "## All string.Compare usages for version strings"
rg -n -C 2 "string\.Compare.*Version|CompareTo\(.*Version|Version\.CompareTo|CompareTo\(.*Metadata\.Version" Flow.Launcher Flow.Launcher.Core Plugins -g '*.cs'
echo "## NuGet / SemanticVersioning package references"
rg -n -g '*.csproj' -g 'packages.lock.json' -g 'packages.config' 'SemanticVersioning|Versioning|Newtonsoft' .
if [ -f Flow.Launcher.csproj ]; then sed -n '1,220p' Flow.Launcher.csproj; fiRepository: Flow-Launcher/Flow.Launcher
Length of output: 9922
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from distutils.version import StrictVersion
samples = [("1.10.0", "1.9.0"), ("1.9.0", "1.10.0")]
for current, newer in samples:
print(f"current={current!r} newer={newer!r}")
print(" string invariant compare sign:", "".join(compart_to_sign(current, newer) for _ in range(1) or [str(__import__('re').match(r'(\d+)\.(\d+)\.(\d+)', current).groups() if False)]))
PYRepository: Flow-Launcher/Flow.Launcher
Length of output: 595
🌐 Web query:
.NET System.Version.CompareTo numeric component version comparison prerelease documentation
💡 Result:
The.NET System.Version class does not support prerelease strings or metadata [1][2][3]. It is designed exclusively to handle numeric versioning components [1][2]. System.Version.CompareTo operates by comparing the four specific numeric components of a version object in order of decreasing importance: major, minor, build, and revision [4][5]. The comparison logic is as follows: 1. Components are compared sequentially: major vs. major, then minor vs. minor, then build vs. build, and finally revision vs. revision [5][6]. 2. For each component pair, the method returns a positive integer if the current object's component is greater, a negative integer if it is smaller, or continues to the next component if they are equal [5][6]. 3. If all defined components are equal, the method returns 0 [7][4]. 4. Any component that is not specified is treated as undefined (internally often represented as -1), and the official documentation notes that an unknown component is assumed to be older than any known component [4][1]. Because System.Version requires all components to be non-negative integers [1][2], it cannot represent or compare semantic versioning (SemVer) prerelease tags (e.g., "1.0.0-alpha") [3]. Developers requiring support for SemVer should use a dedicated library, such as SemVer (SemVersion), which is specifically built to handle prerelease labels and complex version precedence rules [3].
Citations:
- 1: https://learn.microsoft.com/en-us/dotnet/api/system.version.-ctor?view=net-10.0
- 2: https://learn.microsoft.com/en-us/dotnet/api/system.version.parse?view=net-10.0
- 3: https://semver-nuget.org/v3.0.x/Semver.SemVersion.html
- 4: https://learn.microsoft.com/en-us/dotnet/api/system.version.compareto?view=netframework-4.8.1
- 5: https://github.com/dotnet/dotnet/blob/17d11de66cf75b962995c81dd1235fae9aa5ece0/src/runtime/src/libraries/System.Private.CoreLib/src/System/Version.cs
- 6: https://www.dotnetframework.org/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/clr/src/BCL/System/Version@cs/1/Version@cs
- 7: https://learn.microsoft.com/en-us/dotnet/api/system.version.compareto?view=net-10.0
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## Plugin version fields/types"
rg -n -C 4 -g '*.cs' 'public .*Version|Version\s*{.*get|class PluginMetadata|class UserPlugin|interface IPlugin' .
echo "## SemanticVersioning usage context"
rg -n -C 3 -g '*.cs' 'NuGetVersion|SemanticVersioning' .Repository: Flow-Launcher/Flow.Launcher
Length of output: 407
🌐 Web query:
NuGet SemanticVersioning NuGetVersion.TryParse prerelease metadata comparison .NET
💡 Result:
In NuGet, version parsing and comparison for prerelease labels and build metadata follow specific rules implemented in the NuGet.Versioning library [1][2]. Prerelease Labels Prerelease labels (e.g., -alpha, -beta.1) affect version precedence [1]. Comparison Rules: 1. Version Precedence: NuGet follows Semantic Versioning (SemVer) standards, where stable versions are considered higher precedence than prerelease versions [1][2]. 2. Label Comparison: Prerelease components are compared using case-insensitive string comparison [1][2]. This means that 1.0.0-alpha and 1.0.0-Alpha are treated as equal [1][2]. 3. Sorting: When comparing two prerelease versions, NuGet determines precedence by comparing the dot-separated identifiers within the labels [1][3]. If an identifier is numeric, it is compared numerically; otherwise, it is compared lexically [3]. Build Metadata Build metadata (e.g., +20260729, +git.sha1) is identified by the + character [3]. Comparison Rules: 1. Ignored in Comparison: Build metadata has no impact on version precedence, equality, or version ranges [4][5][3]. It is not considered part of the package identity [4][5]. 2. Purpose: It is retained for informational purposes, such as display in user interfaces or diagnostics, but it is effectively ignored during sorting and dependency resolution [4][3]. Implementation Notes - NuGetVersion.TryParse: Use the NuGet.Versioning package for programmatic handling of versions [1][2]. The TryParse method handles the parsing of these components into a NuGetVersion object [6]. - Normalization: When a NuGetVersion is normalized (e.g., via ToNormalizedString), metadata is removed because it does not affect identity or precedence [4][5]. - Legacy Behavior: NuGetVersion supports a 4-segment version (Major.Minor.Patch.Revision) for compatibility with System.Version, in addition to standard SemVer [1][2]. If you are sorting versions, use the VersionComparer class provided by the NuGet.Versioning library to ensure correct logic is applied [1][2][7].
Citations:
- 1: https://learn.microsoft.com/en-us/nuget/concepts/package-versioning
- 2: https://github.com/NuGet/docs.microsoft.com-nuget/blob/main/docs/concepts/Package-Versioning.md
- 3: https://devblogs.microsoft.com/dotnet/supporting-semver-2-0-0/
- 4: https://github.com/NuGet/Home/wiki/SemVer-2.0.0-support
- 5: https://github.com/NuGet/Home/wiki/SemVer2-support-for-nuget.org-(server-side)
- 6: https://github.com/NuGet/NuGet.Client/blob/b56eacca7b4d73463631ec82c4b52867c13482b2/src/NuGet.Core/NuGet.Versioning/NuGetVersionFactory.cs
- 7: https://github.com/NuGetArchive/NuGet.Versioning/blob/master/src/NuGet.Versioning/VersionComparer.cs
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## Plugin version fields/types"
rg -n -C 4 -g '*.cs' 'public string Version|string Version|class PluginMetadata|class UserPlugin|interface IPlugin' .
echo "## SemanticVersioning package usages"
rg -n -C 3 -g '*.cs' 'NuGetVersion|SemanticVersioning|VersionComparer|VersionComparer' .Repository: Flow-Launcher/Flow.Launcher
Length of output: 11779
Compare plugin versions semantically.
Version is a string here, so line 250 treats 1.10.0 as older than 1.9.0; this can hide valid updates. Prefer a semantic-version comparer that also handles prerelease precedence where appropriate, and apply the same semantics to the other plugin version comparisons in PluginInstaller.cs / PluginsManager.cs.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs` around
lines 250 - 251, Replace the lexicographic comparison in the update check around
PluginModified with a semantic-version comparer that correctly orders numeric
components and prerelease versions. Apply the same comparer consistently to all
plugin version comparisons in PluginInstaller.cs and PluginsManager.cs,
preserving the existing update and modification conditions.
There was a problem hiding this comment.
All reported issues were addressed across 5 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Replace lexicographic string.Compare with SemanticVersioning.Version to correctly compare version numbers (e.g., 1.9.0 < 1.10.0).
- Return bool from UpdatePluginAndCheckRestartAsync so callers know success - Clear UpdateInfo only when update actually succeeds (not on cancel/failure) - Notify parent ViewModel via event to refresh toolbar update count
|
I don't think this pull request is the right place to compare versions using Semantic Versioning for the Core component, so if I were to create one, it would be in a separate pull request. I've saved it to my stash, so I can create it right away. |
- Wrap CheckForUpdatesCoreAsync in try-catch within CheckForUpdatesSilentlyAsync - Reset _updatesChecked on failure so the user can retry by re-navigating - Log exceptions via App.API.LogException instead of silently discarding them
Summary
Add plugin update support directly in the Plugins settings tab, making it easy to check for and apply plugin updates without navigating to the Plugin Store tab.
Changes
New Features
File Changes
How It Works
Summary by cubic
Adds plugin update checks and actions directly in the Plugins tab. Shows available updates, lets you update one or all plugins, and keeps counts and badges in sync only after successful updates.
Summary of changes
SemanticVersioning.Version; opening the Plugins tab runs a silent update check once per session, and on failure we log, reset the guard, and allow retry; update flow returns a success flag; per‑plugin badges clear only on successful update; toolbar update count and “Update All” visibility refresh via a view‑model event on update state changes.PluginUpdateWindow; per‑plugin version badge (vX → vY) and “Update” button; commands/state for check, batch update, per‑plugin update, and a shared update‑check routine; bindings for update count and visibility.Release Note
You can now see and install plugin updates directly from the Plugins tab, including updating all plugins at once.
Written for commit eed303f. Summary will update on new commits.