Skip to content

Commit 2d08a15

Browse files
committed
Allow SCM browser re-use across jobs
1 parent d236738 commit 2d08a15

File tree

6 files changed

+226
-17
lines changed

6 files changed

+226
-17
lines changed

src/main/java/hudson/scm/AbstractCvsDescriptor.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* The MIT License
33
*
4-
* Copyright (c) 2012, Michael Clarke
4+
* Copyright (c) 2012-2013, Michael Clarke
55
*
66
* Permission is hereby granted, free of charge, to any person obtaining a copy
77
* of this software and associated documentation files (the "Software"), to deal
@@ -23,9 +23,14 @@
2323
*/
2424
package hudson.scm;
2525

26-
public abstract class AbstractCvsDescriptor<T extends SCM> extends SCMDescriptor<T> implements ICvsDescriptor{
26+
public abstract class AbstractCvsDescriptor<T extends AbstractCvs> extends SCMDescriptor<T> implements ICvsDescriptor{
2727

2828
public AbstractCvsDescriptor(Class<? extends RepositoryBrowser<? extends ChangeLogSet.Entry>> clazz) {
2929
super(clazz);
3030
}
31+
32+
@Override
33+
public boolean isBrowserReusable(T x, T y) {
34+
return true;
35+
}
3136
}

src/main/java/hudson/scm/CVSSCM.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ public static class DescriptorImpl extends AbstractCvsDescriptor<CVSSCM> impleme
377377
private transient String cvsPassFile;
378378
@SuppressWarnings("unused")
379379
private transient String cvsExe;
380+
@SuppressWarnings("unused")
380381
private transient boolean noCompression;
381382

382383
private class RepositoryBrowser {
@@ -505,11 +506,6 @@ public boolean configure(final StaplerRequest req, final JSONObject o) {
505506
return true;
506507
}
507508

508-
@Override
509-
public boolean isBrowserReusable(final CVSSCM x, final CVSSCM y) {
510-
return false;
511-
}
512-
513509
/**
514510
* Returns all {@code CVSROOT} strings used in the current Jenkins
515511
* installation.

src/main/java/hudson/scm/browsers/CvsFacadeRepositoryBrowser.java

+81-2
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,28 @@
2424
package hudson.scm.browsers;
2525

2626
import hudson.Extension;
27+
import hudson.model.AbstractProject;
2728
import hudson.model.Descriptor;
29+
import hudson.model.Hudson;
30+
import hudson.scm.AbstractCvs;
2831
import hudson.scm.CVSChangeLogSet;
2932
import hudson.scm.CVSRepositoryBrowser;
33+
import hudson.scm.CvsRepository;
3034
import hudson.scm.RepositoryBrowser;
35+
import hudson.scm.SCM;
36+
import org.netbeans.lib.cvsclient.CVSRoot;
37+
import org.netbeans.lib.cvsclient.connection.Connection;
38+
import org.netbeans.lib.cvsclient.connection.ConnectionFactory;
3139

3240
import java.io.IOException;
3341
import java.net.URL;
42+
import java.util.HashMap;
43+
import java.util.Map;
3444

3545
public class CvsFacadeRepositoryBrowser extends CVSRepositoryBrowser {
3646

3747
private final CVSRepositoryBrowser legacyBrowser;
48+
private final transient Map<CVSChangeLogSet.CVSChangeLog, CVSRepositoryBrowser> changeToBrowserMap = new HashMap<CVSChangeLogSet.CVSChangeLog, CVSRepositoryBrowser>();
3849

3950
public CvsFacadeRepositoryBrowser(CVSRepositoryBrowser legacyBrowser) {
4051
super();
@@ -76,11 +87,79 @@ public URL getChangeSetLink(CVSChangeLogSet.CVSChangeLog changeSet) throws IOExc
7687
return browser.getChangeSetLink(changeSet);
7788
}
7889

79-
private CVSRepositoryBrowser resolveRepositoryBrowser(CVSChangeLogSet.CVSChangeLog changelog) {
90+
protected CVSRepositoryBrowser resolveRepositoryBrowser(CVSChangeLogSet.CVSChangeLog changelog) {
91+
synchronized (changeToBrowserMap) {
92+
if (!changeToBrowserMap.containsKey(changelog)) {
93+
changeToBrowserMap.put(changelog, calculateRepositoryBrowser(changelog));
94+
}
95+
}
96+
return changeToBrowserMap.get(changelog);
97+
}
98+
99+
private CVSRepositoryBrowser calculateRepositoryBrowser(CVSChangeLogSet.CVSChangeLog changelog) {
100+
80101
if (changelog.getRepository() == null) {
81102
return legacyBrowser;
103+
}
104+
105+
CVSRepositoryBrowser browser = changelog.getRepository().getRepositoryBrowser();
106+
107+
if (browser != null) {
108+
return browser;
109+
}
110+
111+
for (AbstractProject<?, ?> p : Hudson.getInstance().getAllItems(AbstractProject.class)) {
112+
SCM scm = p.getScm();
113+
if (scm instanceof AbstractCvs) {
114+
AbstractCvs cvs = (AbstractCvs) scm;
115+
for (CvsRepository repository : cvs.getRepositories()) {
116+
if (repository.getRepositoryBrowser() != null
117+
&& equals(CVSRoot.parse(repository.getCvsRoot()), CVSRoot.parse(changelog.getRepository().getCvsRoot()))) {
118+
return repository.getRepositoryBrowser();
119+
}
120+
}
121+
}
122+
}
123+
124+
return null;
125+
}
126+
127+
private static boolean equals(CVSRoot root1, CVSRoot root2) {
128+
return toString(root1).equals(toString(root2));
129+
}
130+
131+
private static String toString(CVSRoot root) {
132+
133+
if (root.getHostName() == null) {
134+
if (root.getMethod() == null) {
135+
return root.getRepository();
136+
}
137+
138+
return ":" + root.getMethod() + ":" + root.getRepository();
82139
} else {
83-
return changelog.getRepository().getRepositoryBrowser();
140+
141+
final StringBuilder buf = new StringBuilder();
142+
143+
if (root.getMethod() != null) {
144+
buf.append(':');
145+
buf.append(root.getMethod());
146+
buf.append(':');
147+
}
148+
149+
// hostname
150+
buf.append(root.getHostName());
151+
buf.append(':');
152+
153+
// port
154+
Connection connection = ConnectionFactory.getConnection(root);
155+
if (connection.getPort() > 0) {
156+
buf.append(connection.getPort());
157+
}
158+
159+
// repository
160+
buf.append(root.getRepository());
161+
162+
return buf.toString();
84163
}
85164
}
86165

src/test/java/hudson/scm/CVSSCMTest.java

-8
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,6 @@ public class CVSSCMTest {
4949
@Rule
5050
public VisibleJenkinsRule jenkinsRule = new VisibleJenkinsRule();
5151

52-
53-
//we have to create an inner class since createFreeStyleProject is protected in early versions of JenkinsRule
54-
private static class VisibleJenkinsRule extends JenkinsRule {
55-
public FreeStyleProject createFreeStyleProject() throws IOException {
56-
return super.createFreeStyleProject();
57-
}
58-
}
59-
6052
/**
6153
* Verifies that there's no data loss.
6254
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package hudson.scm;
2+
3+
import hudson.model.FreeStyleProject;
4+
import org.jvnet.hudson.test.JenkinsRule;
5+
6+
import java.io.IOException;
7+
8+
public class VisibleJenkinsRule extends JenkinsRule {
9+
public FreeStyleProject createFreeStyleProject() throws IOException {
10+
return super.createFreeStyleProject();
11+
}
12+
13+
public FreeStyleProject createFreeStyleProject(String name) throws IOException {
14+
return super.createFreeStyleProject(name);
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package hudson.scm.browsers;
2+
3+
import hudson.model.FreeStyleProject;
4+
import hudson.scm.CVSChangeLogSet;
5+
import hudson.scm.CVSSCM;
6+
import hudson.scm.CvsModule;
7+
import hudson.scm.CvsRepository;
8+
import hudson.scm.CvsRepositoryItem;
9+
import hudson.scm.CvsRepositoryLocation;
10+
import hudson.scm.ExcludedRegion;
11+
import hudson.scm.VisibleJenkinsRule;
12+
import org.junit.Before;
13+
import org.junit.Rule;
14+
import org.junit.Test;
15+
16+
import java.io.IOException;
17+
import java.net.MalformedURLException;
18+
import java.net.URL;
19+
import java.util.ArrayList;
20+
import java.util.Arrays;
21+
import java.util.List;
22+
23+
import static org.junit.Assert.assertNull;
24+
import static org.junit.Assert.assertSame;
25+
26+
public class CvsFacadeRepositoryBrowserTest {
27+
28+
@Rule
29+
public VisibleJenkinsRule jenkinsRule = new VisibleJenkinsRule();
30+
31+
private CvsFacadeRepositoryBrowser testCase;
32+
33+
@Before
34+
public void setUp() {
35+
testCase = new CvsFacadeRepositoryBrowser();
36+
}
37+
38+
@Test
39+
public void testResolveBrowser() throws MalformedURLException {
40+
ViewCVS browser = new ViewCVS(new URL("http://localhost/viewcvs/viewcvs.cgi?cvsroot=repo"));
41+
CvsRepository repository = new CvsRepository(":pserver:host:port/path/to/repo", false, null, new ArrayList<CvsRepositoryItem>(), new ArrayList<ExcludedRegion>(), -1, browser);
42+
43+
CVSChangeLogSet.CVSChangeLog changelog = new CVSChangeLogSet.CVSChangeLog();
44+
changelog.setRepository(repository);
45+
assertSame(browser, testCase.resolveRepositoryBrowser(changelog));
46+
}
47+
48+
@Test
49+
public void testResolveOldFile() throws MalformedURLException {
50+
CVSChangeLogSet.CVSChangeLog changelog = new CVSChangeLogSet.CVSChangeLog();
51+
assertNull(testCase.resolveRepositoryBrowser(changelog));
52+
}
53+
54+
@Test
55+
public void testResolveParameterisedRepository() throws IOException {
56+
ViewCVS browser = new ViewCVS(new URL("http://localhost/viewcvs/viewcvs.cgi?cvsroot=repo"));
57+
FreeStyleProject p = jenkinsRule.createFreeStyleProject();
58+
p = jenkinsRule.createFreeStyleProject("useful project");
59+
p.setScm(new CVSSCM(Arrays.asList(new CvsRepository(":pserver:user@host:${otherPort}/path/to/repo", false, null, new ArrayList<CvsRepositoryItem>(), new ArrayList<ExcludedRegion>(), -1, browser)), false, false, false, false, false, false, false));
60+
61+
62+
CvsRepository repository = new CvsRepository(":pserver:host:${port}/path/to/repo", false, null, new ArrayList<CvsRepositoryItem>(), new ArrayList<ExcludedRegion>(), -1, null);
63+
64+
65+
CVSChangeLogSet.CVSChangeLog changelog = new CVSChangeLogSet.CVSChangeLog();
66+
changelog.setRepository(repository);
67+
68+
//we don't expect a browser match, and don't expect an error
69+
assertNull(testCase.resolveRepositoryBrowser(changelog));
70+
}
71+
72+
@Test
73+
public void testResolveBrowserFromAlternativeJob() throws IOException {
74+
// create a few projects with browsers
75+
for (int k = 0; k < 10; k++) {
76+
FreeStyleProject p = jenkinsRule.createFreeStyleProject("job " + k);
77+
List<CvsRepository> repositoryList = new ArrayList<CvsRepository>();
78+
for (int j = 0; j < 5; j++) {
79+
CvsModule[] modules = new CvsModule[10];
80+
for (int i = 0; i < modules.length; i++) {
81+
modules[i] = new CvsModule("remote" + i, "remote" + i);
82+
}
83+
CvsRepositoryItem item = new CvsRepositoryItem(new CvsRepositoryLocation.HeadRepositoryLocation(), modules);
84+
repositoryList.add(new CvsRepository(":pserver:user@host:" + j + "/path/to/repo", false, null, Arrays.asList(item), new ArrayList<ExcludedRegion>(), -1, new ViewCVS(new URL("http://host:" + j + "/viewcvs/viewcvs.cgi?cvsroot=root"))));
85+
}
86+
p.setScm(new CVSSCM(repositoryList, false, false, false, false, false, false, false));
87+
}
88+
89+
FreeStyleProject p = jenkinsRule.createFreeStyleProject("null browser job");
90+
91+
// now add a job with no browser
92+
List<CvsRepository> repositoryList = new ArrayList<CvsRepository>();
93+
for (int j = 0; j < 5; j++) {
94+
CvsModule[] modules = new CvsModule[10];
95+
for (int i = 0; i < modules.length; i++) {
96+
modules[i] = new CvsModule("remote" + i, "remote" + i);
97+
}
98+
CvsRepositoryItem item = new CvsRepositoryItem(new CvsRepositoryLocation.HeadRepositoryLocation(), modules);
99+
repositoryList.add(new CvsRepository(":pserver:user@host:" + j + "/path/to/repo", false, null, Arrays.asList(item), new ArrayList<ExcludedRegion>(), -1, null));
100+
}
101+
p.setScm(new CVSSCM(repositoryList, false, false, false, false, false, false, false));
102+
103+
// add a job with the browser we expect to get, and a cvs root that matches our test root
104+
ViewCVS browser = new ViewCVS(new URL("http://localhost/viewcvs/viewcvs.cgi?cvsroot=repo"));
105+
p = jenkinsRule.createFreeStyleProject("useful project");
106+
p.setScm(new CVSSCM(Arrays.asList(new CvsRepository(":pserver:host:10/path/to/repo", false, null, new ArrayList<CvsRepositoryItem>(), new ArrayList<ExcludedRegion>(), -1, browser)), false, false, false, false, false, false, false));
107+
108+
109+
CvsRepository repository = new CvsRepository(":pserver:host:10/path/to/repo", false, null, new ArrayList<CvsRepositoryItem>(), new ArrayList<ExcludedRegion>(), -1, null);
110+
111+
CVSChangeLogSet.CVSChangeLog changelog = new CVSChangeLogSet.CVSChangeLog();
112+
changelog.setRepository(repository);
113+
assertSame(browser, testCase.resolveRepositoryBrowser(changelog));
114+
115+
//cal again to check caching hasn't broken anything
116+
assertSame(browser, testCase.resolveRepositoryBrowser(changelog));
117+
}
118+
119+
120+
121+
}

0 commit comments

Comments
 (0)