mirror of https://github.com/halo-dev/halo
refactor: plugin author to an object (#2806)
#### What type of PR is this?
/kind improvement
/area core
/kind api-change
#### What this PR does / why we need it:
将 Plugin 的 author 改为 Author 对象与主题保持一致。
移除了测试类中使用的 jar 文件,改为使用时压缩
⚠️ 此为破坏性更新,需要修改 Console 插件列表的展示,以及所有官方插件的 plugin.yaml
#### Special notes for your reviewer:
/cc @halo-dev/sig-halo
#### Does this PR introduce a user-facing change?
```release-note
Require-user-change:将 Plugin 的 author 类型从 String 为 Author
```
pull/2807/head
parent
9f3c7ae378
commit
68ccbb098b
|
@ -1,5 +1,7 @@
|
|||
package run.halo.app.core.extension;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.Instant;
|
||||
|
@ -29,7 +31,7 @@ import run.halo.app.extension.GVK;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
public class Plugin extends AbstractExtension {
|
||||
|
||||
@Schema(required = true)
|
||||
@Schema(requiredMode = REQUIRED)
|
||||
private PluginSpec spec;
|
||||
|
||||
private PluginStatus status;
|
||||
|
@ -54,6 +56,8 @@ public class Plugin extends AbstractExtension {
|
|||
private String displayName;
|
||||
|
||||
/**
|
||||
* plugin version.
|
||||
*
|
||||
* @see <a href="semver.org">semantic version</a>
|
||||
*/
|
||||
@Schema(required = true, pattern = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-("
|
||||
|
@ -62,7 +66,7 @@ public class Plugin extends AbstractExtension {
|
|||
+ ".[0-9a-zA-Z-]+)*))?$")
|
||||
private String version;
|
||||
|
||||
private String author;
|
||||
private PluginAuthor author;
|
||||
|
||||
private String logo;
|
||||
|
||||
|
@ -116,6 +120,16 @@ public class Plugin extends AbstractExtension {
|
|||
private String logo;
|
||||
}
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public static class PluginAuthor {
|
||||
|
||||
@Schema(requiredMode = REQUIRED, minLength = 1)
|
||||
private String name;
|
||||
|
||||
private String website;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public String generateFileName() {
|
||||
return String.format("%s-%s.jar", getMetadata().getName(), spec.getVersion());
|
||||
|
|
|
@ -46,6 +46,8 @@ public class YamlPluginDescriptorFinder implements PluginDescriptorFinder {
|
|||
private DefaultPluginDescriptor convert(Plugin plugin) {
|
||||
String pluginId = plugin.getMetadata().getName();
|
||||
Plugin.PluginSpec spec = plugin.getSpec();
|
||||
Plugin.PluginAuthor author = spec.getAuthor();
|
||||
String provider = (author == null ? StringUtils.EMPTY : author.getName());
|
||||
|
||||
DefaultPluginDescriptor defaultPluginDescriptor =
|
||||
new DefaultPluginDescriptor(pluginId,
|
||||
|
@ -53,7 +55,7 @@ public class YamlPluginDescriptorFinder implements PluginDescriptorFinder {
|
|||
BasePlugin.class.getName(),
|
||||
spec.getVersion(),
|
||||
spec.getRequires(),
|
||||
spec.getAuthor(),
|
||||
provider,
|
||||
joinLicense(spec.getLicense()));
|
||||
// add dependencies
|
||||
spec.getPluginDependencies().forEach((pluginDepName, versionRequire) -> {
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
package run.halo.app.plugin;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import run.halo.app.infra.utils.FileUtils;
|
||||
|
||||
/**
|
||||
* Tests for {@link PluginStartedListener}.
|
||||
|
@ -39,14 +41,22 @@ class PluginStartedListenerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void lookupFromJar() throws FileNotFoundException {
|
||||
File file =
|
||||
ResourceUtils.getFile("classpath:plugin/test-unstructured-resource-loader.jar");
|
||||
void lookupFromJar() throws IOException {
|
||||
Path tempDirectory = Files.createTempDirectory("halo-plugin");
|
||||
try {
|
||||
var plugin001Uri = requireNonNull(
|
||||
ResourceUtils.getFile("classpath:plugin/plugin-0.0.1")).toURI();
|
||||
|
||||
Path targetJarPath = tempDirectory.resolve("plugin-0.0.1.jar");
|
||||
FileUtils.jar(Paths.get(plugin001Uri), targetJarPath);
|
||||
Set<String> unstructuredFilePathFromJar =
|
||||
PluginStartedListener.PluginExtensionLoaderUtils.lookupFromJar(file.toPath());
|
||||
PluginStartedListener.PluginExtensionLoaderUtils.lookupFromJar(targetJarPath);
|
||||
assertThat(unstructuredFilePathFromJar).hasSize(3);
|
||||
assertThat(unstructuredFilePathFromJar).containsAll(Set.of("extensions/roles.yaml",
|
||||
"extensions/reverseProxy.yaml", "extensions/test.yml"));
|
||||
} finally {
|
||||
FileSystemUtils.deleteRecursively(tempDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,22 @@
|
|||
package run.halo.app.plugin;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pf4j.PluginDescriptor;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import run.halo.app.infra.utils.FileUtils;
|
||||
import run.halo.app.infra.utils.JsonUtils;
|
||||
|
||||
/**
|
||||
|
@ -26,11 +30,23 @@ class YamlPluginDescriptorFinderTest {
|
|||
private YamlPluginDescriptorFinder yamlPluginDescriptorFinder;
|
||||
|
||||
private File testFile;
|
||||
private Path tempDirectory;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws FileNotFoundException {
|
||||
void setUp() throws IOException {
|
||||
yamlPluginDescriptorFinder = new YamlPluginDescriptorFinder();
|
||||
testFile = ResourceUtils.getFile("classpath:plugin/test-unstructured-resource-loader.jar");
|
||||
tempDirectory = Files.createTempDirectory("halo-plugin");
|
||||
var plugin002Uri = requireNonNull(
|
||||
ResourceUtils.getFile("classpath:plugin/plugin-0.0.2")).toURI();
|
||||
|
||||
Path targetJarPath = tempDirectory.resolve("plugin-0.0.2.jar");
|
||||
FileUtils.jar(Paths.get(plugin002Uri), targetJarPath);
|
||||
testFile = targetJarPath.toFile();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws IOException {
|
||||
FileSystemUtils.deleteRecursively(tempDirectory);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -64,14 +80,14 @@ class YamlPluginDescriptorFinderTest {
|
|||
String actual = JsonUtils.objectToJson(pluginDescriptor);
|
||||
JSONAssert.assertEquals("""
|
||||
{
|
||||
"pluginId": "io.github.guqing.apples",
|
||||
"pluginDescription": "这是一个用来测试的插件",
|
||||
"pluginId": "fake-plugin",
|
||||
"pluginDescription": "Fake description",
|
||||
"pluginClass": "run.halo.app.plugin.BasePlugin",
|
||||
"version": "0.0.1",
|
||||
"requires": "*",
|
||||
"provider": "guqing",
|
||||
"version": "0.0.2",
|
||||
"requires": ">=2.0.0",
|
||||
"provider": "johnniang",
|
||||
"dependencies": [],
|
||||
"license": "MIT"
|
||||
"license": "GPLv3"
|
||||
}
|
||||
""",
|
||||
actual,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package run.halo.app.plugin;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
|
@ -7,6 +8,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
@ -19,9 +21,11 @@ import org.springframework.core.io.FileSystemResource;
|
|||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.security.util.InMemoryResource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import run.halo.app.core.extension.Plugin;
|
||||
import run.halo.app.extension.Unstructured;
|
||||
import run.halo.app.infra.utils.FileUtils;
|
||||
import run.halo.app.infra.utils.JsonUtils;
|
||||
|
||||
/**
|
||||
|
@ -60,12 +64,20 @@ class YamlPluginFinderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void findFromJar() throws FileNotFoundException {
|
||||
File file =
|
||||
ResourceUtils.getFile("classpath:plugin/test-unstructured-resource-loader.jar");
|
||||
Plugin plugin = pluginFinder.find(file.toPath());
|
||||
void findFromJar() throws IOException, URISyntaxException {
|
||||
Path tempDirectory = Files.createTempDirectory("halo-plugin");
|
||||
try {
|
||||
var plugin002Uri = requireNonNull(
|
||||
getClass().getClassLoader().getResource("plugin/plugin-0.0.2")).toURI();
|
||||
|
||||
Path targetJarPath = tempDirectory.resolve("plugin-0.0.2.jar");
|
||||
FileUtils.jar(Paths.get(plugin002Uri), targetJarPath);
|
||||
Plugin plugin = pluginFinder.find(targetJarPath);
|
||||
assertThat(plugin).isNotNull();
|
||||
assertThat(plugin.getMetadata().getName()).isEqualTo("io.github.guqing.apples");
|
||||
assertThat(plugin.getMetadata().getName()).isEqualTo("fake-plugin");
|
||||
} finally {
|
||||
FileSystemUtils.deleteRecursively(tempDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -77,7 +89,9 @@ class YamlPluginFinderTest {
|
|||
"spec": {
|
||||
"displayName": "a name to show",
|
||||
"version": "0.0.1",
|
||||
"author": "guqing",
|
||||
"author": {
|
||||
"name": "guqing"
|
||||
},
|
||||
"logo": "https://guqing.xyz/avatar",
|
||||
"pluginDependencies": {
|
||||
"banana": "0.0.1"
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ReverseProxy
|
||||
metadata:
|
||||
name: reverse-proxy-template
|
||||
labels:
|
||||
plugin.halo.run/pluginName: io.github.guqing.apples
|
||||
rules:
|
||||
- path: /static/**
|
||||
file:
|
||||
directory: static
|
||||
- path: /admin/**
|
||||
file:
|
||||
directory: admin
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1alpha1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: role-template-view-apples
|
||||
labels:
|
||||
halo.run/role-template: "true"
|
||||
annotations:
|
||||
halo.run/module: "Apples Management"
|
||||
halo.run/alias-name: "Apples View"
|
||||
rules:
|
||||
- apiGroups: [ "apples.guqing.github.com" ]
|
||||
resources: [ "apples" ]
|
||||
verbs: [ "get", "list" ]
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ReverseProxy
|
||||
metadata:
|
||||
name: reverse-proxy-template
|
||||
labels:
|
||||
plugin.halo.run/pluginName: io.github.guqing.apples
|
||||
rules:
|
||||
- path: /static/**
|
||||
file:
|
||||
directory: static
|
||||
- path: /admin/**
|
||||
file:
|
||||
directory: admin
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: v1
|
||||
kind: Plugin
|
||||
metadata:
|
||||
name: plugin-1
|
||||
spec:
|
||||
# 'version' is a valid semantic version string (see semver.org).
|
||||
version: 0.0.1
|
||||
requires: ">=2.0.0"
|
||||
author:
|
||||
name: guqing
|
||||
logo: https://guqing.xyz/avatar
|
||||
pluginDependencies:
|
||||
"banana": "0.0.1"
|
||||
homepage: https://github.com/guqing/halo-plugin-1
|
||||
displayName: "a name to show"
|
||||
description: "Tell me more about this plugin."
|
||||
license:
|
||||
- name: MIT
|
|
@ -6,7 +6,8 @@ spec:
|
|||
# 'version' is a valid semantic version string (see semver.org).
|
||||
version: 0.0.2
|
||||
requires: ">=2.0.0"
|
||||
author: johnniang
|
||||
author:
|
||||
name: johnniang
|
||||
logo: https://halo.run/avatar
|
||||
homepage: https://github.com/halo-sigs/halo-plugin-1
|
||||
displayName: "Fake Display Name"
|
||||
|
|
|
@ -6,7 +6,8 @@ spec:
|
|||
# 'version' is a valid semantic version string (see semver.org).
|
||||
version: 0.0.1
|
||||
requires: ">=2.0.0"
|
||||
author: guqing
|
||||
author:
|
||||
name: guqing
|
||||
logo: https://guqing.xyz/avatar
|
||||
pluginDependencies:
|
||||
"banana": "0.0.1"
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue