mirror of
https://github.com/theonedev/onedev.git
synced 2025-12-08 18:26:30 +00:00
Add Kubernetes restful endpoint to interact with init/sidecar container
This commit is contained in:
parent
fb332489fc
commit
ce57390f71
2
pom.xml
2
pom.xml
@ -195,7 +195,7 @@
|
|||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
<properties>
|
<properties>
|
||||||
<commons.version>1.1.1</commons.version>
|
<commons.version>1.1.2</commons.version>
|
||||||
<antlr.version>4.7.2</antlr.version>
|
<antlr.version>4.7.2</antlr.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@ -45,11 +45,6 @@
|
|||||||
<artifactId>commons-codec</artifactId>
|
<artifactId>commons-codec</artifactId>
|
||||||
<version>1.7</version>
|
<version>1.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-compress</artifactId>
|
|
||||||
<version>1.18</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.xodus</groupId>
|
<groupId>org.jetbrains.xodus</groupId>
|
||||||
<artifactId>xodus-entity-store</artifactId>
|
<artifactId>xodus-entity-store</artifactId>
|
||||||
|
|||||||
@ -205,6 +205,7 @@ import io.onedev.server.search.code.DefaultSearchManager;
|
|||||||
import io.onedev.server.search.code.IndexManager;
|
import io.onedev.server.search.code.IndexManager;
|
||||||
import io.onedev.server.search.code.SearchManager;
|
import io.onedev.server.search.code.SearchManager;
|
||||||
import io.onedev.server.security.BasicAuthenticationFilter;
|
import io.onedev.server.security.BasicAuthenticationFilter;
|
||||||
|
import io.onedev.server.security.CodePullAuthorizationSource;
|
||||||
import io.onedev.server.security.FilterChainConfigurator;
|
import io.onedev.server.security.FilterChainConfigurator;
|
||||||
import io.onedev.server.security.OneAuthorizingRealm;
|
import io.onedev.server.security.OneAuthorizingRealm;
|
||||||
import io.onedev.server.security.OneFilterChainResolver;
|
import io.onedev.server.security.OneFilterChainResolver;
|
||||||
@ -390,6 +391,8 @@ public class CoreModule extends AbstractPluginModule {
|
|||||||
contributeFromPackage(DefaultCISpecProvider.class, DefaultCISpecProvider.class);
|
contributeFromPackage(DefaultCISpecProvider.class, DefaultCISpecProvider.class);
|
||||||
contributeFromPackage(LogNormalizer.class, LogNormalizer.class);
|
contributeFromPackage(LogNormalizer.class, LogNormalizer.class);
|
||||||
|
|
||||||
|
contribute(CodePullAuthorizationSource.class, DefaultJobManager.class);
|
||||||
|
|
||||||
bind(IndexManager.class).to(DefaultIndexManager.class);
|
bind(IndexManager.class).to(DefaultIndexManager.class);
|
||||||
bind(SearchManager.class).to(DefaultSearchManager.class);
|
bind(SearchManager.class).to(DefaultSearchManager.class);
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -21,6 +22,7 @@ import java.util.concurrent.locks.Lock;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.quartz.CronScheduleBuilder;
|
import org.quartz.CronScheduleBuilder;
|
||||||
@ -67,20 +69,20 @@ import io.onedev.server.model.Project;
|
|||||||
import io.onedev.server.model.Setting;
|
import io.onedev.server.model.Setting;
|
||||||
import io.onedev.server.model.Setting.Key;
|
import io.onedev.server.model.Setting.Key;
|
||||||
import io.onedev.server.model.User;
|
import io.onedev.server.model.User;
|
||||||
import io.onedev.server.model.support.JobExecutionContext;
|
import io.onedev.server.model.support.JobContext;
|
||||||
import io.onedev.server.model.support.JobExecutor;
|
import io.onedev.server.model.support.JobExecutor;
|
||||||
import io.onedev.server.model.support.SourceSnapshot;
|
|
||||||
import io.onedev.server.persistence.SessionManager;
|
import io.onedev.server.persistence.SessionManager;
|
||||||
import io.onedev.server.persistence.TransactionManager;
|
import io.onedev.server.persistence.TransactionManager;
|
||||||
import io.onedev.server.persistence.annotation.Sessional;
|
import io.onedev.server.persistence.annotation.Sessional;
|
||||||
import io.onedev.server.persistence.annotation.Transactional;
|
import io.onedev.server.persistence.annotation.Transactional;
|
||||||
|
import io.onedev.server.security.CodePullAuthorizationSource;
|
||||||
import io.onedev.server.util.Input;
|
import io.onedev.server.util.Input;
|
||||||
import io.onedev.server.util.inputspec.InputSpec;
|
import io.onedev.server.util.inputspec.InputSpec;
|
||||||
import io.onedev.server.util.inputspec.SecretInput;
|
import io.onedev.server.util.inputspec.SecretInput;
|
||||||
import io.onedev.server.util.patternset.PatternSet;
|
import io.onedev.server.util.patternset.PatternSet;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class DefaultJobManager implements JobManager, Runnable, SchedulableTask {
|
public class DefaultJobManager implements JobManager, Runnable, SchedulableTask, CodePullAuthorizationSource {
|
||||||
|
|
||||||
private static final int CHECK_INTERVAL = 1000; // check internal in milli-seconds
|
private static final int CHECK_INTERVAL = 1000; // check internal in milli-seconds
|
||||||
|
|
||||||
@ -88,6 +90,8 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
|
|
||||||
private enum Status {STARTED, STOPPING, STOPPED};
|
private enum Status {STARTED, STOPPING, STOPPED};
|
||||||
|
|
||||||
|
private final Map<String, JobContext> jobContexts = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final Map<Long, JobExecution> jobExecutions = new ConcurrentHashMap<>();
|
private final Map<Long, JobExecution> jobExecutions = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final BuildManager buildManager;
|
private final BuildManager buildManager;
|
||||||
@ -246,21 +250,16 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
ObjectId commitId = ObjectId.fromString(build.getCommitHash());
|
ObjectId commitId = ObjectId.fromString(build.getCommitHash());
|
||||||
JobExecutor executor = getJobExecutor(build.getProject(), commitId, job.getName(), job.getEnvironment());
|
JobExecutor executor = getJobExecutor(build.getProject(), commitId, job.getName(), job.getEnvironment());
|
||||||
if (executor != null) {
|
if (executor != null) {
|
||||||
SourceSnapshot snapshot;
|
|
||||||
if (job.isCloneSource())
|
|
||||||
snapshot = new SourceSnapshot(build.getProject(), commitId);
|
|
||||||
else
|
|
||||||
snapshot = null;
|
|
||||||
|
|
||||||
Logger logger = logManager.getLogger(build, job.getLogLevel());
|
Logger logger = logManager.getLogger(build, job.getLogLevel());
|
||||||
|
|
||||||
Long buildId = build.getId();
|
Long buildId = build.getId();
|
||||||
|
String projectName = build.getProject().getName();
|
||||||
JobExecution execution = new JobExecution(executorService.submit(new Runnable() {
|
JobExecution execution = new JobExecution(executorService.submit(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.info("Creating workspace...");
|
logger.info("Creating server workspace...");
|
||||||
File workspace = FileUtils.createTempDir("workspace");
|
File serverWorkspace = FileUtils.createTempDir("server-workspace");
|
||||||
try {
|
try {
|
||||||
Map<String, String> envVars = new HashMap<>();
|
Map<String, String> envVars = new HashMap<>();
|
||||||
Set<String> includeFiles = new HashSet<>();
|
Set<String> includeFiles = new HashSet<>();
|
||||||
@ -274,7 +273,7 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
logger.info("Populating dependencies...");
|
logger.info("Populating dependencies...");
|
||||||
for (BuildDependence dependence: build.getDependencies()) {
|
for (BuildDependence dependence: build.getDependencies()) {
|
||||||
for (DependencyPopulator populator: dependencyPopulators)
|
for (DependencyPopulator populator: dependencyPopulators)
|
||||||
populator.populate(dependence.getDependency(), workspace, logger);
|
populator.populate(dependence.getDependency(), serverWorkspace, logger);
|
||||||
}
|
}
|
||||||
envVars.put("ONEDEV_PROJECT", build.getProject().getName());
|
envVars.put("ONEDEV_PROJECT", build.getProject().getName());
|
||||||
envVars.put("ONEDEV_COMMIT", commitId.name());
|
envVars.put("ONEDEV_COMMIT", commitId.name());
|
||||||
@ -313,8 +312,9 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
logger.info("Executing job with executor '" + executor.getName() + "'...");
|
logger.info("Executing job with executor '" + executor.getName() + "'...");
|
||||||
|
|
||||||
List<String> commands = Splitter.on("\n").trimResults(CharMatcher.is('\r')).splitToList(job.getCommands());
|
List<String> commands = Splitter.on("\n").trimResults(CharMatcher.is('\r')).splitToList(job.getCommands());
|
||||||
executor.execute(new JobExecutionContext(job.getEnvironment(), workspace, envVars, commands,
|
|
||||||
snapshot, job.getCaches(), new PatternSet(includeFiles, excludeFiles), logger) {
|
JobContext jobContext = new JobContext(projectName, job.getEnvironment(), serverWorkspace, envVars, commands,
|
||||||
|
job.isCloneSource(), commitId, job.getCaches(), new PatternSet(includeFiles, excludeFiles), logger) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyJobRunning() {
|
public void notifyJobRunning() {
|
||||||
@ -322,7 +322,6 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.info("Collecting job outcomes...");
|
|
||||||
Build build = buildManager.load(buildId);
|
Build build = buildManager.load(buildId);
|
||||||
build.setStatus(Build.Status.RUNNING);
|
build.setStatus(Build.Status.RUNNING);
|
||||||
build.setRunningDate(new Date());
|
build.setRunningDate(new Date());
|
||||||
@ -332,8 +331,16 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
};
|
||||||
|
|
||||||
|
String jobId = UUID.randomUUID().toString();
|
||||||
|
jobContexts.put(jobId, jobContext);
|
||||||
|
try {
|
||||||
|
executor.execute(jobId, jobContext);
|
||||||
|
} finally {
|
||||||
|
jobContexts.remove(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
sessionManager.run(new Runnable() {
|
sessionManager.run(new Runnable() {
|
||||||
|
|
||||||
@ -342,7 +349,7 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
logger.info("Collecting job outcomes...");
|
logger.info("Collecting job outcomes...");
|
||||||
Build build = buildManager.load(buildId);
|
Build build = buildManager.load(buildId);
|
||||||
for (JobOutcome outcome: job.getOutcomes())
|
for (JobOutcome outcome: job.getOutcomes())
|
||||||
outcome.process(build, workspace, logger);
|
outcome.process(build, serverWorkspace, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -351,10 +358,10 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
logger.error("Error running build", e);
|
logger.error("Error running build", e);
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
logger.info("Deleting workspace...");
|
logger.info("Deleting server workspace...");
|
||||||
executor.cleanDir(workspace);
|
executor.cleanDir(serverWorkspace);
|
||||||
FileUtils.deleteDir(workspace);
|
FileUtils.deleteDir(serverWorkspace);
|
||||||
logger.info("Workspace deleted");
|
logger.info("Server workspace deleted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,6 +379,11 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JobContext getJobContext(String jobId) {
|
||||||
|
return jobContexts.get(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
private void markBuildError(Build build, String errorMessage) {
|
private void markBuildError(Build build, String errorMessage) {
|
||||||
build.setStatus(Build.Status.IN_ERROR, errorMessage);
|
build.setStatus(Build.Status.IN_ERROR, errorMessage);
|
||||||
build.setFinishDate(new Date());
|
build.setFinishDate(new Date());
|
||||||
@ -604,4 +616,15 @@ public class DefaultJobManager implements JobManager, Runnable, SchedulableTask
|
|||||||
return CronScheduleBuilder.dailyAtHourAndMinute(0, 0);
|
return CronScheduleBuilder.dailyAtHourAndMinute(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPullCode(HttpServletRequest request, Project project) {
|
||||||
|
String jobId = request.getHeader(JOB_ID_HTTP_HEADER);
|
||||||
|
if (jobId != null) {
|
||||||
|
JobContext context = getJobContext(jobId);
|
||||||
|
if (context != null)
|
||||||
|
return context.getProjectName().equals(project.getName());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,12 @@ import org.eclipse.jgit.lib.ObjectId;
|
|||||||
import io.onedev.server.model.Build;
|
import io.onedev.server.model.Build;
|
||||||
import io.onedev.server.model.Project;
|
import io.onedev.server.model.Project;
|
||||||
import io.onedev.server.model.User;
|
import io.onedev.server.model.User;
|
||||||
|
import io.onedev.server.model.support.JobContext;
|
||||||
|
|
||||||
public interface JobManager {
|
public interface JobManager {
|
||||||
|
|
||||||
|
public static final String JOB_ID_HTTP_HEADER = "X-ONEDEV-JOB-ID";
|
||||||
|
|
||||||
Build submit(Project project, ObjectId commitId, String jobName,
|
Build submit(Project project, ObjectId commitId, String jobName,
|
||||||
Map<String, List<String>> paramMap, @Nullable User submitter);
|
Map<String, List<String>> paramMap, @Nullable User submitter);
|
||||||
|
|
||||||
@ -20,4 +23,6 @@ public interface JobManager {
|
|||||||
|
|
||||||
void cancel(Build build, @Nullable User canceller);
|
void cancel(Build build, @Nullable User canceller);
|
||||||
|
|
||||||
|
JobContext getJobContext(String jobId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import org.joda.time.format.DateTimeFormat;
|
|||||||
import org.joda.time.format.DateTimeFormatter;
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.unbescape.html.HtmlEscape;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
@ -155,7 +156,7 @@ public class DefaultLogManager implements LogManager {
|
|||||||
try {
|
try {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
for (String line: Splitter.on(EOL_PATTERN).split(Throwables.getStackTraceAsString(throwable)))
|
for (String line: Splitter.on(EOL_PATTERN).split(Throwables.getStackTraceAsString(throwable)))
|
||||||
message += "\n " + line;
|
message += "\n " + HtmlEscape.escapeHtml5(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.startsWith(LogInstruction.PREFIX)) {
|
if (message.startsWith(LogInstruction.PREFIX)) {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -40,6 +41,7 @@ import io.onedev.server.git.exception.GitException;
|
|||||||
import io.onedev.server.model.Project;
|
import io.onedev.server.model.Project;
|
||||||
import io.onedev.server.model.User;
|
import io.onedev.server.model.User;
|
||||||
import io.onedev.server.persistence.annotation.Sessional;
|
import io.onedev.server.persistence.annotation.Sessional;
|
||||||
|
import io.onedev.server.security.CodePullAuthorizationSource;
|
||||||
import io.onedev.server.security.SecurityUtils;
|
import io.onedev.server.security.SecurityUtils;
|
||||||
import io.onedev.server.storage.StorageManager;
|
import io.onedev.server.storage.StorageManager;
|
||||||
import io.onedev.server.util.serverconfig.ServerConfig;
|
import io.onedev.server.util.serverconfig.ServerConfig;
|
||||||
@ -66,15 +68,19 @@ public class GitFilter implements Filter {
|
|||||||
|
|
||||||
private final SettingManager configManager;
|
private final SettingManager configManager;
|
||||||
|
|
||||||
|
private final Set<CodePullAuthorizationSource> codePullAuthorizationSources;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public GitFilter(OneDev oneDev, StorageManager storageManager, ProjectManager projectManager,
|
public GitFilter(OneDev oneDev, StorageManager storageManager, ProjectManager projectManager,
|
||||||
WorkExecutor workManager, ServerConfig serverConfig, SettingManager configManager) {
|
WorkExecutor workManager, ServerConfig serverConfig, SettingManager configManager,
|
||||||
|
Set<CodePullAuthorizationSource> codePullAuthorizationSources) {
|
||||||
this.oneDev = oneDev;
|
this.oneDev = oneDev;
|
||||||
this.storageManager = storageManager;
|
this.storageManager = storageManager;
|
||||||
this.projectManager = projectManager;
|
this.projectManager = projectManager;
|
||||||
this.workExecutor = workManager;
|
this.workExecutor = workManager;
|
||||||
this.serverConfig = serverConfig;
|
this.serverConfig = serverConfig;
|
||||||
this.configManager = configManager;
|
this.configManager = configManager;
|
||||||
|
this.codePullAuthorizationSources = codePullAuthorizationSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPathInfo(HttpServletRequest request) {
|
private String getPathInfo(HttpServletRequest request) {
|
||||||
@ -143,8 +149,7 @@ public class GitFilter implements Filter {
|
|||||||
File gitDir = storageManager.getProjectGitDir(project.getId());
|
File gitDir = storageManager.getProjectGitDir(project.getId());
|
||||||
|
|
||||||
if (GitSmartHttpTools.isUploadPack(request)) {
|
if (GitSmartHttpTools.isUploadPack(request)) {
|
||||||
if (!SecurityUtils.canReadCode(project.getFacade()))
|
checkPullPermission(request, project);
|
||||||
throw new UnauthorizedException("You do not have permission to pull from this project.");
|
|
||||||
workExecutor.submit(new PrioritizedRunnable(PRIORITY) {
|
workExecutor.submit(new PrioritizedRunnable(PRIORITY) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -160,9 +165,8 @@ public class GitFilter implements Filter {
|
|||||||
|
|
||||||
}).get();
|
}).get();
|
||||||
} else {
|
} else {
|
||||||
if (!SecurityUtils.canWriteCode(project.getFacade())) {
|
if (!SecurityUtils.canWriteCode(project.getFacade()))
|
||||||
throw new UnauthorizedException("You do not have permission to push to this project.");
|
throw new UnauthorizedException("You do not have permission to push to this project.");
|
||||||
}
|
|
||||||
workExecutor.submit(new PrioritizedRunnable(PRIORITY) {
|
workExecutor.submit(new PrioritizedRunnable(PRIORITY) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -190,6 +194,20 @@ public class GitFilter implements Filter {
|
|||||||
pack.end();
|
pack.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkPullPermission(HttpServletRequest request, Project project) {
|
||||||
|
if (!SecurityUtils.canReadCode(project.getFacade())) {
|
||||||
|
boolean isAuthorized = false;
|
||||||
|
for (CodePullAuthorizationSource source: codePullAuthorizationSources) {
|
||||||
|
if (source.canPullCode(request, project)) {
|
||||||
|
isAuthorized = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isAuthorized)
|
||||||
|
throw new UnauthorizedException("You do not have permission to pull from this project.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void processRefs(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
protected void processRefs(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
String pathInfo = request.getRequestURI().substring(request.getContextPath().length());
|
String pathInfo = request.getRequestURI().substring(request.getContextPath().length());
|
||||||
pathInfo = StringUtils.stripStart(pathInfo, "/");
|
pathInfo = StringUtils.stripStart(pathInfo, "/");
|
||||||
@ -201,8 +219,7 @@ public class GitFilter implements Filter {
|
|||||||
File gitDir = storageManager.getProjectGitDir(project.getId());
|
File gitDir = storageManager.getProjectGitDir(project.getId());
|
||||||
|
|
||||||
if (service.contains("upload")) {
|
if (service.contains("upload")) {
|
||||||
if (!SecurityUtils.canReadCode(project.getFacade()))
|
checkPullPermission(request, project);
|
||||||
throw new UnauthorizedException("You do not have permission to pull from this project.");
|
|
||||||
writeInitial(response, service);
|
writeInitial(response, service);
|
||||||
new AdvertiseUploadRefsCommand(gitDir).output(response.getOutputStream()).call();
|
new AdvertiseUploadRefsCommand(gitDir).output(response.getOutputStream()).call();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -0,0 +1,121 @@
|
|||||||
|
package io.onedev.server.model.support;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import io.onedev.commons.utils.ExceptionUtils;
|
||||||
|
import io.onedev.server.ci.job.cache.JobCache;
|
||||||
|
import io.onedev.server.git.command.CheckoutCommand;
|
||||||
|
import io.onedev.server.git.command.FetchCommand;
|
||||||
|
import io.onedev.server.util.patternset.PatternSet;
|
||||||
|
|
||||||
|
public abstract class JobContext {
|
||||||
|
|
||||||
|
private final String projectName;
|
||||||
|
|
||||||
|
private final String environment;
|
||||||
|
|
||||||
|
private final File serverWorkspace;
|
||||||
|
|
||||||
|
private final Map<String, String> envVars;
|
||||||
|
|
||||||
|
private final List<String> commands;
|
||||||
|
|
||||||
|
private final boolean cloneSource;
|
||||||
|
|
||||||
|
private final ObjectId commitId;
|
||||||
|
|
||||||
|
private final Collection<JobCache> caches;
|
||||||
|
|
||||||
|
private final PatternSet collectFiles;
|
||||||
|
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
|
public JobContext(String projectName, String environment, File workspace,
|
||||||
|
Map<String, String> envVars, List<String> commands, boolean cloneSource,
|
||||||
|
ObjectId commitId, Collection<JobCache> caches, PatternSet collectFiles,
|
||||||
|
Logger logger) {
|
||||||
|
this.projectName = projectName;
|
||||||
|
this.environment = environment;
|
||||||
|
this.serverWorkspace = workspace;
|
||||||
|
this.envVars = envVars;
|
||||||
|
this.commands = commands;
|
||||||
|
this.cloneSource = cloneSource;
|
||||||
|
this.commitId = commitId;
|
||||||
|
this.caches = caches;
|
||||||
|
this.collectFiles = collectFiles;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProjectName() {
|
||||||
|
return projectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEnvironment() {
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getServerWorkspace() {
|
||||||
|
return serverWorkspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getEnvVars() {
|
||||||
|
return envVars;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getCommands() {
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectId getCommitId() {
|
||||||
|
return commitId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCloneSource() {
|
||||||
|
return cloneSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<JobCache> getCaches() {
|
||||||
|
return caches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PatternSet getCollectFiles() {
|
||||||
|
return collectFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Logger getLogger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchAndCheckout(File gitDir) {
|
||||||
|
new FetchCommand(gitDir).depth(1).from(gitDir.getAbsolutePath()).refspec(commitId.name()).call();
|
||||||
|
new CheckoutCommand(gitDir).refspec(commitId.name()).call();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkoutSource(File dir) {
|
||||||
|
if (new File(dir, ".git").exists()) {
|
||||||
|
try (Git git = Git.open(dir)) {
|
||||||
|
fetchAndCheckout(dir);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try (Git git = Git.init().setDirectory(dir).call()) {
|
||||||
|
fetchAndCheckout(dir);
|
||||||
|
} catch (GitAPIException e) {
|
||||||
|
throw ExceptionUtils.unchecked(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void notifyJobRunning();
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,81 +0,0 @@
|
|||||||
package io.onedev.server.model.support;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
|
|
||||||
import io.onedev.server.ci.job.cache.JobCache;
|
|
||||||
import io.onedev.server.util.patternset.PatternSet;
|
|
||||||
|
|
||||||
public abstract class JobExecutionContext {
|
|
||||||
|
|
||||||
private final String environment;
|
|
||||||
|
|
||||||
private final File workspace;
|
|
||||||
|
|
||||||
private final Map<String, String> envVars;
|
|
||||||
|
|
||||||
private final List<String> commands;
|
|
||||||
|
|
||||||
private final @Nullable SourceSnapshot snapshot;
|
|
||||||
|
|
||||||
private final Collection<JobCache> caches;
|
|
||||||
|
|
||||||
private final PatternSet collectFiles;
|
|
||||||
|
|
||||||
private final Logger logger;
|
|
||||||
|
|
||||||
public JobExecutionContext(String environment, File workspace, Map<String, String> envVars,
|
|
||||||
List<String> commands, @Nullable SourceSnapshot snapshot, Collection<JobCache> caches,
|
|
||||||
PatternSet collectFiles, Logger logger) {
|
|
||||||
this.environment = environment;
|
|
||||||
this.workspace = workspace;
|
|
||||||
this.envVars = envVars;
|
|
||||||
this.commands = commands;
|
|
||||||
this.snapshot = snapshot;
|
|
||||||
this.caches = caches;
|
|
||||||
this.collectFiles = collectFiles;
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEnvironment() {
|
|
||||||
return environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getWorkspace() {
|
|
||||||
return workspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getEnvVars() {
|
|
||||||
return envVars;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getCommands() {
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public SourceSnapshot getSnapshot() {
|
|
||||||
return snapshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<JobCache> getCaches() {
|
|
||||||
return caches;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PatternSet getCollectFiles() {
|
|
||||||
return collectFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Logger getLogger() {
|
|
||||||
return logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void notifyJobRunning();
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -120,7 +120,7 @@ public abstract class JobExecutor implements Serializable {
|
|||||||
this.cacheTTL = cacheTTL;
|
this.cacheTTL = cacheTTL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void execute(JobExecutionContext context);
|
public abstract void execute(String jobId, JobContext context);
|
||||||
|
|
||||||
public final boolean isApplicable(Project project, ObjectId commitId, String jobName, String environment) {
|
public final boolean isApplicable(Project project, ObjectId commitId, String jobName, String environment) {
|
||||||
Matcher matcher = new ChildAwareMatcher();
|
Matcher matcher = new ChildAwareMatcher();
|
||||||
|
|||||||
@ -1,55 +0,0 @@
|
|||||||
package io.onedev.server.model.support;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.eclipse.jgit.api.Git;
|
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
|
||||||
|
|
||||||
import io.onedev.commons.utils.ExceptionUtils;
|
|
||||||
import io.onedev.server.git.command.CheckoutCommand;
|
|
||||||
import io.onedev.server.git.command.FetchCommand;
|
|
||||||
import io.onedev.server.model.Project;
|
|
||||||
|
|
||||||
public class SourceSnapshot {
|
|
||||||
|
|
||||||
private final Project project;
|
|
||||||
|
|
||||||
private final ObjectId commitId;
|
|
||||||
|
|
||||||
public SourceSnapshot(Project project, ObjectId commitId) {
|
|
||||||
this.project = project;
|
|
||||||
this.commitId = commitId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Project getProject() {
|
|
||||||
return project;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjectId getCommitId() {
|
|
||||||
return commitId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fetchAndCheckout(File gitDir) {
|
|
||||||
new FetchCommand(gitDir).depth(1).from(project.getGitDir().getAbsolutePath()).refspec(commitId.name()).call();
|
|
||||||
new CheckoutCommand(gitDir).refspec(commitId.name()).call();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkout(File dir) {
|
|
||||||
if (new File(dir, ".git").exists()) {
|
|
||||||
try (Git git = Git.open(dir)) {
|
|
||||||
fetchAndCheckout(dir);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try (Git git = Git.init().setDirectory(dir).call()) {
|
|
||||||
fetchAndCheckout(dir);
|
|
||||||
} catch (GitAPIException e) {
|
|
||||||
throw ExceptionUtils.unchecked(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -5,12 +5,13 @@ import java.util.Map;
|
|||||||
|
|
||||||
import org.apache.wicket.Component;
|
import org.apache.wicket.Component;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.server.model.Group;
|
import io.onedev.server.model.Group;
|
||||||
import io.onedev.server.model.IssueChange;
|
import io.onedev.server.model.IssueChange;
|
||||||
import io.onedev.server.model.User;
|
import io.onedev.server.model.User;
|
||||||
import io.onedev.server.util.CommentSupport;
|
import io.onedev.server.util.CommentSupport;
|
||||||
import io.onedev.server.web.component.diff.plain.PlainDiffPanel;
|
import io.onedev.server.web.component.diff.plain.PlainDiffPanel;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
public class IssueTitleChangeData implements IssueChangeData {
|
public class IssueTitleChangeData implements IssueChangeData {
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import java.util.stream.Collectors;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.commons.launcher.loader.Listen;
|
import io.onedev.commons.launcher.loader.Listen;
|
||||||
import io.onedev.server.cache.UserInfoManager;
|
import io.onedev.server.cache.UserInfoManager;
|
||||||
import io.onedev.server.entitymanager.IssueWatchManager;
|
import io.onedev.server.entitymanager.IssueWatchManager;
|
||||||
@ -30,7 +32,6 @@ import io.onedev.server.search.entity.QueryWatchBuilder;
|
|||||||
import io.onedev.server.search.entity.issue.IssueQuery;
|
import io.onedev.server.search.entity.issue.IssueQuery;
|
||||||
import io.onedev.server.util.markdown.MarkdownManager;
|
import io.onedev.server.util.markdown.MarkdownManager;
|
||||||
import io.onedev.server.util.markdown.MentionParser;
|
import io.onedev.server.util.markdown.MentionParser;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class IssueNotificationManager {
|
public class IssueNotificationManager {
|
||||||
|
|||||||
@ -39,6 +39,8 @@ import org.eclipse.jgit.treewalk.TreeWalk;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
import io.onedev.commons.jsymbol.Symbol;
|
import io.onedev.commons.jsymbol.Symbol;
|
||||||
import io.onedev.commons.jsymbol.SymbolExtractorRegistry;
|
import io.onedev.commons.jsymbol.SymbolExtractorRegistry;
|
||||||
import io.onedev.commons.launcher.loader.Listen;
|
import io.onedev.commons.launcher.loader.Listen;
|
||||||
@ -50,7 +52,6 @@ import io.onedev.server.persistence.annotation.Transactional;
|
|||||||
import io.onedev.server.search.code.hit.QueryHit;
|
import io.onedev.server.search.code.hit.QueryHit;
|
||||||
import io.onedev.server.search.code.query.BlobQuery;
|
import io.onedev.server.search.code.query.BlobQuery;
|
||||||
import io.onedev.server.storage.StorageManager;
|
import io.onedev.server.storage.StorageManager;
|
||||||
import jersey.repackaged.com.google.common.base.Preconditions;
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class DefaultSearchManager implements SearchManager {
|
public class DefaultSearchManager implements SearchManager {
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
package io.onedev.server.security;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import io.onedev.server.model.Project;
|
||||||
|
|
||||||
|
public interface CodePullAuthorizationSource {
|
||||||
|
|
||||||
|
boolean canPullCode(HttpServletRequest request, Project project);
|
||||||
|
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@ -34,8 +35,7 @@ import io.onedev.server.model.Membership;
|
|||||||
import io.onedev.server.model.User;
|
import io.onedev.server.model.User;
|
||||||
import io.onedev.server.model.support.authenticator.Authenticated;
|
import io.onedev.server.model.support.authenticator.Authenticated;
|
||||||
import io.onedev.server.model.support.authenticator.Authenticator;
|
import io.onedev.server.model.support.authenticator.Authenticator;
|
||||||
import io.onedev.server.persistence.annotation.Sessional;
|
import io.onedev.server.persistence.TransactionManager;
|
||||||
import io.onedev.server.persistence.annotation.Transactional;
|
|
||||||
import io.onedev.server.security.permission.CreateProjects;
|
import io.onedev.server.security.permission.CreateProjects;
|
||||||
import io.onedev.server.security.permission.ProjectPermission;
|
import io.onedev.server.security.permission.ProjectPermission;
|
||||||
import io.onedev.server.security.permission.SystemAdministration;
|
import io.onedev.server.security.permission.SystemAdministration;
|
||||||
@ -61,10 +61,12 @@ public class OneAuthorizingRealm extends AuthorizingRealm {
|
|||||||
private final MembershipManager membershipManager;
|
private final MembershipManager membershipManager;
|
||||||
|
|
||||||
private final GroupManager groupManager;
|
private final GroupManager groupManager;
|
||||||
|
|
||||||
|
private final TransactionManager transactionManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public OneAuthorizingRealm(UserManager userManager, CacheManager cacheManager, SettingManager configManager,
|
public OneAuthorizingRealm(UserManager userManager, CacheManager cacheManager, SettingManager configManager,
|
||||||
MembershipManager membershipManager, GroupManager groupManager) {
|
MembershipManager membershipManager, GroupManager groupManager, TransactionManager transactionManager) {
|
||||||
PasswordMatcher passwordMatcher = new PasswordMatcher();
|
PasswordMatcher passwordMatcher = new PasswordMatcher();
|
||||||
passwordMatcher.setPasswordService(AppLoader.getInstance(PasswordService.class));
|
passwordMatcher.setPasswordService(AppLoader.getInstance(PasswordService.class));
|
||||||
setCredentialsMatcher(passwordMatcher);
|
setCredentialsMatcher(passwordMatcher);
|
||||||
@ -74,6 +76,7 @@ public class OneAuthorizingRealm extends AuthorizingRealm {
|
|||||||
this.configManager = configManager;
|
this.configManager = configManager;
|
||||||
this.membershipManager = membershipManager;
|
this.membershipManager = membershipManager;
|
||||||
this.groupManager = groupManager;
|
this.groupManager = groupManager;
|
||||||
|
this.transactionManager = transactionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<Permission> getDefaultPermissions() {
|
private Collection<Permission> getDefaultPermissions() {
|
||||||
@ -85,48 +88,6 @@ public class OneAuthorizingRealm extends AuthorizingRealm {
|
|||||||
return defaultPermissions;
|
return defaultPermissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Sessional
|
|
||||||
protected Collection<Permission> getObjectPermissionsInSession(Long userId) {
|
|
||||||
Collection<Permission> permissions = new ArrayList<>();
|
|
||||||
|
|
||||||
UserFacade user = null;
|
|
||||||
if (userId != 0L)
|
|
||||||
user = cacheManager.getUser(userId);
|
|
||||||
if (user != null) {
|
|
||||||
permissions.addAll(getDefaultPermissions());
|
|
||||||
if (user.isRoot())
|
|
||||||
permissions.add(new SystemAdministration());
|
|
||||||
permissions.add(new UserAdministration(user));
|
|
||||||
for (MembershipFacade membership: cacheManager.getMemberships().values()) {
|
|
||||||
if (membership.getUserId().equals(userId)) {
|
|
||||||
GroupFacade group = cacheManager.getGroup(membership.getGroupId());
|
|
||||||
if (group.isAdministrator())
|
|
||||||
permissions.add(new SystemAdministration());
|
|
||||||
if (group.isCanCreateProjects())
|
|
||||||
permissions.add(new CreateProjects());
|
|
||||||
for (GroupAuthorizationFacade authorization:
|
|
||||||
cacheManager.getGroupAuthorizations().values()) {
|
|
||||||
if (authorization.getGroupId().equals(group.getId())) {
|
|
||||||
permissions.add(new ProjectPermission(
|
|
||||||
cacheManager.getProject(authorization.getProjectId()),
|
|
||||||
authorization.getPrivilege()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (UserAuthorizationFacade authorization: cacheManager.getUserAuthorizations().values()) {
|
|
||||||
if (authorization.getUserId().equals(userId)) {
|
|
||||||
permissions.add(new ProjectPermission(
|
|
||||||
cacheManager.getProject(authorization.getProjectId()),
|
|
||||||
authorization.getPrivilege()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (configManager.getSecuritySetting().isEnableAnonymousAccess()) {
|
|
||||||
permissions.addAll(getDefaultPermissions());
|
|
||||||
}
|
|
||||||
return permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||||
return new AuthorizationInfo() {
|
return new AuthorizationInfo() {
|
||||||
@ -145,106 +106,150 @@ public class OneAuthorizingRealm extends AuthorizingRealm {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Permission> getObjectPermissions() {
|
public Collection<Permission> getObjectPermissions() {
|
||||||
return getObjectPermissionsInSession((Long) principals.getPrimaryPrincipal());
|
return transactionManager.getSessionManager().call(new Callable<Collection<Permission>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Permission> call() throws Exception {
|
||||||
|
Long userId = (Long) principals.getPrimaryPrincipal();
|
||||||
|
Collection<Permission> permissions = new ArrayList<>();
|
||||||
|
|
||||||
|
UserFacade user = null;
|
||||||
|
if (userId != 0L)
|
||||||
|
user = cacheManager.getUser(userId);
|
||||||
|
if (user != null) {
|
||||||
|
permissions.addAll(getDefaultPermissions());
|
||||||
|
if (user.isRoot())
|
||||||
|
permissions.add(new SystemAdministration());
|
||||||
|
permissions.add(new UserAdministration(user));
|
||||||
|
for (MembershipFacade membership: cacheManager.getMemberships().values()) {
|
||||||
|
if (membership.getUserId().equals(userId)) {
|
||||||
|
GroupFacade group = cacheManager.getGroup(membership.getGroupId());
|
||||||
|
if (group.isAdministrator())
|
||||||
|
permissions.add(new SystemAdministration());
|
||||||
|
if (group.isCanCreateProjects())
|
||||||
|
permissions.add(new CreateProjects());
|
||||||
|
for (GroupAuthorizationFacade authorization:
|
||||||
|
cacheManager.getGroupAuthorizations().values()) {
|
||||||
|
if (authorization.getGroupId().equals(group.getId())) {
|
||||||
|
permissions.add(new ProjectPermission(
|
||||||
|
cacheManager.getProject(authorization.getProjectId()),
|
||||||
|
authorization.getPrivilege()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (UserAuthorizationFacade authorization: cacheManager.getUserAuthorizations().values()) {
|
||||||
|
if (authorization.getUserId().equals(userId)) {
|
||||||
|
permissions.add(new ProjectPermission(
|
||||||
|
cacheManager.getProject(authorization.getProjectId()),
|
||||||
|
authorization.getPrivilege()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (configManager.getSecuritySetting().isEnableAnonymousAccess()) {
|
||||||
|
permissions.addAll(getDefaultPermissions());
|
||||||
|
}
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
protected AuthenticationInfo doGetAuthenticationInfoInTransaction(AuthenticationToken token)
|
|
||||||
throws AuthenticationException {
|
|
||||||
User user = userManager.findByName(((UsernamePasswordToken) token).getUsername());
|
|
||||||
if (user != null && user.isRoot())
|
|
||||||
return user;
|
|
||||||
|
|
||||||
if (user == null || StringUtils.isBlank(user.getPassword())) {
|
|
||||||
Authenticator authenticator = configManager.getAuthenticator();
|
|
||||||
if (authenticator != null) {
|
|
||||||
Authenticated authenticated;
|
|
||||||
try {
|
|
||||||
authenticated = authenticator.authenticate((UsernamePasswordToken) token);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (e instanceof AuthenticationException) {
|
|
||||||
logger.debug("Authentication not passed", e);
|
|
||||||
throw ExceptionUtils.unchecked(e);
|
|
||||||
} else {
|
|
||||||
logger.error("Error authenticating user", e);
|
|
||||||
throw new AuthenticationException("Error authenticating user", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (user != null) {
|
|
||||||
if (authenticated.getEmail() != null)
|
|
||||||
user.setEmail(authenticated.getEmail());
|
|
||||||
if (authenticated.getFullName() != null)
|
|
||||||
user.setFullName(authenticated.getFullName());
|
|
||||||
|
|
||||||
Collection<String> existingGroupNames = new HashSet<>();
|
|
||||||
for (Membership membership: user.getMemberships())
|
|
||||||
existingGroupNames.add(membership.getGroup().getName());
|
|
||||||
if (!authenticated.getGroupNames().isEmpty()) {
|
|
||||||
Collection<String> retrievedGroupNames = new HashSet<>();
|
|
||||||
for (String groupName: authenticated.getGroupNames()) {
|
|
||||||
Group group = groupManager.find(groupName);
|
|
||||||
if (group != null) {
|
|
||||||
if (!existingGroupNames.contains(groupName)) {
|
|
||||||
Membership membership = new Membership();
|
|
||||||
membership.setGroup(group);
|
|
||||||
membership.setUser(user);
|
|
||||||
membershipManager.save(membership);
|
|
||||||
user.getMemberships().add(membership);
|
|
||||||
existingGroupNames.add(groupName);
|
|
||||||
}
|
|
||||||
retrievedGroupNames.add(groupName);
|
|
||||||
} else {
|
|
||||||
logger.debug("Group '{}' from external authenticator is not defined", groupName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Iterator<Membership> it = user.getMemberships().iterator(); it.hasNext();) {
|
|
||||||
Membership membership = it.next();
|
|
||||||
if (!retrievedGroupNames.contains(membership.getGroup().getName())) {
|
|
||||||
it.remove();
|
|
||||||
membershipManager.delete(membership);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
userManager.save(user);
|
|
||||||
} else {
|
|
||||||
user = new User();
|
|
||||||
user.setName(((UsernamePasswordToken) token).getUsername());
|
|
||||||
user.setPassword("");
|
|
||||||
if (authenticated.getEmail() != null)
|
|
||||||
user.setEmail(authenticated.getEmail());
|
|
||||||
if (authenticated.getFullName() != null)
|
|
||||||
user.setFullName(authenticated.getFullName());
|
|
||||||
userManager.save(user);
|
|
||||||
if (authenticated.getGroupNames().isEmpty()) {
|
|
||||||
for (String groupName: authenticator.getDefaultGroupNames()) {
|
|
||||||
Group group = groupManager.find(groupName);
|
|
||||||
if (group != null) {
|
|
||||||
Membership membership = new Membership();
|
|
||||||
membership.setGroup(group);
|
|
||||||
membership.setUser(user);
|
|
||||||
user.getMemberships().add(membership);
|
|
||||||
membershipManager.save(membership);
|
|
||||||
} else {
|
|
||||||
logger.warn("Default group '{}' of external authenticator is not defined", groupName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
user = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
|
protected final AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
|
||||||
throws AuthenticationException {
|
return transactionManager.call(new Callable<AuthenticationInfo>() {
|
||||||
// transaction annotation can not be applied to final method, so we relay to another method
|
|
||||||
return doGetAuthenticationInfoInTransaction(token);
|
@Override
|
||||||
|
public AuthenticationInfo call() throws Exception {
|
||||||
|
User user = userManager.findByName(((UsernamePasswordToken) token).getUsername());
|
||||||
|
if (user != null && user.isRoot())
|
||||||
|
return user;
|
||||||
|
|
||||||
|
if (user == null || StringUtils.isBlank(user.getPassword())) {
|
||||||
|
Authenticator authenticator = configManager.getAuthenticator();
|
||||||
|
if (authenticator != null) {
|
||||||
|
Authenticated authenticated;
|
||||||
|
try {
|
||||||
|
authenticated = authenticator.authenticate((UsernamePasswordToken) token);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof AuthenticationException) {
|
||||||
|
logger.debug("Authentication not passed", e);
|
||||||
|
throw ExceptionUtils.unchecked(e);
|
||||||
|
} else {
|
||||||
|
logger.error("Error authenticating user", e);
|
||||||
|
throw new AuthenticationException("Error authenticating user", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (user != null) {
|
||||||
|
if (authenticated.getEmail() != null)
|
||||||
|
user.setEmail(authenticated.getEmail());
|
||||||
|
if (authenticated.getFullName() != null)
|
||||||
|
user.setFullName(authenticated.getFullName());
|
||||||
|
|
||||||
|
Collection<String> existingGroupNames = new HashSet<>();
|
||||||
|
for (Membership membership: user.getMemberships())
|
||||||
|
existingGroupNames.add(membership.getGroup().getName());
|
||||||
|
if (!authenticated.getGroupNames().isEmpty()) {
|
||||||
|
Collection<String> retrievedGroupNames = new HashSet<>();
|
||||||
|
for (String groupName: authenticated.getGroupNames()) {
|
||||||
|
Group group = groupManager.find(groupName);
|
||||||
|
if (group != null) {
|
||||||
|
if (!existingGroupNames.contains(groupName)) {
|
||||||
|
Membership membership = new Membership();
|
||||||
|
membership.setGroup(group);
|
||||||
|
membership.setUser(user);
|
||||||
|
membershipManager.save(membership);
|
||||||
|
user.getMemberships().add(membership);
|
||||||
|
existingGroupNames.add(groupName);
|
||||||
|
}
|
||||||
|
retrievedGroupNames.add(groupName);
|
||||||
|
} else {
|
||||||
|
logger.debug("Group '{}' from external authenticator is not defined", groupName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Iterator<Membership> it = user.getMemberships().iterator(); it.hasNext();) {
|
||||||
|
Membership membership = it.next();
|
||||||
|
if (!retrievedGroupNames.contains(membership.getGroup().getName())) {
|
||||||
|
it.remove();
|
||||||
|
membershipManager.delete(membership);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userManager.save(user);
|
||||||
|
} else {
|
||||||
|
user = new User();
|
||||||
|
user.setName(((UsernamePasswordToken) token).getUsername());
|
||||||
|
user.setPassword("");
|
||||||
|
if (authenticated.getEmail() != null)
|
||||||
|
user.setEmail(authenticated.getEmail());
|
||||||
|
if (authenticated.getFullName() != null)
|
||||||
|
user.setFullName(authenticated.getFullName());
|
||||||
|
userManager.save(user);
|
||||||
|
if (authenticated.getGroupNames().isEmpty()) {
|
||||||
|
for (String groupName: authenticator.getDefaultGroupNames()) {
|
||||||
|
Group group = groupManager.find(groupName);
|
||||||
|
if (group != null) {
|
||||||
|
Membership membership = new Membership();
|
||||||
|
membership.setGroup(group);
|
||||||
|
membership.setUser(user);
|
||||||
|
user.getMemberships().add(membership);
|
||||||
|
membershipManager.save(membership);
|
||||||
|
} else {
|
||||||
|
logger.warn("Default group '{}' of external authenticator is not defined", groupName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
user = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,10 +5,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
public class BuildConstants {
|
public class BuildConstants {
|
||||||
|
|
||||||
public static final String ATTR_ID = "id";
|
public static final String ATTR_ID = "id";
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
public class CodeCommentConstants {
|
public class CodeCommentConstants {
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.validation.ValidationException;
|
import javax.validation.ValidationException;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.server.web.editable.annotation.Editable;
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
@Editable(order=1200, name=InputSpec.BUILD)
|
@Editable(order=1200, name=InputSpec.BUILD)
|
||||||
public class BuildChoiceInput extends InputSpec {
|
public class BuildChoiceInput extends InputSpec {
|
||||||
|
|||||||
@ -8,8 +8,9 @@ import javax.validation.ValidationException;
|
|||||||
|
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.server.web.editable.annotation.Editable;
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
@Editable(order=1400, name=InputSpec.COMMIT)
|
@Editable(order=1400, name=InputSpec.COMMIT)
|
||||||
public class CommitInput extends InputSpec {
|
public class CommitInput extends InputSpec {
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.validation.ValidationException;
|
import javax.validation.ValidationException;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.server.web.editable.annotation.Editable;
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
@Editable(order=1100, name=InputSpec.ISSUE)
|
@Editable(order=1100, name=InputSpec.ISSUE)
|
||||||
public class IssueChoiceInput extends InputSpec {
|
public class IssueChoiceInput extends InputSpec {
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.validation.ValidationException;
|
import javax.validation.ValidationException;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.server.web.editable.annotation.Editable;
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
@Editable(order=1000, name=InputSpec.PULLREQUEST)
|
@Editable(order=1000, name=InputSpec.PULLREQUEST)
|
||||||
public class PullRequestChoiceInput extends InputSpec {
|
public class PullRequestChoiceInput extends InputSpec {
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.validation.ValidationException;
|
import javax.validation.ValidationException;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.server.web.editable.annotation.Editable;
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
@Editable(order=500, name=InputSpec.SECRET)
|
@Editable(order=500, name=InputSpec.SECRET)
|
||||||
public class SecretInput extends InputSpec {
|
public class SecretInput extends InputSpec {
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import javax.validation.ValidationException;
|
|||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.server.OneDev;
|
import io.onedev.server.OneDev;
|
||||||
import io.onedev.server.util.Usage;
|
import io.onedev.server.util.Usage;
|
||||||
import io.onedev.server.util.facade.GroupFacade;
|
import io.onedev.server.util.facade.GroupFacade;
|
||||||
@ -18,7 +20,6 @@ import io.onedev.server.util.inputspec.groupchoiceinput.defaultvalueprovider.Def
|
|||||||
import io.onedev.server.util.inputspec.groupchoiceinput.defaultvalueprovider.SpecifiedDefaultValue;
|
import io.onedev.server.util.inputspec.groupchoiceinput.defaultvalueprovider.SpecifiedDefaultValue;
|
||||||
import io.onedev.server.web.editable.annotation.Editable;
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
import io.onedev.server.web.editable.annotation.NameOfEmptyValue;
|
import io.onedev.server.web.editable.annotation.NameOfEmptyValue;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
@Editable(order=160, name=InputSpec.GROUP)
|
@Editable(order=160, name=InputSpec.GROUP)
|
||||||
public class GroupChoiceInput extends InputSpec {
|
public class GroupChoiceInput extends InputSpec {
|
||||||
|
|||||||
@ -6,11 +6,12 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.validation.ValidationException;
|
import javax.validation.ValidationException;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.server.util.inputspec.InputSpec;
|
import io.onedev.server.util.inputspec.InputSpec;
|
||||||
import io.onedev.server.util.inputspec.textinput.defaultvalueprovider.DefaultValueProvider;
|
import io.onedev.server.util.inputspec.textinput.defaultvalueprovider.DefaultValueProvider;
|
||||||
import io.onedev.server.web.editable.annotation.Editable;
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
import io.onedev.server.web.editable.annotation.NameOfEmptyValue;
|
import io.onedev.server.web.editable.annotation.NameOfEmptyValue;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
@Editable(order=100, name=InputSpec.TEXT)
|
@Editable(order=100, name=InputSpec.TEXT)
|
||||||
public class TextInput extends InputSpec {
|
public class TextInput extends InputSpec {
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import java.util.stream.Collectors;
|
|||||||
import javax.validation.ValidationException;
|
import javax.validation.ValidationException;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import io.onedev.server.OneDev;
|
import io.onedev.server.OneDev;
|
||||||
import io.onedev.server.entitymanager.UserManager;
|
import io.onedev.server.entitymanager.UserManager;
|
||||||
import io.onedev.server.util.Usage;
|
import io.onedev.server.util.Usage;
|
||||||
@ -19,7 +21,6 @@ import io.onedev.server.util.inputspec.userchoiceinput.defaultvalueprovider.Defa
|
|||||||
import io.onedev.server.util.inputspec.userchoiceinput.defaultvalueprovider.SpecifiedDefaultValue;
|
import io.onedev.server.util.inputspec.userchoiceinput.defaultvalueprovider.SpecifiedDefaultValue;
|
||||||
import io.onedev.server.web.editable.annotation.Editable;
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
import io.onedev.server.web.editable.annotation.NameOfEmptyValue;
|
import io.onedev.server.web.editable.annotation.NameOfEmptyValue;
|
||||||
import jersey.repackaged.com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
@Editable(order=150, name=InputSpec.USER)
|
@Editable(order=150, name=InputSpec.USER)
|
||||||
public class UserChoiceInput extends InputSpec {
|
public class UserChoiceInput extends InputSpec {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import org.apache.wicket.model.IModel;
|
|||||||
import org.apache.wicket.model.Model;
|
import org.apache.wicket.model.Model;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import io.onedev.commons.utils.StringUtils;
|
import io.onedev.commons.utils.StringUtils;
|
||||||
import io.onedev.server.model.support.issue.TransitionSpec;
|
import io.onedev.server.model.support.issue.TransitionSpec;
|
||||||
@ -42,7 +43,6 @@ import io.onedev.server.web.editable.BeanContext;
|
|||||||
import io.onedev.server.web.editable.EditableUtils;
|
import io.onedev.server.web.editable.EditableUtils;
|
||||||
import io.onedev.server.web.page.layout.SideFloating;
|
import io.onedev.server.web.page.layout.SideFloating;
|
||||||
import io.onedev.server.web.util.ConfirmOnClick;
|
import io.onedev.server.web.util.ConfirmOnClick;
|
||||||
import jersey.repackaged.com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public abstract class StateTransitionListPanel extends Panel {
|
public abstract class StateTransitionListPanel extends Panel {
|
||||||
|
|||||||
@ -25,11 +25,12 @@ import org.apache.wicket.markup.repeater.data.ListDataProvider;
|
|||||||
import org.apache.wicket.model.IModel;
|
import org.apache.wicket.model.IModel;
|
||||||
import org.apache.wicket.model.Model;
|
import org.apache.wicket.model.Model;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import io.onedev.server.ci.JobDependency;
|
import io.onedev.server.ci.JobDependency;
|
||||||
import io.onedev.server.web.editable.BeanContext;
|
import io.onedev.server.web.editable.BeanContext;
|
||||||
import io.onedev.server.web.page.layout.SideFloating;
|
import io.onedev.server.web.page.layout.SideFloating;
|
||||||
import io.onedev.server.web.page.layout.SideFloating.Placement;
|
import io.onedev.server.web.page.layout.SideFloating.Placement;
|
||||||
import jersey.repackaged.com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
class DependencyListViewPanel extends Panel {
|
class DependencyListViewPanel extends Panel {
|
||||||
|
|||||||
@ -41,7 +41,7 @@ import io.onedev.server.web.component.modal.ModalLink;
|
|||||||
import io.onedev.server.web.component.modal.ModalPanel;
|
import io.onedev.server.web.component.modal.ModalPanel;
|
||||||
import io.onedev.server.web.editable.BeanContext;
|
import io.onedev.server.web.editable.BeanContext;
|
||||||
import io.onedev.server.web.page.layout.SideFloating;
|
import io.onedev.server.web.page.layout.SideFloating;
|
||||||
import jersey.repackaged.com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class DefaultBoardListPage extends GlobalIssueSettingPage {
|
public class DefaultBoardListPage extends GlobalIssueSettingPage {
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import io.onedev.server.web.component.modal.ModalPanel;
|
|||||||
import io.onedev.server.web.editable.BeanContext;
|
import io.onedev.server.web.editable.BeanContext;
|
||||||
import io.onedev.server.web.editable.EditableUtils;
|
import io.onedev.server.web.editable.EditableUtils;
|
||||||
import io.onedev.server.web.page.layout.SideFloating;
|
import io.onedev.server.web.page.layout.SideFloating;
|
||||||
import jersey.repackaged.com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class IssueFieldListPage extends GlobalIssueSettingPage {
|
public class IssueFieldListPage extends GlobalIssueSettingPage {
|
||||||
|
|||||||
@ -40,7 +40,7 @@ import io.onedev.server.web.component.modal.ModalLink;
|
|||||||
import io.onedev.server.web.component.modal.ModalPanel;
|
import io.onedev.server.web.component.modal.ModalPanel;
|
||||||
import io.onedev.server.web.editable.BeanContext;
|
import io.onedev.server.web.editable.BeanContext;
|
||||||
import io.onedev.server.web.page.layout.SideFloating;
|
import io.onedev.server.web.page.layout.SideFloating;
|
||||||
import jersey.repackaged.com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class IssueStateListPage extends GlobalIssueSettingPage {
|
public class IssueStateListPage extends GlobalIssueSettingPage {
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import org.apache.wicket.validation.IValidationError;
|
|||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
|
import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
|
||||||
|
import io.onedev.commons.utils.ExceptionUtils;
|
||||||
import io.onedev.commons.utils.StringUtils;
|
import io.onedev.commons.utils.StringUtils;
|
||||||
import io.onedev.server.OneDev;
|
import io.onedev.server.OneDev;
|
||||||
import io.onedev.server.git.BlobIdent;
|
import io.onedev.server.git.BlobIdent;
|
||||||
@ -52,7 +53,6 @@ import io.onedev.server.web.component.tabbable.AjaxActionTab;
|
|||||||
import io.onedev.server.web.component.tabbable.Tab;
|
import io.onedev.server.web.component.tabbable.Tab;
|
||||||
import io.onedev.server.web.component.tabbable.Tabbable;
|
import io.onedev.server.web.component.tabbable.Tabbable;
|
||||||
import io.onedev.server.web.page.project.blob.search.result.SearchResultPanel;
|
import io.onedev.server.web.page.project.blob.search.result.SearchResultPanel;
|
||||||
import jersey.repackaged.com.google.common.base.Throwables;
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public abstract class AdvancedSearchPanel extends Panel {
|
public abstract class AdvancedSearchPanel extends Panel {
|
||||||
@ -82,7 +82,7 @@ public abstract class AdvancedSearchPanel extends Panel {
|
|||||||
try {
|
try {
|
||||||
option = activeTab.newInstance();
|
option = activeTab.newInstance();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Throwables.propagate(e);
|
throw ExceptionUtils.unchecked(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,13 @@
|
|||||||
<artifactId>server-plugin</artifactId>
|
<artifactId>server-plugin</artifactId>
|
||||||
<version>3.0.1</version>
|
<version>3.0.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.onedev</groupId>
|
||||||
|
<artifactId>k8s-helper</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
<properties>
|
<properties>
|
||||||
<moduleClass>io.onedev.server.plugin.kubernetes.KubernetesModule</moduleClass>
|
<moduleClass>io.onedev.server.plugin.kubernetes.KubernetesModule</moduleClass>
|
||||||
</properties>
|
</properties>
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import io.onedev.commons.utils.command.Commandline;
|
|||||||
import io.onedev.commons.utils.command.ExecuteResult;
|
import io.onedev.commons.utils.command.ExecuteResult;
|
||||||
import io.onedev.commons.utils.command.LineConsumer;
|
import io.onedev.commons.utils.command.LineConsumer;
|
||||||
import io.onedev.server.OneException;
|
import io.onedev.server.OneException;
|
||||||
import io.onedev.server.model.support.JobExecutionContext;
|
import io.onedev.server.model.support.JobContext;
|
||||||
import io.onedev.server.model.support.JobExecutor;
|
import io.onedev.server.model.support.JobExecutor;
|
||||||
import io.onedev.server.plugin.kubernetes.KubernetesExecutor.TestData;
|
import io.onedev.server.plugin.kubernetes.KubernetesExecutor.TestData;
|
||||||
import io.onedev.server.web.editable.annotation.Editable;
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
@ -125,9 +125,9 @@ public class KubernetesExecutor extends JobExecutor implements Testable<TestData
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(JobExecutionContext context) {
|
public void execute(String jobId, JobContext context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkCaches() {
|
public void checkCaches() {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,113 @@
|
|||||||
|
package io.onedev.server.plugin.kubernetes;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.SystemUtils;
|
||||||
|
|
||||||
|
import io.onedev.commons.utils.FileUtils;
|
||||||
|
import io.onedev.commons.utils.command.Commandline;
|
||||||
|
import io.onedev.commons.utils.command.LineConsumer;
|
||||||
|
import io.onedev.k8shelper.KubernetesHelper;
|
||||||
|
import io.onedev.server.OneDev;
|
||||||
|
import io.onedev.server.entitymanager.SettingManager;
|
||||||
|
import io.onedev.server.model.support.JobContext;
|
||||||
|
import io.onedev.server.model.support.JobExecutor;
|
||||||
|
import io.onedev.server.web.editable.annotation.Editable;
|
||||||
|
|
||||||
|
@Editable(order=400)
|
||||||
|
public class KubernetesHelperTester extends JobExecutor {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(String jobId, JobContext context) {
|
||||||
|
context.notifyJobRunning();
|
||||||
|
|
||||||
|
SettingManager settingManager = OneDev.getInstance(SettingManager.class);
|
||||||
|
String serverUrl = settingManager.getSystemSetting().getServerUrl();
|
||||||
|
|
||||||
|
File workspace = FileUtils.createTempDir("k8s-workspace");
|
||||||
|
try {
|
||||||
|
KubernetesHelper.init(serverUrl, jobId, workspace);
|
||||||
|
|
||||||
|
Future<?> sidecar = OneDev.getInstance(ExecutorService.class).submit(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
KubernetesHelper.sidecar(serverUrl, jobId, workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
Commandline cmd;
|
||||||
|
if (SystemUtils.IS_OS_WINDOWS) {
|
||||||
|
File scriptFile = new File(workspace, "onedev-job-commands.bat");
|
||||||
|
try {
|
||||||
|
FileUtils.writeLines(scriptFile, context.getCommands(), "\r\n");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
cmd = new Commandline("cmd");
|
||||||
|
cmd.addArgs("/c", scriptFile.getAbsolutePath());
|
||||||
|
} else {
|
||||||
|
File scriptFile = new File(workspace, "onedev-job-commands.sh");
|
||||||
|
try {
|
||||||
|
FileUtils.writeLines(scriptFile, context.getCommands(), "\n");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
cmd = new Commandline("sh");
|
||||||
|
cmd.addArgs(scriptFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
cmd.workingDir(workspace);
|
||||||
|
cmd.environments(context.getEnvVars());
|
||||||
|
cmd.execute(new LineConsumer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void consume(String line) {
|
||||||
|
context.getLogger().info(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, new LineConsumer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void consume(String line) {
|
||||||
|
context.getLogger().error(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
}).checkReturnCode();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
new File(workspace, KubernetesHelper.JOB_FINISH_FILE).createNewFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
sidecar.get();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
sidecar.cancel(true);
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
FileUtils.deleteDir(workspace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkCaches() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanDir(File dir) {
|
||||||
|
FileUtils.cleanDir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,11 +2,15 @@ package io.onedev.server.plugin.kubernetes;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.glassfish.jersey.server.ResourceConfig;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import io.onedev.commons.launcher.bootstrap.Bootstrap;
|
||||||
import io.onedev.commons.launcher.loader.AbstractPluginModule;
|
import io.onedev.commons.launcher.loader.AbstractPluginModule;
|
||||||
import io.onedev.commons.launcher.loader.ImplementationProvider;
|
import io.onedev.commons.launcher.loader.ImplementationProvider;
|
||||||
import io.onedev.server.model.support.JobExecutor;
|
import io.onedev.server.model.support.JobExecutor;
|
||||||
|
import io.onedev.server.rest.jersey.JerseyConfigurator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE: Do not forget to rename moduleClass property defined in the pom if you've renamed this class.
|
* NOTE: Do not forget to rename moduleClass property defined in the pom if you've renamed this class.
|
||||||
@ -28,10 +32,23 @@ public class KubernetesModule extends AbstractPluginModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Class<?>> getImplementations() {
|
public Collection<Class<?>> getImplementations() {
|
||||||
return Sets.newHashSet(KubernetesExecutor.class);
|
Collection<Class<?>> implementations = Sets.newHashSet(KubernetesExecutor.class);
|
||||||
|
if (Bootstrap.sandboxMode)
|
||||||
|
implementations.add(KubernetesHelperTester.class);
|
||||||
|
return implementations;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
contribute(JerseyConfigurator.class, new JerseyConfigurator() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(ResourceConfig resourceConfig) {
|
||||||
|
resourceConfig.register(KubernetesResource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,97 @@
|
|||||||
|
package io.onedev.server.plugin.kubernetes;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.StreamingOutput;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import io.onedev.commons.utils.TarUtils;
|
||||||
|
import io.onedev.server.OneException;
|
||||||
|
import io.onedev.server.ci.job.JobManager;
|
||||||
|
import io.onedev.server.model.support.JobContext;
|
||||||
|
|
||||||
|
@Path("/k8s")
|
||||||
|
@Consumes(MediaType.WILDCARD)
|
||||||
|
@Singleton
|
||||||
|
public class KubernetesResource {
|
||||||
|
|
||||||
|
private final JobManager jobManager;
|
||||||
|
|
||||||
|
@Context
|
||||||
|
private HttpServletRequest request;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public KubernetesResource(JobManager jobManager) {
|
||||||
|
this.jobManager = jobManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/job-context")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@GET
|
||||||
|
public Map<String, Object> getJobContextAsMap() {
|
||||||
|
JobContext context = getJobContext();
|
||||||
|
Map<String, Object> contextMap = new HashMap<>();
|
||||||
|
contextMap.put("commands", context.getCommands());
|
||||||
|
contextMap.put("cloneSource", context.isCloneSource());
|
||||||
|
contextMap.put("projectName", context.getProjectName());
|
||||||
|
contextMap.put("commitHash", context.getCommitId().name());
|
||||||
|
contextMap.put("collectFiles.includes", context.getCollectFiles().getIncludes());
|
||||||
|
contextMap.put("collectFiles.excludes", context.getCollectFiles().getExcludes());
|
||||||
|
|
||||||
|
return contextMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/download-dependencies")
|
||||||
|
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
@GET
|
||||||
|
public Response downloadDependencies() {
|
||||||
|
StreamingOutput os = new StreamingOutput() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(OutputStream output) throws IOException {
|
||||||
|
JobContext context = getJobContext();
|
||||||
|
TarUtils.tar(context.getServerWorkspace(), Lists.newArrayList("**"), new ArrayList<>(), output);
|
||||||
|
output.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return Response.ok(os).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/upload-outcomes")
|
||||||
|
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
public Response uploadOutcomes(InputStream is) {
|
||||||
|
JobContext context = getJobContext();
|
||||||
|
TarUtils.untar(is, context.getServerWorkspace());
|
||||||
|
return Response.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JobContext getJobContext() {
|
||||||
|
String jobId = request.getHeader(JobManager.JOB_ID_HTTP_HEADER);
|
||||||
|
if (jobId == null)
|
||||||
|
throw new OneException("Http header '" + JobManager.JOB_ID_HTTP_HEADER + "' is expected");
|
||||||
|
JobContext context = jobManager.getJobContext(jobId);
|
||||||
|
if (context == null)
|
||||||
|
throw new OneException("No job context found for specified job id");
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -37,7 +37,7 @@ import io.onedev.server.ci.job.cache.CacheAllocation;
|
|||||||
import io.onedev.server.ci.job.cache.CacheCallable;
|
import io.onedev.server.ci.job.cache.CacheCallable;
|
||||||
import io.onedev.server.ci.job.cache.CacheRunner;
|
import io.onedev.server.ci.job.cache.CacheRunner;
|
||||||
import io.onedev.server.ci.job.cache.JobCache;
|
import io.onedev.server.ci.job.cache.JobCache;
|
||||||
import io.onedev.server.model.support.JobExecutionContext;
|
import io.onedev.server.model.support.JobContext;
|
||||||
import io.onedev.server.model.support.JobExecutor;
|
import io.onedev.server.model.support.JobExecutor;
|
||||||
import io.onedev.server.plugin.serverdocker.ServerDockerExecutor.TestData;
|
import io.onedev.server.plugin.serverdocker.ServerDockerExecutor.TestData;
|
||||||
import io.onedev.server.util.OneContext;
|
import io.onedev.server.util.OneContext;
|
||||||
@ -159,7 +159,7 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(JobExecutionContext context) {
|
public void execute(String jobId, JobContext context) {
|
||||||
getCapacityRunner().call(new Callable<Void>() {
|
getCapacityRunner().call(new Callable<Void>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -204,16 +204,16 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File effectiveWorkspace = workspaceCache != null? workspaceCache: context.getWorkspace();
|
File effectiveWorkspace = workspaceCache != null? workspaceCache: context.getServerWorkspace();
|
||||||
|
|
||||||
if (context.getSnapshot() != null) {
|
if (context.isCloneSource()) {
|
||||||
logger.info("Cloning source code...");
|
logger.info("Cloning source code...");
|
||||||
context.getSnapshot().checkout(effectiveWorkspace);
|
context.checkoutSource(effectiveWorkspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workspaceCache != null) {
|
if (workspaceCache != null) {
|
||||||
try {
|
try {
|
||||||
FileUtils.copyDirectory(context.getWorkspace(), workspaceCache);
|
FileUtils.copyDirectory(context.getServerWorkspace(), workspaceCache);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -267,7 +267,7 @@ public class ServerDockerExecutor extends JobExecutor implements Testable<TestDa
|
|||||||
int baseLen = workspaceCache.getAbsolutePath().length()+1;
|
int baseLen = workspaceCache.getAbsolutePath().length()+1;
|
||||||
for (File file: context.getCollectFiles().listFiles(workspaceCache)) {
|
for (File file: context.getCollectFiles().listFiles(workspaceCache)) {
|
||||||
try {
|
try {
|
||||||
FileUtils.copyFile(file, new File(context.getWorkspace(), file.getAbsolutePath().substring(baseLen)));
|
FileUtils.copyFile(file, new File(context.getServerWorkspace(), file.getAbsolutePath().substring(baseLen)));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,7 +118,6 @@ public class ProductServletConfigurator implements ServletConfigurator {
|
|||||||
|
|
||||||
ServletHolder jerseyServletHolder = new ServletHolder(jerseyServlet);
|
ServletHolder jerseyServletHolder = new ServletHolder(jerseyServlet);
|
||||||
context.addServlet(jerseyServletHolder, "/rest/*");
|
context.addServlet(jerseyServletHolder, "/rest/*");
|
||||||
context.addServlet(jerseyServletHolder, "/api/v3/*"); // GitHub api compatible
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user