feat: enhance PluginFinder to support check plugin availability by version (#6236)

#### What type of PR is this?
/kind feature
/area core
/area theme
/milestone 2.17.x

#### What this PR does / why we need it:
支持在主题中检查已启动的插件是否符合指定的版本要求,以便可以在某些功能可以正常工作时才渲染

示例
```html
<p th:if="${pluginFinder.available('plugin-search-widget', '>=2.3.0')}>
<!-- do something -->
</p>
```

#### Does this PR introduce a user-facing change?
```release-note
支持在主题中检查已启动的插件是否符合指定的版本要求
```
pull/6279/head
guqing 2024-07-01 17:45:17 +08:00 committed by GitHub
parent bbc6f23b2d
commit 1f4bf8ea47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 57 additions and 3 deletions

View File

@ -9,4 +9,6 @@ package run.halo.app.theme.finders;
public interface PluginFinder {
boolean available(String pluginName);
boolean available(String pluginName, String requiresVersion);
}

View File

@ -2,9 +2,10 @@ package run.halo.app.theme.finders.impl;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.pf4j.PluginManager;
import org.pf4j.PluginState;
import org.pf4j.PluginWrapper;
import run.halo.app.plugin.HaloPluginManager;
import org.springframework.util.Assert;
import run.halo.app.theme.finders.Finder;
import run.halo.app.theme.finders.PluginFinder;
@ -17,17 +18,29 @@ import run.halo.app.theme.finders.PluginFinder;
@Finder("pluginFinder")
@AllArgsConstructor
public class PluginFinderImpl implements PluginFinder {
private final HaloPluginManager haloPluginManager;
private final PluginManager pluginManager;
@Override
public boolean available(String pluginName) {
if (StringUtils.isBlank(pluginName)) {
return false;
}
PluginWrapper pluginWrapper = haloPluginManager.getPlugin(pluginName);
PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginName);
if (pluginWrapper == null) {
return false;
}
return PluginState.STARTED.equals(pluginWrapper.getPluginState());
}
@Override
public boolean available(String pluginName, String requiresVersion) {
Assert.notNull(requiresVersion, "Requires version must not be null.");
if (!this.available(pluginName)) {
return false;
}
var pluginWrapper = pluginManager.getPlugin(pluginName);
var pluginVersion = pluginWrapper.getDescriptor().getVersion();
return pluginManager.getVersionManager()
.checkVersionConstraint(pluginVersion, requiresVersion);
}
}

View File

@ -1,7 +1,9 @@
package run.halo.app.theme.finders.impl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
@ -10,6 +12,8 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.pf4j.DefaultVersionManager;
import org.pf4j.PluginDescriptor;
import org.pf4j.PluginState;
import org.pf4j.PluginWrapper;
import run.halo.app.plugin.HaloPluginManager;
@ -47,4 +51,39 @@ class PluginFinderImplTest {
available = pluginFinder.available("fake-plugin");
assertThat(available).isTrue();
}
@Test
void availableWithVersionTest() {
when(haloPluginManager.getVersionManager()).thenReturn(new DefaultVersionManager());
assertThatThrownBy(() -> pluginFinder.available("fake-plugin", null))
.isInstanceOf(IllegalArgumentException.class);
boolean available = pluginFinder.available("fake-plugin", "1.0.0");
assertThat(available).isFalse();
PluginWrapper mockPluginWrapper = Mockito.mock(PluginWrapper.class);
when(haloPluginManager.getPlugin(eq("fake-plugin")))
.thenReturn(mockPluginWrapper);
when(mockPluginWrapper.getPluginState()).thenReturn(PluginState.STARTED);
var descriptor = mock(PluginDescriptor.class);
when(mockPluginWrapper.getDescriptor()).thenReturn(descriptor);
when(descriptor.getVersion()).thenReturn("1.0.0");
available = pluginFinder.available("fake-plugin", "1.0.0");
assertThat(available).isTrue();
available = pluginFinder.available("fake-plugin", ">=1.0.0");
assertThat(available).isTrue();
available = pluginFinder.available("fake-plugin", "<2.0.0");
assertThat(available).isTrue();
available = pluginFinder.available("fake-plugin", "2.0.0");
assertThat(available).isFalse();
available = pluginFinder.available("fake-plugin", "<1.0.0");
assertThat(available).isFalse();
}
}