Skip to content

Commit 40b68ea

Browse files
zbynekoleg-nenashev
authored andcommitted
[JENKINS-59679] Use plugin URL from the update site rather than the manifest (#4273)
* Use plugin URL from the update site rather than the manifest * Avoid Mockito when not needed * Resolve plugin URL from multiple update sites
1 parent 3a8c1ef commit 40b68ea

File tree

6 files changed

+159
-26
lines changed

6 files changed

+159
-26
lines changed

core/src/main/java/hudson/PluginWrapper.java

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -521,20 +521,30 @@ public String getShortName() {
521521
*/
522522
@Exported
523523
public String getUrl() {
524-
// first look for the manifest entry. This is new in maven-hpi-plugin 1.30
525-
String url = manifest.getMainAttributes().getValue("Url");
526-
if(url!=null) return url;
524+
// first look in update center metadata
525+
List<UpdateSite.Plugin> siteMetadataList = getInfoFromAllSites();
526+
String firstSiteUrl = null;
527+
if (!siteMetadataList.isEmpty()) {
528+
firstSiteUrl = siteMetadataList.get(0).wiki;
529+
if (allUrlsMatch(firstSiteUrl, siteMetadataList)) {
530+
return firstSiteUrl;
531+
}
532+
}
527533

528-
// fallback to update center metadata
529-
UpdateSite.Plugin ui = getInfo();
530-
if(ui!=null) return ui.wiki;
534+
// if update sites give different / empty results,
535+
// use manifest (since maven-hpi-plugin 1.30)
536+
String url = manifest.getMainAttributes().getValue("Url");
537+
if (url != null) {
538+
return url;
539+
}
540+
return firstSiteUrl;
541+
}
531542

532-
return null;
543+
private boolean allUrlsMatch(String url, List<UpdateSite.Plugin> uiList) {
544+
return uiList.stream().allMatch(k -> k.wiki != null && k.wiki.equals(url));
533545
}
534-
535-
536546

537-
@Override
547+
@Override
538548
public String toString() {
539549
return "Plugin:" + getShortName();
540550
}
@@ -972,6 +982,11 @@ public UpdateSite.Plugin getInfo() {
972982
return uc.getPlugin(getShortName());
973983
}
974984

985+
private List<UpdateSite.Plugin> getInfoFromAllSites() {
986+
UpdateCenter uc = Jenkins.get().getUpdateCenter();
987+
return uc.getPluginFromAllSites(getShortName(), getVersionNumber());
988+
}
989+
975990
/**
976991
* Returns true if this plugin has update in the update center.
977992
*

core/src/main/java/hudson/model/UpdateCenter.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,15 +640,36 @@ public String getDefaultBaseUrl() {
640640
}
641641
for (UpdateSite s : sites) {
642642
Plugin p = s.getPlugin(artifactId);
643-
if (p!=null) {
644-
if (minVersion.isNewerThan(new VersionNumber(p.version))) continue;
643+
if (checkMinVersion(p, minVersion)) {
645644
return p;
646645
}
647646
}
648647
return null;
649648
}
650649

651650
/**
651+
* Gets plugin info from all available sites
652+
* @return list of plugins
653+
*/
654+
@Restricted(NoExternalUse.class)
655+
public @Nonnull List<Plugin> getPluginFromAllSites(String artifactId,
656+
@CheckForNull VersionNumber minVersion) {
657+
ArrayList<Plugin> result = new ArrayList<>();
658+
for (UpdateSite s : sites) {
659+
Plugin p = s.getPlugin(artifactId);
660+
if (checkMinVersion(p, minVersion)) {
661+
result.add(p);
662+
}
663+
}
664+
return result;
665+
}
666+
667+
private boolean checkMinVersion(@CheckForNull Plugin p, @CheckForNull VersionNumber minVersion) {
668+
return p != null
669+
&& (minVersion == null || !minVersion.isNewerThan(new VersionNumber(p.version)));
670+
}
671+
672+
/**
652673
* Schedules a Jenkins upgrade.
653674
*/
654675
@RequirePOST

core/src/test/java/hudson/PluginWrapperTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,11 @@ private PluginWrapper buildFailed() {
161161
}
162162

163163
private PluginWrapper build() {
164-
Manifest manifest = mock(Manifest.class);
165-
Attributes attributes = new Attributes();
164+
Manifest manifest = new Manifest();
165+
Attributes attributes = manifest.getMainAttributes();
166166
attributes.put(new Attributes.Name("Short-Name"), name);
167167
attributes.put(new Attributes.Name("Jenkins-Version"), requiredCoreVersion);
168168
attributes.put(new Attributes.Name("Plugin-Version"), version);
169-
when(manifest.getMainAttributes()).thenReturn(attributes);
170169
return new PluginWrapper(
171170
pm,
172171
new File("/tmp/" + name + ".jpi"),

test/src/test/java/hudson/model/UpdateSiteTest.java

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
package hudson.model;
2626

27+
import hudson.PluginWrapper;
28+
import hudson.PluginWrapper.Dependency;
2729
import hudson.model.UpdateSite.Data;
2830
import hudson.util.FormValidation;
2931
import hudson.util.PersistedList;
@@ -32,16 +34,20 @@
3234
import java.io.IOException;
3335
import java.net.URISyntaxException;
3436
import java.net.URL;
37+
import java.util.ArrayList;
3538
import java.util.Arrays;
3639
import java.util.Collections;
3740
import java.util.HashSet;
41+
import java.util.jar.Attributes;
42+
import java.util.jar.Manifest;
3843

3944
import javax.servlet.ServletException;
4045
import javax.servlet.http.HttpServletRequest;
4146
import javax.servlet.http.HttpServletResponse;
4247

4348
import static org.junit.Assert.*;
4449

50+
import jenkins.model.Jenkins;
4551
import jenkins.security.UpdateSiteWarningsConfiguration;
4652
import jenkins.security.UpdateSiteWarningsMonitor;
4753
import org.apache.commons.io.FileUtils;
@@ -107,11 +113,9 @@ public void shutdownWebserver() throws Exception {
107113
}
108114

109115
@Test public void relativeURLs() throws Exception {
110-
PersistedList<UpdateSite> sites = j.jenkins.getUpdateCenter().getSites();
111-
sites.clear();
112116
URL url = new URL(baseUrl, "/plugins/tasks-update-center.json");
113117
UpdateSite site = new UpdateSite(UpdateCenter.ID_DEFAULT, url.toString());
114-
sites.add(site);
118+
overrideUpdateSite(site);
115119
assertEquals(FormValidation.ok(), site.updateDirectly(false).get());
116120
Data data = site.getData();
117121
assertNotNull(data);
@@ -124,6 +128,28 @@ public void shutdownWebserver() throws Exception {
124128
assertEquals("Wrong name of plugin found", "Task Scanner Plug-in", tasksPlugin.getDisplayName());
125129
}
126130

131+
@Test public void wikiUrlFromSingleSite() throws Exception {
132+
UpdateSite site = getUpdateSite("/plugins/tasks-update-center.json");
133+
overrideUpdateSite(site);
134+
PluginWrapper wrapper = buildPluginWrapper("dummy", "https://wiki.jenkins.io/display/JENKINS/dummy");
135+
assertEquals("https://plugins.jenkins.io/dummy", wrapper.getUrl());
136+
}
137+
138+
@Test public void wikiUrlFromMoreSites() throws Exception {
139+
UpdateSite site = getUpdateSite("/plugins/tasks-update-center.json");
140+
UpdateSite alternativeSite = getUpdateSite("/plugins/alternative-update-center.json", "alternative");
141+
overrideUpdateSite(site, alternativeSite);
142+
// sites use different Wiki URL for dummy -> use URL from manifest
143+
PluginWrapper wrapper = buildPluginWrapper("dummy", "https://wiki.jenkins.io/display/JENKINS/dummy");
144+
assertEquals("https://wiki.jenkins.io/display/JENKINS/dummy", wrapper.getUrl());
145+
// sites use the same Wiki URL for tasks -> use it
146+
wrapper = buildPluginWrapper("tasks", "https://wiki.jenkins.io/display/JENKINS/tasks");
147+
assertEquals("https://plugins.jenkins.io/tasks", wrapper.getUrl());
148+
// only one site has it
149+
wrapper = buildPluginWrapper("foo", "https://wiki.jenkins.io/display/JENKINS/foo");
150+
assertEquals("https://plugins.jenkins.io/foo", wrapper.getUrl());
151+
}
152+
127153
@Test public void updateDirectlyWithJson() throws Exception {
128154
UpdateSite us = new UpdateSite("default", new URL(baseUrl, "update-center.json").toExternalForm());
129155
assertNull(us.getPlugin("AdaptivePlugin"));
@@ -141,12 +167,8 @@ public void shutdownWebserver() throws Exception {
141167
}
142168

143169
@Test public void incompleteWarningsJson() throws Exception {
144-
PersistedList<UpdateSite> sites = j.jenkins.getUpdateCenter().getSites();
145-
sites.clear();
146-
URL url = new URL(baseUrl, "/plugins/warnings-update-center-malformed.json");
147-
UpdateSite site = new UpdateSite(UpdateCenter.ID_DEFAULT, url.toString());
148-
sites.add(site);
149-
assertEquals(FormValidation.ok(), site.updateDirectly(false).get());
170+
UpdateSite site = getUpdateSite("/plugins/warnings-update-center-malformed.json");
171+
overrideUpdateSite(site);
150172
assertEquals("number of warnings", 7, site.getData().getWarnings().size());
151173
assertNotEquals("plugin data is present", Collections.emptyMap(), site.getData().plugins);
152174
}
@@ -190,11 +212,38 @@ public void isPluginUpdateCompatible() throws Exception {
190212
assertFalse("isLegacyDefault should be false with null url",new UpdateSite(null,null).isLegacyDefault());
191213
}
192214

193-
194215
private UpdateSite getUpdateSite(String path) throws Exception {
216+
return getUpdateSite(path, UpdateCenter.ID_DEFAULT);
217+
}
218+
219+
private UpdateSite getUpdateSite(String path, String id) throws Exception {
195220
URL url = new URL(baseUrl, path);
196-
UpdateSite site = new UpdateSite(UpdateCenter.ID_DEFAULT, url.toString());
221+
UpdateSite site = new UpdateSite(id, url.toString());
197222
assertEquals(FormValidation.ok(), site.updateDirectly(false).get());
198223
return site;
199224
}
225+
226+
private void overrideUpdateSite(UpdateSite... overrideSites) {
227+
PersistedList<UpdateSite> sites = j.jenkins.getUpdateCenter().getSites();
228+
sites.clear();
229+
sites.addAll(Arrays.asList(overrideSites));
230+
}
231+
232+
private PluginWrapper buildPluginWrapper(String name, String wikiUrl) {
233+
Manifest manifest = new Manifest();
234+
Attributes attributes = manifest.getMainAttributes();
235+
attributes.put(new Attributes.Name("Short-Name"), name);
236+
attributes.put(new Attributes.Name("Plugin-Version"), "1.0.0");
237+
attributes.put(new Attributes.Name("Url"), wikiUrl);
238+
return new PluginWrapper(
239+
Jenkins.get().getPluginManager(),
240+
new File("/tmp/" + name + ".jpi"),
241+
manifest,
242+
null,
243+
null,
244+
new File("/tmp/" + name + ".jpi.disabled"),
245+
null,
246+
new ArrayList<Dependency>()
247+
);
248+
}
200249
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
updateCenter.post(
2+
{"connectionCheckUrl":"http://www.google.com/", // has to be here because updateDirectly sniffs only very limited formats
3+
"core": {
4+
"buildDate": "Dec 31, 1969",
5+
"name": "core",
6+
"url": "jenkins.war",
7+
"version": "23"
8+
},
9+
"id": "alternative",
10+
"plugins": {
11+
"tasks": {
12+
"buildDate": "Dec 17, 2008",
13+
"dependencies": [],
14+
"developers": [{"name": "lokadm"}],
15+
"excerpt": " This plug-in scans for open tasks in a specified set of files in the project modules and visualizes the results. ",
16+
"name": "tasks",
17+
"wiki": "https://plugins.jenkins.io/tasks",
18+
"requiredCore": "1.264",
19+
"sha1": "wtzlciUKiMcg90H5CTYkGX6+r8Y=",
20+
"title": "Jenkins Task Scanner Plug-in",
21+
"url": "tasks.jpi",
22+
"version": "2.23"
23+
},
24+
"dummy": {
25+
"buildDate": "Dec 17, 2008",
26+
"dependencies": [],
27+
"developers": [],
28+
"excerpt": "",
29+
"name": "dummy",
30+
"wiki": "https://plugins.example.com/dummy",
31+
"requiredCore": "1.100",
32+
"sha1": "wtzlcjUKiMcg90H5CTYkGX6+r8Y=",
33+
"title": "Dummy",
34+
"url": "http://nowhere.net/dummy.hpi",
35+
"version": "1.0"
36+
},
37+
"foo": {
38+
"dependencies": [],
39+
"name": "foo",
40+
"wiki": "https://plugins.jenkins.io/foo",
41+
"version": "1.0",
42+
"url": "http://nowhere.net/dummy.hpi",
43+
}
44+
},
45+
"updateCenterVersion": 1
46+
}
47+
);

test/src/test/resources/plugins/tasks-update-center.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ updateCenter.post(
1414
"developers": [{"name": "lokadm"}],
1515
"excerpt": " This plug-in scans for open tasks in a specified set of files in the project modules and visualizes the results. ",
1616
"name": "tasks",
17+
"wiki": "https://plugins.jenkins.io/tasks",
1718
"requiredCore": "1.264",
1819
"sha1": "wtzlciUKiMcg90H5CTYkGX6+r8Y=",
1920
"title": "Jenkins Task Scanner Plug-in",
@@ -26,6 +27,7 @@ updateCenter.post(
2627
"developers": [],
2728
"excerpt": "",
2829
"name": "dummy",
30+
"wiki": "https://plugins.jenkins.io/dummy",
2931
"requiredCore": "1.100",
3032
"sha1": "wtzlcjUKiMcg90H5CTYkGX6+r8Y=",
3133
"title": "Dummy",

0 commit comments

Comments
 (0)