Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to update a check run #980

Merged
merged 4 commits into from
Nov 24, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/main/java/org/kohsuke/github/GHCheckRun.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.kohsuke.github;

import com.fasterxml.jackson.annotation.JsonProperty;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import java.io.IOException;
Expand Down Expand Up @@ -292,4 +293,15 @@ public static enum AnnotationLevel {
NOTICE, WARNING, FAILURE
}

/**
* Updates this check run.
*
* @return a builder which you should customize, then call {@link GHCheckRunBuilder#create}
*/
@Preview
@Deprecated
public @NonNull GHCheckRunBuilder update() {
return new GHCheckRunBuilder(owner, getId());
}

}
35 changes: 25 additions & 10 deletions src/main/java/org/kohsuke/github/GHCheckRunBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,45 @@
import java.util.Locale;

/**
* Drafts a check run.
* Drafts or updates a check run.
*
* @see GHCheckRun
* @see GHRepository#createCheckRun
* @see <a href="https://developer.github.com/v3/checks/runs/#create-a-check-run">documentation</a>
* @see GHCheckRun#update()
* @see <a href="https://developer.github.com/v3/checks/runs/#update-a-check-run">documentation</a>
*/
@SuppressFBWarnings(value = "URF_UNREAD_FIELD", justification = "Jackson serializes these even without a getter")
@Preview
@Deprecated
public final class GHCheckRunBuilder {

private final GHRepository repo;
private final Requester requester;
protected final GHRepository repo;
protected final Requester requester;
private Output output;
private List<Action> actions;

GHCheckRunBuilder(GHRepository repo, String name, String headSHA) {
private GHCheckRunBuilder(GHRepository repo, Requester requester) {
this.repo = repo;
requester = repo.root.createRequest()
.withPreview(Previews.ANTIOPE)
.method("POST")
.with("name", name)
.with("head_sha", headSHA)
.withUrlPath(repo.getApiTailUrl("check-runs"));
this.requester = requester;
}

GHCheckRunBuilder(GHRepository repo, String name, String headSHA) {
this(repo,
repo.root.createRequest()
.withPreview(Previews.ANTIOPE)
.method("POST")
.with("name", name)
.with("head_sha", headSHA)
.withUrlPath(repo.getApiTailUrl("check-runs")));
}

GHCheckRunBuilder(GHRepository repo, long checkId) {
this(repo,
repo.root.createRequest()
.withPreview(Previews.ANTIOPE)
.method("PATCH")
.withUrlPath(repo.getApiTailUrl("check-runs/" + checkId)));
}

public @NonNull GHCheckRunBuilder withDetailsURL(@CheckForNull String detailsURL) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.kohsuke.github;

import io.jsonwebtoken.Jwts;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.Date;

public class AbstractGHAppInstallationTest extends AbstractGitHubWireMockTest {

private static String TEST_APP_ID_1 = "82994";
private static String TEST_APP_ID_2 = "83009";
private static String TEST_APP_ID_3 = "89368";
private static String PRIVATE_KEY_FILE_APP_1 = "/ghapi-test-app-1.private-key.pem";
private static String PRIVATE_KEY_FILE_APP_2 = "/ghapi-test-app-2.private-key.pem";
private static String PRIVATE_KEY_FILE_APP_3 = "/ghapi-test-app-3.private-key.pem";

private String createJwtToken(String keyFileResouceName, String appId) {
try {
String keyPEM = IOUtils.toString(this.getClass().getResource(keyFileResouceName), "US-ASCII")
.replaceAll("(?m)^--.*", "") // remove comments from PEM to allow decoding
.replaceAll("\\s", "");

PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyPEM));
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpecPKCS8);

return Jwts.builder()
.setIssuedAt(Date.from(Instant.now()))
.setExpiration(Date.from(Instant.now().plus(5, ChronoUnit.MINUTES)))
.setIssuer(appId)
.signWith(privateKey)
.compact();
} catch (Exception e) {
throw new RuntimeException("Error creating JWT token.", e);
}
}

private GHAppInstallation getAppInstallationWithToken(String jwtToken) throws IOException {
GitHub gitHub = getGitHubBuilder().withJwtToken(jwtToken)
.withEndpoint(mockGitHub.apiServer().baseUrl())
.build();

GHAppInstallation appInstallation = gitHub.getApp()
.listInstallations()
.toList()
.stream()
.filter(it -> it.getAccount().login.equals("hub4j-test-org"))
.findFirst()
.get();

appInstallation
.setRoot(getGitHubBuilder().withAppInstallationToken(appInstallation.createToken().create().getToken())
.withEndpoint(mockGitHub.apiServer().baseUrl())
.build());

return appInstallation;
}

protected GHAppInstallation getAppInstallationWithTokenApp1() throws IOException {
return getAppInstallationWithToken(createJwtToken(PRIVATE_KEY_FILE_APP_1, TEST_APP_ID_1));
}

protected GHAppInstallation getAppInstallationWithTokenApp2() throws IOException {
return getAppInstallationWithToken(createJwtToken(PRIVATE_KEY_FILE_APP_2, TEST_APP_ID_2));
}

protected GHAppInstallation getAppInstallationWithTokenApp3() throws IOException {
return getAppInstallationWithToken(createJwtToken(PRIVATE_KEY_FILE_APP_3, TEST_APP_ID_3));
}

}
65 changes: 2 additions & 63 deletions src/test/java/org/kohsuke/github/GHAppInstallationTest.java
Original file line number Diff line number Diff line change
@@ -1,72 +1,11 @@
package org.kohsuke.github;

import io.jsonwebtoken.Jwts;
import org.apache.commons.io.IOUtils;
import org.junit.Test;

import java.io.IOException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.List;

public class GHAppInstallationTest extends AbstractGitHubWireMockTest {

private static String TEST_APP_ID_1 = "82994";
private static String TEST_APP_ID_2 = "83009";
private static String PRIVATE_KEY_FILE_APP_1 = "/ghapi-test-app-1.private-key.pem";
private static String PRIVATE_KEY_FILE_APP_2 = "/ghapi-test-app-2.private-key.pem";

private String createJwtToken(String keyFileResouceName, String appId) {
try {
String keyPEM = IOUtils.toString(this.getClass().getResource(keyFileResouceName), "US-ASCII")
.replaceAll("(?m)^--.*", "") // remove comments from PEM to allow decoding
.replaceAll("\\s", "");

PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyPEM));
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpecPKCS8);

return Jwts.builder()
.setIssuedAt(Date.from(Instant.now()))
.setExpiration(Date.from(Instant.now().plus(5, ChronoUnit.MINUTES)))
.setIssuer(appId)
.signWith(privateKey)
.compact();
} catch (Exception e) {
throw new RuntimeException("Error creating JWT token.", e);
}
}

private GHAppInstallation getAppInstallationWithToken(String jwtToken) throws IOException {
GitHub gitHub = getGitHubBuilder().withJwtToken(jwtToken)
.withEndpoint(mockGitHub.apiServer().baseUrl())
.build();

GHAppInstallation appInstallation = gitHub.getApp()
.listInstallations()
.toList()
.stream()
.filter(it -> it.getAccount().login.equals("hub4j-test-org"))
.findFirst()
.get();

appInstallation
.setRoot(getGitHubBuilder().withAppInstallationToken(appInstallation.createToken().create().getToken())
.withEndpoint(mockGitHub.apiServer().baseUrl())
.build());

return appInstallation;
}

private GHAppInstallation getAppInstallationWithTokenApp1() throws IOException {
return getAppInstallationWithToken(createJwtToken(PRIVATE_KEY_FILE_APP_1, TEST_APP_ID_1));
}

private GHAppInstallation getAppInstallationWithTokenApp2() throws IOException {
return getAppInstallationWithToken(createJwtToken(PRIVATE_KEY_FILE_APP_2, TEST_APP_ID_2));
}
public class GHAppInstallationTest extends AbstractGHAppInstallationTest {

@Test
public void testListRepositoriesTwoRepos() throws IOException {
Expand Down
57 changes: 42 additions & 15 deletions src/test/java/org/kohsuke/github/GHCheckRunBuilderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,22 @@

import org.junit.Test;

import java.io.IOException;
import java.util.Date;

import static org.hamcrest.Matchers.containsString;

@SuppressWarnings("deprecation") // preview
public class GHCheckRunBuilderTest extends AbstractGitHubWireMockTest {
public class GHCheckRunBuilderTest extends AbstractGHAppInstallationTest {

protected GitHub getInstallationGithub() throws IOException {
return getAppInstallationWithTokenApp3().getRoot();
}

@Test
public void createCheckRun() throws Exception {
GHCheckRun checkRun = gitHub.getRepository("jglick/github-api-test")
.createCheckRun("foo", "4a929d464a2fae7ee899ce603250f7dab304bc4b")
GHCheckRun checkRun = getInstallationGithub().getRepository("hub4j-test-org/test-checks")
.createCheckRun("foo", "89a9ae301e35e667756034fdc933b1fc94f63fc1")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you needed to update existing tests? Once the mocks are created they should continue to work so long as you are not actually changing the behavior of the existing APIs, which AFAICT you are not.

Copy link
Collaborator

@timja timja Nov 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was to make it easier to update them for others by moving the tests to the test org and an app that others can use I believe (could be a separate pr)

.withStatus(GHCheckRun.Status.COMPLETED)
.withConclusion(GHCheckRun.Conclusion.SUCCESS)
.withDetailsURL("http://nowhere.net/stuff")
Expand All @@ -55,7 +60,7 @@ public void createCheckRun() throws Exception {
.create();
assertEquals("completed", checkRun.getStatus());
assertEquals(1, checkRun.getOutput().getAnnotationsCount());
assertEquals(546384586, checkRun.getId());
assertEquals(1424883286, checkRun.getId());
}

@Test
Expand All @@ -65,46 +70,46 @@ public void createCheckRunManyAnnotations() throws Exception {
output.add(
new GHCheckRunBuilder.Annotation("stuff.txt", 1, GHCheckRun.AnnotationLevel.NOTICE, "hello #" + i));
}
GHCheckRun checkRun = gitHub.getRepository("jglick/github-api-test")
.createCheckRun("big", "4a929d464a2fae7ee899ce603250f7dab304bc4b")
GHCheckRun checkRun = getInstallationGithub().getRepository("hub4j-test-org/test-checks")
.createCheckRun("big", "89a9ae301e35e667756034fdc933b1fc94f63fc1")
.withConclusion(GHCheckRun.Conclusion.SUCCESS)
.add(output)
.create();
assertEquals("completed", checkRun.getStatus());
assertEquals("Big Run", checkRun.getOutput().getTitle());
assertEquals("Lots of stuff here »", checkRun.getOutput().getSummary());
assertEquals(101, checkRun.getOutput().getAnnotationsCount());
assertEquals(546384622, checkRun.getId());
assertEquals(1424883599, checkRun.getId());
}

@Test
public void createCheckRunNoAnnotations() throws Exception {
GHCheckRun checkRun = gitHub.getRepository("jglick/github-api-test")
.createCheckRun("quick", "4a929d464a2fae7ee899ce603250f7dab304bc4b")
GHCheckRun checkRun = getInstallationGithub().getRepository("hub4j-test-org/test-checks")
.createCheckRun("quick", "89a9ae301e35e667756034fdc933b1fc94f63fc1")
.withConclusion(GHCheckRun.Conclusion.NEUTRAL)
.add(new GHCheckRunBuilder.Output("Quick note", "nothing more to see here"))
.create();
assertEquals("completed", checkRun.getStatus());
assertEquals(0, checkRun.getOutput().getAnnotationsCount());
assertEquals(546384705, checkRun.getId());
assertEquals(1424883957, checkRun.getId());
}

@Test
public void createPendingCheckRun() throws Exception {
GHCheckRun checkRun = gitHub.getRepository("jglick/github-api-test")
.createCheckRun("outstanding", "4a929d464a2fae7ee899ce603250f7dab304bc4b")
GHCheckRun checkRun = getInstallationGithub().getRepository("hub4j-test-org/test-checks")
.createCheckRun("outstanding", "89a9ae301e35e667756034fdc933b1fc94f63fc1")
.withStatus(GHCheckRun.Status.IN_PROGRESS)
.create();
assertEquals("in_progress", checkRun.getStatus());
assertNull(checkRun.getConclusion());
assertEquals(546469053, checkRun.getId());
assertEquals(1424883451, checkRun.getId());
}

@Test
public void createCheckRunErrMissingConclusion() throws Exception {
try {
gitHub.getRepository("jglick/github-api-test")
.createCheckRun("outstanding", "4a929d464a2fae7ee899ce603250f7dab304bc4b")
getInstallationGithub().getRepository("hub4j-test-org/test-checks")
.createCheckRun("outstanding", "89a9ae301e35e667756034fdc933b1fc94f63fc1")
.withStatus(GHCheckRun.Status.COMPLETED)
.create();
fail("should have been rejected");
Expand All @@ -114,4 +119,26 @@ public void createCheckRunErrMissingConclusion() throws Exception {
}
}

@Test
public void updateCheckRun() throws Exception {
GHCheckRun checkRun = getInstallationGithub().getRepository("hub4j-test-org/test-checks")
.createCheckRun("foo", "89a9ae301e35e667756034fdc933b1fc94f63fc1")
.withStatus(GHCheckRun.Status.IN_PROGRESS)
.withStartedAt(new Date(999_999_000))
.add(new GHCheckRunBuilder.Output("Some Title", "what happened…")
.add(new GHCheckRunBuilder.Annotation("stuff.txt",
1,
GHCheckRun.AnnotationLevel.NOTICE,
"hello to you too").withTitle("Look here")))
.create();
GHCheckRun updated = checkRun.update()
.withStatus(GHCheckRun.Status.COMPLETED)
.withConclusion(GHCheckRun.Conclusion.SUCCESS)
.withCompletedAt(new Date(999_999_999))
.create();
assertEquals(updated.getStartedAt(), new Date(999_999_000));
assertEquals(updated.getName(), "foo");
assertEquals(1, checkRun.getOutput().getAnnotationsCount());
}

}
28 changes: 28 additions & 0 deletions src/test/resources/ghapi-test-app-3.private-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4vG2q4zLRcQGe
5Z4seo8LY2hROKkdy4LmA96TeCxwDd/bnFIIQGmWMZHVZkyruuLLArTt50/mJ4yC
ggedRiw8CmH8s6iQmZQyRu+6gKVqm5KozQ2omniGAJU6KqZTbUUpvytpmmcWcoLU
eMoLCJTScRK2rofbiSCFy1WwlyVe1b+nBNf2b9VG9bE461K47kgk1cI1/TqZ3QeI
jc/0jV+w7qdTdCqD5A2FyFZa5mU6jj83bVyC0O0AlZlEnwHN58vvN3j7uljF6Mh0
sx+0xtRjmTncl7puUhpQBJrH/pIfjuY5MAefMaOAhXMZM3lZyh75URlO3vh1KKwQ
EJcdCi+FAgMBAAECggEARDIDBf+DJf/iikbXgjHoFlsnCjyxaXdUJhctliDZvq/Q
gKCPQ86La892t2FhUk/WIv0nz18BhsP4wcDAkNVzxOJMU936jw6yv3CiVKXi6pzt
ofS4YxJLBaS3cdaGuetvib6xhvVhss6o70h7xWDwl1L4homdS3SuldV/F4ZkXEJI
v5uyh0TFy44dSS01muJQfZHXGF7Pvqx18CY8p/NSOKTYJRghSI3GiLOD7S12GHi1
dBVp3D9roXCFUG0zijIIntcWnQGoCr71GwQHlwg0hPz3v/lOQZBB814+j5tUKw78
zrXAAIb9yQbsNkmY5rVm69kg+ixG0uq9JVqJmkBvrQKBgQDrmJGuQrfuzE5PoYJC
SYNOzjjTgTc3mCW6mqBTmngOUV/DEX5aLVzMxaHCIuslNjB1Ila6Hg4Am2SFFiUj
OSVZPBe/A+EGU6itxwCzTj7M4jQtVfWRsq8IjaLm0A222RhDp9D/Zc5/T6563obW
n4GT/HOM95CvoYvjdcULPOqWVwKBgQDIvDylKw3dRQm3q2IX34JjFMrJM+wzDXAv
lIsURQFI/jezos95CGS0ArgG0gNn0117ul++N1Tt44YFDOqbG9kzS9ccYukRIe+v
knVkogtXPwLoWR8amOyK2SP7P2DSkrZsE3HRRWhzNARs8RTfa5stp9eKKyrYyXAF
28RC7agngwKBgQDEKCWzd615T/Yr6wdvdZG0fZNm1oFI8o8HTVMMCOLI2QvoeJpB
Lt/DRxGleDlcpD+4ZzzafceezcLl5EhLiXsFTzleOzaSc/lPpw94Oz+iivxyes2Z
37JIZtUpZDTm9t5zBjjHTNafvZJCjyCpdekHc/wpdL6s3M6CNj43WyLexQKBgCDL
eBD39rzmsY67RjxmPLQZSoQSoo04rdJoL0yxdWNKfSkw+Tpp36H1K8GZgArvYj97
lHbMLWjsGhIrKQ0MQLD7u/ocQr2U0MbbY6h8POQVHFF/dfBveX25ugIrOZNNetYv
WxH4h/cCUZLG1EUoHGMaH8GoCcj/J/kdDXRtxWInAoGAQbJ/6Ry5+cLGYgt6e/7Z
33wvwVjRmeZxAiE+msdKqXljGmxHKvat3l4eURh1CSqJ5tw0+J/LzXF2WrK8ncQj
d3S4tPQW7yMBxXhJuFNczowmB8QiXFQCAdFe9sMRYyRe7EHJSNYEFjPuPDEVIfwO
nqEDUjQ6neGvMei09uX1eVk=
-----END PRIVATE KEY-----
Loading