Skip to content

Conversation

jjw24
Copy link
Member

@jjw24 jjw24 commented Sep 4, 2025

Handle MinimumAppVersion parse fail and reorder last manifest fetch date

Follows on from #3932

@jjw24 jjw24 added this to the 2.0.0 milestone Sep 4, 2025
@jjw24 jjw24 requested a review from Jack251970 September 4, 2025 11:50
@jjw24 jjw24 self-assigned this Sep 4, 2025
@jjw24 jjw24 added the Dev branch only An issue or fix for the Dev branch build label Sep 4, 2025
Copy link

gitstream-cm bot commented Sep 4, 2025

🥷 Code experts: Jack251970, taooceros

Jack251970 has most 👩‍💻 activity in the files.
taooceros, Jack251970 have most 🧠 knowledge in the files.

See details

Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs

Activity based on git-commit:

Jack251970
SEP
AUG
JUL 5 additions & 1 deletions
JUN
MAY
APR 10 additions & 7 deletions

Knowledge based on git-blame:
taooceros: 32%
Jack251970: 21%

✨ Comment /gs review for LinearB AI review. Learn how to automate it here.

Copy link

gitstream-cm bot commented Sep 4, 2025

Be a legend 🏆 by adding a before and after screenshot of the changes you made, especially if they are around UI/UX.

Jack251970
Jack251970 previously approved these changes Sep 4, 2025
@Jack251970 Jack251970 requested a review from Copilot September 4, 2025 11:52
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves error handling for plugin manifest processing by adding exception handling for version parsing and optimizes the timing of when the manifest fetch timestamp is recorded.

  • Adds try-catch block around MinimumAppVersion parsing to handle invalid version strings gracefully
  • Moves the lastFetchedAt timestamp update to occur after successful processing instead of at the beginning

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Contributor

coderabbitai bot commented Sep 4, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Defers updating lastFetchedAt until after successfully processing and assigning fetched plugins; refactors IsMinimumAppVersionSatisfied to handle empty values, parse failures (try/catch with exception logging), and explicit version-mismatch logging and boolean returns. No public API signatures changed.

Changes

Cohort / File(s) Summary of Changes
Plugins manifest logic
Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
- UpdateManifestAsync: moved lastFetchedAt assignment to after building/assigning UserPlugins; preserves early return when results empty.
- IsMinimumAppVersionSatisfied: return true when MinimumAppVersion missing; wrap parse in try/catch and log exception on parse failure (exclude plugin); when parsed but app version too low, log informative message and exclude plugin; explicit true/false returns.
- No public signature changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant App as App
  participant PM as PluginsManifest
  participant Repo as PluginRepo

  User->>App: request manifest update
  App->>PM: UpdateManifestAsync()
  PM->>Repo: fetch manifests
  Repo-->>PM: results (empty / items / error)

  alt results empty
    PM-->>App: return (no update)
  else results present
    PM->>PM: build updatedPluginResults
    PM->>PM: UserPlugins = updatedPluginResults
    PM->>PM: lastFetchedAt = now
    PM-->>App: return success
  end
Loading
sequenceDiagram
  autonumber
  participant PM as PluginsManifest
  participant Logger

  PM->>PM: IsMinimumAppVersionSatisfied(minVer, appVer)
  alt minVer null/empty
    PM-->>PM: return true
  else minVer provided
    PM->>PM: try parse minVer
    alt parse fails
      PM->>Logger: Log exception with plugin info
      PM-->>PM: return false
    else parse succeeds
      alt appVer >= minVer
        PM-->>PM: return true
      else appVer < minVer
        PM->>Logger: Log info about required minimum
        PM-->>PM: return false
      end
    end
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested reviewers

  • taooceros
  • Garulf
  • Jack251970
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch update_manifest_url_fetch

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs (1)

76-90: Harden MinimumAppVersion parsing against whitespace and reduce noisy failures.

Trim and treat whitespace-only values as “unset” to avoid excluding valid plugins due to formatting. Keeps the new behavior while reducing exception spam.

Apply this diff:

-            if (string.IsNullOrEmpty(plugin.MinimumAppVersion))
+            if (string.IsNullOrWhiteSpace(plugin.MinimumAppVersion))
                 return true;

             try
             {
-                if (appVersion >= SemanticVersioning.Version.Parse(plugin.MinimumAppVersion))
+                var minimum = plugin.MinimumAppVersion.Trim();
+                if (appVersion >= SemanticVersioning.Version.Parse(minimum))
                     return true;
             }
             catch (Exception e)
             {
-                API.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
+                API.LogException(ClassName, $"Failed to parse the minimum app version '{plugin.MinimumAppVersion}' for plugin {plugin.Name}. "
                     + "Plugin excluded from manifest", e);
                 return false;
             }

Additionally (outside the changed hunk), consider trimming the app version when parsing to be defensive:

// line ~47
var appVersion = SemanticVersioning.Version.Parse(Constant.Version.Trim());
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7208b72 and 80b0b60.

📒 Files selected for processing (1)
  • Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher/App.xaml.cs:246-262
Timestamp: 2025-07-21T09:19:49.684Z
Learning: In Flow Launcher's App.xaml.cs, the asynchronous plugin initialization task (containing AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, and AutoPluginUpdates) does not require additional try-catch error handling according to maintainer Jack251970, as these operations are designed to handle exceptions internally.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher.Core/Plugin/PluginManager.cs:280-292
Timestamp: 2025-07-21T09:19:19.012Z
Learning: In Flow Launcher's PluginManager.cs, the post-initialization operations (RegisterResultsUpdatedEvent, UpdatePluginMetadataTranslation, RegisterPluginActionKeywords, DialogJump.InitializeDialogJumpPlugin, and AddPluginToLists) are designed to be exception-safe and do not require additional try-catch error handling according to the maintainer Jack251970.
Learnt from: taooceros
PR: Flow-Launcher/Flow.Launcher#2616
File: Flow.Launcher/Flow.Launcher.csproj:7-7
Timestamp: 2024-10-08T15:52:58.573Z
Learning: In the Flow Launcher project, the version number in the `Flow.Launcher.csproj` file is dynamically updated during the CI/CD process.
📚 Learning: 2025-07-06T12:21:37.947Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.

Applied to files:

  • Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
📚 Learning: 2025-07-01T05:46:13.251Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.

Applied to files:

  • Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
📚 Learning: 2025-07-21T09:19:49.684Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher/App.xaml.cs:246-262
Timestamp: 2025-07-21T09:19:49.684Z
Learning: In Flow Launcher's App.xaml.cs, the asynchronous plugin initialization task (containing AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, and AutoPluginUpdates) does not require additional try-catch error handling according to maintainer Jack251970, as these operations are designed to handle exceptions internally.

Applied to files:

  • Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
🧬 Code graph analysis (1)
Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs (2)
Plugins/Flow.Launcher.Plugin.WindowsSettings/Log.cs (1)
  • Exception (15-18)
Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs (1)
  • LogException (489-492)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: gitStream.cm
  • GitHub Check: build
🔇 Additional comments (1)
Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs (1)

57-58: Good fix: update lastFetchedAt only after successful processing.

This aligns with the PR goal and prevents stale-success timestamps when fetch returns empty or processing fails.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs (1)

34-36: Bug: unconditional Release() can over-increment semaphore on canceled wait.

If WaitAsync throws (e.g., OperationCanceledException), finally still calls Release(), causing SemaphoreFullException and breaking future updates.

Minimal fix:

-            try
+            var entered = false;
+            try
             {
-                await manifestUpdateLock.WaitAsync(token).ConfigureAwait(false);
+                await manifestUpdateLock.WaitAsync(token).ConfigureAwait(false);
+                entered = true;
                 ...
             }
             finally
             {
-                manifestUpdateLock.Release();
+                if (entered)
+                    manifestUpdateLock.Release();
             }

Optionally handle OperationCanceledException separately to log at Debug/Info and return false gracefully.

Also applies to: 66-69

♻️ Duplicate comments (1)
Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs (1)

84-89: Catching generic Exception here is acceptable per prior discussion.

Previous suggestion to narrow to specific exceptions was declined; the current approach is consistent with that decision.

🧹 Nitpick comments (2)
Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs (2)

38-38: Use UTC clock to avoid DST/clock-skew issues.

Comparisons based on local time can behave oddly across DST jumps and manual clock changes. Prefer UtcNow for both the check and assignment.

Apply:

- if (UserPlugins == null || usePrimaryUrlOnly || DateTime.Now.Subtract(lastFetchedAt) >= fetchTimeout)
+ if (UserPlugins == null || usePrimaryUrlOnly || DateTime.UtcNow - lastFetchedAt >= fetchTimeout)
- lastFetchedAt = DateTime.Now;
+ lastFetchedAt = DateTime.UtcNow;

Also applies to: 57-57


76-77: Treat whitespace-only MinimumAppVersion as empty.

Using IsNullOrWhiteSpace avoids needless parse attempts on " " values.

-            if (string.IsNullOrEmpty(plugin.MinimumAppVersion))
+            if (string.IsNullOrWhiteSpace(plugin.MinimumAppVersion))
                 return true;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 80b0b60 and 5d297c1.

📒 Files selected for processing (1)
  • Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs (2 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: jjw24
PR: Flow-Launcher/Flow.Launcher#3932
File: Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs:48-55
Timestamp: 2025-09-04T11:52:29.074Z
Learning: In Flow Launcher's PluginsManifest.cs, when dealing with version parsing for the MinimumAppVersion feature, maintainer jjw24 prefers to keep the solution simple rather than implementing comprehensive helper methods for SemVer parsing normalization.
📚 Learning: 2025-07-06T12:21:37.947Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.947Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.

Applied to files:

  • Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
📚 Learning: 2025-09-04T11:52:29.074Z
Learnt from: jjw24
PR: Flow-Launcher/Flow.Launcher#3932
File: Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs:48-55
Timestamp: 2025-09-04T11:52:29.074Z
Learning: In Flow Launcher's PluginsManifest.cs, when dealing with version parsing for the MinimumAppVersion feature, maintainer jjw24 prefers to keep the solution simple rather than implementing comprehensive helper methods for SemVer parsing normalization.

Applied to files:

  • Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
📚 Learning: 2025-07-01T05:46:13.251Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.

Applied to files:

  • Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
📚 Learning: 2025-07-21T09:19:49.684Z
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3854
File: Flow.Launcher/App.xaml.cs:246-262
Timestamp: 2025-07-21T09:19:49.684Z
Learning: In Flow Launcher's App.xaml.cs, the asynchronous plugin initialization task (containing AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate, PluginManager.LoadPlugins, PluginManager.InitializePluginsAsync, and AutoPluginUpdates) does not require additional try-catch error handling according to maintainer Jack251970, as these operations are designed to handle exceptions internally.

Applied to files:

  • Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: gitStream.cm
  • GitHub Check: build
🔇 Additional comments (3)
Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs (3)

57-58: Good move: update lastFetchedAt only after successful assignment.

This prevents false positives on fetch freshness if processing fails mid-way.


79-83: Simple, clear version check aligns with maintainer guidance.

Try/catch around a direct parse+compare keeps the flow straightforward per earlier preference to avoid heavy SemVer normalization helpers.


91-92: Confirm desired log level to avoid noisy manifests.

Info-level logs for every excluded plugin could spam logs if many plugins require higher versions. Consider Debug level or a single summary (e.g., count + first N plugin names).

@jjw24 jjw24 merged commit 738a27e into dev Sep 4, 2025
12 checks passed
@jjw24 jjw24 deleted the update_manifest_url_fetch branch September 4, 2025 13:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Dev branch only An issue or fix for the Dev branch build
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants