Skip to content

Commit

Permalink
tycho-versions-plugin: Support ci-friendly versions
Browse files Browse the repository at this point in the history
In PomFile#getVersion(), resolve properties used in the raw version of
the project. This is necessary so that downstream manipulators
(MANIFEST.MF, feature.xml, category.xml, ...) can see the actual version
and act on it.

Fixes eclipse-tycho#3744.
  • Loading branch information
sratz committed May 31, 2024
1 parent 13489c6 commit 1746be2
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Test Artifact
Bundle-SymbolicName: test.artifact
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-17
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<artifactId>test.artifact</artifactId>
<groupId>org.tycho.its</groupId>
<packaging>eclipse-plugin</packaging>
<properties>
<revision>1.0.0-SNAPSHOT</revision>
</properties>
<version>${revision}</version>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho-version}</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,26 @@ public void testUpdatePomsOfModularPom() throws Exception {

}

@Test
public void testCiFriendlyVersion() throws Exception {
String expectedNewVersion = "2.0.0-SNAPSHOT";
String expectedNewOSGiVersion = "2.0.0.qualifier";

Verifier verifier = getVerifier("tycho-version-plugin/set-version/ci_friendly", false);

verifier.addCliOption("-DnewVersion=" + expectedNewVersion);
verifier.executeGoal("org.eclipse.tycho:tycho-versions-plugin:" + VERSION + ":set-version");

verifier.verifyErrorFreeLog();

MavenXpp3Reader pomReader = new MavenXpp3Reader();
Model pomModel = pomReader.read(new FileReader(new File(verifier.getBasedir(), "pom.xml")));
assertEquals("${revision}", pomModel.getVersion());
assertEquals(expectedNewVersion, pomModel.getProperties().getProperty("revision"));
Manifest manifest = getManifest(verifier, ".");
assertEquals(expectedNewOSGiVersion, manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION));
}

public static File file(Verifier verifier, String... path) {
return Path.of(verifier.getBasedir(), path).toFile();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
* Sonatype Inc. - initial API and implementation
* Sebastien Arod - introduce VersionChangesDescriptor
* Bachmann electronic GmbH. - #472579 - Support setting the version for pomless builds
* Christoph Läubrich - Bug 550313 - tycho-versions-plugin uses hard-coded polyglot file
* Christoph Läubrich - Bug 550313 - tycho-versions-plugin uses hard-coded polyglot file
* SAP SE - #3744 - ci-friendly version support
*******************************************************************************/
package org.eclipse.tycho.versions.manipulation;

Expand All @@ -20,13 +21,10 @@

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.codehaus.plexus.component.annotations.Component;
import org.eclipse.tycho.versions.engine.MetadataManipulator;
Expand All @@ -40,6 +38,7 @@
import org.eclipse.tycho.versions.pom.Plugin;
import org.eclipse.tycho.versions.pom.PluginManagement;
import org.eclipse.tycho.versions.pom.PomFile;
import org.eclipse.tycho.versions.pom.PomUtil;
import org.eclipse.tycho.versions.pom.Profile;
import org.eclipse.tycho.versions.pom.Property;

Expand All @@ -51,8 +50,6 @@ public class PomManipulator extends AbstractMetadataManipulator {

public static final String HINT = POM;

private static final Pattern CI_FRIENDLY_EXPRESSION = Pattern.compile("\\$\\{(.+?)\\}");

@Override
public boolean addMoreChanges(ProjectMetadata project, VersionChangesDescriptor versionChangeContext) {
PomFile pom = project.getMetadata(PomFile.class);
Expand Down Expand Up @@ -116,14 +113,8 @@ public void applyChanges(ProjectMetadata project, VersionChangesDescriptor versi
String version = Versions.toMavenVersion(change.getVersion());
String newVersion = Versions.toMavenVersion(change.getNewVersion());
if (isGavEquals(pom, change)) {
String v = pom.getVersion();
if (isCiFriendly(v)) {
//applyPropertyChange(pom, version, newVersion);
Matcher m = CI_FRIENDLY_EXPRESSION.matcher(v.trim());
List<String> ciFriendlyProperties = new ArrayList<String>();
while (m.find()) {
ciFriendlyProperties.add(m.group(1));
}
List<String> ciFriendlyProperties = PomUtil.getContainedPropertyNames(pom.getRawVersion());
if (!ciFriendlyProperties.isEmpty()) {
if (ciFriendlyProperties.size() == 1) {
//thats actually a simply property change
applyPropertyChange(pomName, pom, ciFriendlyProperties.get(0), newVersion);
Expand All @@ -148,7 +139,8 @@ public void applyChanges(ProjectMetadata project, VersionChangesDescriptor versi
}
} else {
GAV parent = pom.getParent();
if (parent != null && isGavEquals(parent, change) && !isCiFriendly(parent.getVersion())) {
if (parent != null && isGavEquals(parent, change)
&& !PomUtil.containsProperties(parent.getVersion())) {
logger.info(" %s//project/parent/version: %s => %s".formatted(pomName, version, newVersion));
parent.setVersion(newVersion);
}
Expand Down Expand Up @@ -180,10 +172,6 @@ public void applyChanges(ProjectMetadata project, VersionChangesDescriptor versi

}

private boolean isCiFriendly(String v) {
return v != null && v.contains("${");
}

protected void changeDependencyManagement(String pomPath, DependencyManagement dependencyManagment,
PomVersionChange change, String version, String newVersion) {
if (dependencyManagment != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
* Contributors:
* Sonatype Inc. - initial API and implementation
* Bachmann electronic GmbH. - #472579 - Support setting the version for pomless builds
* Christoph Läubrich - Bug 550313 - tycho-versions-plugin uses hard-coded polyglot file
* Christoph Läubrich - Bug 550313 - tycho-versions-plugin uses hard-coded polyglot file
* SAP SE - #3744 - ci-friendly version support
*******************************************************************************/
package org.eclipse.tycho.versions.pom;

Expand Down Expand Up @@ -48,8 +49,10 @@ public class PomFile {
private Document document;
private Element project;

/** The (effective) project version */
/** The (raw) project version */
private String version;
/** The ${property}-resolved version, in case of ci-friendly versions */
private String resolvedVersion;
private final boolean preferExplicitProjectVersion;
private final boolean isMutable;

Expand Down Expand Up @@ -142,7 +145,7 @@ private static void removeVersionElementFromXML(Element project) {
/**
* Sets the version in the parent POM declaration. This never affects the (effective) version of
* the project itself.
*
*
* @see #setVersion(String)
*/
public void setParentVersion(String newVersion) {
Expand All @@ -158,13 +161,24 @@ public void setParentVersion(String newVersion) {
*/
public void setVersion(String version) {
this.version = version;
this.resolvedVersion = null;
}

/**
* Returns the (effective) version of the project.
* Returns the (effective) version of the project with properties resolved.
*/
public String getVersion() {
return version;
if (this.resolvedVersion == null) {
this.resolvedVersion = PomUtil.expandProperties(version, getProperties());
}
return this.resolvedVersion;
}

/**
* Returns the literal version of the project without any properties resolved.
*/
public String getRawVersion() {
return this.version;
}

public String getPackaging() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*******************************************************************************
* Copyright (c) 2024 SAP SE and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* SAP SE - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.versions.pom;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PomUtil {

private static final Pattern PROPERTY_PATTERN = Pattern.compile("\\$\\{(.+?)\\}");

/**
* Returns whether the string contains properties <code>${properties}</code>.
*/
public static boolean containsProperties(String str) {
return str != null && str.contains("${");
}

/**
* Expands properties in the given string.
* <p>
* If a property is not found it is left unexpanded.
*
* @param str
* the input string
* @param properties
* possible replacement properties
* @return the expanded string
*/
public static String expandProperties(String str, List<Property> properties) {
if (containsProperties(str)) {
StringBuilder resolvedVersionBuilder = new StringBuilder();
Matcher m = PROPERTY_PATTERN.matcher(str.trim());
while (m.find()) {
String unexpandedProperty = m.group();
String propertyName = m.group(1);
m.appendReplacement(resolvedVersionBuilder,
properties.stream().filter(p -> p.getName().equals(propertyName)).map(p -> p.getValue())
.findFirst().orElse(unexpandedProperty));
}
m.appendTail(resolvedVersionBuilder);
return resolvedVersionBuilder.toString();
} else {
return str;
}
}

/**
* Returns the list of property names that make up the given string.
*/
public static List<String> getContainedPropertyNames(String str) {
if (containsProperties(str)) {
Matcher m = PROPERTY_PATTERN.matcher(str.trim());
List<String> propertyNames = new ArrayList<>();
while (m.find()) {
propertyNames.add(m.group(1));
}
return Collections.unmodifiableList(propertyNames);
}
return List.of();
}
}

0 comments on commit 1746be2

Please sign in to comment.