Skip to content

Commit 78ffe5a

Browse files
authored
Merge pull request #1075 from gsmet/more-workflows
Add support for artifacts and logs of workflow runs
2 parents feba6ed + 9abfdc8 commit 78ffe5a

File tree

51 files changed

+9261
-16
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+9261
-16
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package org.kohsuke.github;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnore;
4+
import org.apache.commons.lang3.StringUtils;
5+
import org.kohsuke.github.function.InputStreamFunction;
6+
7+
import java.io.IOException;
8+
import java.net.URL;
9+
import java.util.Date;
10+
import java.util.Objects;
11+
12+
import static java.util.Objects.requireNonNull;
13+
14+
/**
15+
* An artifact from a workflow run.
16+
*
17+
* @author Guillaume Smet
18+
*/
19+
public class GHArtifact extends GHObject {
20+
21+
// Not provided by the API.
22+
@JsonIgnore
23+
private GHRepository owner;
24+
25+
private String name;
26+
private long sizeInBytes;
27+
private String archiveDownloadUrl;
28+
private boolean expired;
29+
private String expiresAt;
30+
31+
public String getName() {
32+
return name;
33+
}
34+
35+
public long getSizeInBytes() {
36+
return sizeInBytes;
37+
}
38+
39+
public URL getArchiveDownloadUrl() {
40+
return GitHubClient.parseURL(archiveDownloadUrl);
41+
}
42+
43+
public boolean isExpired() {
44+
return expired;
45+
}
46+
47+
public Date getExpiresAt() {
48+
return GitHubClient.parseDate(expiresAt);
49+
}
50+
51+
/**
52+
* @deprecated This object has no HTML URL.
53+
*/
54+
@Override
55+
public URL getHtmlUrl() throws IOException {
56+
return null;
57+
}
58+
59+
/**
60+
* Deletes the artifact.
61+
*
62+
* @throws IOException
63+
* the io exception
64+
*/
65+
public void delete() throws IOException {
66+
root.createRequest().method("DELETE").withUrlPath(getApiRoute()).fetchHttpStatusCode();
67+
}
68+
69+
/**
70+
* Downloads the artifact.
71+
*
72+
* @param <T>
73+
* the type of result
74+
* @param streamFunction
75+
* The {@link InputStreamFunction} that will process the stream
76+
* @throws IOException
77+
* The IO exception.
78+
* @return the result of reading the stream.
79+
*/
80+
public <T> T download(InputStreamFunction<T> streamFunction) throws IOException {
81+
requireNonNull(streamFunction, "Stream function must not be null");
82+
83+
return root.createRequest().method("GET").withUrlPath(getApiRoute(), "zip").fetchStream(streamFunction);
84+
}
85+
86+
private String getApiRoute() {
87+
if (owner == null) {
88+
// Workflow runs returned from search to do not have an owner. Attempt to use url.
89+
final URL url = Objects.requireNonNull(getUrl(), "Missing instance URL!");
90+
return StringUtils.prependIfMissing(url.toString().replace(root.getApiUrl(), ""), "/");
91+
}
92+
return "/repos/" + owner.getOwnerName() + "/" + owner.getName() + "/actions/artifacts/" + getId();
93+
}
94+
95+
GHArtifact wrapUp(GHRepository owner) {
96+
this.owner = owner;
97+
return wrapUp(owner.root);
98+
}
99+
100+
GHArtifact wrapUp(GitHub root) {
101+
this.root = root;
102+
if (owner != null)
103+
owner.wrap(root);
104+
return this;
105+
}
106+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.kohsuke.github;
2+
3+
import java.net.MalformedURLException;
4+
import java.util.Iterator;
5+
6+
import javax.annotation.Nonnull;
7+
8+
/**
9+
* Iterable for artifacts listing.
10+
*/
11+
class GHArtifactsIterable extends PagedIterable<GHArtifact> {
12+
private final transient GHRepository owner;
13+
private final GitHubRequest request;
14+
15+
private GHArtifactsPage result;
16+
17+
public GHArtifactsIterable(GHRepository owner, GitHubRequest.Builder<?> requestBuilder) {
18+
this.owner = owner;
19+
try {
20+
this.request = requestBuilder.build();
21+
} catch (MalformedURLException e) {
22+
throw new GHException("Malformed URL", e);
23+
}
24+
}
25+
26+
@Nonnull
27+
@Override
28+
public PagedIterator<GHArtifact> _iterator(int pageSize) {
29+
return new PagedIterator<>(
30+
adapt(GitHubPageIterator.create(owner.getRoot().getClient(), GHArtifactsPage.class, request, pageSize)),
31+
null);
32+
}
33+
34+
protected Iterator<GHArtifact[]> adapt(final Iterator<GHArtifactsPage> base) {
35+
return new Iterator<GHArtifact[]>() {
36+
public boolean hasNext() {
37+
return base.hasNext();
38+
}
39+
40+
public GHArtifact[] next() {
41+
GHArtifactsPage v = base.next();
42+
if (result == null) {
43+
result = v;
44+
}
45+
return v.getArtifacts(owner);
46+
}
47+
};
48+
}
49+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.kohsuke.github;
2+
3+
/**
4+
* Represents the one page of artifacts result when listing artifacts.
5+
*/
6+
class GHArtifactsPage {
7+
private int total_count;
8+
private GHArtifact[] artifacts;
9+
10+
public int getTotalCount() {
11+
return total_count;
12+
}
13+
14+
GHArtifact[] getArtifacts(GHRepository owner) {
15+
for (GHArtifact artifact : artifacts) {
16+
artifact.wrapUp(owner);
17+
}
18+
return artifacts;
19+
}
20+
}

src/main/java/org/kohsuke/github/GHEventPayload.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,13 +1400,11 @@ void wrapUp(GitHub root) {
14001400
"Expected workflow and workflow_run payload, but got something else. Maybe we've got another type of event?");
14011401
}
14021402
GHRepository repository = getRepository();
1403-
if (repository != null) {
1404-
workflowRun.wrapUp(repository);
1405-
workflow.wrapUp(repository);
1406-
} else {
1407-
workflowRun.wrapUp(root);
1408-
workflow.wrapUp(root);
1403+
if (repository == null) {
1404+
throw new IllegalStateException("Repository must not be null");
14091405
}
1406+
workflowRun.wrapUp(repository);
1407+
workflow.wrapUp(repository);
14101408
}
14111409
}
14121410
}

src/main/java/org/kohsuke/github/GHRepository.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,15 @@
5656

5757
import javax.annotation.Nonnull;
5858

59-
import static java.util.Arrays.*;
59+
import static java.util.Arrays.asList;
6060
import static java.util.Objects.requireNonNull;
61-
import static org.kohsuke.github.internal.Previews.*;
61+
import static org.kohsuke.github.internal.Previews.ANTIOPE;
62+
import static org.kohsuke.github.internal.Previews.ANT_MAN;
63+
import static org.kohsuke.github.internal.Previews.BAPTISTE;
64+
import static org.kohsuke.github.internal.Previews.FLASH;
65+
import static org.kohsuke.github.internal.Previews.INERTIA;
66+
import static org.kohsuke.github.internal.Previews.MERCY;
67+
import static org.kohsuke.github.internal.Previews.SHADOW_CAT;
6268

6369
/**
6470
* A repository on GitHub.
@@ -2961,6 +2967,31 @@ public GHWorkflowRun getWorkflowRun(long id) throws IOException {
29612967
.wrapUp(this);
29622968
}
29632969

2970+
/**
2971+
* Lists all the artifacts of this repository.
2972+
*
2973+
* @return the paged iterable
2974+
*/
2975+
public PagedIterable<GHArtifact> listArtifacts() {
2976+
return new GHArtifactsIterable(this, root.createRequest().withUrlPath(getApiTailUrl("actions/artifacts")));
2977+
}
2978+
2979+
/**
2980+
* Gets an artifact by id.
2981+
*
2982+
* @param id
2983+
* the id of the artifact
2984+
* @return the artifact
2985+
* @throws IOException
2986+
* the io exception
2987+
*/
2988+
public GHArtifact getArtifact(long id) throws IOException {
2989+
return root.createRequest()
2990+
.withUrlPath(getApiTailUrl("actions/artifacts"), String.valueOf(id))
2991+
.fetch(GHArtifact.class)
2992+
.wrapUp(this);
2993+
}
2994+
29642995
// Only used within listTopics().
29652996
private static class Topics {
29662997
public List<String> names;

src/main/java/org/kohsuke/github/GHWorkflowRun.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fasterxml.jackson.annotation.JsonProperty;
44
import org.apache.commons.lang3.StringUtils;
5+
import org.kohsuke.github.function.InputStreamFunction;
56
import org.kohsuke.github.internal.EnumUtils;
67

78
import java.io.IOException;
@@ -13,6 +14,8 @@
1314
import java.util.Locale;
1415
import java.util.Objects;
1516

17+
import static java.util.Objects.requireNonNull;
18+
1619
/**
1720
* A workflow run.
1821
*
@@ -261,6 +264,45 @@ public void rerun() throws IOException {
261264
root.createRequest().method("POST").withUrlPath(getApiRoute(), "rerun").fetchHttpStatusCode();
262265
}
263266

267+
/**
268+
* Lists the artifacts attached to this workflow run.
269+
*
270+
* @return the paged iterable
271+
*/
272+
public PagedIterable<GHArtifact> listArtifacts() {
273+
return new GHArtifactsIterable(owner, root.createRequest().withUrlPath(getApiRoute(), "artifacts"));
274+
}
275+
276+
/**
277+
* Downloads the logs.
278+
* <p>
279+
* The logs are in the form of a zip archive. The full log file is at the root and called {@code 1_build.txt}. Split
280+
* log files are also available in the {@code build} directory.
281+
*
282+
* @param <T>
283+
* the type of result
284+
* @param streamFunction
285+
* The {@link InputStreamFunction} that will process the stream
286+
* @throws IOException
287+
* The IO exception.
288+
* @return the result of reading the stream.
289+
*/
290+
public <T> T downloadLogs(InputStreamFunction<T> streamFunction) throws IOException {
291+
requireNonNull(streamFunction, "Stream function must not be null");
292+
293+
return root.createRequest().method("GET").withUrlPath(getApiRoute(), "logs").fetchStream(streamFunction);
294+
}
295+
296+
/**
297+
* Delete the logs.
298+
*
299+
* @throws IOException
300+
* the io exception
301+
*/
302+
public void deleteLogs() throws IOException {
303+
root.createRequest().method("DELETE").withUrlPath(getApiRoute(), "logs").fetchHttpStatusCode();
304+
}
305+
264306
private String getApiRoute() {
265307
if (owner == null) {
266308
// Workflow runs returned from search to do not have an owner. Attempt to use url.

src/main/java/org/kohsuke/github/GHWorkflowRunQueryBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public GHWorkflowRunQueryBuilder status(Status status) {
9393
@Override
9494
public PagedIterable<GHWorkflowRun> list() {
9595
try {
96-
return new GHWorkflowRunsIterable(root, req.withUrlPath(repo.getApiTailUrl("actions/runs")).build());
96+
return new GHWorkflowRunsIterable(repo, req.withUrlPath(repo.getApiTailUrl("actions/runs")).build());
9797
} catch (MalformedURLException e) {
9898
throw new GHException(e.getMessage(), e);
9999
}

src/main/java/org/kohsuke/github/GHWorkflowRunsIterable.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,22 @@
88
* Iterable for workflow runs listing.
99
*/
1010
class GHWorkflowRunsIterable extends PagedIterable<GHWorkflowRun> {
11-
private final transient GitHub root;
11+
private final GHRepository owner;
1212
private final GitHubRequest request;
1313

1414
private GHWorkflowRunsPage result;
1515

16-
public GHWorkflowRunsIterable(GitHub root, GitHubRequest request) {
17-
this.root = root;
16+
public GHWorkflowRunsIterable(GHRepository owner, GitHubRequest request) {
17+
this.owner = owner;
1818
this.request = request;
1919
}
2020

2121
@Nonnull
2222
@Override
2323
public PagedIterator<GHWorkflowRun> _iterator(int pageSize) {
2424
return new PagedIterator<>(
25-
adapt(GitHubPageIterator.create(root.getClient(), GHWorkflowRunsPage.class, request, pageSize)),
25+
adapt(GitHubPageIterator
26+
.create(owner.getRoot().getClient(), GHWorkflowRunsPage.class, request, pageSize)),
2627
null);
2728
}
2829

@@ -37,7 +38,7 @@ public GHWorkflowRun[] next() {
3738
if (result == null) {
3839
result = v;
3940
}
40-
return v.getWorkflowRuns(root);
41+
return v.getWorkflowRuns(owner);
4142
}
4243
};
4344
}

src/main/java/org/kohsuke/github/GHWorkflowRunsPage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ public int getTotalCount() {
1111
return totalCount;
1212
}
1313

14-
GHWorkflowRun[] getWorkflowRuns(GitHub root) {
14+
GHWorkflowRun[] getWorkflowRuns(GHRepository owner) {
1515
for (GHWorkflowRun workflowRun : workflowRuns) {
16-
workflowRun.wrapUp(root);
16+
workflowRun.wrapUp(owner);
1717
}
1818
return workflowRuns;
1919
}

0 commit comments

Comments
 (0)