From 650ebe5cf00cc403c3170208089f654605751a31 Mon Sep 17 00:00:00 2001 From: Eyal Ben Moshe Date: Thu, 13 Apr 2023 16:23:50 +0300 Subject: [PATCH 01/18] Added the Frogbot badge to the README (#372) --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f503330d..4e62efec 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,15 @@ +
+ +# Artifactory Java Client + +[![Scanned by Frogbot](https://raw.github.com/jfrog/frogbot/master/images/frogbot-badge.svg)](https://github.com/jfrog/frogbot#readme) + |Branch|Status| |:---:|:---:| |master|[![Build status](https://ci.appveyor.com/api/projects/status/sarjlbpi6dfgrd5w/branch/master?svg=true)](https://ci.appveyor.com/project/jfrog-ecosystem/artifactory-client-java/branch/master) |dev|[![Build status](https://ci.appveyor.com/api/projects/status/sarjlbpi6dfgrd5w/branch/dev?svg=true)](https://ci.appveyor.com/project/jfrog-ecosystem/artifactory-client-java/branch/dev) -# Artifactory Java Client +
Artifactory Java client provides simple yet powerful Artifactory connection and management within your Java code. From ab126df8191f877fbcc42b459c3a0b05532dca65 Mon Sep 17 00:00:00 2001 From: Eyal Ben Moshe Date: Thu, 13 Apr 2023 16:23:50 +0300 Subject: [PATCH 02/18] Added the Frogbot badge to the README (#372) --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f503330d..4e62efec 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,15 @@ +
+ +# Artifactory Java Client + +[![Scanned by Frogbot](https://raw.github.com/jfrog/frogbot/master/images/frogbot-badge.svg)](https://github.com/jfrog/frogbot#readme) + |Branch|Status| |:---:|:---:| |master|[![Build status](https://ci.appveyor.com/api/projects/status/sarjlbpi6dfgrd5w/branch/master?svg=true)](https://ci.appveyor.com/project/jfrog-ecosystem/artifactory-client-java/branch/master) |dev|[![Build status](https://ci.appveyor.com/api/projects/status/sarjlbpi6dfgrd5w/branch/dev?svg=true)](https://ci.appveyor.com/project/jfrog-ecosystem/artifactory-client-java/branch/dev) -# Artifactory Java Client +
Artifactory Java client provides simple yet powerful Artifactory connection and management within your Java code. From ba238fe52818e626863a22ee10dbc4ae6d9a73f6 Mon Sep 17 00:00:00 2001 From: idand1741 <130966676+idand1741@users.noreply.github.com> Date: Mon, 15 May 2023 08:14:20 +0300 Subject: [PATCH 03/18] Add an option to perform download with custom headers (#373) --- README.md | 10 ++++++++ .../jfrog/artifactory/client/Artifactory.java | 6 +++++ .../client/DownloadableArtifact.java | 2 ++ .../client/impl/ArtifactoryImpl.java | 25 +++++++++++++++++-- .../client/impl/DownloadableArtifactImpl.java | 14 +++++++++-- .../client/DownloadUploadTests.java | 11 ++++++++ 6 files changed, 64 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4e62efec..e7517e7c 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,16 @@ InputStream iStream = artifactory.repository("RepoName") .doDownload(); ``` +##### Downloading Artifact with custom headers + +```groovy +Map headers = new HashMap<>(); +headers.put("Range", "bytes=0-10"); +InputStream iStream = artifactory.repository("RepoName") + .download("path/to/fileToDownload.txt") + .doDownloadWithHeaders(headers); +``` + #### File, Folder and Repository Info ##### File Info diff --git a/api/src/main/java/org/jfrog/artifactory/client/Artifactory.java b/api/src/main/java/org/jfrog/artifactory/client/Artifactory.java index 892f36ca..602ac661 100644 --- a/api/src/main/java/org/jfrog/artifactory/client/Artifactory.java +++ b/api/src/main/java/org/jfrog/artifactory/client/Artifactory.java @@ -44,10 +44,16 @@ public interface Artifactory extends ApiInterface, AutoCloseable { InputStream getInputStream(String path) throws IOException; + InputStream getInputStreamWithHeaders(String path, Map headers) throws IOException; + default public T get(String path, Class object, Class interfaceObject) throws IOException { return null; } + default public T get(String path, Class object, Class interfaceObject, Map headers) throws IOException { + return null; + } + default public T post(String path, org.apache.http.entity.ContentType contentType, String content, Map headers, Class object, Class interfaceObject) throws IOException { return null; diff --git a/api/src/main/java/org/jfrog/artifactory/client/DownloadableArtifact.java b/api/src/main/java/org/jfrog/artifactory/client/DownloadableArtifact.java index 71f4e8d2..534156dd 100644 --- a/api/src/main/java/org/jfrog/artifactory/client/DownloadableArtifact.java +++ b/api/src/main/java/org/jfrog/artifactory/client/DownloadableArtifact.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Map; /** * @author jbaruch @@ -14,6 +15,7 @@ public interface DownloadableArtifact extends Artifact { InputStream doDownload() throws IOException; + InputStream doDownloadWithHeaders(Map headers) throws IOException; DownloadableArtifact withProperty(String name, Object... values); DownloadableArtifact withProperty(String name, Object value); diff --git a/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryImpl.java b/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryImpl.java index 2da5c184..3093ad42 100644 --- a/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryImpl.java +++ b/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryImpl.java @@ -21,6 +21,7 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URL; +import java.util.HashMap; import java.util.Map; /** @@ -220,6 +221,15 @@ public InputStream getInputStream(String path) throws IOException { throw newHttpResponseException(httpResponse); } + public InputStream getInputStreamWithHeaders(String path, Map headers) throws IOException { + HttpResponse httpResponse = get(path, null, null, headers); + if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK || + httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_PARTIAL_CONTENT) { + return httpResponse.getEntity().getContent(); + } + throw newHttpResponseException(httpResponse); + } + private HttpResponseException newHttpResponseException(HttpResponse httpResponse) throws IOException { String artifactoryResponse = Util.responseToString(httpResponse); StatusLine statusLine = httpResponse.getStatusLine(); @@ -239,12 +249,23 @@ protected Boolean head(String path) throws IOException { } public T get(String path, Class object, Class interfaceObject) throws IOException { - HttpGet httpGet = new HttpGet(); + return this.get(path, object, interfaceObject, new HashMap<>()); + } + public T get(String path, Class object, Class interfaceObject, Map headers) throws IOException { + HttpGet httpGet = new HttpGet(); httpGet.setURI(URI.create(url + path)); + + if (headers != null && !headers.isEmpty()) { + for (String key : headers.keySet()) { + httpGet.setHeader(key, headers.get(key)); + } + } + HttpResponse httpResponse = execute(httpGet); int status = httpResponse.getStatusLine().getStatusCode(); - if (status != HttpStatus.SC_OK && status != HttpStatus.SC_NO_CONTENT && status != HttpStatus.SC_ACCEPTED) { + if (status != HttpStatus.SC_OK && status != HttpStatus.SC_NO_CONTENT && + status != HttpStatus.SC_ACCEPTED && status != HttpStatus.SC_PARTIAL_CONTENT) { throw newHttpResponseException(httpResponse); } diff --git a/services/src/main/java/org/jfrog/artifactory/client/impl/DownloadableArtifactImpl.java b/services/src/main/java/org/jfrog/artifactory/client/impl/DownloadableArtifactImpl.java index 119c9d7c..8f5b0b7b 100644 --- a/services/src/main/java/org/jfrog/artifactory/client/impl/DownloadableArtifactImpl.java +++ b/services/src/main/java/org/jfrog/artifactory/client/impl/DownloadableArtifactImpl.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.HashMap; +import java.util.Map; /** * Created by eyalb on 21/06/2018. @@ -22,12 +23,21 @@ public class DownloadableArtifactImpl extends ArtifactBase } public InputStream doDownload() throws IOException { + String uri = generateUriWithParams(); + return artifactory.getInputStream(uri); + } + + public InputStream doDownloadWithHeaders(Map headers) throws IOException { + String uri = generateUriWithParams(); + return artifactory.getInputStreamWithHeaders(uri, headers); + } + + private String generateUriWithParams() { String params = parseParams(props, "=") + parseParams(mandatoryProps, "+="); if (params.length() > 0) { params = ";" + params; } - String uri = String.format("/%s/%s%s", repo, path, params); - return artifactory.getInputStream(uri); + return String.format("/%s/%s%s", repo, path, params); } public DownloadableArtifact withProperty(String name, Object... values) { diff --git a/services/src/test/java/org/jfrog/artifactory/client/DownloadUploadTests.java b/services/src/test/java/org/jfrog/artifactory/client/DownloadUploadTests.java index c311a645..5a543dda 100644 --- a/services/src/test/java/org/jfrog/artifactory/client/DownloadUploadTests.java +++ b/services/src/test/java/org/jfrog/artifactory/client/DownloadUploadTests.java @@ -19,7 +19,9 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.testng.Assert.*; @@ -284,4 +286,13 @@ public void testDownloadWithMandatoryAndNonMandatoryProperties() throws IOExcept .withProperty("foo", "bar").withMandatoryProperty("colors", "red").doDownload(); assertEquals(textFrom(inputStream), textFrom(this.getClass().getResourceAsStream("/sample.txt"))); } + + @Test(dependsOnMethods = "testUploadWithSingleProperty") + public void testDownloadWithHeaders() throws IOException { + Map headers = new HashMap<>(); + headers.put("Range", "bytes=0-10"); + InputStream inputStream = artifactory.repository(localRepository.getKey()).download(PATH).doDownloadWithHeaders(headers); + String actual = textFrom(inputStream); + assertEquals(actual, textFrom(this.getClass().getResourceAsStream("/sample.txt")).substring(0, 11)); + } } From 596e506e1e44348f3b4189afe1f2c0395d16f1f3 Mon Sep 17 00:00:00 2001 From: Yahav Itzhak Date: Mon, 15 May 2023 11:30:37 +0300 Subject: [PATCH 04/18] Update RELEASE.md --- RELEASE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index dad899cc..53da0cfb 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,5 +1,8 @@ # Release Notes +## 2.14.0 (May 15, 2023) +- Add an option to perform download with custom headers. + ## 2.13.1 (Jan 29, 2023) - Change contentType to enable APIs with chinese parameter. From 3824e1ab9faee18f7bf94a9680707d6f5350c7fb Mon Sep 17 00:00:00 2001 From: JFrog Pipelines Step Date: Mon, 15 May 2023 08:37:06 +0000 Subject: [PATCH 05/18] [artifactory-release] Release version 2.14.0 [skipRun] --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3fe652cf..b61a337c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -currentVersion=2.13.x-SNAPSHOT +currentVersion=2.14.0 From 30c41dbb847fa889d15522b558e5981b6a2a4d7e Mon Sep 17 00:00:00 2001 From: JFrog Pipelines Step Date: Mon, 15 May 2023 08:40:23 +0000 Subject: [PATCH 06/18] [artifactory-release] Next development version [skipRun] --- gradle.properties | 2 +- .../src/main/resources/artifactory.client.release.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index b61a337c..4bf545f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -currentVersion=2.14.0 +currentVersion=2.14.x-SNAPSHOT diff --git a/services/src/main/resources/artifactory.client.release.properties b/services/src/main/resources/artifactory.client.release.properties index f1c77e38..1d0cfe2c 100644 --- a/services/src/main/resources/artifactory.client.release.properties +++ b/services/src/main/resources/artifactory.client.release.properties @@ -1 +1 @@ -version=2.13.x-SNAPSHOT \ No newline at end of file +version=2.14.0 \ No newline at end of file From e8f128fefcc71cfdf0c22d2a2c182b8fceaaa3d7 Mon Sep 17 00:00:00 2001 From: Assaf Attias <49212512+attiasas@users.noreply.github.com> Date: Wed, 5 Jul 2023 11:41:49 +0300 Subject: [PATCH 07/18] Update pipelines.snapshot.yml --- release/pipelines.snapshot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/pipelines.snapshot.yml b/release/pipelines.snapshot.yml index 739aab88..c8b6729d 100644 --- a/release/pipelines.snapshot.yml +++ b/release/pipelines.snapshot.yml @@ -16,7 +16,7 @@ pipelines: inputResources: - name: javaClientSnapshotGit integrations: - - name: entplus_deployer + - name: ecosys_entplus_deployer execution: onStart: # Save gradle cache @@ -35,7 +35,7 @@ pipelines: # Configure JFrog CLI - curl -fL https://install-cli.jfrog.io | sh - jf c rm --quiet - - jf c add internal --url=$int_entplus_deployer_url --user=$int_entplus_deployer_user --password=$int_entplus_deployer_apikey + - jf c add internal --url=$int_ecosys_entplus_deployer_url --user=$int_ecosys_entplus_deployer_user --password=$int_ecosys_entplus_deployer_apikey - jf gradlec --use-wrapper --deploy-ivy-desc=false --deploy-maven-desc --uses-plugin --repo-resolve ecosys-maven-remote --repo-deploy ecosys-oss-snapshot-local # Run audit From 433128d76b16b229efa72fc758235c1263ba12f0 Mon Sep 17 00:00:00 2001 From: Assaf Attias <49212512+attiasas@users.noreply.github.com> Date: Wed, 5 Jul 2023 11:48:45 +0300 Subject: [PATCH 08/18] Update pipelines.release.yml --- release/pipelines.release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/pipelines.release.yml b/release/pipelines.release.yml index f3638db6..13b5525c 100644 --- a/release/pipelines.release.yml +++ b/release/pipelines.release.yml @@ -21,7 +21,7 @@ pipelines: - name: javaClientReleaseGit integrations: - name: il_automation - - name: entplus_deployer + - name: ecosys_entplus_deployer - name: mvn_central execution: onExecute: @@ -47,7 +47,7 @@ pipelines: # Configure JFrog CLI - curl -fL https://install-cli.jfrog.io | sh - jf c rm --quiet - - jf c add internal --url=$int_entplus_deployer_url --user=$int_entplus_deployer_user --password=$int_entplus_deployer_apikey + - jf c add internal --url=$int_ecosys_entplus_deployer_url --user=$int_ecosys_entplus_deployer_user --password=$int_ecosys_entplus_deployer_apikey - jf gradlec --use-wrapper --deploy-ivy-desc=false --deploy-maven-desc --uses-plugin --repo-resolve ecosys-maven-remote --repo-deploy ecosys-oss-release-local # Sync changes with dev From 1c2ec2ced885c7c146e43743c06ea6dd1c6dbebe Mon Sep 17 00:00:00 2001 From: Shimi Bandiel Date: Thu, 20 Jul 2023 08:05:49 -0700 Subject: [PATCH 09/18] Support for Cargo (#376) --- .../settings/CargoRepositorySettings.java | 10 +++ .../impl/jackson/RepositorySettingsMixIn.java | 3 +- .../impl/FederatedRepositoryBuilderImpl.java | 2 +- .../impl/LocalRepositoryBuilderImpl.java | 2 +- .../client/model/impl/PackageTypeImpl.java | 3 +- .../impl/RemoteRepositoryBuilderImpl.java | 2 +- .../impl/CargoRepositorySettingsImpl.java | 63 +++++++++++++ .../CargoPackageTypeRepositoryTests.groovy | 89 +++++++++++++++++++ 8 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 api/src/main/java/org/jfrog/artifactory/client/model/repository/settings/CargoRepositorySettings.java create mode 100644 services/src/main/java/org/jfrog/artifactory/client/model/repository/settings/impl/CargoRepositorySettingsImpl.java create mode 100644 services/src/test/groovy/org/jfrog/artifactory/client/CargoPackageTypeRepositoryTests.groovy diff --git a/api/src/main/java/org/jfrog/artifactory/client/model/repository/settings/CargoRepositorySettings.java b/api/src/main/java/org/jfrog/artifactory/client/model/repository/settings/CargoRepositorySettings.java new file mode 100644 index 00000000..35605f59 --- /dev/null +++ b/api/src/main/java/org/jfrog/artifactory/client/model/repository/settings/CargoRepositorySettings.java @@ -0,0 +1,10 @@ +package org.jfrog.artifactory.client.model.repository.settings; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public interface CargoRepositorySettings extends RepositorySettings { + String getGitRegistryUrl(); + Boolean isCargoInternalIndex(); + Boolean isCargoAnonymousAccess(); +} 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 872e3363..2d21e320 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 @@ -41,7 +41,8 @@ @JsonSubTypes.Type(value = CondaRepositorySettingsImpl.class, name = "conda"), @JsonSubTypes.Type(value = PuppetRepositorySettingsImpl.class, name = "puppet"), @JsonSubTypes.Type(value = HelmRepositorySettingsImpl.class, name = "helm"), - @JsonSubTypes.Type(value = GoRepositorySettingsImpl.class, name = "go") + @JsonSubTypes.Type(value = GoRepositorySettingsImpl.class, name = "go"), + @JsonSubTypes.Type(value = CargoRepositorySettingsImpl.class, name = "cargo") }) 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 2042a85e..e807a15d 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 + 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 )); 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 a4a0a9f6..2d7a04bd 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 + 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 )); 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 84ef4fea..df7c7848 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 @@ -31,7 +31,8 @@ public enum PackageTypeImpl implements PackageType { chef, puppet, helm, - go; + go, + cargo; @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 87bf7ec4..8b2625ec 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 + 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 )); private String url; diff --git a/services/src/main/java/org/jfrog/artifactory/client/model/repository/settings/impl/CargoRepositorySettingsImpl.java b/services/src/main/java/org/jfrog/artifactory/client/model/repository/settings/impl/CargoRepositorySettingsImpl.java new file mode 100644 index 00000000..66309fbd --- /dev/null +++ b/services/src/main/java/org/jfrog/artifactory/client/model/repository/settings/impl/CargoRepositorySettingsImpl.java @@ -0,0 +1,63 @@ +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.AbstractRepositorySettings; +import org.jfrog.artifactory.client.model.repository.settings.CargoRepositorySettings; + +import java.util.Objects; + +public class CargoRepositorySettingsImpl extends AbstractRepositorySettings implements CargoRepositorySettings { + public static String defaultLayout = "simple-default"; + private String gitRegistryUrl; + private Boolean cargoInternalIndex; + private Boolean cargoAnonymousAccess; + + public CargoRepositorySettingsImpl() { + super(defaultLayout); + } + + public PackageType getPackageType() { + return PackageTypeImpl.cargo; + } + + @Override + public String getGitRegistryUrl() { + return gitRegistryUrl; + } + + public void setGitRegistryUrl(String tRegistryUrl) { + this.gitRegistryUrl = tRegistryUrl; + } + + @Override + public Boolean isCargoInternalIndex() { + return cargoInternalIndex; + } + + public void setCargoInternalIndex(Boolean cargoInternalIndex) { + this.cargoInternalIndex = cargoInternalIndex; + } + + @Override + public Boolean isCargoAnonymousAccess() { + return cargoAnonymousAccess; + } + + public void setCargoAnonymousAccess(Boolean cargoAnonymousAccess) { + this.cargoAnonymousAccess = cargoAnonymousAccess; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CargoRepositorySettingsImpl that = (CargoRepositorySettingsImpl) o; + return Objects.equals(gitRegistryUrl, that.gitRegistryUrl) && Objects.equals(cargoInternalIndex, that.cargoInternalIndex) && Objects.equals(cargoAnonymousAccess, that.cargoAnonymousAccess); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), gitRegistryUrl, cargoInternalIndex, cargoAnonymousAccess); + } +} diff --git a/services/src/test/groovy/org/jfrog/artifactory/client/CargoPackageTypeRepositoryTests.groovy b/services/src/test/groovy/org/jfrog/artifactory/client/CargoPackageTypeRepositoryTests.groovy new file mode 100644 index 00000000..c1742572 --- /dev/null +++ b/services/src/test/groovy/org/jfrog/artifactory/client/CargoPackageTypeRepositoryTests.groovy @@ -0,0 +1,89 @@ +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.impl.CargoRepositorySettingsImpl +import org.testng.annotations.BeforeMethod +import org.testng.annotations.Test + +class CargoPackageTypeRepositoryTests extends BaseRepositoryTests { + + CargoPackageTypeRepositoryTests() { + remoteRepoUrl = "https://index.crates.io" + } + + @Override + RepositorySettings getRepositorySettings(RepositoryType repositoryType) { + def settings = new CargoRepositorySettingsImpl() + + settings.with { + // remote + cargoAnonymousAccess = rnd.nextBoolean() + cargoInternalIndex = rnd.nextBoolean() + gitRegistryUrl = "https://index.crates.io/" + } + + return settings + } + + @BeforeMethod + protected void setUp() { + prepareVirtualRepo = false + super.setUp() + } + + @Test(groups = "cargoPackageTypeRepo") + void testCargoLocalRepo() { + 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(CargoRepositorySettingsImpl.defaultLayout)) + resp.getRepositorySettings().with { + assertThat(packageType, CoreMatchers.is(expectedSettings.getPackageType())) + assertThat(repoLayout, CoreMatchers.is(expectedSettings.getRepoLayout())) + + // remote + assertThat(cargoInternalIndex, CoreMatchers.is(expectedSettings.cargoInternalIndex)) + assertThat(cargoAnonymousAccess, CoreMatchers.is(expectedSettings.cargoAnonymousAccess)) + } + } + + @Test(groups = "cargoPackageTypeRepo") + void testCargoFederatedRepo() { + 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(CargoRepositorySettingsImpl.defaultLayout)) + resp.getRepositorySettings().with { + assertThat(packageType, CoreMatchers.is(expectedSettings.getPackageType())) + assertThat(repoLayout, CoreMatchers.is(expectedSettings.getRepoLayout())) + + // remote + assertThat(cargoInternalIndex, CoreMatchers.is(expectedSettings.cargoInternalIndex)) + assertThat(cargoAnonymousAccess, CoreMatchers.is(expectedSettings.cargoAnonymousAccess)) + } + } + + @Test(groups = "cargoPackageTypeRepo") + void testCargoRemoteRepo() { + 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(CargoRepositorySettingsImpl.defaultLayout)) + resp.getRepositorySettings().with { + assertThat(packageType, CoreMatchers.is(expectedSettings.getPackageType())) + assertThat(repoLayout, CoreMatchers.is(expectedSettings.getRepoLayout())) + + // remote + assertThat(cargoInternalIndex, CoreMatchers.is(expectedSettings.cargoInternalIndex)) + assertThat(cargoAnonymousAccess, CoreMatchers.is(expectedSettings.cargoAnonymousAccess)) + } + } +} \ No newline at end of file From e17f64ddfc3929f748898f372344c7342573517e Mon Sep 17 00:00:00 2001 From: eyalbe4 Date: Fri, 21 Jul 2023 12:09:34 +0300 Subject: [PATCH 10/18] Update release notes --- RELEASE.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 53da0cfb..cd3a88ad 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,7 +1,10 @@ # Release Notes +## 2.14.0 (July 21, 2023) +- Support for the Cargo package manager. + ## 2.14.0 (May 15, 2023) -- Add an option to perform download with custom headers. +- New option for performing download with custom headers. ## 2.13.1 (Jan 29, 2023) - Change contentType to enable APIs with chinese parameter. From 82c47790cd33c1b7be9fe1d5d7c09d5e2cacb88d Mon Sep 17 00:00:00 2001 From: eyalbe4 Date: Fri, 21 Jul 2023 12:22:03 +0300 Subject: [PATCH 11/18] Update release notes --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index cd3a88ad..5983e7ec 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,6 +1,6 @@ # Release Notes -## 2.14.0 (July 21, 2023) +## 2.15.0 (July 21, 2023) - Support for the Cargo package manager. ## 2.14.0 (May 15, 2023) From 41d391f69f0901cb60daf246f51722cb6f7d9399 Mon Sep 17 00:00:00 2001 From: JFrog Pipelines Step Date: Fri, 21 Jul 2023 09:39:52 +0000 Subject: [PATCH 12/18] [artifactory-release] Release version 2.15.0 [skipRun] --- gradle.properties | 2 +- .../src/main/resources/artifactory.client.release.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 4bf545f6..baad2032 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -currentVersion=2.14.x-SNAPSHOT +currentVersion=2.15.0 diff --git a/services/src/main/resources/artifactory.client.release.properties b/services/src/main/resources/artifactory.client.release.properties index 1d0cfe2c..43c409cb 100644 --- a/services/src/main/resources/artifactory.client.release.properties +++ b/services/src/main/resources/artifactory.client.release.properties @@ -1 +1 @@ -version=2.14.0 \ No newline at end of file +version=2.14.x-SNAPSHOT \ No newline at end of file From 102bee91a946403d9d18abe7b96f08ce7a0e4864 Mon Sep 17 00:00:00 2001 From: Adi Guberman <89910521+adigfrog@users.noreply.github.com> Date: Wed, 20 Sep 2023 14:33:42 +0300 Subject: [PATCH 13/18] Add Streaming Rest Call - returning the response input stream without the wrappers (#379) --- README.md | 25 +++++++- .../jfrog/artifactory/client/Artifactory.java | 6 ++ .../client/ArtifactoryResponse.java | 11 +--- .../client/ArtifactoryStreamingResponse.java | 13 +++++ .../client/BaseArtifactoryResponse.java | 13 +++++ .../impl/AbstractArtifactoryResponseImpl.java | 27 +++++++++ .../client/impl/ArtifactoryImpl.java | 21 ++++++- .../client/impl/ArtifactoryResponseImpl.java | 18 +----- .../ArtifactoryStreamingResponseImpl.java | 39 +++++++++++++ .../client/StreamingRestCallTest.java | 57 +++++++++++++++++++ 10 files changed, 202 insertions(+), 28 deletions(-) create mode 100644 api/src/main/java/org/jfrog/artifactory/client/ArtifactoryStreamingResponse.java create mode 100644 api/src/main/java/org/jfrog/artifactory/client/BaseArtifactoryResponse.java create mode 100644 services/src/main/groovy/org/jfrog/artifactory/client/impl/AbstractArtifactoryResponseImpl.java create mode 100644 services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryStreamingResponseImpl.java create mode 100644 services/src/test/java/org/jfrog/artifactory/client/StreamingRestCallTest.java diff --git a/README.md b/README.md index e7517e7c..ac178b96 100644 --- a/README.md +++ b/README.md @@ -851,16 +851,37 @@ org.apache.http.Header[] headers = response.getAllHeaders(); org.apache.http.StatusLine statusLine = response.getStatusLine(); // A convenience method for verifying success -assert response.isSuccessResponse() +assert response.isSuccessResponse(); // Get the response raw body -String rawBody = response.rawBody(); +String rawBody = response.getRawBody(); // If the the response raw body has a JSON format, populate an object with the body content, // by providing a object's class. List> parsedBody = response.parseBody(List.class); ``` +Executing an Artifactory streaming REST API + +```groovy +ArtifactoryRequest repositoryRequest = new ArtifactoryRequestImpl().apiUrl("api/repositories") + .method(ArtifactoryRequest.Method.GET) + .responseType(ArtifactoryRequest.ContentType.JSON); +ArtifactoryStreamingResponse response = artifactory.streamingRestCall(repositoryRequest); + +// Get the response headers +org.apache.http.Header[] headers = response.getAllHeaders(); + +// Get the response status information +org.apache.http.StatusLine statusLine = response.getStatusLine(); + +// A convenience method for verifying success +assert response.isSuccessResponse(); + +// Get the response raw body using input stream +String rawBody = IOUtils.toString(response.getInputStream(), StandardCharsets.UTF_8); +``` + ## Building and Testing the Sources The code is built using Gradle and includes integration tests. diff --git a/api/src/main/java/org/jfrog/artifactory/client/Artifactory.java b/api/src/main/java/org/jfrog/artifactory/client/Artifactory.java index 602ac661..d36fbe90 100644 --- a/api/src/main/java/org/jfrog/artifactory/client/Artifactory.java +++ b/api/src/main/java/org/jfrog/artifactory/client/Artifactory.java @@ -1,6 +1,8 @@ package org.jfrog.artifactory.client; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpUriRequest; import java.io.IOException; import java.io.InputStream; @@ -42,10 +44,14 @@ public interface Artifactory extends ApiInterface, AutoCloseable { ArtifactoryResponse restCall(ArtifactoryRequest artifactoryRequest) throws IOException; + ArtifactoryStreamingResponse streamingRestCall(ArtifactoryRequest artifactoryRequest) throws IOException; + InputStream getInputStream(String path) throws IOException; InputStream getInputStreamWithHeaders(String path, Map headers) throws IOException; + HttpResponse execute(HttpUriRequest request) throws IOException; + default public T get(String path, Class object, Class interfaceObject) throws IOException { return null; } diff --git a/api/src/main/java/org/jfrog/artifactory/client/ArtifactoryResponse.java b/api/src/main/java/org/jfrog/artifactory/client/ArtifactoryResponse.java index 883eaa98..be1ee510 100644 --- a/api/src/main/java/org/jfrog/artifactory/client/ArtifactoryResponse.java +++ b/api/src/main/java/org/jfrog/artifactory/client/ArtifactoryResponse.java @@ -1,7 +1,5 @@ package org.jfrog.artifactory.client; -import org.apache.http.Header; -import org.apache.http.StatusLine; import java.io.IOException; @@ -9,15 +7,10 @@ * ArtifactoryResponse object returned from {@link Artifactory#restCall(ArtifactoryRequest)}. * acts as a wrapper for {@link org.apache.http.HttpResponse} but removes the need to handle response stream. */ -public interface ArtifactoryResponse { - - Header[] getAllHeaders(); - - StatusLine getStatusLine(); +public interface ArtifactoryResponse extends BaseArtifactoryResponse { String getRawBody(); T parseBody(Class toType) throws IOException; - boolean isSuccessResponse(); -} +} \ No newline at end of file diff --git a/api/src/main/java/org/jfrog/artifactory/client/ArtifactoryStreamingResponse.java b/api/src/main/java/org/jfrog/artifactory/client/ArtifactoryStreamingResponse.java new file mode 100644 index 00000000..0cb2deb0 --- /dev/null +++ b/api/src/main/java/org/jfrog/artifactory/client/ArtifactoryStreamingResponse.java @@ -0,0 +1,13 @@ +package org.jfrog.artifactory.client; + +import java.io.IOException; +import java.io.InputStream; + + +/** + * ArtifactoryStreamingResponse object returned from {@link Artifactory#streamingRestCall(ArtifactoryRequest)}. + * acts as a wrapper for {@link org.apache.http.HttpResponse}. + */ +public interface ArtifactoryStreamingResponse extends BaseArtifactoryResponse, AutoCloseable { + InputStream getInputStream() throws IOException; +} diff --git a/api/src/main/java/org/jfrog/artifactory/client/BaseArtifactoryResponse.java b/api/src/main/java/org/jfrog/artifactory/client/BaseArtifactoryResponse.java new file mode 100644 index 00000000..d52c2258 --- /dev/null +++ b/api/src/main/java/org/jfrog/artifactory/client/BaseArtifactoryResponse.java @@ -0,0 +1,13 @@ +package org.jfrog.artifactory.client; +import org.apache.http.Header; +import org.apache.http.StatusLine; + +public interface BaseArtifactoryResponse { + + Header[] getAllHeaders(); + + StatusLine getStatusLine(); + + boolean isSuccessResponse(); + +} diff --git a/services/src/main/groovy/org/jfrog/artifactory/client/impl/AbstractArtifactoryResponseImpl.java b/services/src/main/groovy/org/jfrog/artifactory/client/impl/AbstractArtifactoryResponseImpl.java new file mode 100644 index 00000000..cf64ccd8 --- /dev/null +++ b/services/src/main/groovy/org/jfrog/artifactory/client/impl/AbstractArtifactoryResponseImpl.java @@ -0,0 +1,27 @@ +package org.jfrog.artifactory.client.impl; + +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; + +public abstract class AbstractArtifactoryResponseImpl { + + private final HttpResponse httpResponse; + + public AbstractArtifactoryResponseImpl(HttpResponse httpResponse) { + this.httpResponse = httpResponse; + } + + public HttpResponse getHttpResponse() { + return httpResponse; + } + + public Header[] getAllHeaders() { + return this.httpResponse.getAllHeaders(); + } + + public StatusLine getStatusLine() { + return this.httpResponse.getStatusLine(); + } + +} diff --git a/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryImpl.java b/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryImpl.java index 3093ad42..ae159a2c 100644 --- a/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryImpl.java +++ b/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryImpl.java @@ -132,6 +132,24 @@ public ArtifactorySystem system() { */ @Override public ArtifactoryResponse restCall(ArtifactoryRequest artifactoryRequest) throws IOException { + HttpResponse httpResponse = handleArtifactoryRequest(artifactoryRequest); + return new ArtifactoryResponseImpl(httpResponse); + } + + /** + * Create a REST call to artifactory with a generic request + * + * @param artifactoryRequest that should be sent to artifactory + * @return {@link ArtifactoryStreamingResponse} Artifactory response in accordance with the request, + * which includes a reference to the inputStream. + */ + @Override + public ArtifactoryStreamingResponse streamingRestCall(ArtifactoryRequest artifactoryRequest) throws IOException { + HttpResponse httpResponse = handleArtifactoryRequest(artifactoryRequest); + return new ArtifactoryStreamingResponseImpl(httpResponse); + } + + private HttpResponse handleArtifactoryRequest(ArtifactoryRequest artifactoryRequest) throws IOException { HttpRequestBase httpRequest; String requestPath = "/" + artifactoryRequest.getApiUrl(); @@ -194,7 +212,7 @@ public ArtifactoryResponse restCall(ArtifactoryRequest artifactoryRequest) throw } HttpResponse httpResponse = execute(httpRequest); - return new ArtifactoryResponseImpl(httpResponse); + return httpResponse; } private void setEntity(HttpEntityEnclosingRequestBase httpRequest, Object body, ContentType contentType) throws JsonProcessingException { @@ -369,6 +387,7 @@ public String delete(String path) throws IOException { return Util.responseToString(httpResponse); } + @Override public HttpResponse execute(HttpUriRequest request) throws IOException { HttpClientContext clientContext = HttpClientContext.create(); if (clientContext.getAttribute(PreemptiveAuthInterceptor.ORIGINAL_HOST_CONTEXT_PARAM) == null) { diff --git a/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryResponseImpl.java b/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryResponseImpl.java index aeefc202..9ca8328d 100644 --- a/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryResponseImpl.java +++ b/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryResponseImpl.java @@ -1,25 +1,22 @@ package org.jfrog.artifactory.client.impl; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; import org.apache.http.util.EntityUtils; import org.jfrog.artifactory.client.ArtifactoryResponse; import org.jfrog.artifactory.client.impl.util.Util; import java.io.IOException; -public class ArtifactoryResponseImpl implements ArtifactoryResponse { +public class ArtifactoryResponseImpl extends AbstractArtifactoryResponseImpl implements ArtifactoryResponse { private static final ObjectMapper objectMapper = new ObjectMapper(); - private HttpResponse httpResponse; private String rawBody; ArtifactoryResponseImpl(HttpResponse httpResponse) throws IOException { - this.httpResponse = httpResponse; + super(httpResponse); HttpEntity entity = httpResponse.getEntity(); @@ -34,16 +31,6 @@ public class ArtifactoryResponseImpl implements ArtifactoryResponse { } } - @Override - public Header[] getAllHeaders() { - return this.httpResponse.getAllHeaders(); - } - - @Override - public StatusLine getStatusLine() { - return this.httpResponse.getStatusLine(); - } - @Override public String getRawBody() { return this.rawBody; @@ -62,7 +49,6 @@ public T parseBody(Class toType) throws IOException { @Override public boolean isSuccessResponse() { int status = getStatusLine().getStatusCode(); - return status >= 200 && status < 300; } } diff --git a/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryStreamingResponseImpl.java b/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryStreamingResponseImpl.java new file mode 100644 index 00000000..57080a64 --- /dev/null +++ b/services/src/main/groovy/org/jfrog/artifactory/client/impl/ArtifactoryStreamingResponseImpl.java @@ -0,0 +1,39 @@ +package org.jfrog.artifactory.client.impl; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.jfrog.artifactory.client.ArtifactoryStreamingResponse; + +import java.io.IOException; +import java.io.InputStream; + +public class ArtifactoryStreamingResponseImpl extends AbstractArtifactoryResponseImpl implements ArtifactoryStreamingResponse { + + public ArtifactoryStreamingResponseImpl(HttpResponse httpResponse) { + super(httpResponse); + } + + @Override + public InputStream getInputStream() throws IOException { + InputStream is = null; + HttpEntity entity = getHttpResponse().getEntity(); + if (entity != null) { + is = entity.getContent(); + } + return is; + } + + @Override + public boolean isSuccessResponse() { + int status = getStatusLine().getStatusCode(); + return (status == HttpStatus.SC_OK || + status == HttpStatus.SC_PARTIAL_CONTENT); + } + + @Override + public void close() throws Exception { + IOUtils.close(getInputStream()); + } +} diff --git a/services/src/test/java/org/jfrog/artifactory/client/StreamingRestCallTest.java b/services/src/test/java/org/jfrog/artifactory/client/StreamingRestCallTest.java new file mode 100644 index 00000000..c29df72a --- /dev/null +++ b/services/src/test/java/org/jfrog/artifactory/client/StreamingRestCallTest.java @@ -0,0 +1,57 @@ +package org.jfrog.artifactory.client; + +import org.apache.commons.io.IOUtils; +import org.jfrog.artifactory.client.impl.ArtifactoryRequestImpl; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import static org.testng.Assert.*; + +public class StreamingRestCallTest extends ArtifactoryTestsBase { + + @Test + public void testDownloadWithHeadersByStreamingRestCall() throws IOException { + InputStream inputStream = this.getClass().getResourceAsStream("/sample.txt"); + assertNotNull(inputStream); + artifactory.repository(localRepository.getKey()).upload(PATH, inputStream).withProperty("color", "blue") + .withProperty("color", "red").doUpload(); + + Map headers = new HashMap<>(); + headers.put("Range", "bytes=0-10"); + ArtifactoryRequest request = new ArtifactoryRequestImpl() + .apiUrl(localRepository.getKey() + "/" + PATH) + .method(ArtifactoryRequest.Method.GET) + .setHeaders(headers) + .requestType(ArtifactoryRequest.ContentType.JSON); + + ArtifactoryStreamingResponse response = artifactory.streamingRestCall(request); + assertTrue(response.isSuccessResponse()); + + inputStream = response.getInputStream(); + String actual = textFrom(inputStream); + assertEquals(actual, textFrom(this.getClass().getResourceAsStream("/sample.txt")).substring(0, 11)); + } + + @Test + public void testErrorStreamingRestCall() throws IOException { + ArtifactoryRequest request = new ArtifactoryRequestImpl() + .apiUrl(localRepository.getKey() + "/" + PATH + "shouldNotExist") + .method(ArtifactoryRequest.Method.GET) + .requestType(ArtifactoryRequest.ContentType.JSON); + ArtifactoryStreamingResponse response = artifactory.streamingRestCall(request); + assertFalse(response.isSuccessResponse()); + assertEquals(response.getStatusLine().getStatusCode(), 404); + String raw = IOUtils.toString(response.getInputStream(), StandardCharsets.UTF_8); + assertEquals(raw, "{\n" + + " \"errors\" : [ {\n" + + " \"status\" : 404,\n" + + " \"message\" : \"File not found.\"\n" + + " } ]\n" + + "}"); + } +} From 1f99196939e1f64633e460aa8086d51dd037b3bc Mon Sep 17 00:00:00 2001 From: JFrog Pipelines Step Date: Wed, 20 Sep 2023 12:01:16 +0000 Subject: [PATCH 14/18] [artifactory-release] Release version 2.16.0 [skipRun] --- gradle.properties | 2 +- .../src/main/resources/artifactory.client.release.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index baad2032..f47ffd75 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -currentVersion=2.15.0 +currentVersion=2.16.0 diff --git a/services/src/main/resources/artifactory.client.release.properties b/services/src/main/resources/artifactory.client.release.properties index 43c409cb..38b63b57 100644 --- a/services/src/main/resources/artifactory.client.release.properties +++ b/services/src/main/resources/artifactory.client.release.properties @@ -1 +1 @@ -version=2.14.x-SNAPSHOT \ No newline at end of file +version=2.15.0 \ No newline at end of file From 26cefdcae0b51d32014d8264775828a7f4f106c8 Mon Sep 17 00:00:00 2001 From: Yahav Itzhak Date: Wed, 20 Sep 2023 15:17:53 +0300 Subject: [PATCH 15/18] Update RELEASE.md --- RELEASE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index 5983e7ec..2e9e02e6 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,5 +1,8 @@ # Release Notes +| Release notes moved to https://github.com/jfrog/artifactory-client-java/releases | +|----------------------------------------------------------------------------------------------------------------------------------------------------------| + ## 2.15.0 (July 21, 2023) - Support for the Cargo package manager. From e9c98c6bdd0223548644f2646175b14192b09b73 Mon Sep 17 00:00:00 2001 From: Yahav Itzhak Date: Sun, 1 Oct 2023 10:09:46 +0300 Subject: [PATCH 16/18] Automatically generated release notes (#382) --- .github/release.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/release.yml diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..50210177 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,20 @@ +changelog: + exclude: + labels: + - ignore for release + categories: + - title: Breaking Changes 🚨 + labels: + - breaking change + - title: Exciting New Features 🎉 + labels: + - new feature + - title: Improvements 🌱 + labels: + - improvement + - title: Bug Fixes 🛠 + labels: + - bug + - title: Other Changes 📚 + labels: + - "*" From 47f68e364940f1de6c4a856524be42868bfa7738 Mon Sep 17 00:00:00 2001 From: Yahav Itzhak Date: Sun, 1 Oct 2023 10:31:03 +0300 Subject: [PATCH 17/18] Migrate tests to GitHub Actions (#381) --- .github/workflows/tests.yml | 52 ++++++++++++++++++ README.md | 8 +-- ci/appveyor.yml | 20 ------- .../client/ArtifactoryTestsBase.java | 55 +++++-------------- .../client/StreamingRestCallTest.java | 7 +-- 5 files changed, 72 insertions(+), 70 deletions(-) create mode 100644 .github/workflows/tests.yml delete mode 100644 ci/appveyor.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..62c27dc8 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,52 @@ +name: Tests +on: + push: + branches: + - '**' + tags-ignore: + - '**' + # Triggers the workflow on labeled PRs only. + pull_request_target: + types: [ labeled ] +# Ensures that only the latest commit is running for each PR at a time. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.ref }} + cancel-in-progress: true +jobs: + Tests: + if: contains(github.event.pull_request.labels.*.name, 'safe to test') || github.event_name == 'push' + name: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu, windows, macOS ] + include: + - os: windows + gradlewSuffix: .bat + runs-on: ${{ matrix.os }}-latest + steps: + - name: Install Go + uses: actions/setup-go@v4 + with: + go-version: 1.20.x + cache: false + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Setup Artifactory + run: | + go install github.com/jfrog/jfrog-testing-infra/local-rt-setup@latest + ~/go/bin/local-rt-setup + env: + RTLIC: ${{secrets.RTLIC}} + GOPROXY: direct + + - name: Install Java + uses: actions/setup-java@v3 + with: + java-version: "8" + distribution: "temurin" + + - name: Run tests + run: ./gradlew${{ matrix.gradlewSuffix }} clean test diff --git a/README.md b/README.md index ac178b96..46dbd037 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ [![Scanned by Frogbot](https://raw.github.com/jfrog/frogbot/master/images/frogbot-badge.svg)](https://github.com/jfrog/frogbot#readme) -|Branch|Status| -|:---:|:---:| -|master|[![Build status](https://ci.appveyor.com/api/projects/status/sarjlbpi6dfgrd5w/branch/master?svg=true)](https://ci.appveyor.com/project/jfrog-ecosystem/artifactory-client-java/branch/master) -|dev|[![Build status](https://ci.appveyor.com/api/projects/status/sarjlbpi6dfgrd5w/branch/dev?svg=true)](https://ci.appveyor.com/project/jfrog-ecosystem/artifactory-client-java/branch/dev) +| Branch |Status| +|:------:|:---:| +|master|[![Test](https://github.com/jfrog/artifactory-client-java/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/jfrog/artifactory-client-java/actions/workflows/tests.yml?query=branch%3Amaster) +|dev|[![Test](https://github.com/jfrog/artifactory-client-java/actions/workflows/tests.yml/badge.svg?branch=dev)](https://github.com/jfrog/artifactory-client-java/actions/workflows/tests.yml?query=branch%3Adev) diff --git a/ci/appveyor.yml b/ci/appveyor.yml deleted file mode 100644 index d4fca21d..00000000 --- a/ci/appveyor.yml +++ /dev/null @@ -1,20 +0,0 @@ -image: - - Visual Studio 2017 - - Ubuntu - -stack: jdk 8 -environment: - APPVEYOR_SAVE_CACHE_ON_ERROR: true - APPVEYOR_YML_DISABLE_PS_LINUX: true - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 - -test_script: - - sh: ./gradlew test - - cmd: gradlew.bat test - -# Don't actually build. -build: off - -cache: - - C:\Users\appveyor\.gradle\ -> build.gradle - - /home/appveyor/.gradle/ -> build.gradle diff --git a/services/src/test/java/org/jfrog/artifactory/client/ArtifactoryTestsBase.java b/services/src/test/java/org/jfrog/artifactory/client/ArtifactoryTestsBase.java index 43088f41..13b254a8 100644 --- a/services/src/test/java/org/jfrog/artifactory/client/ArtifactoryTestsBase.java +++ b/services/src/test/java/org/jfrog/artifactory/client/ArtifactoryTestsBase.java @@ -1,7 +1,8 @@ package org.jfrog.artifactory.client; -import org.apache.http.client.HttpResponseException; +import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpEntity; +import org.apache.http.client.HttpResponseException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; @@ -13,6 +14,7 @@ import org.jfrog.artifactory.client.model.repository.settings.impl.MavenRepositorySettingsImpl; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; + import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -20,10 +22,10 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Properties; + import static org.apache.commons.codec.binary.Base64.encodeBase64; import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.apache.commons.lang3.StringUtils.remove; -import static org.testng.Assert.fail; /** * @author jbaruch @@ -58,12 +60,12 @@ public void init() throws IOException { props.load(inputStream); } - url = readParam(props, "url"); + url = readParam(props, "url", "http://localhost:8081/artifactory"); if (!url.endsWith("/")) { url += "/"; } - username = readParam(props, "username"); - password = readParam(props, "password"); + username = readParam(props, "username", "admin"); + password = readParam(props, "password", "password"); filePath = "a/b"; fileSize = 141185; fileMd5 = "8f17d4271b86478a2731deebdab8c846"; @@ -97,39 +99,12 @@ public void init() throws IOException { } } - public static String readParam(Properties props, String paramName) { - String paramValue = null; - if (props.size() > 0) { - paramValue = props.getProperty(CLIENTTESTS_ARTIFACTORY_PROPERTIES_PREFIX + paramName); - } - if (paramValue == null) { - paramValue = System.getProperty(CLIENTTESTS_ARTIFACTORY_PROPERTIES_PREFIX + paramName); - } - if (paramValue == null) { - paramValue = System.getenv(CLIENTTESTS_ARTIFACTORY_ENV_VAR_PREFIX + paramName.toUpperCase()); - } - if (paramValue == null) { - failInit(); - } - return paramValue; - } - - private static void failInit() { - String message = - new StringBuilder("Failed to load test Artifactory instance credentials. ") - .append("Looking for System properties '") - .append(CLIENTTESTS_ARTIFACTORY_PROPERTIES_PREFIX) - .append("url', ") - .append(CLIENTTESTS_ARTIFACTORY_PROPERTIES_PREFIX) - .append("username' and ") - .append(CLIENTTESTS_ARTIFACTORY_PROPERTIES_PREFIX) - .append("password' or a properties file with those properties in classpath ") - .append("or Environment variables '") - .append(CLIENTTESTS_ARTIFACTORY_ENV_VAR_PREFIX).append("URL', ") - .append(CLIENTTESTS_ARTIFACTORY_ENV_VAR_PREFIX).append("USERNAME' and ") - .append(CLIENTTESTS_ARTIFACTORY_ENV_VAR_PREFIX).append("PASSWORD'").toString(); - - fail(message); + public static String readParam(Properties props, String paramName, String defaultValue) { + return StringUtils.firstNonBlank( + props.getProperty(CLIENTTESTS_ARTIFACTORY_PROPERTIES_PREFIX + paramName), + System.getProperty(CLIENTTESTS_ARTIFACTORY_PROPERTIES_PREFIX + paramName), + System.getenv(CLIENTTESTS_ARTIFACTORY_ENV_VAR_PREFIX + paramName.toUpperCase()), + defaultValue); } @AfterClass @@ -208,8 +183,8 @@ protected String deleteRepoIfExists(String repoName) { try { return artifactory.repository(repoName).delete(); } catch (Exception e) { - if (e instanceof HttpResponseException && ((HttpResponseException)e).getStatusCode() == 404) { - //if repo wasn't found - that's ok. + if (e instanceof HttpResponseException && ((HttpResponseException) e).getStatusCode() == 404) { + //if repo wasn't found - that's ok. return e.getMessage(); } else { throw e; diff --git a/services/src/test/java/org/jfrog/artifactory/client/StreamingRestCallTest.java b/services/src/test/java/org/jfrog/artifactory/client/StreamingRestCallTest.java index c29df72a..7261831e 100644 --- a/services/src/test/java/org/jfrog/artifactory/client/StreamingRestCallTest.java +++ b/services/src/test/java/org/jfrog/artifactory/client/StreamingRestCallTest.java @@ -47,11 +47,6 @@ public void testErrorStreamingRestCall() throws IOException { assertFalse(response.isSuccessResponse()); assertEquals(response.getStatusLine().getStatusCode(), 404); String raw = IOUtils.toString(response.getInputStream(), StandardCharsets.UTF_8); - assertEquals(raw, "{\n" + - " \"errors\" : [ {\n" + - " \"status\" : 404,\n" + - " \"message\" : \"File not found.\"\n" + - " } ]\n" + - "}"); + assertTrue(raw.contains("File not found"), "Expected response to contain 'File not found'.\nResponse:" + raw); } } From 777f4c9bcac6262938140d06d2fa5bba0449e657 Mon Sep 17 00:00:00 2001 From: Yahav Itzhak Date: Sun, 1 Oct 2023 11:36:45 +0300 Subject: [PATCH 18/18] Create removeLabel.yml --- .github/workflows/removeLabel.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/removeLabel.yml diff --git a/.github/workflows/removeLabel.yml b/.github/workflows/removeLabel.yml new file mode 100644 index 00000000..67be7e8d --- /dev/null +++ b/.github/workflows/removeLabel.yml @@ -0,0 +1,18 @@ +name: Remove Label +on: + pull_request_target: + types: [labeled] +# Ensures that only the latest commit is running for each PR at a time. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.ref }} + cancel-in-progress: true +jobs: + Remove-Label: + if: contains(github.event.pull_request.labels.*.name, 'safe to test') + name: Remove label + runs-on: ubuntu-latest + steps: + - name: Remove 'safe to test' + uses: actions-ecosystem/action-remove-labels@v1 + with: + labels: "safe to test"