Skip to content

Commit 064d694

Browse files
authored
Merge pull request #1081 from gsmet/workflow-jobs
Add support for workflow jobs
2 parents 578fe08 + 18e7138 commit 064d694

File tree

30 files changed

+5236
-30
lines changed

30 files changed

+5236
-30
lines changed

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3052,6 +3052,22 @@ public GHArtifact getArtifact(long id) throws IOException {
30523052
.wrapUp(this);
30533053
}
30543054

3055+
/**
3056+
* Gets a job from a workflow run by id.
3057+
*
3058+
* @param id
3059+
* the id of the job
3060+
* @return the job
3061+
* @throws IOException
3062+
* the io exception
3063+
*/
3064+
public GHWorkflowJob getWorkflowJob(long id) throws IOException {
3065+
return root.createRequest()
3066+
.withUrlPath(getApiTailUrl("/actions/jobs/"), String.valueOf(id))
3067+
.fetch(GHWorkflowJob.class)
3068+
.wrapUp(this);
3069+
}
3070+
30553071
// Only used within listTopics().
30563072
private static class Topics {
30573073
public List<String> names;
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
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.GHWorkflowRun.Conclusion;
6+
import org.kohsuke.github.GHWorkflowRun.Status;
7+
import org.kohsuke.github.function.InputStreamFunction;
8+
9+
import java.io.IOException;
10+
import java.net.URL;
11+
import java.util.ArrayList;
12+
import java.util.Date;
13+
import java.util.List;
14+
import java.util.Objects;
15+
16+
import static java.util.Objects.requireNonNull;
17+
18+
/**
19+
* A workflow run job.
20+
*
21+
* @author Guillaume Smet
22+
*/
23+
public class GHWorkflowJob extends GHObject {
24+
25+
// Not provided by the API.
26+
@JsonIgnore
27+
private GHRepository owner;
28+
29+
private String name;
30+
31+
private String headSha;
32+
33+
private String startedAt;
34+
private String completedAt;
35+
36+
private String status;
37+
private String conclusion;
38+
39+
private long runId;
40+
41+
private String htmlUrl;
42+
private String checkRunUrl;
43+
44+
private List<Step> steps = new ArrayList<>();
45+
46+
/**
47+
* The name of the job.
48+
*
49+
* @return the name
50+
*/
51+
public String getName() {
52+
return name;
53+
}
54+
55+
/**
56+
* Gets the HEAD SHA.
57+
*
58+
* @return sha for the HEAD commit
59+
*/
60+
public String getHeadSha() {
61+
return headSha;
62+
}
63+
64+
/**
65+
* When was this job started?
66+
*
67+
* @return start date
68+
*/
69+
public Date getStartedAt() {
70+
return GitHubClient.parseDate(startedAt);
71+
}
72+
73+
/**
74+
* When was this job completed?
75+
*
76+
* @return completion date
77+
*/
78+
public Date getCompletedAt() {
79+
return GitHubClient.parseDate(completedAt);
80+
}
81+
82+
/**
83+
* Gets status of the job.
84+
* <p>
85+
* Can be {@code UNKNOWN} if the value returned by GitHub is unknown from the API.
86+
*
87+
* @return status of the job
88+
*/
89+
public Status getStatus() {
90+
return Status.from(status);
91+
}
92+
93+
/**
94+
* Gets the conclusion of the job.
95+
* <p>
96+
* Can be {@code UNKNOWN} if the value returned by GitHub is unknown from the API.
97+
*
98+
* @return conclusion of the job
99+
*/
100+
public Conclusion getConclusion() {
101+
return Conclusion.from(conclusion);
102+
}
103+
104+
/**
105+
* The run id.
106+
*
107+
* @return the run id
108+
*/
109+
public long getRunId() {
110+
return runId;
111+
}
112+
113+
@Override
114+
public URL getHtmlUrl() {
115+
return GitHubClient.parseURL(htmlUrl);
116+
}
117+
118+
/**
119+
* The check run URL.
120+
*
121+
* @return the check run url
122+
*/
123+
public URL getCheckRunUrl() {
124+
return GitHubClient.parseURL(checkRunUrl);
125+
}
126+
127+
/**
128+
* Gets the execution steps of this job.
129+
*
130+
* @return the execution steps
131+
*/
132+
public List<Step> getSteps() {
133+
return steps;
134+
}
135+
136+
/**
137+
* Repository to which the job belongs.
138+
*
139+
* @return the repository
140+
*/
141+
public GHRepository getRepository() {
142+
return owner;
143+
}
144+
145+
/**
146+
* Downloads the logs.
147+
* <p>
148+
* The logs are returned as a text file.
149+
*
150+
* @param <T>
151+
* the type of result
152+
* @param streamFunction
153+
* The {@link InputStreamFunction} that will process the stream
154+
* @throws IOException
155+
* The IO exception.
156+
* @return the result of reading the stream.
157+
*/
158+
public <T> T downloadLogs(InputStreamFunction<T> streamFunction) throws IOException {
159+
requireNonNull(streamFunction, "Stream function must not be null");
160+
161+
return root.createRequest().method("GET").withUrlPath(getApiRoute(), "logs").fetchStream(streamFunction);
162+
}
163+
164+
private String getApiRoute() {
165+
if (owner == null) {
166+
// Workflow runs returned from search to do not have an owner. Attempt to use url.
167+
final URL url = Objects.requireNonNull(getUrl(), "Missing instance URL!");
168+
return StringUtils.prependIfMissing(url.toString().replace(root.getApiUrl(), ""), "/");
169+
170+
}
171+
return "/repos/" + owner.getOwnerName() + "/" + owner.getName() + "/actions/jobs/" + getId();
172+
}
173+
174+
GHWorkflowJob wrapUp(GHRepository owner) {
175+
this.owner = owner;
176+
return wrapUp(owner.root);
177+
}
178+
179+
GHWorkflowJob wrapUp(GitHub root) {
180+
this.root = root;
181+
if (owner != null) {
182+
owner.wrap(root);
183+
}
184+
return this;
185+
}
186+
187+
public static class Step {
188+
189+
private String name;
190+
private int number;
191+
192+
private String startedAt;
193+
private String completedAt;
194+
195+
private String status;
196+
private String conclusion;
197+
198+
/**
199+
* Gets the name of the step.
200+
*
201+
* @return name
202+
*/
203+
public String getName() {
204+
return name;
205+
}
206+
207+
/**
208+
* Gets the sequential number of the step.
209+
*
210+
* @return number
211+
*/
212+
public int getNumber() {
213+
return number;
214+
}
215+
216+
/**
217+
* When was this step started?
218+
*
219+
* @return start date
220+
*/
221+
public Date getStartedAt() {
222+
return GitHubClient.parseDate(startedAt);
223+
}
224+
225+
/**
226+
* When was this step completed?
227+
*
228+
* @return completion date
229+
*/
230+
public Date getCompletedAt() {
231+
return GitHubClient.parseDate(completedAt);
232+
}
233+
234+
/**
235+
* Gets status of the step.
236+
* <p>
237+
* Can be {@code UNKNOWN} if the value returned by GitHub is unknown from the API.
238+
*
239+
* @return status of the step
240+
*/
241+
public Status getStatus() {
242+
return Status.from(status);
243+
}
244+
245+
/**
246+
* Gets the conclusion of the step.
247+
* <p>
248+
* Can be {@code UNKNOWN} if the value returned by GitHub is unknown from the API.
249+
*
250+
* @return conclusion of the step
251+
*/
252+
public Conclusion getConclusion() {
253+
return Conclusion.from(conclusion);
254+
}
255+
}
256+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.kohsuke.github;
2+
3+
import java.net.MalformedURLException;
4+
5+
/**
6+
* Lists up jobs of a workflow run with some filtering.
7+
*
8+
* @author Guillaume Smet
9+
*/
10+
public class GHWorkflowJobQueryBuilder extends GHQueryBuilder<GHWorkflowJob> {
11+
private final GHRepository repo;
12+
13+
GHWorkflowJobQueryBuilder(GHWorkflowRun workflowRun) {
14+
super(workflowRun.getRepository().root);
15+
this.repo = workflowRun.getRepository();
16+
req.withUrlPath(repo.getApiTailUrl("actions/runs"), String.valueOf(workflowRun.getId()), "jobs");
17+
}
18+
19+
/**
20+
* Apply a filter to only return the jobs of the most recent execution of the workflow run.
21+
*
22+
* @return the workflow run job query builder
23+
*/
24+
public GHWorkflowJobQueryBuilder latest() {
25+
req.with("filter", "latest");
26+
return this;
27+
}
28+
29+
/**
30+
* Apply a filter to return jobs from all executions of this workflow run.
31+
*
32+
* @return the workflow run job run query builder
33+
*/
34+
public GHWorkflowJobQueryBuilder all() {
35+
req.with("filter", "all");
36+
return this;
37+
}
38+
39+
@Override
40+
public PagedIterable<GHWorkflowJob> list() {
41+
try {
42+
return new GHWorkflowJobsIterable(repo, req.build());
43+
} catch (MalformedURLException e) {
44+
throw new GHException(e.getMessage(), e);
45+
}
46+
}
47+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.kohsuke.github;
2+
3+
import java.util.Iterator;
4+
5+
import javax.annotation.Nonnull;
6+
7+
/**
8+
* Iterable for workflow run jobs listing.
9+
*/
10+
class GHWorkflowJobsIterable extends PagedIterable<GHWorkflowJob> {
11+
private final GHRepository repo;
12+
private final GitHubRequest request;
13+
14+
private GHWorkflowJobsPage result;
15+
16+
public GHWorkflowJobsIterable(GHRepository repo, GitHubRequest request) {
17+
this.repo = repo;
18+
this.request = request;
19+
}
20+
21+
@Nonnull
22+
@Override
23+
public PagedIterator<GHWorkflowJob> _iterator(int pageSize) {
24+
return new PagedIterator<>(
25+
adapt(GitHubPageIterator.create(repo.root.getClient(), GHWorkflowJobsPage.class, request, pageSize)),
26+
null);
27+
}
28+
29+
protected Iterator<GHWorkflowJob[]> adapt(final Iterator<GHWorkflowJobsPage> base) {
30+
return new Iterator<GHWorkflowJob[]>() {
31+
public boolean hasNext() {
32+
return base.hasNext();
33+
}
34+
35+
public GHWorkflowJob[] next() {
36+
GHWorkflowJobsPage v = base.next();
37+
if (result == null) {
38+
result = v;
39+
}
40+
return v.getWorkflowJobs(repo);
41+
}
42+
};
43+
}
44+
}
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 jobs result when listing jobs from a workflow run.
5+
*/
6+
class GHWorkflowJobsPage {
7+
private int total_count;
8+
private GHWorkflowJob[] jobs;
9+
10+
public int getTotalCount() {
11+
return total_count;
12+
}
13+
14+
GHWorkflowJob[] getWorkflowJobs(GHRepository repo) {
15+
for (GHWorkflowJob job : jobs) {
16+
job.wrapUp(repo);
17+
}
18+
return jobs;
19+
}
20+
}

0 commit comments

Comments
 (0)