mirror of https://github.com/halo-dev/halo
feat: plugin supports multiple ways of specifying licenses (#2152)
* feat: plugin supports multiple ways of specifying licenses * feat: add unit test case for deserialize licensepull/2158/head^2
parent
83d668b0a9
commit
fcbf0031a4
|
@ -1,10 +1,14 @@
|
|||
package run.halo.app.plugin;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import run.halo.app.extension.AbstractExtension;
|
||||
import run.halo.app.extension.GVK;
|
||||
|
@ -42,7 +46,8 @@ public class Plugin extends AbstractExtension {
|
|||
|
||||
private String description;
|
||||
|
||||
private String license;
|
||||
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||
private List<License> license;
|
||||
|
||||
/**
|
||||
* SemVer format.
|
||||
|
@ -51,4 +56,19 @@ public class Plugin extends AbstractExtension {
|
|||
|
||||
private String pluginClass = BasePlugin.class.getName();
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class License {
|
||||
private String name;
|
||||
private String url;
|
||||
|
||||
public License() {
|
||||
}
|
||||
|
||||
public License(String name) {
|
||||
this.name = name;
|
||||
this.url = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,16 @@ package run.halo.app.plugin;
|
|||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.pf4j.DefaultPluginDescriptor;
|
||||
import org.pf4j.PluginDependency;
|
||||
import org.pf4j.PluginDescriptor;
|
||||
import org.pf4j.PluginDescriptorFinder;
|
||||
import org.pf4j.util.FileUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Find a plugin descriptor for a plugin path.
|
||||
|
@ -41,6 +45,7 @@ public class YamlPluginDescriptorFinder implements PluginDescriptorFinder {
|
|||
private DefaultPluginDescriptor convert(Plugin plugin) {
|
||||
String pluginId = plugin.getMetadata().getName();
|
||||
Plugin.PluginSpec spec = plugin.getSpec();
|
||||
|
||||
DefaultPluginDescriptor defaultPluginDescriptor =
|
||||
new DefaultPluginDescriptor(pluginId,
|
||||
spec.getDescription(),
|
||||
|
@ -48,7 +53,7 @@ public class YamlPluginDescriptorFinder implements PluginDescriptorFinder {
|
|||
spec.getVersion(),
|
||||
spec.getRequires(),
|
||||
spec.getAuthor(),
|
||||
spec.getLicense());
|
||||
joinLicense(spec.getLicense()));
|
||||
// add dependencies
|
||||
spec.getPluginDependencies().forEach((pluginDepName, versionRequire) -> {
|
||||
PluginDependency dependency =
|
||||
|
@ -57,4 +62,13 @@ public class YamlPluginDescriptorFinder implements PluginDescriptorFinder {
|
|||
});
|
||||
return defaultPluginDescriptor;
|
||||
}
|
||||
|
||||
private String joinLicense(List<Plugin.License> licenses) {
|
||||
if (CollectionUtils.isEmpty(licenses)) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return licenses.stream()
|
||||
.map(Plugin.License::getName)
|
||||
.collect(Collectors.joining(","));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.pf4j.PluginRuntimeException;
|
||||
import org.pf4j.util.FileUtils;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import run.halo.app.extension.Unstructured;
|
||||
import run.halo.app.infra.utils.YamlUnstructuredLoader;
|
||||
|
||||
|
@ -70,8 +71,13 @@ public class YamlPluginFinder {
|
|||
if (Files.notExists(propertiesPath)) {
|
||||
throw new PluginRuntimeException("Cannot find '{}' path", propertiesPath);
|
||||
}
|
||||
Resource propertyResource = new FileSystemResource(propertiesPath);
|
||||
return unstructuredToPlugin(propertyResource);
|
||||
}
|
||||
|
||||
protected Plugin unstructuredToPlugin(Resource propertyResource) {
|
||||
YamlUnstructuredLoader yamlUnstructuredLoader =
|
||||
new YamlUnstructuredLoader(new FileSystemResource(propertiesPath));
|
||||
new YamlUnstructuredLoader(propertyResource);
|
||||
List<Unstructured> unstructuredList = yamlUnstructuredLoader.load();
|
||||
if (unstructuredList.size() != 1) {
|
||||
throw new PluginRuntimeException("Unable to find plugin descriptor file '{}'",
|
||||
|
|
|
@ -13,7 +13,10 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.pf4j.PluginRuntimeException;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.security.util.InMemoryResource;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import run.halo.app.extension.Unstructured;
|
||||
import run.halo.app.infra.utils.JsonUtils;
|
||||
|
||||
/**
|
||||
|
@ -38,33 +41,36 @@ class YamlPluginFinderTest {
|
|||
Plugin plugin = pluginFinder.find(testPath);
|
||||
assertThat(plugin).isNotNull();
|
||||
JSONAssert.assertEquals("""
|
||||
{
|
||||
"spec": {
|
||||
"displayName": "a name to show",
|
||||
"version": "0.0.1",
|
||||
"author": "guqing",
|
||||
"logo": "https://guqing.xyz/avatar",
|
||||
"pluginDependencies": {
|
||||
"banana": "0.0.1"
|
||||
{
|
||||
"spec": {
|
||||
"displayName": "a name to show",
|
||||
"version": "0.0.1",
|
||||
"author": "guqing",
|
||||
"logo": "https://guqing.xyz/avatar",
|
||||
"pluginDependencies": {
|
||||
"banana": "0.0.1"
|
||||
},
|
||||
"homepage": "https://github.com/guqing/halo-plugin-1",
|
||||
"description": "Tell me more about this plugin.",
|
||||
"license": [{
|
||||
"name": "MIT",
|
||||
"url": ""
|
||||
}],
|
||||
"requires": ">=2.0.0",
|
||||
"pluginClass": "run.halo.app.plugin.BasePlugin"
|
||||
},
|
||||
"homepage": "https://github.com/guqing/halo-plugin-1",
|
||||
"description": "Tell me more about this plugin.",
|
||||
"license": "MIT",
|
||||
"requires": ">=2.0.0",
|
||||
"pluginClass": "run.halo.app.plugin.BasePlugin"
|
||||
},
|
||||
"apiVersion": "v1",
|
||||
"kind": "Plugin",
|
||||
"metadata": {
|
||||
"name": "plugin-1",
|
||||
"labels": null,
|
||||
"annotations": null,
|
||||
"version": null,
|
||||
"creationTimestamp": null,
|
||||
"deletionTimestamp": null
|
||||
"apiVersion": "v1",
|
||||
"kind": "Plugin",
|
||||
"metadata": {
|
||||
"name": "plugin-1",
|
||||
"labels": null,
|
||||
"annotations": null,
|
||||
"version": null,
|
||||
"creationTimestamp": null,
|
||||
"deletionTimestamp": null
|
||||
}
|
||||
}
|
||||
}
|
||||
""",
|
||||
""",
|
||||
JsonUtils.objectToJson(plugin),
|
||||
false);
|
||||
}
|
||||
|
@ -77,4 +83,94 @@ class YamlPluginFinderTest {
|
|||
}).isInstanceOf(PluginRuntimeException.class)
|
||||
.hasMessage("Cannot find '/tmp/plugin.yaml' path");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptArrayLicense() throws JSONException, JsonProcessingException {
|
||||
Resource pluginResource = new InMemoryResource("""
|
||||
apiVersion: v1
|
||||
kind: Plugin
|
||||
metadata:
|
||||
name: plugin-1
|
||||
spec:
|
||||
license: "MIT"
|
||||
""");
|
||||
Plugin plugin = pluginFinder.unstructuredToPlugin(pluginResource);
|
||||
assertThat(plugin.getSpec()).isNotNull();
|
||||
JSONAssert.assertEquals("""
|
||||
[{
|
||||
"name": "MIT",
|
||||
"url": ""
|
||||
}]
|
||||
""", JsonUtils.objectToJson(plugin.getSpec().getLicense()), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptMultipleItemArrayLicense() throws JsonProcessingException, JSONException {
|
||||
Resource pluginResource = new InMemoryResource("""
|
||||
apiVersion: v1
|
||||
kind: Plugin
|
||||
metadata:
|
||||
name: plugin-1
|
||||
spec:
|
||||
license: ["MIT", "Apache-2.0"]
|
||||
""");
|
||||
Plugin plugin = pluginFinder.unstructuredToPlugin(pluginResource);
|
||||
assertThat(plugin.getSpec()).isNotNull();
|
||||
JSONAssert.assertEquals("""
|
||||
[{
|
||||
"name": "MIT",
|
||||
"url": ""
|
||||
},
|
||||
{
|
||||
"name": "Apache-2.0",
|
||||
"url": ""
|
||||
}]
|
||||
""", JsonUtils.objectToJson(plugin.getSpec().getLicense()), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptArrayObjectLicense() throws JSONException, JsonProcessingException {
|
||||
Resource pluginResource = new InMemoryResource("""
|
||||
apiVersion: v1
|
||||
kind: Plugin
|
||||
metadata:
|
||||
name: plugin-1
|
||||
spec:
|
||||
license:
|
||||
- name: MIT
|
||||
url: https://exmple.com
|
||||
""");
|
||||
Plugin plugin = pluginFinder.unstructuredToPlugin(pluginResource);
|
||||
assertThat(plugin.getSpec()).isNotNull();
|
||||
JSONAssert.assertEquals("""
|
||||
[{
|
||||
"name": "MIT",
|
||||
"url": "https://exmple.com"
|
||||
}]
|
||||
""", JsonUtils.objectToJson(plugin.getSpec().getLicense()), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deserializeLicense() throws JSONException, JsonProcessingException {
|
||||
String pluginJson = """
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Plugin",
|
||||
"metadata": {
|
||||
"name": "plugin-1"
|
||||
},
|
||||
"spec": {
|
||||
"license": [
|
||||
{
|
||||
"name": "MIT",
|
||||
"url": "https://exmple.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
""";
|
||||
Plugin plugin = Unstructured.OBJECT_MAPPER.readValue(pluginJson, Plugin.class);
|
||||
assertThat(plugin.getSpec()).isNotNull();
|
||||
JSONAssert.assertEquals(pluginJson, JsonUtils.objectToJson(plugin), false);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue