feat: able to use k8s helper image from custom registry (#1408)

This commit is contained in:
Robin Shen 2023-06-06 21:33:14 +08:00
parent 92aa5bcfce
commit 7c56912426
44 changed files with 213 additions and 95 deletions

View File

@ -9,7 +9,7 @@
<version>1.2.0</version>
</parent>
<artifactId>server</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
<packaging>pom</packaging>
<build>
<finalName>${project.groupId}.${project.artifactId}-${project.version}</finalName>
@ -615,7 +615,7 @@
</repositories>
<properties>
<commons.version>2.7.16</commons.version>
<agent.version>1.8.16</agent.version>
<agent.version>1.8.17</agent.version>
<slf4j.version>1.7.36</slf4j.version>
<logback.version>1.2.11</logback.version>
<antlr.version>4.7.2</antlr.version>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<build>
<plugins>

View File

@ -5433,5 +5433,28 @@ public class DataMigrator {
}
}
}
private void migrate126(File dataDir, Stack<Integer> versions) {
for (File file: dataDir.listFiles()) {
if (file.getName().startsWith("Settings.xml")) {
VersionedXmlDoc dom = VersionedXmlDoc.fromFile(file);
for (Element element: dom.getRootElement().elements()) {
String key = element.elementTextTrim("key");
if (key.equals("JOB_EXECUTORS")) {
Element valueElement = element.element("value");
if (valueElement != null) {
for (Element executorElement: valueElement.elements()) {
if (executorElement.getName().contains("KubernetesExecutor")
|| executorElement.getName().contains("DockerExecutor")) {
executorElement.addElement("imageMappings");
}
}
}
}
}
dom.writeToFile(file, false);
}
}
}
}

View File

@ -0,0 +1,40 @@
package io.onedev.server.model.support;
import io.onedev.agent.job.ImageMappingFacade;
import io.onedev.server.annotation.Editable;
import java.io.Serializable;
@Editable
public class ImageMapping implements Serializable {
private static final long serialVersionUID = 1L;
private String from;
private String to;
@Editable(order=100, description = "A Java regular expression matching image (registry/repo:tag)")
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
@Editable(order=200, description = "Target image to use. Note that group reference can be used to " +
"refer to part of original image based on defined from pattern")
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public ImageMappingFacade getFacade() {
return new ImageMappingFacade(from, to);
}
}

View File

@ -4,7 +4,7 @@ import java.io.Serializable;
import javax.validation.constraints.NotEmpty;
import io.onedev.k8shelper.RegistryLoginFacade;
import io.onedev.agent.job.RegistryLoginFacade;
import io.onedev.server.annotation.Editable;
import io.onedev.server.annotation.Password;

View File

@ -1,28 +1,27 @@
package io.onedev.server.git;
import java.io.File;
import java.io.IOException;
import javax.annotation.Nullable;
import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.RmCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
import org.junit.Assert;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.onedev.commons.loader.AppLoader;
import io.onedev.commons.loader.AppLoaderMocker;
import io.onedev.commons.utils.FileUtils;
import io.onedev.server.git.location.GitLocation;
import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.RmCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
import org.junit.Assert;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
public abstract class AbstractGitTest extends AppLoaderMocker {
@ -38,23 +37,24 @@ public abstract class AbstractGitTest extends AppLoaderMocker {
protected void setup() {
gitDir = FileUtils.createTempDir();
try {
git = Git.init().setInitialBranch("main").setBare(false).setDirectory(gitDir).call();
try (var ignored = Git.init().setInitialBranch("main").setBare(false).setDirectory(gitDir).call()) {
} catch (IllegalStateException | GitAPIException e) {
throw new RuntimeException(e);
}
var config = git.getRepository().getConfig();
config.setEnum(ConfigConstants.CONFIG_DIFF_SECTION, null,
ConfigConstants.CONFIG_KEY_ALGORITHM, SupportedAlgorithm.HISTOGRAM);
config.setBoolean(ConfigConstants.CONFIG_COMMIT_SECTION, null,
ConfigConstants.CONFIG_KEY_GPGSIGN, false);
try {
config.save();
git = Git.wrap(new FileRepository(new File(gitDir, ".git")) {
@Override
public FileBasedConfig getConfig() {
// avoid loading user config
return new FileBasedConfig(new File(getDirectory(), "config"), FS.DETECTED);
}
});
} catch (IOException e) {
throw new RuntimeException(e);
}
Mockito.when(AppLoader.getInstance(GitLocation.class)).thenReturn(new GitLocation() {
private static final long serialVersionUID = 1L;
@ -92,7 +92,7 @@ public abstract class AbstractGitTest extends AppLoaderMocker {
@Override
protected void teardown() {
git.close();
git.getRepository().close();
FileUtils.deleteDir(gitDir, 3);
}

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<build>
<resources>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.authenticator.ldap.LdapModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.buildspec.gradle.GradleModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.buildspec.maven.MavenModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.buildspec.node.NodePluginModule</moduleClass>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.executor.kubernetes.KubernetesModule</moduleClass>

View File

@ -7,8 +7,8 @@ import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.onedev.agent.DockerExecutorUtils;
import io.onedev.agent.job.FailedException;
import io.onedev.agent.job.ImageMappingFacade;
import io.onedev.commons.bootstrap.Bootstrap;
import io.onedev.commons.utils.*;
import io.onedev.commons.utils.command.Commandline;
@ -27,6 +27,7 @@ import io.onedev.server.entitymanager.SettingManager;
import io.onedev.server.job.JobContext;
import io.onedev.server.job.JobManager;
import io.onedev.server.job.JobRunnable;
import io.onedev.server.model.support.ImageMapping;
import io.onedev.server.model.support.RegistryLogin;
import io.onedev.server.model.support.administration.jobexecutor.JobExecutor;
import io.onedev.server.model.support.administration.jobexecutor.NodeSelectorEntry;
@ -36,7 +37,6 @@ import io.onedev.server.terminal.CommandlineShell;
import io.onedev.server.terminal.Shell;
import io.onedev.server.terminal.Terminal;
import io.onedev.server.web.util.Testable;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang3.RandomUtils;
@ -52,7 +52,6 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@ -60,14 +59,13 @@ import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import static io.onedev.agent.DockerExecutorUtils.*;
import static io.onedev.agent.DockerExecutorUtils.buildDockerConfig;
import static io.onedev.k8shelper.KubernetesHelper.*;
import static io.onedev.server.util.CollectionUtils.newHashMap;
import static io.onedev.server.util.CollectionUtils.newLinkedHashMap;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.*;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.codec.binary.Base64.encodeBase64String;
@Editable(order=KubernetesExecutor.ORDER, description="This executor runs build jobs as pods in a kubernetes cluster. "
@ -109,10 +107,14 @@ public class KubernetesExecutor extends JobExecutor implements Testable<TestData
private String memoryLimit;
private List<ImageMapping> imageMappings = new ArrayList<>();
private transient volatile OsInfo osInfo;
private transient volatile String containerName;
private transient List<ImageMappingFacade> imageMappingFacades;
@Editable(order=20, description="Optionally specify node selector of the job pods")
public List<NodeSelectorEntry> getNodeSelector() {
return nodeSelector;
@ -221,6 +223,19 @@ public class KubernetesExecutor extends JobExecutor implements Testable<TestData
this.kubeCtlPath = kubeCtlPath;
}
@Editable(order=28000, group="More Settings", description = "Optionally maps a docker image to a different " +
"image. The first matching entry will take effect, or image will remain unchanged if no matching entries " +
"found. For instance a mapping entry with <code>From</code> specified as <code>1dev/k8s-helper-linux:(.*)</code>, " +
"and <code>To</code> specified as <code>my-local-registry/k8s-helper-linux:$1</code> will map the " +
"k8s helper image from official docker registry to local registry, with repository and tag unchanged")
public List<ImageMapping> getImageMappings() {
return imageMappings;
}
public void setImageMappings(List<ImageMapping> imageMappings) {
this.imageMappings = imageMappings;
}
@Override
public void execute(JobContext jobContext, TaskLogger jobLogger) {
var clusterManager = OneDev.getInstance(ClusterManager.class);
@ -668,7 +683,7 @@ public class KubernetesExecutor extends JobExecutor implements Testable<TestData
Map<String, Object> podSpec = new LinkedHashMap<>();
Map<Object, Object> containerSpec = newLinkedHashMap(
"name", "default",
"image", jobService.getImage());
"image", mapImage(jobService.getImage()));
Map<Object, Object> resourcesSpec = newLinkedHashMap(
"requests", newLinkedHashMap(
"cpu", getCpuRequest(),
@ -960,7 +975,7 @@ public class KubernetesExecutor extends JobExecutor implements Testable<TestData
helperImageSuffix = "linux";
}
String helperImage = IMAGE_REPO_PREFIX + "-" + helperImageSuffix + ":" + KubernetesHelper.getVersion();
String helperImage = mapImage(IMAGE_REPO_PREFIX + "-" + helperImageSuffix + ":" + KubernetesHelper.getVersion());
List<Map<Object, Object>> commonEnvs = new ArrayList<>();
commonEnvs.add(newLinkedHashMap(
@ -992,7 +1007,7 @@ public class KubernetesExecutor extends JobExecutor implements Testable<TestData
stepContainerSpec = newHashMap(
"name", containerName,
"image", execution.getImage());
"image", mapImage(execution.getImage()));
if (commandFacade.isUseTTY())
stepContainerSpec.put("tty", true);
stepContainerSpec.put("volumeMounts", commonVolumeMounts);
@ -1005,7 +1020,7 @@ public class KubernetesExecutor extends JobExecutor implements Testable<TestData
OsContainer container = runContainerFacade.getContainer(osInfo);
stepContainerSpec = newHashMap(
"name", containerName,
"image", container.getImage());
"image", mapImage(container.getImage()));
if (runContainerFacade.isUseTTY())
stepContainerSpec.put("tty", true);
@ -1023,11 +1038,11 @@ public class KubernetesExecutor extends JobExecutor implements Testable<TestData
"mountPath", entry.getValue(),
"subPath", subPath));
}
// if (runContainerFacade.isKaniko()) {
if (runContainerFacade.isKaniko()) {
volumeMounts.add(newLinkedHashMap(
"name", "docker-config",
"mountPath", "/kaniko/.docker"));
// }
}
stepContainerSpec.put("volumeMounts", volumeMounts);
List<Map<Object, Object>> envs = new ArrayList<>(commonEnvs);
@ -1543,6 +1558,16 @@ public class KubernetesExecutor extends JobExecutor implements Testable<TestData
}
}
private List<ImageMappingFacade> getImageMappingFacades() {
if (imageMappingFacades == null)
imageMappingFacades = getImageMappings().stream().map(it->it.getFacade()).collect(toList());
return imageMappingFacades;
}
private String mapImage(String image) {
return ImageMappingFacade.map(getImageMappingFacades(), image);
}
private static interface AbortChecker {
@Nullable

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -15,6 +15,7 @@ import io.onedev.server.entitymanager.AgentManager;
import io.onedev.server.job.*;
import io.onedev.server.job.log.LogManager;
import io.onedev.server.job.log.ServerJobLogger;
import io.onedev.server.model.support.ImageMapping;
import io.onedev.server.model.support.RegistryLogin;
import io.onedev.server.persistence.SessionManager;
import io.onedev.server.plugin.executor.serverdocker.ServerDockerExecutor;
@ -107,6 +108,7 @@ public class RemoteDockerExecutor extends ServerDockerExecutor {
getName(), agentData.getName()));
var registryLogins = getRegistryLogins().stream().map(RegistryLogin::getFacade).collect(toList());
var imageMappings = getImageMappings().stream().map(ImageMapping::getFacade).collect(toList());
List<Map<String, Serializable>> services = new ArrayList<>();
for (Service service : jobContext.getServices())
@ -116,7 +118,7 @@ public class RemoteDockerExecutor extends ServerDockerExecutor {
DockerJobData jobData = new DockerJobData(jobToken, getName(), jobContext.getProjectPath(),
jobContext.getProjectId(), jobContext.getRefName(), jobContext.getCommitId().name(),
jobContext.getBuildNumber(), jobContext.getActions(), jobContext.getRetried(),
services, registryLogins, isMountDockerSock(), getDockerSockPath(),
services, registryLogins, imageMappings, isMountDockerSock(), getDockerSockPath(),
getCpuLimit(), getMemoryLimit(), getRunOptions(), getNetworkOptions());
try {

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.executor.serverdocker.ServerDockerModule</moduleClass>

View File

@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
import io.onedev.agent.DockerExecutorUtils;
import io.onedev.agent.ExecutorUtils;
import io.onedev.agent.job.FailedException;
import io.onedev.agent.job.ImageMappingFacade;
import io.onedev.commons.bootstrap.Bootstrap;
import io.onedev.commons.loader.AppLoader;
import io.onedev.commons.utils.*;
@ -21,6 +22,7 @@ import io.onedev.server.job.JobContext;
import io.onedev.server.job.JobManager;
import io.onedev.server.job.JobRunnable;
import io.onedev.server.job.ResourceAllocator;
import io.onedev.server.model.support.ImageMapping;
import io.onedev.server.model.support.RegistryLogin;
import io.onedev.server.model.support.administration.jobexecutor.JobExecutor;
import io.onedev.server.plugin.executor.serverdocker.ServerDockerExecutor.TestData;
@ -75,13 +77,17 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
private String concurrency;
private List<ImageMapping> imageMappings = new ArrayList<>();
private transient volatile File hostBuildHome;
private transient volatile LeafFacade runningStep;
private transient volatile String containerName;
private static transient volatile String hostInstallPath;
private transient List<ImageMappingFacade> imageMappingFacades;
private static volatile String hostInstallPath;
@Editable(order=400, description="Specify login information for docker registries if necessary")
public List<RegistryLogin> getRegistryLogins() {
@ -127,17 +133,6 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
this.mountDockerSock = mountDockerSock;
}
@Editable(order=530, group="More Settings", description = "Optionally specify docker options to create network. " +
"Multiple options should be separated by space, and single option containing spaces should be quoted")
@ReservedOptions({"-d", "(--driver)=.*"})
public String getNetworkOptions() {
return networkOptions;
}
public void setNetworkOptions(String networkOptions) {
this.networkOptions = networkOptions;
}
@Editable(order=50010, group="More Settings", placeholder = "No limit", description = "" +
"Optionally specify cpu limit of jobs/services using this executor. This will be " +
"used as option <a href='https://docs.docker.com/config/containers/resource_constraints/#cpu' target='_blank'>--cpus</a> " +
@ -174,6 +169,17 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
this.runOptions = runOptions;
}
@Editable(order=50075, group="More Settings", description = "Optionally specify docker options to create network. " +
"Multiple options should be separated by space, and single option containing spaces should be quoted")
@ReservedOptions({"-d", "(--driver)=.*"})
public String getNetworkOptions() {
return networkOptions;
}
public void setNetworkOptions(String networkOptions) {
this.networkOptions = networkOptions;
}
@Editable(order=50100, group="More Settings", placeholder="Use default", description=""
+ "Optionally specify docker executable, for instance <i>/usr/local/bin/docker</i>. "
+ "Leave empty to use docker executable in PATH")
@ -185,6 +191,17 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
this.dockerExecutable = dockerExecutable;
}
@Editable(order=50150, group="More Settings", description = "Optionally maps a docker image to a different " +
"image. The first matching entry will take effect, or image will remain unchanged if no matching " +
"entries found")
public List<ImageMapping> getImageMappings() {
return imageMappings;
}
public void setImageMappings(List<ImageMapping> imageMappings) {
this.imageMappings = imageMappings;
}
private Commandline newDocker() {
Commandline docker;
if (getDockerExecutable() != null)
@ -275,8 +292,8 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
OsInfo osInfo = OneDev.getInstance(OsInfo.class);
for (Service jobService : jobContext.getServices()) {
jobLogger.log("Starting service (name: " + jobService.getName() + ", image: " + jobService.getImage() + ")...");
startService(newDocker(), network, jobService.toMap(), osInfo, getCpuLimit(), getMemoryLimit(), jobLogger);
startService(newDocker(), network, jobService.toMap(), osInfo, getImageMappingFacades(),
getCpuLimit(), getMemoryLimit(), jobLogger);
}
File hostWorkspace = new File(hostBuildHome, "workspace");
@ -310,6 +327,7 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
List<String> arguments, Map<String, String> environments,
@Nullable String workingDir, Map<String, String> volumeMounts,
List<Integer> position, boolean useTTY, boolean kaniko) {
image = mapImage(image);
// Uninstall symbol links as docker can not process it well
cache.uninstallSymbolinks(hostWorkspace);
containerName = network + "-step-" + stringifyStepPosition(position);
@ -631,6 +649,16 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
}
return hostInstallPath + path.substring(installPath.length());
}
private List<ImageMappingFacade> getImageMappingFacades() {
if (imageMappingFacades == null)
imageMappingFacades = getImageMappings().stream().map(it->it.getFacade()).collect(toList());
return imageMappingFacades;
}
private String mapImage(String image) {
return ImageMappingFacade.map(getImageMappingFacades(), image);
}
@Override
public void test(TestData testData, TaskLogger jobLogger) {

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.executor.servershell.ServerShellModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.imports.bitbucketcloud.BitbucketModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.imports.gitea.GiteaModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.imports.github.GitHubModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.imports.gitlab.GitLabModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.imports.jiracloud.JiraModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.imports.url.UrlModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.imports.youtrack.YouTrackModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.notification.discord.DiscordModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.notification.slack.SlackModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.report.coverage.CoverageModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.report.markdown.MarkdownModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.report.problem.ProblemModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.report.unittest.UnitTestModule</moduleClass>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.sso.discord.DiscordModule</moduleClass>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server-plugin</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<properties>
<moduleClass>io.onedev.server.plugin.sso.openid.OpenIdModule</moduleClass>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>io.onedev</groupId>
<artifactId>server</artifactId>
<version>8.3.4</version>
<version>8.3.5</version>
</parent>
<dependencies>
<dependency>