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;
|
package run.halo.app.core.extension;
|
||||||
|
|
||||||
|
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
@ -29,7 +31,7 @@ import run.halo.app.extension.GVK;
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class Plugin extends AbstractExtension {
|
public class Plugin extends AbstractExtension {
|
||||||
|
|
||||||
@Schema(required = true)
|
@Schema(requiredMode = REQUIRED)
|
||||||
private PluginSpec spec;
|
private PluginSpec spec;
|
||||||
|
|
||||||
private PluginStatus status;
|
private PluginStatus status;
|
||||||
|
@ -54,6 +56,8 @@ public class Plugin extends AbstractExtension {
|
||||||
private String displayName;
|
private String displayName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* plugin version.
|
||||||
|
*
|
||||||
* @see <a href="semver.org">semantic version</a>
|
* @see <a href="semver.org">semantic version</a>
|
||||||
*/
|
*/
|
||||||
@Schema(required = true, pattern = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-("
|
@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-]+)*))?$")
|
+ ".[0-9a-zA-Z-]+)*))?$")
|
||||||
private String version;
|
private String version;
|
||||||
|
|
||||||
private String author;
|
private PluginAuthor author;
|
||||||
|
|
||||||
private String logo;
|
private String logo;
|
||||||
|
|
||||||
|
@ -116,6 +120,16 @@ public class Plugin extends AbstractExtension {
|
||||||
private String logo;
|
private String logo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ToString
|
||||||
|
public static class PluginAuthor {
|
||||||
|
|
||||||
|
@Schema(requiredMode = REQUIRED, minLength = 1)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String website;
|
||||||
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public String generateFileName() {
|
public String generateFileName() {
|
||||||
return String.format("%s-%s.jar", getMetadata().getName(), spec.getVersion());
|
return String.format("%s-%s.jar", getMetadata().getName(), spec.getVersion());
|
||||||
|
|
|
@ -46,6 +46,8 @@ public class YamlPluginDescriptorFinder implements PluginDescriptorFinder {
|
||||||
private DefaultPluginDescriptor convert(Plugin plugin) {
|
private DefaultPluginDescriptor convert(Plugin plugin) {
|
||||||
String pluginId = plugin.getMetadata().getName();
|
String pluginId = plugin.getMetadata().getName();
|
||||||
Plugin.PluginSpec spec = plugin.getSpec();
|
Plugin.PluginSpec spec = plugin.getSpec();
|
||||||
|
Plugin.PluginAuthor author = spec.getAuthor();
|
||||||
|
String provider = (author == null ? StringUtils.EMPTY : author.getName());
|
||||||
|
|
||||||
DefaultPluginDescriptor defaultPluginDescriptor =
|
DefaultPluginDescriptor defaultPluginDescriptor =
|
||||||
new DefaultPluginDescriptor(pluginId,
|
new DefaultPluginDescriptor(pluginId,
|
||||||
|
@ -53,7 +55,7 @@ public class YamlPluginDescriptorFinder implements PluginDescriptorFinder {
|
||||||
BasePlugin.class.getName(),
|
BasePlugin.class.getName(),
|
||||||
spec.getVersion(),
|
spec.getVersion(),
|
||||||
spec.getRequires(),
|
spec.getRequires(),
|
||||||
spec.getAuthor(),
|
provider,
|
||||||
joinLicense(spec.getLicense()));
|
joinLicense(spec.getLicense()));
|
||||||
// add dependencies
|
// add dependencies
|
||||||
spec.getPluginDependencies().forEach((pluginDepName, versionRequire) -> {
|
spec.getPluginDependencies().forEach((pluginDepName, versionRequire) -> {
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
package run.halo.app.plugin;
|
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.assertThat;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.util.FileSystemUtils;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
|
import run.halo.app.infra.utils.FileUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link PluginStartedListener}.
|
* Tests for {@link PluginStartedListener}.
|
||||||
|
@ -39,14 +41,22 @@ class PluginStartedListenerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void lookupFromJar() throws FileNotFoundException {
|
void lookupFromJar() throws IOException {
|
||||||
File file =
|
Path tempDirectory = Files.createTempDirectory("halo-plugin");
|
||||||
ResourceUtils.getFile("classpath:plugin/test-unstructured-resource-loader.jar");
|
try {
|
||||||
Set<String> unstructuredFilePathFromJar =
|
var plugin001Uri = requireNonNull(
|
||||||
PluginStartedListener.PluginExtensionLoaderUtils.lookupFromJar(file.toPath());
|
ResourceUtils.getFile("classpath:plugin/plugin-0.0.1")).toURI();
|
||||||
assertThat(unstructuredFilePathFromJar).hasSize(3);
|
|
||||||
assertThat(unstructuredFilePathFromJar).containsAll(Set.of("extensions/roles.yaml",
|
Path targetJarPath = tempDirectory.resolve("plugin-0.0.1.jar");
|
||||||
"extensions/reverseProxy.yaml", "extensions/test.yml"));
|
FileUtils.jar(Paths.get(plugin001Uri), targetJarPath);
|
||||||
|
Set<String> unstructuredFilePathFromJar =
|
||||||
|
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;
|
package run.halo.app.plugin;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.pf4j.PluginDescriptor;
|
import org.pf4j.PluginDescriptor;
|
||||||
import org.skyscreamer.jsonassert.JSONAssert;
|
import org.skyscreamer.jsonassert.JSONAssert;
|
||||||
|
import org.springframework.util.FileSystemUtils;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
|
import run.halo.app.infra.utils.FileUtils;
|
||||||
import run.halo.app.infra.utils.JsonUtils;
|
import run.halo.app.infra.utils.JsonUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,11 +30,23 @@ class YamlPluginDescriptorFinderTest {
|
||||||
private YamlPluginDescriptorFinder yamlPluginDescriptorFinder;
|
private YamlPluginDescriptorFinder yamlPluginDescriptorFinder;
|
||||||
|
|
||||||
private File testFile;
|
private File testFile;
|
||||||
|
private Path tempDirectory;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() throws FileNotFoundException {
|
void setUp() throws IOException {
|
||||||
yamlPluginDescriptorFinder = new YamlPluginDescriptorFinder();
|
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
|
@Test
|
||||||
|
@ -64,14 +80,14 @@ class YamlPluginDescriptorFinderTest {
|
||||||
String actual = JsonUtils.objectToJson(pluginDescriptor);
|
String actual = JsonUtils.objectToJson(pluginDescriptor);
|
||||||
JSONAssert.assertEquals("""
|
JSONAssert.assertEquals("""
|
||||||
{
|
{
|
||||||
"pluginId": "io.github.guqing.apples",
|
"pluginId": "fake-plugin",
|
||||||
"pluginDescription": "这是一个用来测试的插件",
|
"pluginDescription": "Fake description",
|
||||||
"pluginClass": "run.halo.app.plugin.BasePlugin",
|
"pluginClass": "run.halo.app.plugin.BasePlugin",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"requires": "*",
|
"requires": ">=2.0.0",
|
||||||
"provider": "guqing",
|
"provider": "johnniang",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"license": "MIT"
|
"license": "GPLv3"
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
actual,
|
actual,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package run.halo.app.plugin;
|
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.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
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.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
@ -19,9 +21,11 @@ import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.security.util.InMemoryResource;
|
import org.springframework.security.util.InMemoryResource;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
import org.springframework.util.FileSystemUtils;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
import run.halo.app.core.extension.Plugin;
|
import run.halo.app.core.extension.Plugin;
|
||||||
import run.halo.app.extension.Unstructured;
|
import run.halo.app.extension.Unstructured;
|
||||||
|
import run.halo.app.infra.utils.FileUtils;
|
||||||
import run.halo.app.infra.utils.JsonUtils;
|
import run.halo.app.infra.utils.JsonUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,12 +64,20 @@ class YamlPluginFinderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void findFromJar() throws FileNotFoundException {
|
void findFromJar() throws IOException, URISyntaxException {
|
||||||
File file =
|
Path tempDirectory = Files.createTempDirectory("halo-plugin");
|
||||||
ResourceUtils.getFile("classpath:plugin/test-unstructured-resource-loader.jar");
|
try {
|
||||||
Plugin plugin = pluginFinder.find(file.toPath());
|
var plugin002Uri = requireNonNull(
|
||||||
assertThat(plugin).isNotNull();
|
getClass().getClassLoader().getResource("plugin/plugin-0.0.2")).toURI();
|
||||||
assertThat(plugin.getMetadata().getName()).isEqualTo("io.github.guqing.apples");
|
|
||||||
|
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("fake-plugin");
|
||||||
|
} finally {
|
||||||
|
FileSystemUtils.deleteRecursively(tempDirectory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -77,7 +89,9 @@ class YamlPluginFinderTest {
|
||||||
"spec": {
|
"spec": {
|
||||||
"displayName": "a name to show",
|
"displayName": "a name to show",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"author": "guqing",
|
"author": {
|
||||||
|
"name": "guqing"
|
||||||
|
},
|
||||||
"logo": "https://guqing.xyz/avatar",
|
"logo": "https://guqing.xyz/avatar",
|
||||||
"pluginDependencies": {
|
"pluginDependencies": {
|
||||||
"banana": "0.0.1"
|
"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' is a valid semantic version string (see semver.org).
|
||||||
version: 0.0.2
|
version: 0.0.2
|
||||||
requires: ">=2.0.0"
|
requires: ">=2.0.0"
|
||||||
author: johnniang
|
author:
|
||||||
|
name: johnniang
|
||||||
logo: https://halo.run/avatar
|
logo: https://halo.run/avatar
|
||||||
homepage: https://github.com/halo-sigs/halo-plugin-1
|
homepage: https://github.com/halo-sigs/halo-plugin-1
|
||||||
displayName: "Fake Display Name"
|
displayName: "Fake Display Name"
|
||||||
|
|
|
@ -6,7 +6,8 @@ spec:
|
||||||
# 'version' is a valid semantic version string (see semver.org).
|
# 'version' is a valid semantic version string (see semver.org).
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
requires: ">=2.0.0"
|
requires: ">=2.0.0"
|
||||||
author: guqing
|
author:
|
||||||
|
name: guqing
|
||||||
logo: https://guqing.xyz/avatar
|
logo: https://guqing.xyz/avatar
|
||||||
pluginDependencies:
|
pluginDependencies:
|
||||||
"banana": "0.0.1"
|
"banana": "0.0.1"
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue