Skip to content

Commit c355e12

Browse files
[BUG] Custom POM configuration for ZIP publication produces duplicit tags (url, scm) (#3656) (#3678)
* [BUG] Custom POM configuration for ZIP publication produces duplicit tags (url, scm) Signed-off-by: Andriy Redko <[email protected]> * Added test case for pluginZip with POM Signed-off-by: Andriy Redko <[email protected]> * Support both Gradle 6.8.x and Gradle 7.4.x Signed-off-by: Andriy Redko <[email protected]> (cherry picked from commit 304d830) Co-authored-by: Andriy Redko <[email protected]>
1 parent 877d733 commit c355e12

File tree

2 files changed

+147
-21
lines changed

2 files changed

+147
-21
lines changed

buildSrc/src/main/java/org/opensearch/gradle/PublishPlugin.java

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.github.jengelman.gradle.plugins.shadow.ShadowExtension;
3737
import groovy.util.Node;
3838
import groovy.util.NodeList;
39+
3940
import org.opensearch.gradle.info.BuildParams;
4041
import org.opensearch.gradle.precommit.PomValidationPrecommitPlugin;
4142
import org.opensearch.gradle.util.Util;
@@ -55,6 +56,9 @@
5556
import org.gradle.api.tasks.bundling.Jar;
5657
import org.gradle.language.base.plugins.LifecycleBasePlugin;
5758

59+
import java.lang.invoke.MethodHandle;
60+
import java.lang.invoke.MethodHandles;
61+
import java.lang.invoke.MethodType;
5862
import java.util.concurrent.Callable;
5963

6064
import static org.opensearch.gradle.util.GradleUtils.maybeConfigure;
@@ -146,9 +150,49 @@ public String call() throws Exception {
146150

147151
private static void addScmInfo(XmlProvider xml) {
148152
Node root = xml.asNode();
149-
root.appendNode("url", Util.urlFromOrigin(BuildParams.getGitOrigin()));
150-
Node scmNode = root.appendNode("scm");
151-
scmNode.appendNode("url", BuildParams.getGitOrigin());
153+
Node url = null, scm = null;
154+
155+
for (final Object child : root.children()) {
156+
if (child instanceof Node) {
157+
final Node node = (Node) child;
158+
final Object name = node.name();
159+
160+
try {
161+
// For Gradle 6.8 and below, the class is groovy.xml.QName
162+
// For Gradle 7.4 and above, the class is groovy.namespace.QName
163+
if (name != null && name.getClass().getSimpleName().equals("QName")) {
164+
final MethodHandle handle = MethodHandles.publicLookup()
165+
.findVirtual(name.getClass(), "matches", MethodType.methodType(boolean.class, Object.class))
166+
.bindTo(name);
167+
168+
if ((boolean) handle.invoke("url")) {
169+
url = node;
170+
} else if ((boolean) handle.invoke("scm")) {
171+
scm = node;
172+
}
173+
}
174+
} catch (final Throwable ex) {
175+
// Not a suitable QName type we could use ...
176+
}
177+
178+
if ("url".equals(name)) {
179+
url = node;
180+
} else if ("scm".equals(name)) {
181+
scm = node;
182+
}
183+
}
184+
}
185+
186+
// Only include URL section if it is not provided in the POM already
187+
if (url == null) {
188+
root.appendNode("url", Util.urlFromOrigin(BuildParams.getGitOrigin()));
189+
}
190+
191+
// Only include SCM section if it is not provided in the POM already
192+
if (scm == null) {
193+
Node scmNode = root.appendNode("scm");
194+
scmNode.appendNode("url", BuildParams.getGitOrigin());
195+
}
152196
}
153197

154198
/** Adds a javadocJar task to generate a jar containing javadocs. */

buildSrc/src/test/java/org/opensearch/gradle/pluginzip/PublishTests.java

Lines changed: 100 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,26 +52,62 @@ public void tearDown() {
5252

5353
@Test
5454
public void testZipPublish() throws IOException, XmlPullParserException {
55-
Project project = ProjectBuilder.builder().build();
5655
String zipPublishTask = "publishPluginZipPublicationToZipStagingRepository";
57-
// Apply the opensearch.pluginzip plugin
58-
project.getPluginManager().apply("opensearch.pluginzip");
59-
// Check if the plugin has been applied to the project
60-
assertTrue(project.getPluginManager().hasPlugin("opensearch.pluginzip"));
61-
// Check if the project has the task from class PublishToMavenRepository after plugin apply
62-
assertNotNull(project.getTasks().withType(PublishToMavenRepository.class));
63-
// Create a mock bundlePlugin task
64-
Zip task = project.getTasks().create("bundlePlugin", Zip.class);
65-
Publish.configMaven(project);
66-
// Check if the main task publishPluginZipPublicationToZipStagingRepository exists after plugin apply
67-
assertTrue(project.getTasks().getNames().contains(zipPublishTask));
68-
assertNotNull("Task to generate: ", project.getTasks().getByName(zipPublishTask));
69-
// Run Gradle functional tests, but calling a build.gradle file, that resembles the plugin publish behavior
56+
prepareProjectForPublishTask(zipPublishTask);
57+
58+
// Generate the build.gradle file
59+
String buildFileContent = "apply plugin: 'maven-publish' \n"
60+
+ "apply plugin: 'java' \n"
61+
+ "publishing {\n"
62+
+ " repositories {\n"
63+
+ " maven {\n"
64+
+ " url = 'local-staging-repo/'\n"
65+
+ " name = 'zipStaging'\n"
66+
+ " }\n"
67+
+ " }\n"
68+
+ " publications {\n"
69+
+ " pluginZip(MavenPublication) {\n"
70+
+ " groupId = 'org.opensearch.plugin' \n"
71+
+ " artifactId = 'sample-plugin' \n"
72+
+ " version = '2.0.0.0' \n"
73+
+ " artifact('sample-plugin.zip') \n"
74+
+ " }\n"
75+
+ " }\n"
76+
+ "}";
77+
writeString(projectDir.newFile("build.gradle"), buildFileContent);
78+
// Execute the task publishPluginZipPublicationToZipStagingRepository
79+
List<String> allArguments = new ArrayList<String>();
80+
allArguments.add("build");
81+
allArguments.add(zipPublishTask);
82+
GradleRunner runner = GradleRunner.create();
83+
runner.forwardOutput();
84+
runner.withPluginClasspath();
85+
runner.withArguments(allArguments);
86+
runner.withProjectDir(projectDir.getRoot());
87+
BuildResult result = runner.build();
88+
// Check if task publishMavenzipPublicationToZipstagingRepository has ran well
89+
assertEquals(SUCCESS, result.task(":" + zipPublishTask).getOutcome());
90+
// check if the zip has been published to local staging repo
91+
assertTrue(
92+
new File(projectDir.getRoot(), "local-staging-repo/org/opensearch/plugin/sample-plugin/2.0.0.0/sample-plugin-2.0.0.0.zip")
93+
.exists()
94+
);
95+
assertEquals(SUCCESS, result.task(":" + "build").getOutcome());
96+
// Parse the maven file and validate the groupID to org.opensearch.plugin
97+
MavenXpp3Reader reader = new MavenXpp3Reader();
98+
Model model = reader.read(
99+
new FileReader(
100+
new File(projectDir.getRoot(), "local-staging-repo/org/opensearch/plugin/sample-plugin/2.0.0.0/sample-plugin-2.0.0.0.pom")
101+
)
102+
);
103+
assertEquals(model.getGroupId(), "org.opensearch.plugin");
104+
}
105+
106+
@Test
107+
public void testZipPublishWithPom() throws IOException, XmlPullParserException {
108+
String zipPublishTask = "publishPluginZipPublicationToZipStagingRepository";
109+
Project project = prepareProjectForPublishTask(zipPublishTask);
70110

71-
// Create a sample plugin zip file
72-
File sampleZip = new File(projectDir.getRoot(), "sample-plugin.zip");
73-
Files.createFile(sampleZip.toPath());
74-
writeString(projectDir.newFile("settings.gradle"), "");
75111
// Generate the build.gradle file
76112
String buildFileContent = "apply plugin: 'maven-publish' \n"
77113
+ "apply plugin: 'java' \n"
@@ -88,6 +124,26 @@ public void testZipPublish() throws IOException, XmlPullParserException {
88124
+ " artifactId = 'sample-plugin' \n"
89125
+ " version = '2.0.0.0' \n"
90126
+ " artifact('sample-plugin.zip') \n"
127+
+ " pom {\n"
128+
+ " name = 'sample-plugin'\n"
129+
+ " description = 'sample-description'\n"
130+
+ " licenses {\n"
131+
+ " license {\n"
132+
+ " name = \"The Apache License, Version 2.0\"\n"
133+
+ " url = \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n"
134+
+ " }\n"
135+
+ " }\n"
136+
+ " developers {\n"
137+
+ " developer {\n"
138+
+ " name = 'opensearch'\n"
139+
+ " url = 'https://github.com/opensearch-project/OpenSearch'\n"
140+
+ " }\n"
141+
+ " }\n"
142+
+ " url = 'https://github.com/opensearch-project/OpenSearch'\n"
143+
+ " scm {\n"
144+
+ " url = 'https://github.com/opensearch-project/OpenSearch'\n"
145+
+ " }\n"
146+
+ " }"
91147
+ " }\n"
92148
+ " }\n"
93149
+ "}";
@@ -118,6 +174,32 @@ public void testZipPublish() throws IOException, XmlPullParserException {
118174
)
119175
);
120176
assertEquals(model.getGroupId(), "org.opensearch.plugin");
177+
assertEquals(model.getUrl(), "https://github.com/opensearch-project/OpenSearch");
178+
}
179+
180+
protected Project prepareProjectForPublishTask(String zipPublishTask) throws IOException {
181+
Project project = ProjectBuilder.builder().build();
182+
183+
// Apply the opensearch.pluginzip plugin
184+
project.getPluginManager().apply("opensearch.pluginzip");
185+
// Check if the plugin has been applied to the project
186+
assertTrue(project.getPluginManager().hasPlugin("opensearch.pluginzip"));
187+
// Check if the project has the task from class PublishToMavenRepository after plugin apply
188+
assertNotNull(project.getTasks().withType(PublishToMavenRepository.class));
189+
// Create a mock bundlePlugin task
190+
Zip task = project.getTasks().create("bundlePlugin", Zip.class);
191+
Publish.configMaven(project);
192+
// Check if the main task publishPluginZipPublicationToZipStagingRepository exists after plugin apply
193+
assertTrue(project.getTasks().getNames().contains(zipPublishTask));
194+
assertNotNull("Task to generate: ", project.getTasks().getByName(zipPublishTask));
195+
// Run Gradle functional tests, but calling a build.gradle file, that resembles the plugin publish behavior
196+
197+
// Create a sample plugin zip file
198+
File sampleZip = new File(projectDir.getRoot(), "sample-plugin.zip");
199+
Files.createFile(sampleZip.toPath());
200+
writeString(projectDir.newFile("settings.gradle"), "");
201+
202+
return project;
121203
}
122204

123205
private void writeString(File file, String string) throws IOException {

0 commit comments

Comments
 (0)