Skip to content

Commit

Permalink
Merge pull request #45 from ahippler/feature/reduce-api-calls
Browse files Browse the repository at this point in the history
Reduce api calls by reusing aql file info
  • Loading branch information
jonesbusy committed Jun 11, 2024
2 parents 0f82809 + 5f873b8 commit 1828c15
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import java.util.List;
import java.util.stream.Collectors;
import org.jfrog.artifactory.client.*;
import org.jfrog.artifactory.client.model.File;
import org.jfrog.artifactory.client.model.*;
import org.jfrog.filespecs.FileSpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -111,15 +111,19 @@ public boolean isFolder(String targetPath) throws IOException {
* @return the list of files in the folder
* @throws IOException if the files cannot be listed
*/
public List<String> list(String targetPath) throws IOException {
public List<FileInfo> list(String targetPath) throws IOException {
if (!isFolder(targetPath)) {
LOGGER.debug(String.format("Target path %s is not a folder. Cannot list files", targetPath));
return List.of();
}
FileSpec fileSpec = FileSpec.fromString(
String.format("{\"files\": [{\"pattern\": \"%s/%s*\"}]}", this.config.repository, targetPath));
return artifactory.searches().artifactsByFileSpec(fileSpec).stream()
.map((item -> String.format("%s/%s", item.getPath(), item.getName())))
.map((item -> new FileInfo(
String.format("%s/%s", item.getPath(), item.getName()),
item.getModified().getTime(),
item.getSize(),
item.getType())))
.collect(Collectors.toList());
}

Expand Down Expand Up @@ -213,6 +217,41 @@ public void close() throws Exception {
artifactory.close();
}

public static final class FileInfo implements Serializable {
private static final long serialVersionUID = 1L;
private final String path;
private final long lastUpdated;
private final long size;
private final AqlItemType type;

public FileInfo(String path, long lastUpdated, long size, AqlItemType type) {
this.path = path;
this.lastUpdated = lastUpdated;
this.size = size;
this.type = type;
}

public String getPath() {
return path;
}

public long getLastUpdated() {
return lastUpdated;

Check warning on line 239 in src/main/java/io/jenkins/plugins/artifactory_artifacts/ArtifactoryClient.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 239 is not covered by tests
}

public long getSize() {
return size;
}

public boolean isDirectory() {
return type.equals(AqlItemType.FOLDER);
}

public boolean isFile() {
return type.equals(AqlItemType.FILE);
}
}

public static final class ArtifactoryConfig implements Serializable {
private static final long serialVersionUID = 1L;
private final String serverUrl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import jenkins.util.VirtualFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -25,10 +25,18 @@ public class ArtifactoryVirtualFile extends ArtifactoryAbstractVirtualFile {
private final String key;

private final transient Run<?, ?> build;
private final ArtifactoryClient.FileInfo fileInfo;

public ArtifactoryVirtualFile(String key, Run<?, ?> build) {
this.key = key;
this.build = build;
this.fileInfo = null;
}

public ArtifactoryVirtualFile(ArtifactoryClient.FileInfo fileInfo, Run<?, ?> build) {
this.key = fileInfo.getPath();
this.build = build;
this.fileInfo = fileInfo;
}

public String getKey() {
Expand Down Expand Up @@ -65,6 +73,9 @@ public VirtualFile getParent() {

@Override
public boolean isDirectory() throws IOException {
if (this.fileInfo != null) {

Check warning on line 76 in src/main/java/io/jenkins/plugins/artifactory_artifacts/ArtifactoryVirtualFile.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 76 is only partially covered, one branch is missing
return this.fileInfo.isDirectory();
}
String keyWithNoSlash = Utils.stripTrailingSlash(this.key);
if (keyWithNoSlash.endsWith("/*view*")) {
return false;
Expand All @@ -79,6 +90,9 @@ public boolean isDirectory() throws IOException {

@Override
public boolean isFile() throws IOException {
if (this.fileInfo != null) {

Check warning on line 93 in src/main/java/io/jenkins/plugins/artifactory_artifacts/ArtifactoryVirtualFile.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 93 is only partially covered, one branch is missing
return this.fileInfo.isFile();
}
String keyS = this.key + "/";
if (keyS.endsWith("/*view*/")) {
return false;
Expand Down Expand Up @@ -116,6 +130,9 @@ public VirtualFile child(@NonNull String name) {

@Override
public long length() throws IOException {
if (this.fileInfo != null) {

Check warning on line 133 in src/main/java/io/jenkins/plugins/artifactory_artifacts/ArtifactoryVirtualFile.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 133 is only partially covered, one branch is missing
return this.fileInfo.getSize();
}
try (ArtifactoryClient client = buildArtifactoryClient()) {
return client.size(this.key);
} catch (Exception e) {
Expand All @@ -126,6 +143,9 @@ public long length() throws IOException {

@Override
public long lastModified() throws IOException {
if (this.fileInfo != null) {
return this.fileInfo.getLastUpdated();

Check warning on line 147 in src/main/java/io/jenkins/plugins/artifactory_artifacts/ArtifactoryVirtualFile.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 146-147 are not covered by tests
}
try (ArtifactoryClient client = buildArtifactoryClient()) {
return client.lastUpdated(this.key);
} catch (Exception e) {
Expand Down Expand Up @@ -168,12 +188,10 @@ private ArtifactoryClient buildArtifactoryClient() {
*/
private List<VirtualFile> listFilesFromPrefix(String prefix) {
try (ArtifactoryClient client = buildArtifactoryClient()) {
List<String> files = client.list(prefix);
List<VirtualFile> virtualFiles = new ArrayList<>();
for (String file : files) {
virtualFiles.add(new ArtifactoryVirtualFile(Utils.stripTrailingSlash(file), this.build));
}
return virtualFiles;
List<ArtifactoryClient.FileInfo> files = client.list(prefix);
return files.stream()
.map(info -> new ArtifactoryVirtualFile(info, this.build))
.collect(Collectors.toList());
} catch (Exception e) {
LOGGER.warn(String.format("Failed to list files from prefix %s", prefix), e);
return Collections.emptyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,6 @@ protected void setupWireMockStubs(
+ "\""
+ "}";

// JSON response for single artifact
String artifactResponse = "{"
+ "\"created\": \"2024-03-17T13:20:19.836Z\","
+ "\"createdBy\": \"admin\","
+ "\"lastModified\": \"2024-03-17T13:20:19.836Z\","
+ "\"lastUpdated\": \"2024-03-17T13:20:19.836Z\","
+ "\"modifiedBy\": \"admin\","
+ "\"path\": \"" + artifactBasePath + "/" + artifact + "\","
+ "\"repo\": \"my-generic-repo\","
+ "\"uri\": \"http://localhost:" + wmRuntimeInfo.getHttpPort() + "/artifactory" + artifactBasePath + "/"
+ artifact + "\""
+ "}";

String stashApiResponse = "{"
+ "\"created\": \"2024-03-17T13:20:19.836Z\","
+ "\"createdBy\": \"admin\","
Expand All @@ -106,16 +93,16 @@ protected void setupWireMockStubs(
+ "}";

// AQL response
String aqlResponse = "{\"results\": [{\"name\": \"" + artifact
+ "\", \"repo\": \"my-generic-repo\", \"path\": \"" + prefix + "/" + jobName + "/1/artifacts\"}]}";
String aqlResponse = "{\"results\": [{"
+ "\"name\": \"" + artifact
+ "\", \"type\": \"file\", \"modified\": \"2024-03-17T13:20:19.836Z\", \"size\": 1234,"
+ "\"repo\": \"my-generic-repo\", \"path\": \"" + prefix + "/" + jobName + "/1/artifacts\"}]}";

// Register GET requests

// Artifacts
wireMock.register(WireMock.get(WireMock.urlEqualTo(urlEncodeParts(artifactBasePath + "/")))
.willReturn(WireMock.okJson(artifactsResponse)));
wireMock.register(WireMock.get(WireMock.urlEqualTo(urlEncodeParts(artifactBasePath + "/" + artifact)))
.willReturn(WireMock.okJson(artifactResponse)));

// Stashes API
wireMock.register(WireMock.get(WireMock.urlEqualTo(urlEncodeParts(stashApiBasePath + "/" + stash)))
Expand Down

0 comments on commit 1828c15

Please sign in to comment.