mirror of https://github.com/apache/archiva.git
[MRM-1362] Add simple 'CRUD' pages for project-level metadata along with a "generic metadata" plugin
o removed project metadata custom tag o enable delete of generic metadata properties o added unit tests for adding and deleting properties o clear facet properties read from file before doing the update so that removed facet properties are not retained when updating project version metadata git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@952127 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a946c2e933
commit
8891e9fdd2
|
@ -24,7 +24,6 @@ import com.opensymphony.xwork2.Validateable;
|
||||||
import org.apache.archiva.metadata.generic.GenericMetadataFacet;
|
import org.apache.archiva.metadata.generic.GenericMetadataFacet;
|
||||||
import org.apache.archiva.metadata.model.ArtifactMetadata;
|
import org.apache.archiva.metadata.model.ArtifactMetadata;
|
||||||
import org.apache.archiva.metadata.model.Dependency;
|
import org.apache.archiva.metadata.model.Dependency;
|
||||||
import org.apache.archiva.metadata.model.License;
|
|
||||||
import org.apache.archiva.metadata.model.MailingList;
|
import org.apache.archiva.metadata.model.MailingList;
|
||||||
import org.apache.archiva.metadata.model.ProjectVersionMetadata;
|
import org.apache.archiva.metadata.model.ProjectVersionMetadata;
|
||||||
import org.apache.archiva.metadata.model.ProjectVersionReference;
|
import org.apache.archiva.metadata.model.ProjectVersionReference;
|
||||||
|
@ -57,6 +56,7 @@ import java.util.Map;
|
||||||
* @plexus.component role="com.opensymphony.xwork2.Action" role-hint="showArtifactAction"
|
* @plexus.component role="com.opensymphony.xwork2.Action" role-hint="showArtifactAction"
|
||||||
* instantiation-strategy="per-lookup"
|
* instantiation-strategy="per-lookup"
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings( "serial" )
|
||||||
public class ShowArtifactAction
|
public class ShowArtifactAction
|
||||||
extends AbstractRepositoryBasedAction
|
extends AbstractRepositoryBasedAction
|
||||||
implements Validateable
|
implements Validateable
|
||||||
|
@ -106,12 +106,8 @@ public class ShowArtifactAction
|
||||||
|
|
||||||
private boolean dependencyTree = false;
|
private boolean dependencyTree = false;
|
||||||
|
|
||||||
private ProjectVersionMetadata projectMetadata;
|
|
||||||
|
|
||||||
private String deleteItem;
|
private String deleteItem;
|
||||||
|
|
||||||
private String itemValue;
|
|
||||||
|
|
||||||
private Map<String, String> genericMetadata;
|
private Map<String, String> genericMetadata;
|
||||||
|
|
||||||
private String propertyName;
|
private String propertyName;
|
||||||
|
@ -335,13 +331,7 @@ public class ShowArtifactAction
|
||||||
|
|
||||||
genericMetadata.put( propertyName, propertyValue );
|
genericMetadata.put( propertyName, propertyValue );
|
||||||
|
|
||||||
GenericMetadataFacet genericMetadataFacet = new GenericMetadataFacet();
|
updateProjectMetadata( projectMetadata );
|
||||||
genericMetadataFacet.fromProperties( genericMetadata );
|
|
||||||
|
|
||||||
// add updated facet
|
|
||||||
projectMetadata.addFacet( genericMetadataFacet );
|
|
||||||
|
|
||||||
metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
|
|
||||||
|
|
||||||
projectMetadata = getProjectVersionMetadata();
|
projectMetadata = getProjectVersionMetadata();
|
||||||
|
|
||||||
|
@ -355,94 +345,55 @@ public class ShowArtifactAction
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String updateProjectMetadata()
|
public String deleteMetadataEntry()
|
||||||
{
|
{
|
||||||
metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
|
ProjectVersionMetadata projectMetadata = getProjectVersionMetadata();
|
||||||
|
String errorMsg = null;
|
||||||
|
|
||||||
|
if ( projectMetadata == null )
|
||||||
|
{
|
||||||
|
addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ) != null )
|
||||||
|
{
|
||||||
|
genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
|
||||||
|
|
||||||
|
if ( !StringUtils.isEmpty( deleteItem ) )
|
||||||
|
{
|
||||||
|
genericMetadata.remove( deleteItem );
|
||||||
|
|
||||||
|
updateProjectMetadata( projectMetadata );
|
||||||
|
|
||||||
|
projectMetadata = getProjectVersionMetadata();
|
||||||
|
|
||||||
|
genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
|
||||||
|
|
||||||
|
model = projectMetadata;
|
||||||
|
|
||||||
|
addActionMessage( "Property successfully deleted." );
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteItem = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addActionError( errorMsg != null ? errorMsg : "No generic metadata facet for this artifact." );
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String deleteMetadataEntry()
|
private void updateProjectMetadata( ProjectVersionMetadata projectMetadata )
|
||||||
{
|
{
|
||||||
projectMetadata = getProjectVersionMetadata();
|
GenericMetadataFacet genericMetadataFacet = new GenericMetadataFacet();
|
||||||
|
genericMetadataFacet.fromProperties( genericMetadata );
|
||||||
|
|
||||||
if ( !StringUtils.isEmpty( deleteItem ) && !StringUtils.isEmpty( itemValue ) )
|
projectMetadata.addFacet( genericMetadataFacet );
|
||||||
{
|
|
||||||
if ( "dependency".equals( deleteItem ) )
|
|
||||||
{
|
|
||||||
removeDependency();
|
|
||||||
}
|
|
||||||
else if ( "mailingList".equals( deleteItem ) )
|
|
||||||
{
|
|
||||||
removeMailingList();
|
|
||||||
}
|
|
||||||
else if ( "license".equals( deleteItem ) )
|
|
||||||
{
|
|
||||||
removeLicense();
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteItem = "";
|
metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
|
||||||
itemValue = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateProjectMetadata();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeDependency()
|
|
||||||
{
|
|
||||||
List<Dependency> dependencies = projectMetadata.getDependencies();
|
|
||||||
List<Dependency> newDependencies = new ArrayList<Dependency>();
|
|
||||||
|
|
||||||
if ( dependencies != null )
|
|
||||||
{
|
|
||||||
for ( Dependency dependency : dependencies )
|
|
||||||
{
|
|
||||||
if ( !StringUtils.equals( itemValue, dependency.getArtifactId() ) )
|
|
||||||
{
|
|
||||||
newDependencies.add( dependency );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
projectMetadata.setDependencies( newDependencies );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeMailingList()
|
|
||||||
{
|
|
||||||
List<MailingList> mailingLists = projectMetadata.getMailingLists();
|
|
||||||
List<MailingList> newMailingLists = new ArrayList<MailingList>();
|
|
||||||
|
|
||||||
if ( mailingLists != null )
|
|
||||||
{
|
|
||||||
for ( MailingList mailingList : mailingLists )
|
|
||||||
{
|
|
||||||
if ( !StringUtils.equals( itemValue, mailingList.getName() ) )
|
|
||||||
{
|
|
||||||
newMailingLists.add( mailingList );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
projectMetadata.setMailingLists( newMailingLists );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeLicense()
|
|
||||||
{
|
|
||||||
List<License> licenses = projectMetadata.getLicenses();
|
|
||||||
List<License> newLicenses = new ArrayList<License>();
|
|
||||||
|
|
||||||
if ( licenses != null )
|
|
||||||
{
|
|
||||||
for ( License license : licenses )
|
|
||||||
{
|
|
||||||
if ( !StringUtils.equals( itemValue, license.getName() ) )
|
|
||||||
{
|
|
||||||
newLicenses.add( license );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
projectMetadata.setLicenses( newLicenses );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -539,36 +490,16 @@ public class ShowArtifactAction
|
||||||
return artifacts.keySet();
|
return artifacts.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
|
|
||||||
{
|
|
||||||
this.repositoryFactory = repositoryFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDependencyTree()
|
public boolean isDependencyTree()
|
||||||
{
|
{
|
||||||
return dependencyTree;
|
return dependencyTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProjectVersionMetadata getProjectMetadata()
|
|
||||||
{
|
|
||||||
return projectMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProjectMetadata( ProjectVersionMetadata projectMetadata )
|
|
||||||
{
|
|
||||||
this.projectMetadata = projectMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeleteItem( String deleteItem )
|
public void setDeleteItem( String deleteItem )
|
||||||
{
|
{
|
||||||
this.deleteItem = deleteItem;
|
this.deleteItem = deleteItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setItemValue( String itemValue )
|
|
||||||
{
|
|
||||||
this.itemValue = itemValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getGenericMetadata()
|
public Map<String, String> getGenericMetadata()
|
||||||
{
|
{
|
||||||
return genericMetadata;
|
return genericMetadata;
|
||||||
|
@ -599,6 +530,16 @@ public class ShowArtifactAction
|
||||||
this.propertyValue = propertyValue;
|
this.propertyValue = propertyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
|
||||||
|
{
|
||||||
|
this.repositoryFactory = repositoryFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMetadataRepository( MetadataRepository metadataRepository )
|
||||||
|
{
|
||||||
|
this.metadataRepository = metadataRepository;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: move this into the artifact metadata itself via facets where necessary
|
// TODO: move this into the artifact metadata itself via facets where necessary
|
||||||
|
|
||||||
public class ArtifactDownloadInfo
|
public class ArtifactDownloadInfo
|
||||||
|
|
|
@ -1,305 +0,0 @@
|
||||||
package org.apache.maven.archiva.web.tags;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.servlet.jsp.JspException;
|
|
||||||
import javax.servlet.jsp.tagext.TagSupport;
|
|
||||||
|
|
||||||
import org.apache.archiva.metadata.model.Dependency;
|
|
||||||
import org.apache.archiva.metadata.model.License;
|
|
||||||
import org.apache.archiva.metadata.model.MailingList;
|
|
||||||
import org.apache.archiva.metadata.model.ProjectVersionMetadata;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ProjectMetadataTag
|
|
||||||
*
|
|
||||||
* Outputs the project metadata attributes, used in the Metadata tab in artifact browse.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings( "serial" )
|
|
||||||
public class ProjectMetadataTag
|
|
||||||
extends TagSupport
|
|
||||||
{
|
|
||||||
private Logger log = LoggerFactory.getLogger( ProjectMetadataTag.class );
|
|
||||||
|
|
||||||
private Object object;
|
|
||||||
|
|
||||||
private String groupId;
|
|
||||||
|
|
||||||
private String artifactId;
|
|
||||||
|
|
||||||
private String version;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release()
|
|
||||||
{
|
|
||||||
object = null;
|
|
||||||
super.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int doStartTag()
|
|
||||||
throws JspException
|
|
||||||
{
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
|
|
||||||
if ( object == null )
|
|
||||||
{
|
|
||||||
buf.append( "Error generating project metadata." );
|
|
||||||
log.error( "Unable to generate project metadata for null object." );
|
|
||||||
}
|
|
||||||
else if ( object instanceof ProjectVersionMetadata )
|
|
||||||
{
|
|
||||||
ProjectVersionMetadata metadata = (ProjectVersionMetadata) object;
|
|
||||||
|
|
||||||
buildProjectMetadata( buf, metadata );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buf.append( "Unable to generate project metadata for object " ).append( object.getClass().getName() );
|
|
||||||
}
|
|
||||||
|
|
||||||
out( buf.toString() );
|
|
||||||
|
|
||||||
return EVAL_BODY_INCLUDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void out( String msg )
|
|
||||||
throws JspException
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
pageContext.getOut().print( msg );
|
|
||||||
}
|
|
||||||
catch ( IOException e )
|
|
||||||
{
|
|
||||||
throw new JspException( "Unable to output to jsp page context." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildProjectMetadata( StringBuffer metadataEntries, ProjectVersionMetadata projectMetadata )
|
|
||||||
{
|
|
||||||
startList( metadataEntries );
|
|
||||||
|
|
||||||
addListItem( "project.metadata.id=", projectMetadata.getId(), metadataEntries );
|
|
||||||
addListItem( "project.url=", projectMetadata.getUrl(), metadataEntries );
|
|
||||||
addListItem( "project.name=", projectMetadata.getName(), metadataEntries );
|
|
||||||
addListItem( "project.description=", projectMetadata.getDescription(), metadataEntries );
|
|
||||||
|
|
||||||
if ( projectMetadata.getOrganization() != null )
|
|
||||||
{
|
|
||||||
startListItem( "organization", metadataEntries );
|
|
||||||
startList( metadataEntries );
|
|
||||||
addListItem( "organization.name=", projectMetadata.getOrganization().getName(), metadataEntries );
|
|
||||||
addListItem( "organization.url=", projectMetadata.getOrganization().getUrl(), metadataEntries );
|
|
||||||
endList( metadataEntries );
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( projectMetadata.getIssueManagement() != null )
|
|
||||||
{
|
|
||||||
startListItem( "issueManagement", metadataEntries );
|
|
||||||
startList( metadataEntries );
|
|
||||||
addListItem( "issueManagement.system=", projectMetadata.getIssueManagement().getSystem(), metadataEntries );
|
|
||||||
addListItem( "issueManagement.url=", projectMetadata.getIssueManagement().getUrl(), metadataEntries );
|
|
||||||
endList( metadataEntries );
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( projectMetadata.getScm() != null )
|
|
||||||
{
|
|
||||||
startListItem( "scm", metadataEntries );
|
|
||||||
startList( metadataEntries );
|
|
||||||
addListItem( "scm.url=", projectMetadata.getScm().getUrl(), metadataEntries );
|
|
||||||
addListItem( "scm.connection=", projectMetadata.getScm().getConnection(), metadataEntries );
|
|
||||||
addListItem( "scm.developer.connection=", projectMetadata.getScm().getDeveloperConnection(),
|
|
||||||
metadataEntries );
|
|
||||||
endList( metadataEntries );
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( projectMetadata.getCiManagement() != null )
|
|
||||||
{
|
|
||||||
startListItem( "ciManagement", metadataEntries );
|
|
||||||
startList( metadataEntries );
|
|
||||||
addListItem( "ciManagement.system=", projectMetadata.getCiManagement().getSystem(), metadataEntries );
|
|
||||||
addListItem( "ciManagement.url=", projectMetadata.getCiManagement().getUrl(), metadataEntries );
|
|
||||||
endList( metadataEntries );
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( projectMetadata.getLicenses() != null && !projectMetadata.getLicenses().isEmpty() )
|
|
||||||
{
|
|
||||||
startListItem( "licenses", metadataEntries );
|
|
||||||
List<License> licenses = projectMetadata.getLicenses();
|
|
||||||
int ctr = 0;
|
|
||||||
startList( metadataEntries );
|
|
||||||
for ( License license : licenses )
|
|
||||||
{
|
|
||||||
createDeleteLink( "license", license.getName(), metadataEntries );
|
|
||||||
startList( metadataEntries );
|
|
||||||
addListItem( "licenses." + ctr + ".name=", license.getName(), metadataEntries );
|
|
||||||
addListItem( "licenses." + ctr + ".url=", license.getUrl(), metadataEntries );
|
|
||||||
endList( metadataEntries );
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
ctr++;
|
|
||||||
}
|
|
||||||
endList( metadataEntries );
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( projectMetadata.getMailingLists() != null && !projectMetadata.getMailingLists().isEmpty() )
|
|
||||||
{
|
|
||||||
startListItem( "mailingLists", metadataEntries );
|
|
||||||
List<MailingList> lists = projectMetadata.getMailingLists();
|
|
||||||
List<String> otherArchives;
|
|
||||||
int ctr = 0;
|
|
||||||
int archiveCtr = 0;
|
|
||||||
|
|
||||||
startList( metadataEntries );
|
|
||||||
for ( MailingList list : lists )
|
|
||||||
{
|
|
||||||
createDeleteLink( "mailingList", list.getName(), metadataEntries );
|
|
||||||
startList( metadataEntries );
|
|
||||||
addListItem( "mailingLists." + ctr + ".name=", list.getName(), metadataEntries );
|
|
||||||
addListItem( "mailingLists." + ctr + ".archive.url=", list.getMainArchiveUrl(), metadataEntries );
|
|
||||||
addListItem( "mailingLists." + ctr + ".post=", list.getPostAddress(), metadataEntries );
|
|
||||||
addListItem( "mailingLists." + ctr + ".subscribe=", list.getSubscribeAddress(), metadataEntries );
|
|
||||||
addListItem( "mailingLists." + ctr + ".unsubscribe=", list.getUnsubscribeAddress(), metadataEntries );
|
|
||||||
startListItem( "mailingLists." + ctr + ".otherArchives", metadataEntries );
|
|
||||||
|
|
||||||
if ( list.getOtherArchives() != null && list.getOtherArchives().size() > 0 )
|
|
||||||
{
|
|
||||||
archiveCtr = 0;
|
|
||||||
otherArchives = list.getOtherArchives();
|
|
||||||
|
|
||||||
startList( metadataEntries );
|
|
||||||
for ( String archive : otherArchives )
|
|
||||||
{
|
|
||||||
addListItem( "mailingLists." + ctr + ".otherArchives." + archiveCtr + "=", archive,
|
|
||||||
metadataEntries );
|
|
||||||
metadataEntries.append( archive );
|
|
||||||
archiveCtr++;
|
|
||||||
}
|
|
||||||
endList( metadataEntries );
|
|
||||||
}
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
endList( metadataEntries );
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
ctr++;
|
|
||||||
}
|
|
||||||
endList( metadataEntries );
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( projectMetadata.getDependencies() != null && !projectMetadata.getDependencies().isEmpty() )
|
|
||||||
{
|
|
||||||
startListItem( "dependencies", metadataEntries );
|
|
||||||
List<Dependency> dependencies = projectMetadata.getDependencies();
|
|
||||||
int ctr = 0;
|
|
||||||
|
|
||||||
startList( metadataEntries );
|
|
||||||
|
|
||||||
for ( Dependency dependency : dependencies )
|
|
||||||
{
|
|
||||||
createDeleteLink( "dependency", dependency.getArtifactId(), metadataEntries );
|
|
||||||
startList( metadataEntries );
|
|
||||||
addListItem( "dependency." + ctr + ".group.id=", dependency.getGroupId(), metadataEntries );
|
|
||||||
addListItem( "dependency." + ctr + ".artifact.id=", dependency.getArtifactId(), metadataEntries );
|
|
||||||
addListItem( "dependency." + ctr + ".version=", dependency.getVersion(), metadataEntries );
|
|
||||||
addListItem( "dependency." + ctr + ".classifier=", dependency.getClassifier(), metadataEntries );
|
|
||||||
addListItem( "dependency." + ctr + ".type=", dependency.getType(), metadataEntries );
|
|
||||||
addListItem( "dependency." + ctr + ".scope=", dependency.getScope(), metadataEntries );
|
|
||||||
addListItem( "dependency." + ctr + ".system.path=", dependency.getSystemPath(), metadataEntries );
|
|
||||||
endList( metadataEntries );
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
ctr++;
|
|
||||||
}
|
|
||||||
endList( metadataEntries );
|
|
||||||
|
|
||||||
endListItem( metadataEntries );
|
|
||||||
}
|
|
||||||
|
|
||||||
endList( metadataEntries );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startList( StringBuffer metadataEntries )
|
|
||||||
{
|
|
||||||
metadataEntries.append( "\n<ul>" );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void endList( StringBuffer metadataEntries )
|
|
||||||
{
|
|
||||||
metadataEntries.append( "\n</ul>" );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addListItem( String label, String value, StringBuffer metadataEntries )
|
|
||||||
{
|
|
||||||
String newValue = StringUtils.isEmpty( value ) ? "" : value;
|
|
||||||
metadataEntries.append( "\n<li>" ).append( label ).append( newValue ).append( "</li>" );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startListItem( String value, StringBuffer metadataEntries )
|
|
||||||
{
|
|
||||||
metadataEntries.append( "\n<li>" ).append( value );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void endListItem( StringBuffer metadataEntries )
|
|
||||||
{
|
|
||||||
metadataEntries.append( "\n</li>" );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createDeleteLink( String name, String value, StringBuffer metadataEntries )
|
|
||||||
{
|
|
||||||
metadataEntries.append( "\n<li>" ).append( value )
|
|
||||||
.append( "\n<a href=\"showProjectMetadata!deleteMetadataEntry.action?" )
|
|
||||||
.append( "groupId=" ).append( groupId )
|
|
||||||
.append( "&artifactId=" ).append( artifactId )
|
|
||||||
.append( "&version=" ).append( version )
|
|
||||||
.append( "&deleteItem=" ).append( name )
|
|
||||||
.append( "&itemValue=").append( value ).append( "\" >" )
|
|
||||||
.append( "<img src=\"images/icons/delete.gif\"/>" ).append( "</a>" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setObject( Object object )
|
|
||||||
{
|
|
||||||
this.object = object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGroupId( String groupId )
|
|
||||||
{
|
|
||||||
this.groupId = groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setArtifactId( String artifactId )
|
|
||||||
{
|
|
||||||
this.artifactId = artifactId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersion( String version )
|
|
||||||
{
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -228,10 +228,8 @@
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
<action name="deleteMetadataEntry" class="showArtifactAction" method="deleteMetadataEntry">
|
<action name="deleteMetadataEntry" class="showArtifactAction" method="deleteMetadataEntry">
|
||||||
<result name="success" type="redirect-action">
|
<result name="input">/WEB-INF/jsp/showArtifact.jsp</result>
|
||||||
<param name="actionName">showProjectMetadata</param>
|
<result name="success">/WEB-INF/jsp/showArtifact.jsp</result>
|
||||||
<param name="namespace">/</param>
|
|
||||||
</result>
|
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
</package>
|
</package>
|
||||||
|
|
|
@ -61,25 +61,20 @@
|
||||||
<c:if test="${!empty genericMetadata}">
|
<c:if test="${!empty genericMetadata}">
|
||||||
<ul>
|
<ul>
|
||||||
<c:forEach var="prop" items="${genericMetadata}">
|
<c:forEach var="prop" items="${genericMetadata}">
|
||||||
<li>${prop.key}=${prop.value}</li>
|
<c:url var="deletePropertyUrl" value="showProjectMetadata!deleteMetadataEntry.action">
|
||||||
|
<c:param name="groupId" value="${groupId}"/>
|
||||||
|
<c:param name="artifactId" value="${artifactId}"/>
|
||||||
|
<c:param name="version" value="${version}"/>
|
||||||
|
<c:param name="deleteItem" value="${prop.key}"/>
|
||||||
|
</c:url>
|
||||||
|
<li>${prop.key}=${prop.value}
|
||||||
|
<a href="${deletePropertyUrl}">
|
||||||
|
<img src="<c:url value="/images/icons/delete.gif" />" alt="Delete" width="12" length="12"/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</c:forEach>
|
</c:forEach>
|
||||||
</ul>
|
</ul>
|
||||||
</c:if>
|
</c:if>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<s:if test="hasActionMessages()">
|
|
||||||
<div id="messages">
|
|
||||||
<s:actionmessage/>
|
|
||||||
</div>
|
|
||||||
</s:if>
|
|
||||||
<s:if test="hasActionErrors()">
|
|
||||||
<div id="messages">
|
|
||||||
<s:actionerror/>
|
|
||||||
</div>
|
|
||||||
</s:if>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<%-- <archiva:project-metadata object="${projectMetadata}" groupId="${groupId}" artifactId="${artifactId}" version="${version}" /> --%>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -249,6 +249,11 @@
|
||||||
<s:actionmessage />
|
<s:actionmessage />
|
||||||
</div>
|
</div>
|
||||||
</s:if>
|
</s:if>
|
||||||
|
<s:if test="hasActionErrors()">
|
||||||
|
<div id="messages">
|
||||||
|
<s:actionerror/>
|
||||||
|
</div>
|
||||||
|
</s:if>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -110,45 +110,4 @@
|
||||||
|
|
||||||
</tag>
|
</tag>
|
||||||
|
|
||||||
<tag>
|
|
||||||
|
|
||||||
<name>project-metadata</name>
|
|
||||||
<tag-class>org.apache.maven.archiva.web.tags.ProjectMetadataTag</tag-class>
|
|
||||||
<body-content>empty</body-content>
|
|
||||||
<description><![CDATA[Render the project metadata tree from the provided ProjectMetadataVersion object]]></description>
|
|
||||||
|
|
||||||
<attribute>
|
|
||||||
<name>object</name>
|
|
||||||
<required>true</required>
|
|
||||||
<rtexprvalue>true</rtexprvalue>
|
|
||||||
|
|
||||||
<description><![CDATA[The Object to Render]]></description>
|
|
||||||
</attribute>
|
|
||||||
|
|
||||||
<attribute>
|
|
||||||
<name>groupId</name>
|
|
||||||
<required>true</required>
|
|
||||||
<rtexprvalue>true</rtexprvalue>
|
|
||||||
|
|
||||||
<description><![CDATA[The groupId]]></description>
|
|
||||||
</attribute>
|
|
||||||
|
|
||||||
<attribute>
|
|
||||||
<name>artifactId</name>
|
|
||||||
<required>true</required>
|
|
||||||
<rtexprvalue>true</rtexprvalue>
|
|
||||||
|
|
||||||
<description><![CDATA[The artifactId]]></description>
|
|
||||||
</attribute>
|
|
||||||
|
|
||||||
<attribute>
|
|
||||||
<name>version</name>
|
|
||||||
<required>true</required>
|
|
||||||
<rtexprvalue>true</rtexprvalue>
|
|
||||||
|
|
||||||
<description><![CDATA[The version]]></description>
|
|
||||||
</attribute>
|
|
||||||
|
|
||||||
</tag>
|
|
||||||
|
|
||||||
</taglib>
|
</taglib>
|
||||||
|
|
|
@ -27,9 +27,14 @@ import org.apache.archiva.metadata.model.Dependency;
|
||||||
import org.apache.archiva.metadata.model.MailingList;
|
import org.apache.archiva.metadata.model.MailingList;
|
||||||
import org.apache.archiva.metadata.model.ProjectVersionMetadata;
|
import org.apache.archiva.metadata.model.ProjectVersionMetadata;
|
||||||
import org.apache.archiva.metadata.model.ProjectVersionReference;
|
import org.apache.archiva.metadata.model.ProjectVersionReference;
|
||||||
|
import org.apache.archiva.metadata.repository.MetadataRepository;
|
||||||
|
import org.apache.archiva.metadata.repository.file.FileMetadataRepository;
|
||||||
import org.apache.archiva.metadata.repository.memory.TestMetadataResolver;
|
import org.apache.archiva.metadata.repository.memory.TestMetadataResolver;
|
||||||
import org.apache.archiva.metadata.repository.storage.maven2.MavenArtifactFacet;
|
import org.apache.archiva.metadata.repository.storage.maven2.MavenArtifactFacet;
|
||||||
import org.apache.maven.archiva.common.utils.VersionUtil;
|
import org.apache.maven.archiva.common.utils.VersionUtil;
|
||||||
|
import org.apache.maven.archiva.configuration.ArchivaConfiguration;
|
||||||
|
import org.apache.maven.archiva.configuration.Configuration;
|
||||||
|
import org.apache.maven.archiva.configuration.DefaultArchivaConfiguration;
|
||||||
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
|
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
|
||||||
import org.apache.maven.archiva.repository.ManagedRepositoryContent;
|
import org.apache.maven.archiva.repository.ManagedRepositoryContent;
|
||||||
import org.apache.maven.archiva.repository.RepositoryContentFactory;
|
import org.apache.maven.archiva.repository.RepositoryContentFactory;
|
||||||
|
@ -396,6 +401,61 @@ public class ShowArtifactActionTest
|
||||||
assertTrue( action.getArtifacts().isEmpty() );
|
assertTrue( action.getArtifacts().isEmpty() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testAddAndDeleteMetadataProperty()
|
||||||
|
{
|
||||||
|
ProjectVersionMetadata versionMetadata = createProjectModel( TEST_VERSION );
|
||||||
|
|
||||||
|
metadataResolver.setProjectVersion( TEST_REPO, TEST_GROUP_ID, TEST_ARTIFACT_ID, versionMetadata );
|
||||||
|
|
||||||
|
setActionParameters();
|
||||||
|
action.setPropertyName( "foo" );
|
||||||
|
action.setPropertyValue( "bar" );
|
||||||
|
action.setRepositoryId( TEST_REPO );
|
||||||
|
|
||||||
|
String result = action.addMetadataProperty();
|
||||||
|
|
||||||
|
assertActionSuccess( action, result );
|
||||||
|
assertActionParameters( action );
|
||||||
|
|
||||||
|
Map<String, String> genericMetadata = action.getGenericMetadata();
|
||||||
|
assertNotNull( genericMetadata.get( TEST_GENERIC_METADATA_PROPERTY_NAME ) );
|
||||||
|
assertEquals( genericMetadata.get( TEST_GENERIC_METADATA_PROPERTY_NAME ), TEST_GENERIC_METADATA_PROPERTY_VALUE );
|
||||||
|
|
||||||
|
assertNotNull( genericMetadata.get( "foo" ) );
|
||||||
|
assertEquals( "bar", genericMetadata.get( "foo" ) );
|
||||||
|
|
||||||
|
assertEquals( TEST_REPO, action.getRepositoryId() );
|
||||||
|
assertNotNull( action.getModel() );
|
||||||
|
assertNull( action.getDependees() );
|
||||||
|
assertNull( action.getDependencies() );
|
||||||
|
assertNull( action.getMailingLists() );
|
||||||
|
assertTrue( action.getArtifacts().isEmpty() );
|
||||||
|
|
||||||
|
// test delete property
|
||||||
|
setActionParameters();
|
||||||
|
action.setDeleteItem( "foo" );
|
||||||
|
|
||||||
|
result = action.deleteMetadataEntry();
|
||||||
|
|
||||||
|
assertEquals( Action.SUCCESS, result );
|
||||||
|
assertActionParameters( action );
|
||||||
|
assertTrue( !action.getActionMessages().isEmpty() );
|
||||||
|
assertTrue( action.getActionMessages().contains( "Property successfully deleted." ) );
|
||||||
|
|
||||||
|
genericMetadata = action.getGenericMetadata();
|
||||||
|
assertNotNull( genericMetadata.get( TEST_GENERIC_METADATA_PROPERTY_NAME ) );
|
||||||
|
assertEquals( genericMetadata.get( TEST_GENERIC_METADATA_PROPERTY_NAME ), TEST_GENERIC_METADATA_PROPERTY_VALUE );
|
||||||
|
|
||||||
|
assertNull( genericMetadata.get( "foo" ) );
|
||||||
|
|
||||||
|
assertEquals( TEST_REPO, action.getRepositoryId() );
|
||||||
|
assertNotNull( action.getModel() );
|
||||||
|
assertNull( action.getDependees() );
|
||||||
|
assertNull( action.getDependencies() );
|
||||||
|
assertNull( action.getMailingLists() );
|
||||||
|
assertTrue( action.getArtifacts().isEmpty() );
|
||||||
|
}
|
||||||
|
|
||||||
private void assertArtifacts( List<ArtifactMetadata> expectedArtifacts,
|
private void assertArtifacts( List<ArtifactMetadata> expectedArtifacts,
|
||||||
Map<String, List<ShowArtifactAction.ArtifactDownloadInfo>> artifactMap )
|
Map<String, List<ShowArtifactAction.ArtifactDownloadInfo>> artifactMap )
|
||||||
{
|
{
|
||||||
|
@ -575,10 +635,25 @@ public class ShowArtifactActionTest
|
||||||
ManagedRepositoryConfiguration config = new ManagedRepositoryConfiguration();
|
ManagedRepositoryConfiguration config = new ManagedRepositoryConfiguration();
|
||||||
config.setId( TEST_REPO );
|
config.setId( TEST_REPO );
|
||||||
config.setLocation( getTestFile( "target/test-repo" ).getAbsolutePath() );
|
config.setLocation( getTestFile( "target/test-repo" ).getAbsolutePath() );
|
||||||
|
|
||||||
ManagedRepositoryContent content = new ManagedDefaultRepositoryContent();
|
ManagedRepositoryContent content = new ManagedDefaultRepositoryContent();
|
||||||
content.setRepository( config );
|
content.setRepository( config );
|
||||||
factory.getManagedRepositoryContent( TEST_REPO );
|
factory.getManagedRepositoryContent( TEST_REPO );
|
||||||
|
|
||||||
|
FileMetadataRepository metadataRepo = ( FileMetadataRepository ) lookup( MetadataRepository.class );
|
||||||
|
MockControl archivaConfigControl = MockControl.createControl( ArchivaConfiguration.class );
|
||||||
|
ArchivaConfiguration archivaConfig = (ArchivaConfiguration) archivaConfigControl.getMock();
|
||||||
|
|
||||||
|
Configuration configuration = new Configuration();
|
||||||
|
configuration.addManagedRepository( config );
|
||||||
|
metadataRepo.setConfiguration( archivaConfig );
|
||||||
|
archivaConfig.getConfiguration();
|
||||||
|
|
||||||
|
action.setMetadataRepository( metadataRepo );
|
||||||
|
|
||||||
|
archivaConfigControl.setDefaultReturnValue( configuration );
|
||||||
control.setDefaultReturnValue( content );
|
control.setDefaultReturnValue( content );
|
||||||
control.replay();
|
control.replay();
|
||||||
|
archivaConfigControl.replay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,6 +165,40 @@ public abstract class AbstractMetadataRepositoryTest
|
||||||
assertEquals( Collections.<String>emptyList(), new ArrayList<String>( metadata.getFacetIds() ) );
|
assertEquals( Collections.<String>emptyList(), new ArrayList<String>( metadata.getFacetIds() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testUpdateProjectVersionMetadataWithExistingFacetsFacetPropertyWasRemoved()
|
||||||
|
throws MetadataResolutionException
|
||||||
|
{
|
||||||
|
ProjectVersionMetadata metadata = new ProjectVersionMetadata();
|
||||||
|
metadata.setId( TEST_PROJECT_VERSION );
|
||||||
|
|
||||||
|
Map<String, String> additionalProps = new HashMap<String,String>();
|
||||||
|
additionalProps.put( "deleteKey", "deleteValue" );
|
||||||
|
|
||||||
|
MetadataFacet facet = new TestMetadataFacet( TEST_FACET_ID, "baz", additionalProps );
|
||||||
|
metadata.addFacet( facet );
|
||||||
|
repository.updateProjectVersion( TEST_REPO_ID, TEST_NAMESPACE, TEST_PROJECT, metadata );
|
||||||
|
|
||||||
|
metadata = repository.getProjectVersion( TEST_REPO_ID, TEST_NAMESPACE, TEST_PROJECT, TEST_PROJECT_VERSION );
|
||||||
|
assertEquals( Collections.singleton( TEST_FACET_ID ), metadata.getFacetIds() );
|
||||||
|
|
||||||
|
TestMetadataFacet testFacet = (TestMetadataFacet) metadata.getFacet( TEST_FACET_ID );
|
||||||
|
Map<String, String> facetProperties = testFacet.toProperties();
|
||||||
|
|
||||||
|
assertEquals( "deleteValue", facetProperties.get( "deleteKey" ) );
|
||||||
|
|
||||||
|
facetProperties.remove( "deleteKey" );
|
||||||
|
|
||||||
|
TestMetadataFacet newTestFacet = new TestMetadataFacet( TEST_FACET_ID, testFacet.getValue(), facetProperties );
|
||||||
|
metadata.addFacet( newTestFacet );
|
||||||
|
|
||||||
|
repository.updateProjectVersion( TEST_REPO_ID, TEST_NAMESPACE, TEST_PROJECT, metadata );
|
||||||
|
|
||||||
|
metadata = repository.getProjectVersion( TEST_REPO_ID, TEST_NAMESPACE, TEST_PROJECT, TEST_PROJECT_VERSION );
|
||||||
|
assertEquals( Collections.singleton( TEST_FACET_ID ), metadata.getFacetIds() );
|
||||||
|
testFacet = (TestMetadataFacet) metadata.getFacet( TEST_FACET_ID );
|
||||||
|
assertFalse( testFacet.toProperties().containsKey( "deleteKey" ) );
|
||||||
|
}
|
||||||
|
|
||||||
public void testUpdateArtifactMetadataWithExistingFacets()
|
public void testUpdateArtifactMetadataWithExistingFacets()
|
||||||
{
|
{
|
||||||
ArtifactMetadata metadata = createArtifact();
|
ArtifactMetadata metadata = createArtifact();
|
||||||
|
@ -614,6 +648,10 @@ public abstract class AbstractMetadataRepositoryTest
|
||||||
{
|
{
|
||||||
private String testFacetId;
|
private String testFacetId;
|
||||||
|
|
||||||
|
private Map<String, String> additionalProps;
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
private TestMetadataFacet( String value )
|
private TestMetadataFacet( String value )
|
||||||
{
|
{
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -626,7 +664,11 @@ public abstract class AbstractMetadataRepositoryTest
|
||||||
testFacetId = facetId;
|
testFacetId = facetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String value;
|
private TestMetadataFacet( String facetId, String value, Map<String, String> additionalProps )
|
||||||
|
{
|
||||||
|
this( facetId, value );
|
||||||
|
this.additionalProps = additionalProps;
|
||||||
|
}
|
||||||
|
|
||||||
public String getFacetId()
|
public String getFacetId()
|
||||||
{
|
{
|
||||||
|
@ -641,10 +683,24 @@ public abstract class AbstractMetadataRepositoryTest
|
||||||
public Map<String, String> toProperties()
|
public Map<String, String> toProperties()
|
||||||
{
|
{
|
||||||
if ( value != null )
|
if ( value != null )
|
||||||
|
{
|
||||||
|
if( additionalProps == null )
|
||||||
{
|
{
|
||||||
return Collections.singletonMap( "foo", value );
|
return Collections.singletonMap( "foo", value );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
Map<String, String> props = new HashMap<String, String>();
|
||||||
|
props.put( "foo", value );
|
||||||
|
|
||||||
|
for( String key : additionalProps.keySet() )
|
||||||
|
{
|
||||||
|
props.put( key, additionalProps.get( key ) );
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
@ -657,6 +713,18 @@ public abstract class AbstractMetadataRepositoryTest
|
||||||
{
|
{
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
properties.remove( "foo" );
|
||||||
|
|
||||||
|
if( additionalProps == null )
|
||||||
|
{
|
||||||
|
additionalProps = new HashMap<String, String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
for( String key: properties.keySet() )
|
||||||
|
{
|
||||||
|
additionalProps.put( key, properties.get( key ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue()
|
public String getValue()
|
||||||
|
|
|
@ -19,7 +19,6 @@ package org.apache.archiva.metadata.generic;
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,9 @@ public class FileMetadataRepository
|
||||||
{
|
{
|
||||||
properties.remove( name );
|
properties.remove( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear the facet contents so old properties are no longer written
|
||||||
|
clearMetadataFacetProperties( versionMetadata, properties );
|
||||||
}
|
}
|
||||||
properties.setProperty( "id", versionMetadata.getId() );
|
properties.setProperty( "id", versionMetadata.getId() );
|
||||||
setProperty( properties, "name", versionMetadata.getName() );
|
setProperty( properties, "name", versionMetadata.getName() );
|
||||||
|
@ -225,6 +228,27 @@ public class FileMetadataRepository
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearMetadataFacetProperties( ProjectVersionMetadata versionMetadata, Properties properties )
|
||||||
|
{
|
||||||
|
List<Object> propsToRemove = new ArrayList<Object>();
|
||||||
|
for ( MetadataFacet facet : versionMetadata.getFacetList() )
|
||||||
|
{
|
||||||
|
for ( Object key : properties.keySet() )
|
||||||
|
{
|
||||||
|
String keyString = ( String ) key;
|
||||||
|
if( keyString.startsWith( facet.getFacetId() + ":" ) )
|
||||||
|
{
|
||||||
|
propsToRemove.add( key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for( Object key : propsToRemove )
|
||||||
|
{
|
||||||
|
properties.remove( key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void updateProjectReference( String repoId, String namespace, String projectId, String projectVersion,
|
public void updateProjectReference( String repoId, String namespace, String projectId, String projectVersion,
|
||||||
ProjectVersionReference reference )
|
ProjectVersionReference reference )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue