mirror of https://github.com/apache/maven.git
[MNG-5180] Versioning's snapshot version list is not included in metadata merge
Co-authored-by: Konrad Windszus <kwin@apache.org> This closes #681
This commit is contained in:
parent
e327be3d85
commit
1e33a57264
|
@ -38,6 +38,11 @@ under the License.
|
|||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -88,6 +88,11 @@ under the License.
|
|||
<codeSegment>
|
||||
<version>1.0.0+</version>
|
||||
<code><![CDATA[
|
||||
private String getSnapshotVersionKey( SnapshotVersion sv )
|
||||
{
|
||||
return sv.getClassifier() + ":" + sv.getExtension();
|
||||
}
|
||||
|
||||
public boolean merge( Metadata sourceMetadata )
|
||||
{
|
||||
boolean changed = false;
|
||||
|
@ -178,11 +183,13 @@ under the License.
|
|||
Snapshot snapshot = versioning.getSnapshot();
|
||||
if ( snapshot != null )
|
||||
{
|
||||
boolean updateSnapshotVersions = false;
|
||||
if ( s == null )
|
||||
{
|
||||
s = new Snapshot();
|
||||
v.setSnapshot( s );
|
||||
changed = true;
|
||||
updateSnapshotVersions = true;
|
||||
}
|
||||
|
||||
// overwrite
|
||||
|
@ -191,6 +198,7 @@ under the License.
|
|||
{
|
||||
s.setTimestamp( snapshot.getTimestamp() );
|
||||
changed = true;
|
||||
updateSnapshotVersions = true;
|
||||
}
|
||||
if ( s.getBuildNumber() != snapshot.getBuildNumber() )
|
||||
{
|
||||
|
@ -202,6 +210,34 @@ under the License.
|
|||
s.setLocalCopy( snapshot.isLocalCopy() );
|
||||
changed = true;
|
||||
}
|
||||
if ( updateSnapshotVersions )
|
||||
{
|
||||
java.util.Map<String, SnapshotVersion> versions = new java.util.LinkedHashMap<>();
|
||||
// never convert from legacy to new format if either source or target is legacy format
|
||||
if ( !v.getSnapshotVersions().isEmpty() )
|
||||
{
|
||||
for ( SnapshotVersion sv : versioning.getSnapshotVersions() )
|
||||
{
|
||||
String key = getSnapshotVersionKey( sv );
|
||||
versions.put( key, sv );
|
||||
}
|
||||
// never convert from legacy format
|
||||
if ( !versions.isEmpty() )
|
||||
{
|
||||
for ( SnapshotVersion sv : v.getSnapshotVersions() )
|
||||
{
|
||||
String key = getSnapshotVersionKey( sv );
|
||||
if ( !versions.containsKey( key ) )
|
||||
{
|
||||
versions.put( key, sv );
|
||||
}
|
||||
}
|
||||
}
|
||||
v.setSnapshotVersions( new java.util.ArrayList<SnapshotVersion>( versions.values() ) );
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +277,7 @@ under the License.
|
|||
<name>lastUpdated</name>
|
||||
<version>1.0.0+</version>
|
||||
<type>String</type>
|
||||
<description>When the metadata was last updated (both "groupId/artifactId" and "groupId/artifactId/version" directories)</description>
|
||||
<description>When the metadata was last updated (both "groupId/artifactId" and "groupId/artifactId/version" directories). The timestamp is expressed using UTC in the format yyyyMMddHHmmss.</description>
|
||||
</field>
|
||||
<field xdoc.separator="blank">
|
||||
<name>snapshot</name>
|
||||
|
@ -254,7 +290,7 @@ under the License.
|
|||
<field>
|
||||
<name>snapshotVersions</name>
|
||||
<version>1.1.0+</version>
|
||||
<description>Information for each sub-artifact available in this artifact snapshot.</description>
|
||||
<description>Information for each sub-artifact available in this artifact snapshot. This is only the most recent SNAPSHOT for each unique extension/classifier combination.</description>
|
||||
<association>
|
||||
<type>SnapshotVersion</type>
|
||||
<multiplicity>*</multiplicity>
|
||||
|
@ -289,7 +325,7 @@ under the License.
|
|||
<field>
|
||||
<name>timestamp</name>
|
||||
<version>1.0.0+</version>
|
||||
<description>The time it was deployed</description>
|
||||
<description>The timestamp when this version was deployed. The timestamp is expressed using UTC in the format yyyyMMdd.HHmmss.</description>
|
||||
<type>String</type>
|
||||
</field>
|
||||
<field>
|
||||
|
@ -316,26 +352,30 @@ under the License.
|
|||
<name>classifier</name>
|
||||
<version>1.1.0+</version>
|
||||
<type>String</type>
|
||||
<description>The classifier of the sub-artifact.</description>
|
||||
<description>The classifier of the sub-artifact. Each classifier and extension pair may only appear once.</description>
|
||||
<defaultValue></defaultValue>
|
||||
<identifier>true</identifier>
|
||||
</field>
|
||||
<field>
|
||||
<name>extension</name>
|
||||
<version>1.1.0+</version>
|
||||
<type>String</type>
|
||||
<description>The file extension of the sub-artifact.</description>
|
||||
<description>The file extension of the sub-artifact. Each classifier and extension pair may only appear once.</description>
|
||||
<identifier>true</identifier>
|
||||
</field>
|
||||
<field xml.tagName="value">
|
||||
<name>version</name>
|
||||
<version>1.1.0+</version>
|
||||
<type>String</type>
|
||||
<description>The resolved snapshot version of the sub-artifact.</description>
|
||||
<identifier>true</identifier>
|
||||
</field>
|
||||
<field>
|
||||
<name>updated</name>
|
||||
<version>1.1.0+</version>
|
||||
<type>String</type>
|
||||
<description>The timestamp when this version information was last updated. The timestamp is expressed using UTC in the format yyyyMMddHHmmss.</description>
|
||||
<identifier>true</identifier>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
package org.apache.maven.artifact.repository.metadata;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.eclipse.aether.artifact.Artifact;
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MetadataTest
|
||||
{
|
||||
|
||||
Artifact artifact;
|
||||
|
||||
Metadata target;
|
||||
|
||||
@BeforeEach
|
||||
void before()
|
||||
{
|
||||
artifact = new DefaultArtifact( "myGroup:myArtifact:1.0-SNAPSHOT" );
|
||||
target = createMetadataFromArtifact( artifact );
|
||||
}
|
||||
|
||||
/*--- START test common metadata ---*/
|
||||
@Test
|
||||
void mergeEmptyMetadata()
|
||||
throws Exception
|
||||
{
|
||||
Metadata metadata = new Metadata();
|
||||
assertFalse( metadata.merge( new Metadata() ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeDifferentGAV()
|
||||
throws Exception
|
||||
{
|
||||
// merge implicitly assumes that merge is only called on the same GAV and does not perform any validation here!
|
||||
Metadata source = new Metadata();
|
||||
source.setArtifactId( "source-artifact" );
|
||||
source.setGroupId( "source-group" );
|
||||
source.setVersion( "2.0" );
|
||||
assertFalse( target.merge( source ) );
|
||||
assertEquals( "myArtifact", target.getArtifactId() );
|
||||
assertEquals( "myGroup", target.getGroupId() );
|
||||
assertEquals( "1.0-SNAPSHOT", target.getVersion() );
|
||||
}
|
||||
/*--- END test common metadata ---*/
|
||||
|
||||
/*--- START test "groupId/artifactId/version" metadata ---*/
|
||||
@Test
|
||||
void mergeSnapshotWithEmptyList()
|
||||
throws Exception
|
||||
{
|
||||
Snapshot snapshot = new Snapshot();
|
||||
snapshot.setBuildNumber( 3 );
|
||||
snapshot.setTimestamp( "20200710.072412" );
|
||||
target.getVersioning().setSnapshot( snapshot );
|
||||
target.getVersioning().setLastUpdated( "20200921071745" );
|
||||
SnapshotVersion sv = new SnapshotVersion();
|
||||
sv.setClassifier( "sources" );
|
||||
sv.setExtension( "jar" );
|
||||
sv.setUpdated( "20200710072412" );
|
||||
target.getVersioning().addSnapshotVersion( sv );
|
||||
|
||||
Metadata source = createMetadataFromArtifact( artifact );
|
||||
// nothing should be actually changed, but still merge returns true
|
||||
assertTrue( target.merge( source ) );
|
||||
|
||||
// NOTE! Merge updates last updated to source
|
||||
assertEquals( "20200921071745", source.getVersioning().getLastUpdated() );
|
||||
|
||||
assertEquals( "myArtifact", target.getArtifactId() );
|
||||
assertEquals( "myGroup", target.getGroupId() );
|
||||
|
||||
assertEquals( 3, target.getVersioning().getSnapshot().getBuildNumber() );
|
||||
assertEquals( "20200710.072412", target.getVersioning().getSnapshot().getTimestamp() );
|
||||
|
||||
assertEquals( 1, target.getVersioning().getSnapshotVersions().size() );
|
||||
assertEquals( "sources", target.getVersioning().getSnapshotVersions().get( 0 ).getClassifier() );
|
||||
assertEquals( "jar", target.getVersioning().getSnapshotVersions().get( 0 ).getExtension() );
|
||||
assertEquals( "20200710072412", target.getVersioning().getSnapshotVersions().get( 0 ).getUpdated() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeWithSameSnapshotWithDifferentVersionsAndNewerLastUpdated()
|
||||
{
|
||||
Metadata source = createMetadataFromArtifact( artifact );
|
||||
Date before = new Date( System.currentTimeMillis() - 5000 );
|
||||
Date after = new Date( System.currentTimeMillis() );
|
||||
addSnapshotVersion( target.getVersioning(), "jar", before, "1", 1 );
|
||||
SnapshotVersion sv2 =
|
||||
addSnapshotVersion( source.getVersioning(), "jar", after, "1.0-" + formatDate( after, true ) + "-2", 2 );
|
||||
SnapshotVersion sv3 =
|
||||
addSnapshotVersion( source.getVersioning(), "pom", after, "1.0-" + formatDate( after, true ) + "-2", 2 );
|
||||
assertTrue( target.merge( source ) );
|
||||
Versioning actualVersioning = target.getVersioning();
|
||||
assertEquals( 2, actualVersioning.getSnapshotVersions().size() );
|
||||
assertEquals( sv2, actualVersioning.getSnapshotVersions().get( 0 ) );
|
||||
assertEquals( sv3, actualVersioning.getSnapshotVersions().get( 1 ) );
|
||||
assertEquals( formatDate( after, false ), actualVersioning.getLastUpdated() );
|
||||
assertEquals( formatDate( after, true ), actualVersioning.getSnapshot().getTimestamp() );
|
||||
assertEquals( 2, actualVersioning.getSnapshot().getBuildNumber() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeWithSameSnapshotWithDifferentVersionsAndOlderLastUpdated()
|
||||
{
|
||||
Metadata source = createMetadataFromArtifact( artifact );
|
||||
Date before = new Date( System.currentTimeMillis() - 5000 );
|
||||
Date after = new Date( System.currentTimeMillis() );
|
||||
SnapshotVersion sv1 = addSnapshotVersion( target.getVersioning(), after, artifact );
|
||||
addSnapshotVersion( source.getVersioning(), before, artifact );
|
||||
// nothing should be updated, as the target was already updated at a later date than source
|
||||
assertFalse( target.merge( source ) );
|
||||
assertEquals( 1, target.getVersioning().getSnapshotVersions().size() );
|
||||
assertEquals( sv1, target.getVersioning().getSnapshotVersions().get( 0 ) );
|
||||
assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() );
|
||||
assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeWithSameSnapshotWithSameVersionAndTimestamp()
|
||||
{
|
||||
Metadata source = createMetadataFromArtifact( artifact );
|
||||
Date date = new Date();
|
||||
addSnapshotVersion( target.getVersioning(), date, artifact );
|
||||
SnapshotVersion sv1 = addSnapshotVersion( source.getVersioning(), date, artifact );
|
||||
// although nothing has changed merge returns true, as the last modified date is equal
|
||||
// TODO: improve merge here?
|
||||
assertTrue( target.merge( source ) );
|
||||
assertEquals( 1, target.getVersioning().getSnapshotVersions().size() );
|
||||
assertEquals( sv1, target.getVersioning().getSnapshotVersions().get( 0 ) );
|
||||
assertEquals( formatDate( date, false ), target.getVersioning().getLastUpdated() );
|
||||
assertEquals( formatDate( date, true ), target.getVersioning().getSnapshot().getTimestamp() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeLegacyWithSnapshotLegacy()
|
||||
{
|
||||
Metadata source = createMetadataFromArtifact( artifact );
|
||||
Date before = new Date( System.currentTimeMillis() - 5000 );
|
||||
Date after = new Date( System.currentTimeMillis() );
|
||||
// legacy metadata did not have "versioning.snapshotVersions"
|
||||
addSnapshotVersionLegacy( target.getVersioning(), before, 1 );
|
||||
addSnapshotVersionLegacy( source.getVersioning(), after, 2 );
|
||||
// although nothing has changed merge returns true, as the last modified date is equal
|
||||
// TODO: improve merge here?
|
||||
assertTrue( target.merge( source ) );
|
||||
assertEquals( 0, target.getVersioning().getSnapshotVersions().size() );
|
||||
assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() );
|
||||
assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeLegacyWithSnapshot()
|
||||
{
|
||||
Metadata source = createMetadataFromArtifact( artifact );
|
||||
Date before = new Date( System.currentTimeMillis() - 5000 );
|
||||
Date after = new Date( System.currentTimeMillis() );
|
||||
// legacy metadata did not have "versioning.snapshotVersions"
|
||||
addSnapshotVersionLegacy( target.getVersioning(), before, 1 );
|
||||
addSnapshotVersion( source.getVersioning(), after, artifact );
|
||||
// although nothing has changed merge returns true, as the last modified date is equal
|
||||
// TODO: improve merge here?
|
||||
assertTrue( target.merge( source ) );
|
||||
// never convert from legacy format to v1.1 format
|
||||
assertEquals( 0, target.getVersioning().getSnapshotVersions().size() );
|
||||
assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() );
|
||||
assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() );
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeWithSnapshotLegacy()
|
||||
{
|
||||
Metadata source = createMetadataFromArtifact( artifact );
|
||||
Date before = new Date( System.currentTimeMillis() - 5000 );
|
||||
Date after = new Date( System.currentTimeMillis() );
|
||||
addSnapshotVersion( target.getVersioning(), before, artifact );
|
||||
// legacy metadata did not have "versioning.snapshotVersions"
|
||||
addSnapshotVersionLegacy( source.getVersioning(), after, 2 );
|
||||
// although nothing has changed merge returns true, as the last modified date is equal
|
||||
// TODO: improve merge here?
|
||||
assertTrue( target.merge( source ) );
|
||||
// the result must be legacy format as well
|
||||
assertEquals( 0, target.getVersioning().getSnapshotVersions().size() );
|
||||
assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() );
|
||||
assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() );
|
||||
assertEquals( 2, target.getVersioning().getSnapshot().getBuildNumber() );
|
||||
}
|
||||
/*-- END test "groupId/artifactId/version" metadata ---*/
|
||||
|
||||
/*-- START helper methods to populate metadata objects ---*/
|
||||
private static final String SNAPSHOT = "SNAPSHOT";
|
||||
|
||||
private static final String DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT = "yyyyMMdd.HHmmss";
|
||||
|
||||
private static final String DEFAULT_DATE_FORMAT = "yyyyMMddHHmmss";
|
||||
|
||||
private static String formatDate( Date date, boolean forSnapshotTimestamp )
|
||||
{
|
||||
// logic from metadata.mdo, class "Versioning"
|
||||
TimeZone timezone = TimeZone.getTimeZone( "UTC" );
|
||||
DateFormat fmt =
|
||||
new SimpleDateFormat( forSnapshotTimestamp ? DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT : DEFAULT_DATE_FORMAT );
|
||||
fmt.setCalendar( new GregorianCalendar() );
|
||||
fmt.setTimeZone( timezone );
|
||||
return fmt.format( date );
|
||||
}
|
||||
|
||||
private static Metadata createMetadataFromArtifact( Artifact artifact )
|
||||
{
|
||||
Metadata metadata = new Metadata();
|
||||
metadata.setArtifactId( artifact.getArtifactId() );
|
||||
metadata.setGroupId( artifact.getGroupId() );
|
||||
metadata.setVersion( artifact.getVersion() );
|
||||
metadata.setVersioning( new Versioning() );
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private static SnapshotVersion addSnapshotVersion( Versioning versioning, Date timestamp, Artifact artifact )
|
||||
{
|
||||
int buildNumber = 1;
|
||||
// this generates timestamped versions like maven-resolver-provider:
|
||||
// https://github.com/apache/maven/blob/03df5f7c639db744a3597c7175c92c8e2a27767b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java#L79
|
||||
String version = artifact.getVersion();
|
||||
String qualifier = formatDate( timestamp, true ) + '-' + buildNumber;
|
||||
version = version.substring( 0, version.length() - SNAPSHOT.length() ) + qualifier;
|
||||
return addSnapshotVersion( versioning, artifact.getExtension(), timestamp, version, buildNumber );
|
||||
}
|
||||
|
||||
private static SnapshotVersion addSnapshotVersion( Versioning versioning, String extension, Date timestamp,
|
||||
String version, int buildNumber )
|
||||
{
|
||||
Snapshot snapshot = new Snapshot();
|
||||
snapshot.setBuildNumber( buildNumber );
|
||||
snapshot.setTimestamp( formatDate( timestamp, true ) );
|
||||
|
||||
SnapshotVersion sv = new SnapshotVersion();
|
||||
sv.setExtension( extension );
|
||||
sv.setVersion( version );
|
||||
sv.setUpdated( formatDate( timestamp, false ) );
|
||||
versioning.addSnapshotVersion( sv );
|
||||
|
||||
// make the new snapshot the current one
|
||||
versioning.setSnapshot( snapshot );
|
||||
versioning.setLastUpdatedTimestamp( timestamp );
|
||||
return sv;
|
||||
}
|
||||
|
||||
// the format written by Maven 2
|
||||
// (https://maven.apache.org/ref/2.2.1/maven-repository-metadata/repository-metadata.html)
|
||||
private static void addSnapshotVersionLegacy( Versioning versioning, Date timestamp, int buildNumber )
|
||||
{
|
||||
Snapshot snapshot = new Snapshot();
|
||||
snapshot.setBuildNumber( buildNumber );
|
||||
snapshot.setTimestamp( formatDate( timestamp, true ) );
|
||||
|
||||
versioning.setSnapshot( snapshot );
|
||||
versioning.setLastUpdatedTimestamp( timestamp );
|
||||
}
|
||||
/*-- END helper methods to populate metadata objects ---*/
|
||||
}
|
Loading…
Reference in New Issue