diff --git a/.gitignore b/.gitignore index 210b2e2..a410fbd 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ out # ci config for local ci build .circleci/local-config.yml venv* +/.metadata/ +**/bin +**/target diff --git a/README.md b/README.md index 0025752..39cda33 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ The table below outlines what version of Nexus Repository the plugin was built a | v0.2.1 | 3.31.0-01 | | v0.2.2 | 3.38.0-01 / 3.39.0.01 | | v0.3.0 | \>= 3.41.0 | +| v0.3.1 | \>= 3.41.0 | If a new version of Nexus Repository is released and the plugin needs changes, a new release will be made, and this table will be updated to indicate which version of Nexus Repository it will function against. This is done on a time diff --git a/nexus-repository-ansiblegalaxy-it/pom.xml b/nexus-repository-ansiblegalaxy-it/pom.xml index d7fd5bd..b1667f5 100644 --- a/nexus-repository-ansiblegalaxy-it/pom.xml +++ b/nexus-repository-ansiblegalaxy-it/pom.xml @@ -19,7 +19,7 @@ org.sonatype.nexus.plugins nexus-repository-ansiblegalaxy-parent - 0.3.0 + 0.3.2 nexus-repository-ansiblegalaxy-it diff --git a/nexus-repository-ansiblegalaxy/pom.xml b/nexus-repository-ansiblegalaxy/pom.xml index 6b7e16f..ec75ef0 100644 --- a/nexus-repository-ansiblegalaxy/pom.xml +++ b/nexus-repository-ansiblegalaxy/pom.xml @@ -19,7 +19,7 @@ org.sonatype.nexus.plugins nexus-repository-ansiblegalaxy-parent - 0.3.0 + 0.3.2 nexus-repository-ansiblegalaxy diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyApiRepositoryAdapter.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyApiRepositoryAdapter.java new file mode 100644 index 0000000..dbc59b2 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyApiRepositoryAdapter.java @@ -0,0 +1,83 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.api; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.sonatype.nexus.common.collect.NestedAttributesMap; +import org.sonatype.nexus.common.text.Strings2; +import org.sonatype.nexus.repository.Repository; +import org.sonatype.nexus.repository.rest.api.SimpleApiRepositoryAdapter; +import org.sonatype.nexus.repository.rest.api.model.AbstractApiRepository; +import org.sonatype.nexus.repository.routing.RoutingRuleStore; +import org.sonatype.nexus.repository.types.HostedType; +import org.sonatype.nexus.repository.types.ProxyType; + +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyFormat; +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyAttributes; +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyHostedApiRepository; +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyProxyApiRepository; + +@Named(AnsibleGalaxyFormat.NAME) +public class AnsibleGalaxyApiRepositoryAdapter + extends SimpleApiRepositoryAdapter +{ + private static final String ANSIBLEGALAXY = "ansiblegalaxy"; + + @Inject + public AnsibleGalaxyApiRepositoryAdapter(final RoutingRuleStore routingRuleStore) { + super(routingRuleStore); + } + + @Override + public AbstractApiRepository adapt(final Repository repository) { + boolean online = repository.getConfiguration().isOnline(); + String name = repository.getName(); + String url = repository.getUrl(); + + switch( repository.getType().toString()) { + case HostedType.NAME: + return new AnsibleGalaxyHostedApiRepository( + repository.getName(), + repository.getUrl(), + repository.getConfiguration().isOnline(), + getHostedStorageAttributes(repository), + getCleanupPolicyAttributes(repository), + getComponentAttributes(repository), + createAnsibleGalaxyAttributes(repository) + ); + case ProxyType.NAME: + return new AnsibleGalaxyProxyApiRepository( + repository.getName(), + repository.getUrl(), + repository.getConfiguration().isOnline(), + getHostedStorageAttributes(repository), + getCleanupPolicyAttributes(repository), + getProxyAttributes(repository), + getNegativeCacheAttributes(repository), + getHttpClientAttributes(repository), + getRoutingRuleName(repository), + getReplicationAttributes(repository), + createAnsibleGalaxyAttributes(repository) + ); + default: + return super.adapt(repository); + } + } + + private AnsibleGalaxyAttributes createAnsibleGalaxyAttributes(final Repository repository) { + String disposition = repository.getConfiguration().attributes(ANSIBLEGALAXY).get("contentDisposition", String.class); + return new AnsibleGalaxyAttributes(disposition); + } +} diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyAttributes.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyAttributes.java new file mode 100644 index 0000000..07065eb --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyAttributes.java @@ -0,0 +1,37 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy; + +import javax.validation.constraints.NotEmpty; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModelProperty; + +public class AnsibleGalaxyAttributes +{ + @ApiModelProperty(value = "Content Disposition", + allowableValues = "INLINE,ATTACHMENT", example = "ATTACHMENT") + @NotEmpty + private final String contentDisposition; + + @JsonCreator + public AnsibleGalaxyAttributes( + @JsonProperty("contentDisposition") final String contentDisposition) { + this.contentDisposition = contentDisposition; + } + + public String getContentDisposition() { + return contentDisposition; + } +} diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyHostedApiRepository.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyHostedApiRepository.java new file mode 100644 index 0000000..dc2264f --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyHostedApiRepository.java @@ -0,0 +1,54 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy; + +import javax.validation.constraints.NotNull; + +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyFormat; +import org.sonatype.nexus.repository.rest.api.model.CleanupPolicyAttributes; +import org.sonatype.nexus.repository.rest.api.model.ComponentAttributes; +import org.sonatype.nexus.repository.rest.api.model.HostedStorageAttributes; +import org.sonatype.nexus.repository.rest.api.model.SimpleApiHostedRepository; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyAttributes; + +/** + * @since 3.41 + */ +public class AnsibleGalaxyHostedApiRepository + extends SimpleApiHostedRepository +{ + @NotNull + private final AnsibleGalaxyAttributes ansiblegalaxy; + + @JsonCreator + public AnsibleGalaxyHostedApiRepository( + @JsonProperty("name") final String name, + @JsonProperty("url") final String url, + @JsonProperty("online") final Boolean online, + @JsonProperty("storage") final HostedStorageAttributes storage, + @JsonProperty("cleanup") final CleanupPolicyAttributes cleanup, + @JsonProperty("component") final ComponentAttributes component, + @JsonProperty("ansiblegalaxy") final AnsibleGalaxyAttributes ansiblegalaxy) + { + super(name, AnsibleGalaxyFormat.NAME, url, online, storage, cleanup, component); + this.ansiblegalaxy = ansiblegalaxy; + } + + public AnsibleGalaxyAttributes getAnsibleGalaxy() { + return ansiblegalaxy; + } +} diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyProxyApiRepository.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyProxyApiRepository.java new file mode 100644 index 0000000..c61346d --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AnsibleGalaxyProxyApiRepository.java @@ -0,0 +1,63 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy; + +import javax.validation.constraints.NotNull; + +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyFormat; +import org.sonatype.nexus.repository.rest.api.model.CleanupPolicyAttributes; +import org.sonatype.nexus.repository.rest.api.model.HttpClientAttributes; +import org.sonatype.nexus.repository.rest.api.model.NegativeCacheAttributes; +import org.sonatype.nexus.repository.rest.api.model.ProxyAttributes; +import org.sonatype.nexus.repository.rest.api.model.ReplicationAttributes; +import org.sonatype.nexus.repository.rest.api.model.SimpleApiProxyRepository; +import org.sonatype.nexus.repository.rest.api.model.StorageAttributes; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyAttributes; + +/** + * @since 3.41 + */ +public class AnsibleGalaxyProxyApiRepository + extends SimpleApiProxyRepository +{ + + @NotNull + private final AnsibleGalaxyAttributes ansiblegalaxy; + + public AnsibleGalaxyProxyApiRepository( + @JsonProperty("name") final String name, + @JsonProperty("url") final String url, + @JsonProperty("online") final Boolean online, + @JsonProperty("storage") final StorageAttributes storage, + @JsonProperty("cleanup") final CleanupPolicyAttributes cleanup, + @JsonProperty("proxy") final ProxyAttributes proxy, + @JsonProperty("negativeCache") final NegativeCacheAttributes negativeCache, + @JsonProperty("httpClient") final HttpClientAttributes httpClient, + @JsonProperty("routingRuleName") final String routingRuleName, + @JsonProperty("replication") @JsonInclude(value= Include.NON_EMPTY, content=Include.NON_NULL) + final ReplicationAttributes replication, + @JsonProperty("ansiblegalaxy") final AnsibleGalaxyAttributes ansiblegalaxy) + { + super(name, AnsibleGalaxyFormat.NAME, url, online, storage, cleanup, proxy, negativeCache, httpClient, routingRuleName, replication); + this.ansiblegalaxy = ansiblegalaxy; + } + + public AnsibleGalaxyAttributes getAnsibleGalaxy() { + return ansiblegalaxy; + } +} \ No newline at end of file diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AssetKind.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AssetKind.java index 78a5e89..e5f31e5 100644 --- a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AssetKind.java +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/AssetKind.java @@ -26,6 +26,7 @@ public enum AssetKind { API_METADATA(METADATA), COLLECTION_DETAIL(METADATA), COLLECTION_VERSION_LIST(METADATA), + COLLECTION_VERSION_LIST_LIMIT(METADATA), COLLECTION_VERSION_DETAIL(METADATA), COLLECTION_ARTIFACT(CONTENT), ROLE_SEARCH(METADATA), diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/ContentDisposition.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/ContentDisposition.java new file mode 100644 index 0000000..693e567 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/ContentDisposition.java @@ -0,0 +1,28 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy; + +public enum ContentDisposition { + INLINE("inline"), + ATTACHMENT("attachment"); + + private final String value; + + ContentDisposition(final String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/ContentDispositionHandler.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/ContentDispositionHandler.java new file mode 100644 index 0000000..0fa17e4 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/ContentDispositionHandler.java @@ -0,0 +1,44 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy; + +import javax.annotation.Nonnull; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.sonatype.nexus.repository.view.Context; +import org.sonatype.nexus.repository.view.Handler; +import org.sonatype.nexus.repository.view.Response; + +import static org.sonatype.nexus.repository.http.HttpMethods.GET; + + +public class ContentDispositionHandler + implements Handler +{ + public static final String CONTENT_DISPOSITION_CONFIG_KEY = "contentDisposition"; + + @Nonnull + @Override + public Response handle(@Nonnull final Context context) throws Exception { + Response response = context.proceed(); + String action = context.getRequest().getAction(); + if (GET.equals(action)) { + String contentDisposition = context.getRepository().getConfiguration().attributes("ansiblegalaxy") + .get(CONTENT_DISPOSITION_CONFIG_KEY, String.class, ContentDisposition.INLINE.name()); + + response.getHeaders().replace("Content-Disposition", ContentDisposition.valueOf(contentDisposition).getValue()); + } + return response; + } +} diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/AnsibleGalaxyRecipeSupport.groovy b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/AnsibleGalaxyRecipeSupport.groovy index 7f56d86..797e87b 100644 --- a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/AnsibleGalaxyRecipeSupport.groovy +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/AnsibleGalaxyRecipeSupport.groovy @@ -151,6 +151,14 @@ abstract class AnsibleGalaxyRecipeSupport setAssetKind(AssetKind.COLLECTION_VERSION_LIST) ) } + // /api/v3/plugin/ansible/content/published/collections/index/ansible/netcommon/versions/ + static Matcher collectionVersionListMatcherPages() { + LogicMatchers.and( + new ActionMatcher(GET, HEAD), + new QueryTokenMatcher("/api/{apiversion}/plugin/ansible/content/published/collections/index/{author}/{module}/versions/", [limit: "limit", offset: "offset"]), + setAssetKind(AssetKind.COLLECTION_VERSION_LIST_LIMIT) + ) + } static Matcher collectionVersionDetailMatcher() { LogicMatchers.and( @@ -161,6 +169,14 @@ abstract class AnsibleGalaxyRecipeSupport } static Matcher collectionArtifactMatcher() { + LogicMatchers.and( + new ActionMatcher(GET, HEAD), + new TokenMatcher("/api/{apiversion}/plugin/ansible/content/published/collections/artifacts/{author}-{module}-{version}.tar.gz"), + setAssetKind(AssetKind.COLLECTION_ARTIFACT) + ) + } + + static Matcher collectionArtifactV2Matcher() { LogicMatchers.and( new ActionMatcher(GET, HEAD), new TokenMatcher("/download/{author}-{module}-{version}.tar.gz"), @@ -168,10 +184,12 @@ abstract class AnsibleGalaxyRecipeSupport ) } + // https://repo.angeloxx.lan/repository/galaxy/api/v3/plugin/ansible/content/published/collections/artifacts/telekom_mms-icinga_director-1.34.1.tar.gz + // /api/v3/plugin/ansible/content/published/collections/artifacts/telekom_mms-icinga_director-1.34.1.tar.gz static Matcher collectionArtifactIhmMatcher() { LogicMatchers.and( new ActionMatcher(GET, HEAD), - new TokenMatcher("/collection/{author}/{module}/{version}/{author}-{module}-{version}.tar.gz"), + new TokenMatcher("/api/{apiversion}/plugin/ansible/content/published/collections/artifacts/{author}-{module}-{version}.tar.gz"), setAssetKind(AssetKind.COLLECTION_ARTIFACT) ) } diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/hosted/AnsibleGalaxyHostedFacetImpl.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/hosted/AnsibleGalaxyHostedFacetImpl.java index 307ed7a..d507c8e 100644 --- a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/hosted/AnsibleGalaxyHostedFacetImpl.java +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/hosted/AnsibleGalaxyHostedFacetImpl.java @@ -43,6 +43,7 @@ import static org.sonatype.nexus.plugins.ansiblegalaxy.internal.util.AnsibleGalaxyDataAccess.HASH_ALGORITHMS; import static org.sonatype.nexus.repository.storage.AssetEntityAdapter.P_ASSET_KIND; import static org.sonatype.nexus.repository.storage.MetadataNodeEntityAdapter.P_NAME; +import static org.sonatype.nexus.repository.storage.ComponentEntityAdapter.P_VERSION; @Named @@ -85,7 +86,7 @@ public AnsibleGalaxyHostedFacetImpl(AnsibleGalaxyDataAccess ansibleGalaxyDataAcc this.sorting = new ArrayList<>(); this.sorting.add(SortBuilders.fieldSort(P_NAME).order(SortOrder.ASC)); - this.sorting.add(SortBuilders.fieldSort(ComponentEntityAdapter.P_VERSION).order(SortOrder.ASC)); + this.sorting.add(SortBuilders.fieldSort(P_VERSION).order(SortOrder.ASC)); } @TransactionalTouchBlob @@ -171,8 +172,8 @@ private AnsibleGalaxyModules getModuleReleasesFromSearchResponse( list.add(getRepository()); String baseUrlRepo = getRepository().getUrl(); Iterable assets; - assets = tx.findAssets(Query.builder().where(P_NAME).like(String.format("%%%s/%s%%", user, module)).build(), list); - long count = tx.countAssets(Query.builder().where(P_NAME).like(String.format("%%%s/%s%%", user, module)).build(), list); + assets = tx.findAssets(Query.builder().where(P_NAME).like(String.format("%%%s-%s%%", user, module)).build(), list); + long count = tx.countAssets(Query.builder().where(P_NAME).like(String.format("%%%s-%s%%", user, module)).build(), list); AnsibleGalaxyModules releases = moduleBuilder.parse(count, count, 0, context); for (Asset asset : assets) { @@ -194,14 +195,20 @@ public Content moduleByNameAndVersion(Context context, String user, String modul list.add(getRepository()); String baseUrlRepo = getRepository().getUrl(); Asset asset = null; + String asset_version = null; Iterable assets; - assets = tx.findAssets(Query.builder().where(P_NAME).like(String.format("%%%s/%s%%", user, module)).build(), list); + assets = tx.findAssets(Query + .builder() + .where(P_NAME).like(String.format("%%%s-%s%%", user, module, version)) + .build(), list); for (Asset assetX : assets) { asset = assetX; - break; + asset_version = (String) asset.formatAttributes().get("version"); + if ( asset_version.equals(version) ) { break; } } + AnsibleGalaxyModule result = new AnsibleGalaxyModule(); - result.setVersion(version) + result.setVersion(asset_version) .setHref(ansibleGalaxyPathUtils.parseHref(baseUrlRepo, asset.attributes().child("ansiblegalaxy").get("name").toString(), asset.attributes().child("ansiblegalaxy").get("version").toString())) .setDownload_url(ansibleGalaxyPathUtils.download(baseUrlRepo, user, module, version)) .setNamespace(new AnsibleGalaxyModule.AnsibleGalaxyModuleNamespace().setName(user)) @@ -273,5 +280,4 @@ private Component findOrCreateComponent(final StorageTx tx, } return component; } -} - +} \ No newline at end of file diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/hosted/AnsibleGalaxyHostedRecipe.groovy b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/hosted/AnsibleGalaxyHostedRecipe.groovy index 99045be..597e1f5 100644 --- a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/hosted/AnsibleGalaxyHostedRecipe.groovy +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/hosted/AnsibleGalaxyHostedRecipe.groovy @@ -112,7 +112,6 @@ class AnsibleGalaxyHostedRecipe .handler(hostedHandlers.collectionVersionDetail) .create()) - builder.route(new Route.Builder().matcher(collectionArtifactMatcher()) .handler(timingHandler) .handler(securityHandler) diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/AnsibleGalaxyProxyFacetImpl.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/AnsibleGalaxyProxyFacetImpl.java index fbfbbc2..af4576a 100644 --- a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/AnsibleGalaxyProxyFacetImpl.java +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/AnsibleGalaxyProxyFacetImpl.java @@ -14,6 +14,9 @@ import org.apache.commons.lang3.StringUtils; import org.apache.http.client.methods.HttpRequestBase; +import org.eclipse.aether.util.version.GenericVersionScheme; +import org.eclipse.aether.version.InvalidVersionSpecificationException; +import org.eclipse.aether.version.Version; import org.slf4j.Logger; import org.sonatype.goodies.common.Loggers; import org.sonatype.nexus.plugins.ansiblegalaxy.AssetKind; @@ -112,6 +115,8 @@ protected Content getCachedContent(final Context context) { return getAsset(ansiblegalaxyPathUtils.collectionDetailPath(matcherState)); case COLLECTION_VERSION_LIST: return getAsset(ansiblegalaxyPathUtils.collectionVersionPagedPath(matcherState)); + case COLLECTION_VERSION_LIST_LIMIT: + return getAsset(ansiblegalaxyPathUtils.collectionVersionLimitPath(matcherState)); case COLLECTION_VERSION_DETAIL: return getAsset(ansiblegalaxyPathUtils.collectionVersionDetailPath(matcherState)); case COLLECTION_ARTIFACT: @@ -152,6 +157,8 @@ protected Content store(final Context context, final Content content) throws IOE return putAsset(context, content, ansiblegalaxyPathUtils.collectionDetailPath(matcherState), assetKind); case COLLECTION_VERSION_LIST: return putAsset(context, content, ansiblegalaxyPathUtils.collectionVersionPagedPath(matcherState), assetKind); + case COLLECTION_VERSION_LIST_LIMIT: + return putAsset(context, content, ansiblegalaxyPathUtils.collectionVersionLimitPath(matcherState), assetKind); case COLLECTION_VERSION_DETAIL: return putComponent(context, ansiblegalaxyPathUtils.getCollectionAttributes(matcherState), content, ansiblegalaxyPathUtils.collectionVersionDetailPath(matcherState), assetKind); @@ -222,6 +229,26 @@ private InputStream getUpdatedContent(Context context, AssetKind assetKind, Inpu replacers.add(new JsonPostpendReplacer(downloadUrlFieldName, queryString)); } + return new ReplacerStream(replacers).getReplacedContent(in); + } else if (assetKind == AssetKind.COLLECTION_VERSION_LIST || assetKind == AssetKind.COLLECTION_VERSION_LIST_LIMIT) { + + List replacers = new ArrayList<>(); + + /* API Bug IMHO - https://github.com/ansible/awx/issues/14495 */ + replacers.add(new JsonPrependReplacer("first", "/repository/" + getRepository().getName())); + replacers.add(new JsonPrependReplacer("previous", "/repository/" + getRepository().getName())); + replacers.add(new JsonPrependReplacer("last", "/repository/" + getRepository().getName())); + replacers.add(new JsonPrependReplacer("next", "/repository/" + getRepository().getName())); + + // If client version < 2.13.9 remove "next" (backward compatibility, reduce options) + String userAgent = context.getRequest().getHeaders().get("User-Agent"); + if (userAgent != null && userAgent.startsWith("ansible-galaxy/")) { + if (isUserAgentVersionLowerOrEqual(userAgent, "2.13.9")) { + log.info("Backward compatibility layer in action, mind some versions will be omitted"); + replacers.add(new JsonSearchReplacer("next", "")); + } + } + return new ReplacerStream(replacers).getReplacedContent(in); } @@ -230,6 +257,20 @@ private InputStream getUpdatedContent(Context context, AssetKind assetKind, Inpu return new ReplacerStream(urlReplacer).getReplacedContent(in); } + private boolean isUserAgentVersionLowerOrEqual(String userAgent, String targetVersionString) { + try { + String version = userAgent.split("/")[1]; + GenericVersionScheme versionScheme = new GenericVersionScheme(); + Version userAgentVersion = versionScheme.parseVersion(version); + Version targetVersion = versionScheme.parseVersion(targetVersionString); + + return userAgentVersion.compareTo(targetVersion) <= 0; + } catch (InvalidVersionSpecificationException e) { + log.info("isUserAgentVersionLowerOrEqual returns an error ({} vs {}), assuming false", userAgent, targetVersionString); + return false; + } + } + private String getModuleName(Context context) { String path = context.getRequest().getPath().replaceFirst(ROLE_VERSION_URI_SUFFIX, ""); Request roleDetailRequest = new Request.Builder().copy(context.getRequest()).action(HttpMethods.GET).path(path) diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/AnsibleGalaxyProxyRecipe.groovy b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/AnsibleGalaxyProxyRecipe.groovy index f75b3d9..90d107b 100644 --- a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/AnsibleGalaxyProxyRecipe.groovy +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/AnsibleGalaxyProxyRecipe.groovy @@ -77,8 +77,10 @@ class AnsibleGalaxyProxyRecipe apiInternalsMatcher(), collectionDetailMatcher(), collectionVersionListMatcher(), + collectionVersionListMatcherPages(), collectionVersionDetailMatcher(), collectionArtifactMatcher(), + collectionArtifactV2Matcher(), collectionArtifactIhmMatcher(), roleSearchMatcher(), roleDetailMatcher(), diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/replacer/JsonSearchReplacer.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/replacer/JsonSearchReplacer.java index 168a466..d63462a 100644 --- a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/replacer/JsonSearchReplacer.java +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/proxy/replacer/JsonSearchReplacer.java @@ -32,8 +32,17 @@ public JsonSearchReplacer(String jsonFieldName, String search, String replace) { this.replace = checkNotNull(replace); } + public JsonSearchReplacer(String jsonFieldName, String replace) { + super(jsonFieldName); + this.search = null; + this.replace = checkNotNull(replace); + } + @Override protected String getUpdatedContent(JsonNode field) { + if (search == null) { + return replace; + } return field.asText().replaceAll(search, replace); } diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/util/AnsibleGalaxyPathUtils.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/util/AnsibleGalaxyPathUtils.java index 92580a9..383fc96 100644 --- a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/util/AnsibleGalaxyPathUtils.java +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/util/AnsibleGalaxyPathUtils.java @@ -77,6 +77,13 @@ public String page_size(final TokenMatcher.State state) { return StringUtils.defaultIfBlank(state.getTokens().get("page_size"), "20"); } + public String offset(final TokenMatcher.State state) { + return StringUtils.defaultIfBlank(state.getTokens().get("offset"), "0"); + } + public String limit(final TokenMatcher.State state) { + return StringUtils.defaultIfBlank(state.getTokens().get("limit"), "100"); + } + public TokenMatcher.State matcherState(final Context context) { State state = context.getAttributes().require(TokenMatcher.State.class); log.debug("matched state tokens: {}", state.getTokens()); @@ -112,6 +119,15 @@ public String collectionVersionPagedPath(final State matcherState) { return String.format("%s/%s/%s/versions%s.json", COLLECTION_PATH, author, module, page); } + public String collectionVersionLimitPath(final State matcherState) { + String author = author(matcherState); + String module = module(matcherState); + String offset = offset(matcherState); + String limit = limit(matcherState); + + return String.format("%s/%s/%s/versions-offset-%s-%s.json", COLLECTION_PATH, author, module, offset, limit); + } + public String roleSearchPath(final State matcherState) { String author = author(matcherState); String module = module(matcherState); @@ -156,11 +172,15 @@ public String artifactPath(final String author, final String module, final Strin public String download(String baseUrlRepo, final String author, final String module, final String version) { - return String.format("%s/download/%s.tar.gz", baseUrlRepo, author + "-" + module + "-" + version); + return String.format("%s/api/v3/plugin/ansible/content/published/collections/artifacts/%s.tar.gz", baseUrlRepo, author + "-" + module + "-" + version); } public String collectionArtifactPath(final State matcherState) { - return String.format("%s/%s", COLLECTION_PATH, artifactPath(matcherState)); + String author = author(matcherState); + String module = module(matcherState); + String version = version(matcherState); + //return String.format("%s/%s", COLLECTION_PATH, artifactPath(matcherState)); + return String.format("api/v3/plugin/ansible/content/published/collections/artifacts/%s-%s-%s.tar.gz", author, module, version); } public String parseHref(String baseUrlRepo, final String name, final String version) { @@ -169,7 +189,8 @@ public String parseHref(String baseUrlRepo, final String name, final String vers } public String collectionArtifactPath(final String author, final String module, final String version) { - return String.format("%s/%s", COLLECTION_PATH, artifactPath(author, module, version)); + // return String.format("%s/%s", COLLECTION_PATH, artifactPath(author, module, version)); + return String.format("api/v3/plugin/ansible/content/published/collections/artifacts/%s-%s-%s.tar.gz", author, module, version); } public String collectionNamePath(final String author, final String module) { diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyAttributes.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyAttributes.java new file mode 100644 index 0000000..f050a21 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyAttributes.java @@ -0,0 +1,45 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.rest; + +import org.sonatype.nexus.plugins.ansiblegalaxy.ContentDisposition; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModelProperty; + +/** + * REST API model of ansiblegalaxy attributes for repositories API + * + * @since 3.25 + */ +public class AnsibleGalaxyAttributes +{ + + public static final String CONTENT_DISPOSITION = "contentDisposition"; + + @ApiModelProperty(value = "Content Disposition", + allowableValues = "INLINE,ATTACHMENT", example = "ATTACHMENT") + private final ContentDisposition contentDisposition; + + @JsonCreator + public AnsibleGalaxyAttributes( + @JsonProperty(CONTENT_DISPOSITION) final ContentDisposition contentDisposition) + { + this.contentDisposition = contentDisposition; + } + + public ContentDisposition getContentDisposition() { + return contentDisposition; + } +} diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoriesApiResource.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoriesApiResource.java new file mode 100644 index 0000000..b313738 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoriesApiResource.java @@ -0,0 +1,75 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.rest; + +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import org.sonatype.nexus.repository.rest.api.AbstractHostedRepositoriesApiResource; +import org.sonatype.nexus.validation.Validate; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.shiro.authz.annotation.RequiresAuthentication; + +import static org.sonatype.nexus.rest.ApiDocConstants.API_REPOSITORY_MANAGEMENT; +import static org.sonatype.nexus.rest.ApiDocConstants.AUTHENTICATION_REQUIRED; +import static org.sonatype.nexus.rest.ApiDocConstants.INSUFFICIENT_PERMISSIONS; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_CREATED; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_UPDATED; + +/** + * @since 3.24 + */ +@Api(value = API_REPOSITORY_MANAGEMENT) +public abstract class AnsibleGalaxyHostedRepositoriesApiResource + extends AbstractHostedRepositoriesApiResource +{ + @ApiOperation("Create ansiblegalaxy hosted repository") + @ApiResponses(value = { + @ApiResponse(code = 201, message = REPOSITORY_CREATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @POST + @RequiresAuthentication + @Validate + @Override + public Response createRepository(AnsibleGalaxyHostedRepositoryApiRequest request) { + return super.createRepository(request); + } + + @ApiOperation("Update ansiblegalaxy hosted repository") + @ApiResponses(value = { + @ApiResponse(code = 204, message = REPOSITORY_UPDATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @PUT + @Path("/{repositoryName}") + @RequiresAuthentication + @Validate + @Override + public Response updateRepository( + final AnsibleGalaxyHostedRepositoryApiRequest request, + @ApiParam(value = "Name of the repository to update") @PathParam("repositoryName") final String repositoryName) + { + return super.updateRepository(request, repositoryName); + } +} \ No newline at end of file diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoriesApiResourceV1.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoriesApiResourceV1.java new file mode 100644 index 0000000..5b2dd02 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoriesApiResourceV1.java @@ -0,0 +1,33 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.rest; + +import javax.inject.Named; +import javax.inject.Singleton; +import javax.ws.rs.Path; + +import org.sonatype.nexus.repository.rest.api.RepositoriesApiResourceV1; + +import static org.sonatype.nexus.plugins.ansiblegalaxy.rest.AnsibleGalaxyHostedRepositoriesApiResourceV1.RESOURCE_URI; + +/** + * @since 3.26 + */ +@Named +@Singleton +@Path(RESOURCE_URI) +public class AnsibleGalaxyHostedRepositoriesApiResourceV1 + extends AnsibleGalaxyHostedRepositoriesApiResource +{ + static final String RESOURCE_URI = RepositoriesApiResourceV1.RESOURCE_URI + "/ansiblegalaxy/hosted"; +} diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoryApiRequest.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoryApiRequest.java new file mode 100644 index 0000000..ddae95a --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoryApiRequest.java @@ -0,0 +1,53 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.rest; + +import org.sonatype.nexus.repository.rest.api.model.CleanupPolicyAttributes; +import org.sonatype.nexus.repository.rest.api.model.ComponentAttributes; +import org.sonatype.nexus.repository.rest.api.model.HostedRepositoryApiRequest; +import org.sonatype.nexus.repository.rest.api.model.HostedStorageAttributes; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyFormat; +import org.sonatype.nexus.plugins.ansiblegalaxy.rest.AnsibleGalaxyAttributes; +import static org.sonatype.nexus.plugins.ansiblegalaxy.ContentDisposition.ATTACHMENT; + +/** + * @since 3.24 + */ +@JsonIgnoreProperties({"format", "type"}) +public class AnsibleGalaxyHostedRepositoryApiRequest + extends HostedRepositoryApiRequest +{ + private final AnsibleGalaxyAttributes ansiblegalaxy; + + @JsonCreator + public AnsibleGalaxyHostedRepositoryApiRequest( + @JsonProperty("name") final String name, + @JsonProperty("online") final Boolean online, + @JsonProperty("storage") final HostedStorageAttributes storage, + @JsonProperty("cleanup") final CleanupPolicyAttributes cleanup, + @JsonProperty("ansiblegalaxy") final AnsibleGalaxyAttributes ansiblegalaxy, + @JsonProperty("component") final ComponentAttributes componentAttributes) + { + super(name, AnsibleGalaxyFormat.NAME, online, storage, cleanup, componentAttributes); + this.ansiblegalaxy = ansiblegalaxy != null ? ansiblegalaxy : new AnsibleGalaxyAttributes(ATTACHMENT); + } + + public AnsibleGalaxyAttributes getAnsibleGalaxy() { + return ansiblegalaxy; + } +} \ No newline at end of file diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoryApiRequestToConfigurationConverter.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoryApiRequestToConfigurationConverter.java new file mode 100644 index 0000000..42271e5 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyHostedRepositoryApiRequestToConfigurationConverter.java @@ -0,0 +1,35 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.rest; + +import javax.inject.Named; + +import org.sonatype.nexus.repository.config.Configuration; +import org.sonatype.nexus.repository.rest.api.HostedRepositoryApiRequestToConfigurationConverter; + +import static org.sonatype.nexus.plugins.ansiblegalaxy.rest.AnsibleGalaxyAttributes.CONTENT_DISPOSITION; + +/** + * @since 3.25 + */ +@Named +public class AnsibleGalaxyHostedRepositoryApiRequestToConfigurationConverter + extends HostedRepositoryApiRequestToConfigurationConverter +{ + @Override + public Configuration convert(final AnsibleGalaxyHostedRepositoryApiRequest request) { + Configuration configuration = super.convert(request); + configuration.attributes("ansiblegalaxy").set(CONTENT_DISPOSITION, request.getAnsibleGalaxy().getContentDisposition().name()); + return configuration; + } +} \ No newline at end of file diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoriesApiResource.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoriesApiResource.java new file mode 100644 index 0000000..8e80d7f --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoriesApiResource.java @@ -0,0 +1,75 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.rest; + +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import org.sonatype.nexus.repository.rest.api.AbstractProxyRepositoriesApiResource; +import org.sonatype.nexus.validation.Validate; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.shiro.authz.annotation.RequiresAuthentication; + +import static org.sonatype.nexus.rest.ApiDocConstants.API_REPOSITORY_MANAGEMENT; +import static org.sonatype.nexus.rest.ApiDocConstants.AUTHENTICATION_REQUIRED; +import static org.sonatype.nexus.rest.ApiDocConstants.INSUFFICIENT_PERMISSIONS; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_CREATED; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_UPDATED; + +/** + * @since 3.24 + */ +@Api(value = API_REPOSITORY_MANAGEMENT) +public abstract class AnsibleGalaxyProxyRepositoriesApiResource + extends AbstractProxyRepositoriesApiResource +{ + @ApiOperation("Create ansiblegalaxy proxy repository") + @ApiResponses(value = { + @ApiResponse(code = 201, message = REPOSITORY_CREATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @POST + @RequiresAuthentication + @Validate + @Override + public Response createRepository(final AnsibleGalaxyProxyRepositoryApiRequest request) { + return super.createRepository(request); + } + + @ApiOperation("Update ansiblegalaxy proxy repository") + @ApiResponses(value = { + @ApiResponse(code = 204, message = REPOSITORY_UPDATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @PUT + @Path("/{repositoryName}") + @RequiresAuthentication + @Validate + @Override + public Response updateRepository( + final AnsibleGalaxyProxyRepositoryApiRequest request, + @ApiParam(value = "Name of the repository to update") @PathParam("repositoryName") final String repositoryName) + { + return super.updateRepository(request, repositoryName); + } +} \ No newline at end of file diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoriesApiResourceV1.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoriesApiResourceV1.java new file mode 100644 index 0000000..34bb995 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoriesApiResourceV1.java @@ -0,0 +1,33 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.rest; + +import javax.inject.Named; +import javax.inject.Singleton; +import javax.ws.rs.Path; + +import org.sonatype.nexus.repository.rest.api.RepositoriesApiResourceV1; + +import static org.sonatype.nexus.plugins.ansiblegalaxy.rest.AnsibleGalaxyProxyRepositoriesApiResourceV1.RESOURCE_URI; + +/** + * @since 3.26 + */ +@Named +@Singleton +@Path(RESOURCE_URI) +public class AnsibleGalaxyProxyRepositoriesApiResourceV1 + extends AnsibleGalaxyProxyRepositoriesApiResource +{ + static final String RESOURCE_URI = RepositoriesApiResourceV1.RESOURCE_URI + "/ansiblegalaxy/proxy"; +} diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoryApiRequest.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoryApiRequest.java new file mode 100644 index 0000000..2ccd158 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoryApiRequest.java @@ -0,0 +1,64 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.rest; + +import org.sonatype.nexus.plugins.ansiblegalaxy.AnsibleGalaxyFormat; +import org.sonatype.nexus.plugins.ansiblegalaxy.rest.AnsibleGalaxyAttributes; +import org.sonatype.nexus.repository.rest.api.model.CleanupPolicyAttributes; +import org.sonatype.nexus.repository.rest.api.model.HttpClientAttributes; +import org.sonatype.nexus.repository.rest.api.model.NegativeCacheAttributes; +import org.sonatype.nexus.repository.rest.api.model.ProxyAttributes; +import org.sonatype.nexus.repository.rest.api.model.ProxyRepositoryApiRequest; +import org.sonatype.nexus.repository.rest.api.model.ReplicationAttributes; +import org.sonatype.nexus.repository.rest.api.model.StorageAttributes; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; + +import static org.sonatype.nexus.plugins.ansiblegalaxy.ContentDisposition.ATTACHMENT; + +/** + * @since 3.24 + */ +@JsonIgnoreProperties({"format", "type"}) +public class AnsibleGalaxyProxyRepositoryApiRequest + extends ProxyRepositoryApiRequest +{ + private final AnsibleGalaxyAttributes ansiblegalaxy; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + @SuppressWarnings("squid:S00107") // suppress constructor parameter count + public AnsibleGalaxyProxyRepositoryApiRequest( + @JsonProperty("name") final String name, + @JsonProperty("online") final Boolean online, + @JsonProperty("storage") final StorageAttributes storage, + @JsonProperty("cleanup") final CleanupPolicyAttributes cleanup, + @JsonProperty("proxy") final ProxyAttributes proxy, + @JsonProperty("negativeCache") final NegativeCacheAttributes negativeCache, + @JsonProperty("httpClient") final HttpClientAttributes httpClient, + @JsonProperty("routingRule") final String routingRule, + @JsonProperty("ansiblegalaxy") final AnsibleGalaxyAttributes ansiblegalaxy, + @JsonProperty("replication") @JsonInclude(value= Include.NON_EMPTY, content=Include.NON_NULL) + final ReplicationAttributes replication) + { + super(name, AnsibleGalaxyFormat.NAME, online, storage, cleanup, proxy, negativeCache, httpClient, routingRule, replication); + this.ansiblegalaxy = ansiblegalaxy != null ? ansiblegalaxy : new AnsibleGalaxyAttributes(ATTACHMENT); + } + + public AnsibleGalaxyAttributes getAnsibleGalaxy() { + return ansiblegalaxy; + } +} \ No newline at end of file diff --git a/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoryApiRequestToConfigurationConverter.java b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoryApiRequestToConfigurationConverter.java new file mode 100644 index 0000000..2dd3aa9 --- /dev/null +++ b/nexus-repository-ansiblegalaxy/src/main/java/org/sonatype/nexus/plugins/ansiblegalaxy/rest/AnsibleGalaxyProxyRepositoryApiRequestToConfigurationConverter.java @@ -0,0 +1,42 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2020-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.plugins.ansiblegalaxy.rest; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.sonatype.nexus.repository.config.Configuration; +import org.sonatype.nexus.repository.rest.api.ProxyRepositoryApiRequestToConfigurationConverter; +import org.sonatype.nexus.repository.routing.RoutingRuleStore; + +import static org.sonatype.nexus.plugins.ansiblegalaxy.rest.AnsibleGalaxyAttributes.CONTENT_DISPOSITION; + +/** + * @since 3.25 + */ +@Named +public class AnsibleGalaxyProxyRepositoryApiRequestToConfigurationConverter + extends ProxyRepositoryApiRequestToConfigurationConverter +{ + @Inject + public AnsibleGalaxyProxyRepositoryApiRequestToConfigurationConverter(final RoutingRuleStore routingRuleStore) { + super(routingRuleStore); + } + + @Override + public Configuration convert(final AnsibleGalaxyProxyRepositoryApiRequest request) { + Configuration configuration = super.convert(request); + configuration.attributes("ansiblegalaxy").set(CONTENT_DISPOSITION, request.getAnsibleGalaxy().getContentDisposition().name()); + return configuration; + } +} \ No newline at end of file diff --git a/nexus-repository-ansiblegalaxy/src/test/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/AnsibleGalaxyRecipeSupportTest.java b/nexus-repository-ansiblegalaxy/src/test/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/AnsibleGalaxyRecipeSupportTest.java index 8102960..9c0b553 100644 --- a/nexus-repository-ansiblegalaxy/src/test/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/AnsibleGalaxyRecipeSupportTest.java +++ b/nexus-repository-ansiblegalaxy/src/test/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/AnsibleGalaxyRecipeSupportTest.java @@ -60,7 +60,7 @@ public void setUp() { @Test public void testCollectionArtifactTar() { - when(request.getPath()).thenReturn("/download/azure-azcollection-1.3.1.tar.gz"); + when(request.getPath()).thenReturn("/api/v3/plugin/ansible/content/published/collections/artifacts/azure-azcollection-1.3.1.tar.gz"); Matcher matcher = collectionArtifactMatcher(); boolean matches = matcher.matches(context); assertTrue(matches); @@ -76,7 +76,7 @@ public void testCollectionArtifactTar() { @Test public void testCollectionBranchArtifactTar() { - when(request.getPath()).thenReturn("/download/azure-azcollection-master.tar.gz"); + when(request.getPath()).thenReturn("/api/v3/plugin/ansible/content/published/collections/artifacts/azure-azcollection-master.tar.gz"); Matcher matcher = collectionArtifactMatcher(); boolean matches = matcher.matches(context); assertTrue(matches); diff --git a/nexus-repository-ansiblegalaxy/src/test/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/util/AnsibleGalaxyPathUtilsTest.java b/nexus-repository-ansiblegalaxy/src/test/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/util/AnsibleGalaxyPathUtilsTest.java index c99bdf2..5716892 100644 --- a/nexus-repository-ansiblegalaxy/src/test/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/util/AnsibleGalaxyPathUtilsTest.java +++ b/nexus-repository-ansiblegalaxy/src/test/java/org/sonatype/nexus/plugins/ansiblegalaxy/internal/util/AnsibleGalaxyPathUtilsTest.java @@ -126,7 +126,7 @@ public void roleMetadataPagedPath() { public void collectionArtifactPath() { String result = underTest.collectionArtifactPath(state); - assertThat(result, is(equalTo("collection/azure/azcollection/1.2.0/azure-azcollection-1.2.0.tar.gz"))); + assertThat(result, is(equalTo("api/v3/plugin/ansible/content/published/collections/artifacts/azure-azcollection-1.2.0.tar.gz"))); } @Test diff --git a/pom.xml b/pom.xml index f2bd637..204d598 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ nexus-repository-ansiblegalaxy-parent - 0.3.0 + 0.3.2 pom 2020