From 7f9128402f56ff4649f75692ca1d037b77afc907 Mon Sep 17 00:00:00 2001 From: Julien Coste Date: Wed, 17 Jul 2024 14:56:48 +0200 Subject: [PATCH] Add support for OCI package type #386 --- .../settings/OciRepositorySettings.java | 8 ++ .../impl/jackson/RepositorySettingsMixIn.java | 3 +- .../impl/FederatedRepositoryBuilderImpl.java | 2 +- .../impl/LocalRepositoryBuilderImpl.java | 2 +- .../client/model/impl/PackageTypeImpl.java | 3 +- .../impl/RemoteRepositoryBuilderImpl.java | 2 +- .../impl/VirtualRepositoryBuilderImpl.java | 2 +- .../impl/OciRepositorySettingsImpl.java | 34 +++++ .../OciPackageTypeRepositoryTests.groovy | 129 ++++++++++++++++++ 9 files changed, 179 insertions(+), 6 deletions(-) create mode 100644 api/src/main/java/org/jfrog/artifactory/client/model/repository/settings/OciRepositorySettings.java create mode 100644 services/src/main/java/org/jfrog/artifactory/client/model/repository/settings/impl/OciRepositorySettingsImpl.java create mode 100644 services/src/test/groovy/org/jfrog/artifactory/client/OciPackageTypeRepositoryTests.groovy diff --git a/api/src/main/java/org/jfrog/artifactory/client/model/repository/settings/OciRepositorySettings.java b/api/src/main/java/org/jfrog/artifactory/client/model/repository/settings/OciRepositorySettings.java new file mode 100644 index 00000000..251c4167 --- /dev/null +++ b/api/src/main/java/org/jfrog/artifactory/client/model/repository/settings/OciRepositorySettings.java @@ -0,0 +1,8 @@ +package org.jfrog.artifactory.client.model.repository.settings; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public interface OciRepositorySettings extends DockerRepositorySettings { + +} diff --git a/services/src/main/java/org/jfrog/artifactory/client/impl/jackson/RepositorySettingsMixIn.java b/services/src/main/java/org/jfrog/artifactory/client/impl/jackson/RepositorySettingsMixIn.java index 7439f7e9..bf5f60e1 100644 --- a/services/src/main/java/org/jfrog/artifactory/client/impl/jackson/RepositorySettingsMixIn.java +++ b/services/src/main/java/org/jfrog/artifactory/client/impl/jackson/RepositorySettingsMixIn.java @@ -43,7 +43,8 @@ @JsonSubTypes.Type(value = HelmRepositorySettingsImpl.class, name = "helm"), @JsonSubTypes.Type(value = GoRepositorySettingsImpl.class, name = "go"), @JsonSubTypes.Type(value = CargoRepositorySettingsImpl.class, name = "cargo"), - @JsonSubTypes.Type(value = TerraformRepositorySettingsImpl.class, name = "terraform") + @JsonSubTypes.Type(value = TerraformRepositorySettingsImpl.class, name = "terraform"), + @JsonSubTypes.Type(value = OciRepositorySettingsImpl.class, name = "oci") }) public abstract class RepositorySettingsMixIn { diff --git a/services/src/main/java/org/jfrog/artifactory/client/model/impl/FederatedRepositoryBuilderImpl.java b/services/src/main/java/org/jfrog/artifactory/client/model/impl/FederatedRepositoryBuilderImpl.java index 9e25dac5..d74a1525 100644 --- a/services/src/main/java/org/jfrog/artifactory/client/model/impl/FederatedRepositoryBuilderImpl.java +++ b/services/src/main/java/org/jfrog/artifactory/client/model/impl/FederatedRepositoryBuilderImpl.java @@ -16,7 +16,7 @@ */ public class FederatedRepositoryBuilderImpl extends NonVirtualRepositoryBuilderBase implements FederatedRepositoryBuilder { private static Set federatedRepositorySupportedTypes = new HashSet<>(Arrays.asList( - bower, cocoapods, cran, conda, debian, docker, gems, generic, gitlfs, gradle, ivy, maven, npm, nuget, opkg, pypi, sbt, vagrant, yum, rpm, composer, conan, chef, puppet, helm, go, cargo, terraform + bower, cocoapods, cran, conda, debian, docker, gems, generic, gitlfs, gradle, ivy, maven, npm, nuget, opkg, pypi, sbt, vagrant, yum, rpm, composer, conan, chef, puppet, helm, go, cargo, terraform, oci )); protected List members = new ArrayList<>(); diff --git a/services/src/main/java/org/jfrog/artifactory/client/model/impl/LocalRepositoryBuilderImpl.java b/services/src/main/java/org/jfrog/artifactory/client/model/impl/LocalRepositoryBuilderImpl.java index 0d536340..d06590f8 100644 --- a/services/src/main/java/org/jfrog/artifactory/client/model/impl/LocalRepositoryBuilderImpl.java +++ b/services/src/main/java/org/jfrog/artifactory/client/model/impl/LocalRepositoryBuilderImpl.java @@ -17,7 +17,7 @@ */ public class LocalRepositoryBuilderImpl extends NonVirtualRepositoryBuilderBase implements LocalRepositoryBuilder { private static Set localRepositorySupportedTypes = new HashSet(Arrays.asList( - bower, cocoapods, cran, conda, debian, docker, gems, generic, gitlfs, gradle, ivy, maven, npm, nuget, opkg, pypi, sbt, vagrant, yum, rpm, composer, conan, chef, puppet, helm, go, cargo, terraform + bower, cocoapods, cran, conda, debian, docker, gems, generic, gitlfs, gradle, ivy, maven, npm, nuget, opkg, pypi, sbt, vagrant, yum, rpm, composer, conan, chef, puppet, helm, go, cargo, terraform, oci )); protected LocalRepositoryBuilderImpl() { diff --git a/services/src/main/java/org/jfrog/artifactory/client/model/impl/PackageTypeImpl.java b/services/src/main/java/org/jfrog/artifactory/client/model/impl/PackageTypeImpl.java index 23d85eb1..b78bf385 100644 --- a/services/src/main/java/org/jfrog/artifactory/client/model/impl/PackageTypeImpl.java +++ b/services/src/main/java/org/jfrog/artifactory/client/model/impl/PackageTypeImpl.java @@ -33,7 +33,8 @@ public enum PackageTypeImpl implements PackageType { helm, go, cargo, - terraform; + terraform, + oci; @Override public boolean isCustom() { diff --git a/services/src/main/java/org/jfrog/artifactory/client/model/impl/RemoteRepositoryBuilderImpl.java b/services/src/main/java/org/jfrog/artifactory/client/model/impl/RemoteRepositoryBuilderImpl.java index bef2adc0..1031005f 100644 --- a/services/src/main/java/org/jfrog/artifactory/client/model/impl/RemoteRepositoryBuilderImpl.java +++ b/services/src/main/java/org/jfrog/artifactory/client/model/impl/RemoteRepositoryBuilderImpl.java @@ -17,7 +17,7 @@ */ public class RemoteRepositoryBuilderImpl extends NonVirtualRepositoryBuilderBase implements RemoteRepositoryBuilder { private static Set remoteRepositorySupportedTypes = new HashSet(Arrays.asList( - bower, cocoapods, cran, conda, debian, docker, gems, generic, gitlfs, gradle, ivy, maven, npm, nuget, opkg, p2, pypi, sbt, vcs, yum, rpm, composer, conan, chef, puppet, helm, go, cargo, terraform + bower, cocoapods, cran, conda, debian, docker, gems, generic, gitlfs, gradle, ivy, maven, npm, nuget, opkg, p2, pypi, sbt, vcs, yum, rpm, composer, conan, chef, puppet, helm, go, cargo, terraform, oci )); private String url; diff --git a/services/src/main/java/org/jfrog/artifactory/client/model/impl/VirtualRepositoryBuilderImpl.java b/services/src/main/java/org/jfrog/artifactory/client/model/impl/VirtualRepositoryBuilderImpl.java index b29b8b54..eff46cf2 100644 --- a/services/src/main/java/org/jfrog/artifactory/client/model/impl/VirtualRepositoryBuilderImpl.java +++ b/services/src/main/java/org/jfrog/artifactory/client/model/impl/VirtualRepositoryBuilderImpl.java @@ -15,7 +15,7 @@ */ public class VirtualRepositoryBuilderImpl extends RepositoryBuilderBase implements VirtualRepositoryBuilder { private static Set virtualRepositorySupportedTypes = new HashSet(Arrays.asList( - bower, cran, conda, docker, debian, gems, generic, gitlfs, gradle, ivy, maven, npm, nuget, p2, pypi, sbt, yum, rpm, composer, conan, chef, puppet, helm, go, terraform + bower, cran, conda, docker, debian, gems, generic, gitlfs, gradle, ivy, maven, npm, nuget, p2, pypi, sbt, yum, rpm, composer, conan, chef, puppet, helm, go, terraform, oci )); private Collection repositories = Collections.emptyList(); diff --git a/services/src/main/java/org/jfrog/artifactory/client/model/repository/settings/impl/OciRepositorySettingsImpl.java b/services/src/main/java/org/jfrog/artifactory/client/model/repository/settings/impl/OciRepositorySettingsImpl.java new file mode 100644 index 00000000..c925ef86 --- /dev/null +++ b/services/src/main/java/org/jfrog/artifactory/client/model/repository/settings/impl/OciRepositorySettingsImpl.java @@ -0,0 +1,34 @@ +package org.jfrog.artifactory.client.model.repository.settings.impl; + +import org.jfrog.artifactory.client.model.PackageType; +import org.jfrog.artifactory.client.model.impl.PackageTypeImpl; +import org.jfrog.artifactory.client.model.repository.settings.OciRepositorySettings; + +public class OciRepositorySettingsImpl extends DockerRepositorySettingsImpl implements OciRepositorySettings { + public static String defaultLayout = "simple-default"; + + public OciRepositorySettingsImpl() { + super(); + } + + public PackageType getPackageType() { + return PackageTypeImpl.oci; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof OciRepositorySettingsImpl)) return false; + if (!super.equals(o)) return false; + + OciRepositorySettingsImpl that = (OciRepositorySettingsImpl) o; + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + return result; + } +} diff --git a/services/src/test/groovy/org/jfrog/artifactory/client/OciPackageTypeRepositoryTests.groovy b/services/src/test/groovy/org/jfrog/artifactory/client/OciPackageTypeRepositoryTests.groovy new file mode 100644 index 00000000..70ada252 --- /dev/null +++ b/services/src/test/groovy/org/jfrog/artifactory/client/OciPackageTypeRepositoryTests.groovy @@ -0,0 +1,129 @@ +package org.jfrog.artifactory.client + +import org.hamcrest.CoreMatchers +import org.jfrog.artifactory.client.model.RepositoryType +import org.jfrog.artifactory.client.model.repository.settings.RepositorySettings +import org.jfrog.artifactory.client.model.repository.settings.docker.DockerApiVersion +import org.jfrog.artifactory.client.model.repository.settings.impl.OciRepositorySettingsImpl +import org.testng.annotations.BeforeMethod +import org.testng.annotations.Test + +/** + * test that client correctly sends and receives repository configuration with `oci` package type + * + */ +class OciPackageTypeRepositoryTests extends BaseRepositoryTests { + + OciPackageTypeRepositoryTests() { + remoteRepoUrl = "https://registry-1.docker.io" + } + + @Override + RepositorySettings getRepositorySettings(RepositoryType repositoryType) { + def settings = new OciRepositorySettingsImpl() + + settings.with { + // local + dockerApiVersion = DockerApiVersion.V2 + dockerTagRetention = Math.abs(rnd.nextInt()) + + // remote + enableTokenAuthentication = rnd.nextBoolean() + listRemoteFolderItems = rnd.nextBoolean() + } + + return settings + } + + @BeforeMethod + protected void setUp() { + storeArtifactsLocallyInRemoteRepo = true + super.setUp() + } + + @Test(groups = "ociPackageTypeRepo") + void testOciLocalRepo() { + artifactory.repositories().create(0, localRepo) + def expectedSettings = localRepo.repositorySettings + + def resp = artifactory.repository(localRepo.getKey()).get() + assertThat(resp, CoreMatchers.notNullValue()) + assertThat(resp.repoLayoutRef, CoreMatchers.is(OciRepositorySettingsImpl.defaultLayout)) + resp.getRepositorySettings().with { + assertThat(packageType, CoreMatchers.is(expectedSettings.getPackageType())) + assertThat(repoLayout, CoreMatchers.is(expectedSettings.getRepoLayout())) + + // local + assertThat(dockerApiVersion, CoreMatchers.is(expectedSettings.getDockerApiVersion())) + assertThat(dockerTagRetention, CoreMatchers.is(expectedSettings.getDockerTagRetention())) + + // remote + assertThat(enableTokenAuthentication, CoreMatchers.is(CoreMatchers.nullValue())) + assertThat(listRemoteFolderItems, CoreMatchers.is(CoreMatchers.nullValue())) + } + } + + @Test(groups = "ociPackageTypeRepo") + void testOciFederatedRepo() { + artifactory.repositories().create(0, federatedRepo) + def expectedSettings = federatedRepo.repositorySettings + + def resp = artifactory.repository(federatedRepo.getKey()).get() + assertThat(resp, CoreMatchers.notNullValue()) + assertThat(resp.repoLayoutRef, CoreMatchers.is(OciRepositorySettingsImpl.defaultLayout)) + resp.getRepositorySettings().with { + assertThat(packageType, CoreMatchers.is(expectedSettings.getPackageType())) + assertThat(repoLayout, CoreMatchers.is(expectedSettings.getRepoLayout())) + + // local + assertThat(dockerApiVersion, CoreMatchers.is(expectedSettings.getDockerApiVersion())) + + // remote + assertThat(enableTokenAuthentication, CoreMatchers.is(CoreMatchers.nullValue())) + assertThat(listRemoteFolderItems, CoreMatchers.is(CoreMatchers.nullValue())) + } + } + + @Test(groups = "ociPackageTypeRepo") + void testOciRemoteRepo() { + artifactory.repositories().create(0, remoteRepo) + def expectedSettings = remoteRepo.repositorySettings + + def resp = artifactory.repository(remoteRepo.getKey()).get() + assertThat(resp, CoreMatchers.notNullValue()) + assertThat(resp.repoLayoutRef, CoreMatchers.is(OciRepositorySettingsImpl.defaultLayout)) + resp.getRepositorySettings().with { + assertThat(packageType, CoreMatchers.is(expectedSettings.getPackageType())) + assertThat(repoLayout, CoreMatchers.is(expectedSettings.getRepoLayout())) + + // local + assertThat(dockerApiVersion, CoreMatchers.is(expectedSettings.getDockerApiVersion())) + // always in resp payload + + // remote + assertThat(enableTokenAuthentication, CoreMatchers.is(expectedSettings.getEnableTokenAuthentication())) + assertThat(listRemoteFolderItems, CoreMatchers.is(expectedSettings.getListRemoteFolderItems())) + } + } + + @Test(groups = "ociPackageTypeRepo") + void testDockerVirtualRepo() { + artifactory.repositories().create(0, virtualRepo) + def expectedSettings = virtualRepo.repositorySettings + + def resp = artifactory.repository(virtualRepo.getKey()).get() + assertThat(resp, CoreMatchers.notNullValue()) + assertThat(resp.repoLayoutRef, CoreMatchers.is(OciRepositorySettingsImpl.defaultLayout)) + resp.getRepositorySettings().with { + assertThat(packageType, CoreMatchers.is(expectedSettings.getPackageType())) + assertThat(repoLayout, CoreMatchers.is(expectedSettings.getRepoLayout())) + + // local + assertThat(dockerApiVersion, CoreMatchers.is(expectedSettings.getDockerApiVersion())) + + // remote + assertThat(enableTokenAuthentication, CoreMatchers.is(CoreMatchers.nullValue())) + assertThat(listRemoteFolderItems, CoreMatchers.is(CoreMatchers.nullValue())) + } + } +}