Skip to content

Commit cc2677e

Browse files
committed
chore: Improvements, bugfixes and translations
1 parent 45975fd commit cc2677e

27 files changed

Lines changed: 875 additions & 626 deletions

server-core/src/main/java/io/onedev/server/model/support/administration/SystemSetting.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ public void setAvatarServiceUrl(String avatarServiceUrl) {
201201
this.avatarServiceUrl = avatarServiceUrl;
202202
}
203203

204-
@Editable(order=700, name="Default Fork Root", placeholder="No fork root", description="""
204+
@Editable(order=700, name="Default Fork Root", placeholder="No default fork root", description="""
205205
When forking from the UI, the default target project will be created as
206206
<default fork root>/<account name>/<project name> if specified
207207
(users forking need permission to create child projects under the fork

server-core/src/main/java/io/onedev/server/service/IssueService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,6 @@ List<Issue> query(Subject subject, @Nullable ProjectScope projectScope, EntityQu
105105

106106
String suggestBranch(Issue issue);
107107

108+
String ensureBranch(Subject subject, Issue issue);
109+
108110
}

server-core/src/main/java/io/onedev/server/service/impl/DefaultIssueService.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import java.io.ObjectStreamException;
99
import java.io.Serializable;
10+
import java.text.MessageFormat;
1011
import java.util.ArrayList;
1112
import java.util.Collection;
1213
import java.util.Date;
@@ -29,9 +30,11 @@
2930
import javax.persistence.criteria.Root;
3031
import javax.persistence.criteria.Subquery;
3132

33+
import org.apache.shiro.authz.UnauthorizedException;
3234
import org.apache.shiro.subject.Subject;
3335
import org.eclipse.jgit.lib.ObjectId;
3436
import org.eclipse.jgit.lib.Repository;
37+
import org.eclipse.jgit.revwalk.RevCommit;
3538
import org.hibernate.criterion.Order;
3639
import org.hibernate.criterion.Restrictions;
3740
import org.hibernate.query.Query;
@@ -66,7 +69,9 @@
6669
import io.onedev.server.event.project.issue.IssuesDeleted;
6770
import io.onedev.server.event.project.issue.IssuesMoved;
6871
import io.onedev.server.event.system.SystemStarting;
72+
import io.onedev.server.exception.NotAcceptableException;
6973
import io.onedev.server.git.GitUtils;
74+
import io.onedev.server.git.service.GitService;
7075
import io.onedev.server.model.AbstractEntity;
7176
import io.onedev.server.model.Issue;
7277
import io.onedev.server.model.IssueAuthorization;
@@ -169,6 +174,9 @@ public class DefaultIssueService extends BaseEntityService<Issue> implements Iss
169174

170175
@Inject
171176
private IssueTouchService touchService;
177+
178+
@Inject
179+
private GitService gitService;
172180

173181
private SequenceGenerator numberGenerator;
174182

@@ -1381,4 +1389,32 @@ public String suggestBranch(Issue issue) {
13811389
}
13821390
}
13831391

1392+
@Override
1393+
public String ensureBranch(Subject subject, Issue issue) {
1394+
if (issue.getBranch() != null)
1395+
return issue.getBranch();
1396+
1397+
Project project = issue.getProject();
1398+
String suggestedBranch = suggestBranch(issue);
1399+
1400+
if (!SecurityUtils.canCreateBranch(project, suggestedBranch))
1401+
throw new UnauthorizedException("No permission to create branch: " + suggestedBranch);
1402+
1403+
if (project.getBranchRef(suggestedBranch) != null) {
1404+
throw new NotAcceptableException(MessageFormat.format("Branch \"{0}\" already exists", suggestedBranch));
1405+
} else {
1406+
String defaultBranch = project.getDefaultBranch();
1407+
if (defaultBranch == null) {
1408+
throw new NotAcceptableException("Default branch is not available");
1409+
} else {
1410+
RevCommit commit = project.getRevCommit(defaultBranch, true);
1411+
if (!project.isCommitSignatureRequirementSatisfied(SecurityUtils.getUser(subject), suggestedBranch, commit)) {
1412+
throw new NotAcceptableException("Valid signature required for head commit of this branch per branch protection rule");
1413+
} else {
1414+
gitService.createBranch(project, suggestedBranch, defaultBranch);
1415+
return suggestedBranch;
1416+
}
1417+
}
1418+
}
1419+
}
13841420
}

server-core/src/main/java/io/onedev/server/web/component/issue/list/IssueListPanel.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
<a wicket:id="copy" t:data-tippy-content="Copy issue number and title" class="copy mr-2 btn btn-icon btn-xs btn-light btn-hover-primary">
6161
<wicket:svg href="copy" class="icon"/>
6262
</a>
63+
<a wicket:id="workspaces" class="workspaces mr-2 btn btn-icon btn-xs btn-light btn-hover-primary" t:data-tippy-content="Workspaces on this issue"><wicket:svg href="workspace" class="icon"/></a>
6364
<a wicket:id="pin" t:data-tippy-content="Pin this issue" class="pin mr-2 btn btn-icon btn-xs btn-light btn-hover-primary">
6465
<wicket:svg href="pin" class="icon"/>
6566
</a>

server-core/src/main/java/io/onedev/server/web/component/issue/list/IssueListPanel.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.text.MessageFormat;
1515
import java.util.ArrayList;
1616
import java.util.Collection;
17+
import java.util.HashMap;
1718
import java.util.HashSet;
1819
import java.util.Iterator;
1920
import java.util.LinkedHashMap;
@@ -143,6 +144,7 @@
143144
import io.onedev.server.web.component.user.ident.Mode;
144145
import io.onedev.server.web.component.user.ident.UserIdentPanel;
145146
import io.onedev.server.web.component.watchstatus.WatchStatusPanel;
147+
import io.onedev.server.web.component.workspace.speclist.WorkspaceSpecListPanel;
146148
import io.onedev.server.web.editable.BeanContext;
147149
import io.onedev.server.web.page.project.issues.create.NewIssuePage;
148150
import io.onedev.server.web.page.project.issues.imports.IssueImportPage;
@@ -183,6 +185,8 @@ protected IssueQuery load() {
183185

184186
private boolean querySubmitted = true;
185187

188+
private transient Map<Long, Boolean> canCreateWorkspaceCache = new HashMap<>();
189+
186190
public IssueListPanel(String id, IModel<String> queryModel) {
187191
super(id);
188192
this.queryStringModel = queryModel;
@@ -1959,6 +1963,41 @@ protected Issue getIssue() {
19591963
fragment.add(new CopyToClipboardLink("copy",
19601964
Model.of(issue.getTitle() + " (" + issue.getReference().toString(getProject()) + ")")));
19611965

1966+
fragment.add(new DropdownLink("workspaces") {
1967+
1968+
@Override
1969+
protected Component newContent(String id, FloatingPanel dropdown) {
1970+
return new WorkspaceSpecListPanel(id) {
1971+
1972+
@Override
1973+
protected Project getProject() {
1974+
return getIssue().getProject();
1975+
}
1976+
1977+
@Override
1978+
protected String getBranch(boolean createIfNotExist) {
1979+
if (createIfNotExist)
1980+
return getIssueService().ensureBranch(SecurityUtils.getSubject(), getIssue());
1981+
else
1982+
return getIssue().getBranch();
1983+
}
1984+
1985+
private Issue getIssue() {
1986+
return (Issue) fragment.getDefaultModelObject();
1987+
}
1988+
1989+
};
1990+
}
1991+
1992+
@Override
1993+
protected void onConfigure() {
1994+
super.onConfigure();
1995+
var issue = (Issue) fragment.getDefaultModelObject();
1996+
setVisible(canCreateWorkspace(issue.getProject()));
1997+
}
1998+
1999+
});
2000+
19622001
fragment.add(new AjaxLink<Void>("pin") {
19632002

19642003
@Override
@@ -2222,6 +2261,13 @@ protected void onBatchUpdated(AjaxRequestTarget target) {
22222261

22232262
protected void onBatchDeleted(AjaxRequestTarget target) {
22242263
}
2264+
2265+
private boolean canCreateWorkspace(Project project) {
2266+
if (canCreateWorkspaceCache == null)
2267+
canCreateWorkspaceCache = new HashMap<>();
2268+
return canCreateWorkspaceCache.computeIfAbsent(project.getId(), it ->
2269+
SecurityUtils.canWriteCode(project) && !project.getHierarchyWorkspaceSpecs().isEmpty());
2270+
}
22252271

22262272
@Override
22272273
public void renderHead(IHeaderResponse response) {

server-core/src/main/java/io/onedev/server/web/component/issue/operation/IssueOperationsPanel.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.util.Collection;
44

5+
import javax.inject.Inject;
6+
57
import org.apache.wicket.Component;
68
import org.apache.wicket.markup.head.CssHeaderItem;
79
import org.apache.wicket.markup.head.IHeaderResponse;
@@ -14,6 +16,7 @@
1416
import io.onedev.server.model.Issue;
1517
import io.onedev.server.model.Project;
1618
import io.onedev.server.security.SecurityUtils;
19+
import io.onedev.server.service.IssueService;
1720
import io.onedev.server.web.behavior.ChangeObserver;
1821
import io.onedev.server.web.component.floating.FloatingPanel;
1922
import io.onedev.server.web.component.issue.IssueStateBadge;
@@ -23,6 +26,9 @@
2326

2427
public abstract class IssueOperationsPanel extends Panel {
2528

29+
@Inject
30+
private IssueService issueService;
31+
2632
public IssueOperationsPanel(String id) {
2733
super(id);
2834
}
@@ -43,21 +49,28 @@ protected Issue getIssue() {
4349

4450
@Override
4551
protected Component newContent(String id, FloatingPanel dropdown) {
46-
return new WorkspaceSpecListPanel(id, getIssue().getBranch()) {
52+
return new WorkspaceSpecListPanel(id) {
4753

4854
@Override
4955
protected Project getProject() {
5056
return getIssue().getProject();
5157
}
5258

59+
@Override
60+
protected String getBranch(boolean createIfNotExist) {
61+
if (createIfNotExist)
62+
return issueService.ensureBranch(SecurityUtils.getSubject(), getIssue());
63+
else
64+
return getIssue().getBranch();
65+
}
66+
5367
};
5468
}
5569

5670
@Override
5771
protected void onConfigure() {
5872
super.onConfigure();
5973
setVisible(SecurityUtils.canWriteCode(getIssue().getProject())
60-
&& getIssue().getBranch() != null
6174
&& !getIssue().getProject().getHierarchyWorkspaceSpecs().isEmpty());
6275
}
6376

server-core/src/main/java/io/onedev/server/web/component/issue/side/IssueSidePanel.java

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,13 @@
4343
import org.apache.wicket.model.LoadableDetachableModel;
4444
import org.apache.wicket.model.PropertyModel;
4545
import org.apache.wicket.request.mapper.parameter.PageParameters;
46-
import org.eclipse.jgit.revwalk.RevCommit;
4746

4847
import com.google.common.collect.Lists;
4948

49+
import io.onedev.commons.utils.ExplicitException;
5050
import io.onedev.server.OneDev;
5151
import io.onedev.server.buildspecmodel.inputspec.Input;
5252
import io.onedev.server.entityreference.EntityReference;
53-
import io.onedev.server.git.service.GitService;
5453
import io.onedev.server.model.AbstractEntity;
5554
import io.onedev.server.model.Issue;
5655
import io.onedev.server.model.IssueVote;
@@ -100,9 +99,6 @@ public abstract class IssueSidePanel extends Panel {
10099
@Inject
101100
private IssueService issueService;
102101

103-
@Inject
104-
private GitService gitService;
105-
106102
private boolean confidential;
107103

108104
private Component watchesContainer;
@@ -430,28 +426,11 @@ protected void onConfigure() {
430426

431427
@Override
432428
public void onClick(AjaxRequestTarget target) {
433-
User user = SecurityUtils.getAuthUser();
434-
if (user == null)
435-
throw new RestartResponseAtInterceptPageException(LoginPage.class);
436-
437-
Project project = getProject();
438-
String suggestedBranch = issueService.suggestBranch(getIssue());
439-
440-
if (project.getBranchRef(suggestedBranch) != null) {
441-
getSession().error(MessageFormat.format(_T("Branch \"{0}\" already exists"), suggestedBranch));
442-
} else {
443-
String defaultBranch = project.getDefaultBranch();
444-
if (defaultBranch == null) {
445-
getSession().error(_T("Default branch is not available"));
446-
} else {
447-
RevCommit commit = project.getRevCommit(defaultBranch, true);
448-
if (!project.isCommitSignatureRequirementSatisfied(user, suggestedBranch, commit)) {
449-
getSession().error(_T("Valid signature required for head commit of this branch per branch protection rule"));
450-
} else {
451-
gitService.createBranch(project, suggestedBranch, defaultBranch);
452-
getSession().success(MessageFormat.format(_T("Branch \"{0}\" created"), suggestedBranch));
453-
}
454-
}
429+
try {
430+
var branch = issueService.ensureBranch(SecurityUtils.getSubject(), getIssue());
431+
getSession().success(MessageFormat.format(_T("Branch \"{0}\" created"), branch));
432+
} catch (ExplicitException e) {
433+
getSession().error(e.getMessage());
455434
}
456435
target.add(IssueSidePanel.this);
457436
onBranchCreated(target);

server-core/src/main/java/io/onedev/server/web/component/workspace/CreateWorkspaceLink.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,19 @@ public abstract class CreateWorkspaceLink extends AjaxLink<Void> {
1616
@Inject
1717
private WorkspaceService workspaceService;
1818

19-
private final String branch;
20-
21-
public CreateWorkspaceLink(String componentId, String branch) {
19+
public CreateWorkspaceLink(String componentId) {
2220
super(componentId);
23-
this.branch = branch;
2421
}
2522

2623
protected abstract Project getProject();
2724

25+
protected abstract String getBranch();
26+
2827
protected abstract WorkspaceSpec getSpec();
2928

3029
@Override
3130
public void onClick(AjaxRequestTarget target) {
32-
var workspace = workspaceService.create(SecurityUtils.getUser(), getProject(), branch, getSpec().getName());
31+
var workspace = workspaceService.create(SecurityUtils.getUser(), getProject(), getBranch(), getSpec().getName());
3332
setResponsePage(WorkspaceDashboardPage.class, WorkspaceDashboardPage.paramsOf(workspace));
3433
}
3534

0 commit comments

Comments
 (0)